USB Libraries Help > USB Host Libraries > USB Host Layer Library > Using the Library > How the Library Works > Host Layer Initialization
MPLAB Harmony USB Stack
Host Layer Initialization

The Host Layer must be initialized with relevant data to enable correct operation. This initialization must be performed in the SYS_Initialize function of the MPLAB Harmony application. The Host Layer will require the USB Controller Peripheral driver to be initialized for host mode operation (and hence operate as a HCD). This initialization must be performed in the SYS_Initialize function. The order in which the Host Layer and the USB Peripheral Driver are initialized does not affect the Host Layer operation. The Host Layer could be initialized before or after the USB Controller Peripheral Driver initialization. 

The Host Layer requires the following information for initialization:

  • The HCD interface for each bus
  • The Target Peripheral List (TPL)

The Host Layer is capable of operating more than one USB device. This is possible on PIC32 microcontrollers that feature multiple USB Controller Peripherals. The one instance of the Host Layer manages multiple HCDs. The interface to each to every instance of the HCD that the Host Layer must operate must be specified in the Host Layer initialization. The total number of USB devices the Host Layer should manage is defined statically by the USB_HOST_CONTROLLERS_NUMBER configuration macro in the system_config.h file. The following code shows an example initialization of a PIC32MX USB HCD. 

Example: PIC32MZ USB HCD Initialization  

/* This code shows an example of how to initialize the PIC32MX USB
 * Driver for host mode operation. For more details on the PIC32MX Full-Speed
 * USB Driver, please refer to the Driver Libraries documentation. */

/* Include the full-speed USB driver header file */
#include "driver/usb/usbfs/drv_usbfs.h"

/* Create a driver initialization data structure */
DRV_USBFS_INIT drvUSBFSInit;

/* The PIC32MX Full-Speed USB Driver when operating in host mode requires an
 * endpoint table (a byte array) whose size should be 32 bytes. This table should
 * be aligned at 512 byte address boundary */
uint8_t __attribute__((aligned(512))) endpointTable[32];

/* Configure the driver initialization data structure */
DRV_USBFS_INIT drvUSBFSInit =
{
    /* This parameter should be set to SYS_MODULE_POWER_RUN_FULL. */
    .moduleInit = {SYS_MODULE_POWER_RUN_FULL},

    /* Driver operates in Host mode */
    .operationMode = USB_OPMODE_HOST,

    /* USB module interrupt source */
    .interruptSource = INT_SOURCE_USB_1,

    /* Continue operation when CPU is in Idle mode */
    .stopInIdle = false,

    /* Do not suspend operation when CPU enters Sleep mode */
    .suspendInSleep = false,

    /* The USB module index */
    .usbID = USB_ID_1,

    /* The maximum current that the VBUS supply can provide */
    .rootHubAvailableCurrent = 500,

    /* Pointer to the endpoint table */
    .endpointTable = endpointTable,

    /* Pointer to the Port Power Enable function. Driver will cause this
     * function when the port power must be enabled */
    .portPowerEnable = PortPowerEnable,

    /* Pointer to the Port Over Current Detect function. Driver will cause this
     * function periodically to check if the port current has exceeded limit */
    .portOverCurrentDetect = PortOverCurrentDetect,

    /* Pointer to the Port LED indication function. The driver will call this
     * function to update the Port LED status */
    .portIndication = PortIndication

};

/* USB Driver system module object */
SYS_MODULE_OBJ drvUSBObj = SYS_MODULE_OBJ_INVALID;

void SYS_Initialize(void * data)
{
    /* Initialize the driver */
    drvUSBObj = DRV_USBFS_Initialize(DRV_USBFS_INDEX_0, (SYS_MODULE_INIT *)(&drvUSBFSInit));
}

void SYS_Tasks(void)
{
    /* Call the driver tasks routine in SYS_Tasks() function *//
    DRV_USBFS_Tasks(drvUSBObj);
}

void __ISR(_USB_1_VECTOR, ipl4AUTO) _IntHandlerUSBInstance0(void)
{
    /* Call the driver interrupt tasks routine in the USB module ISR */
    DRV_USBFS_Tasks_ISR(sysObj.drvUSBModuleObj);
}

The Host Layer Initialization requires a USB_HOST_HCD data structure. This data structure specifies the HCD module index and the HCD Host Layer Interface for each bus. The following code shows the USB_HOST_HCD data structure is initialized for a single USB Controller Peripheral PIC32MX microcontroller device. 

Example: Data Structure Initialized for a Single USB Controller Peripheral PIC32MX MCU  

/* This code shows an example of setting up the USB_HOST_HCD data
 * structure for the PIC32MX USB controller */

USB_HOST_HCD usbHostHCD =
{
    /* This is the driver instance index that the USB Host Layer will use */
    .drvIndex = DRV_USBFS_INDEX_0,

    /* This is the interface to the PIC32MX USB HCD. The
     * DRV_USBHS_HOST_INTERFACE pointer is exported by the PIC32MX Host Mode USB
     * Driver. */
    .hcdInterface = DRV_USBHS_HOST_INTERFACE
};

The other important component required for USB Host Layer initialization is the Target Peripheral List (TPL). Embedded USB Hosts unlike standard USB Host are not expected to support all USB Device Types. The device types to be supported are specified in the TPL. The TPL contains an entry for every device type that the Embedded USB host must support. If the attached device matches the criteria specified in the TPL entry , the Host Layer attaches the driver corresponding to that entry to the manage device. A device may match multiple entries in the TPL. This happens in the case of composite devices. 

An entry in the TPL contains the following information:

  • Device Type: This specifies whether the Host must inspect the VID, PID field or Class, Subclass and Protocol fields while matching the attached device to the entry
  • Flags: These flags provide the system designer with various options while matching the attached device to a driver. For example, a flag can be specified to ignore the device PID and only consider the VID while matching VID PID device.
  • PID Mask: This is a PID mask that can be applied to the PID before matching the PID to the attached device PID
  • Driver: This is the pointer to the interface of the client driver that should manage the device if the matching criteria is met

The following code shows an example TPL table. 

Example: TPL Table  

    /* This code shows some examples of configuring the USB Host Layer
     * TPL Table. In this example, the USB Host layer is configured to support
     * three different types of devices. */

    USB_HOST_TARGET_PERIPHERAL_LIST usbHostTPL[4] =
    {

        /* Catch every device with the exact Vendor ID = 0x04D9 and Product ID = 0x0001.
         * Every other device will not load this driver. */
        TPL_DEVICE_VID_PID( 0x04D9, 0x0001, &driverInitData, &DEVICE_DRIVER_EXAMPLE1_Driver ),

        /* This driver will catch any device with the Vendor ID of 0x04D9 and any
         * product ID = 0x0000 or 0x0002-0x00FF.  The entry in the TPL before this
         * caught the Product ID = 0x0001 case so that is why it is not caught by
         * this entry.  Those devices have already been caught. */
        TPL_DEVICE_VID_PID_MASKED( 0x04D9, 0x0002, 0xFF00, &driverInitData, &DEVICE_DRIVER_EXAMPLE2_Driver ),

        /* This entry will catch all other devices. */
        TPL_DEVICE_ANY( &driverInitData, &DEVICE_DRIVER_EXAMPLE3_Driver ),

        /* This entry will catch only a HID boot keyboard.  All other devices,
         * including other HID keyboards that are non-boot, will be skipped by this
         * entry. This driver will handle only this specific case. */
        TPL_INTERFACE_CLASS_SUBCLASS_PROTOCOL( USB_HID_CLASS_CODE, USB_HID_SUBCLASS_CODE_BOOT_INTERFACE,
                                               USB_HID_PROTOCOL_CODE_KEYBOARD, &hidDriverInitData,
                                               USB_HOST_HID_BOOT_KEYBOARD_DRIVER ),

        /* This entry will catch all CDC-ACM devices.  It filters on the class and
         * subclass but ignores the protocol since the driver will handle all
         * possible protocol options. */
        TPL_INTERFACE_CLASS_SUBCLASS( USB_CDC_CLASS_CODE, USB_CDC_SUBCLASS_CODE_ABSTRACT_CONTROL_MODEL,
                                      &cdcDriverInitData, USB_HOST_CDC_ACM_DRIVER ),

        /* This will catch all instances of the MSD class regardless subclass or
         * protocol.  In this case the driver will sort out if it supports the
         * device or not. */
        TPL_INTERFACE_CLASS( USB_MSD_CLASS_CODE, &msdDriverInitData, USB_HOST_MSD_DRIVER ),

        /* Any unclaimed interfaces can be sent to a particular driver if desired.
         * This can be used to create a similar mechanism that libUSB or WinUSB
         * provides on a PC where any unused interface can be opened and utilized by
         * these drivers. */
        TPL_INTERFACE_ANY( &driverInitData, USB_HOST_VENDOR_DRIVER )
    }

The Host Layer can now be initialized. The following code shows how the USB_HOST_HCD and the TPL table are specified in the USB_HOST_INIT (the Host Layer Initialization) data structure. In addition, the following figure illustrates the various initialization inputs needed by the Host Layer.

The USB_HOST_Initialize function is called to initialize the Host Layer. The initialization process may not complete when the USB_HOST_Initialization function exits. This will complete in subsequent calls to the USB_HOST_Tasks function. 

Example: Specifying the TPL Table  

/* This code shows an example of the USB Host Layer Initialization data
 * structure. In this case the number of TPL entries is one and there is only
 * one HCD (and hence only one USB bus) in the application */

const USB_HOST_TPL_ENTRY USBTPList[1] =
{
    /* This is the TPL */
    TPL_INTERFACE_CLASS_SUBCLASS_PROTOCOL(0x08, 0x06, 0x50, NULL,  USB_HOST_MSD_INTERFACE)

};

const USB_HOST_HCD hcdTable =
{
    /* The HCD table only contains one entry */
    .drvIndex = DRV_USBFS_INDEX_0,
    .hcdInterface = DRV_USBFS_HOST_INTERFACE
};

const USB_HOST_INIT usbHostInitData =
{
    /* This is the Host Layer Initialization data structure */
    .nTPLEntries = 1,
    .tplList = (USB_HOST_TPL_ENTRY *)USBTPList,
    .hostControllerDrivers = (USB_HOST_HCD *)&hcdTable

};