USB Device Hardware Porting Guide#

The Micrium OS USB Device module uses a hardware driver that can be customized for any USB device controller using a Board Support Package (BSP). The BSP has two purposes:

  • It initializes and configures any resources needed by the USB controller but which are provided by an external module.

  • It provides hardware information to the USB device driver.

Micrium provides example BSPs for some popular platforms. If one is available for your platform, we recommend that you use it as a starting point. However, if no example BSP is available for your platform, the information in this section will help you understand how to correctly port the USB device module to your platform.

Note that each USB device controller (that you are planning to use) will require a BSP and all the steps described in this section will have to be performed for each of them.

USB Device BSP Functions Guide#

The Board Support Package contains a set of functions that support your hardware platform on Micrium OS. These functions are called by the USB device driver to perform hardware configuration or initialization of IO pins, interrupts, etc. It is your responsibility to either create these functions from scratch or to modify example code to fit your needs and the specifics of your hardware.

Each of these functions is described below.

Initialize#

The first function you need to implement is a generic initialization function which is called by the driver only once at initialization. Listing - Init function signature in the USB Device BSP Functions Guide page shows the signature of this function.

Listing - Init function signature#
void  BSP_USBD_EFM32_STK_Init (USBD_DRV  *p_drv);

Its purpose is to initialize any resources that will be necessary to the USB device controller, such as IO pins, power, ISR registration, clock, etc.

This function also receives an argument called p_drv. This argument will be useful when handling the USB device controller-related interrupts. It is then important to either save it as a global variable in your BSP or, if your interrupt controller supports this feature, pass it to your interrupt vector directly.

Connect#

The second function to implement is a function that is called by the driver when the initialization is done, and the controller is started via the function USBD_DevStart(). Listing - Conn function signature in the USB Device BSP Functions Guide page shows the signature of the function.

Listing - Conn function signature#
void  BSP_USBD_EFM32_STK_Conn (void);

Its purpose is to set the pull-up pin to signal the device connection to the host. Note that this may be handled directly by the USB controller, which means that this function may remain empty.

Disconnect#

The third function to implement is called by the driver when the controller is stopped via the USBD_DevStop() function. Listing - Disconn function signature in the USB Device BSP Functions Guide page shows the signature of the function.

Listing - Disconn function signature#
void  BSP_USBD_EFM32_STK_Disconn (void);

Its purpose is to clear the pull-up pin to signal the device disconnection to the host. Note that this may be handled directly by the USB controller, which means that this function may remain empty.

ISR Handling#

Each USB Device driver has an ISR handler function that must be called each time a USB device interrupt is triggered. However, for most platforms, it will be necessary to implement an intermediate ISR handler in the BSP. This BSP ISR will then call the driver's ISR handler. This is necessary, as some interrupt controllers may require the interrupt status to be cleared each time it is triggered. It is also necessary if your interrupt controller does not support passing an argument to the interrupt vector, as the driver's ISR handler takes the p_drv received in the Init() function of the BSP as an argument.

Note that your BSP ISR handler must be registered to the interrupt controller in the Init() function.

Listing - Example of BSP ISR implementation in the USB Device BSP Functions Guide page shows an example of an ISR handler implemented in the BSP (that follows the CMSIS naming standard).

Listing - Example of BSP ISR implementation#
void USB_IRQHandler (void)
{
    /* TODO: Clear interrupt status, if needed. */

    OSIntEnter();
    BSP_USBD_DrvPtr->API_Ptr->ISR_Handler(BSP_USBD_DrvPtr);                  (1)
    OSIntExit();
}

(1) Here, the driver's ISR is called. Note that the global variable BSP_USBD_DrvPtr is a copy of the p_drv argument received from the BSP Init() function.

USB Device Hardware Information#

Endpoint Information Table#

Your USB device controller has a set of pipes (used as endpoints) that are available to the USB device software. Micrium OS USB Device must be provided with information about these pipes. The way to provide this information is by using a table of elements of type USBD_DRV_EP_INFO. Note that the last element of the table must be a null entry.

The information regarding the pipes of your USB device controller can be found in the manual for your MCU.

Table - USBD_DRV_EP_INFO structure in the USB Device Hardware Information page describes each configuration field available in this structure.

Table - USBD_DRV_EP_INFO structure#

Field

Description

.Attrib

This is a bitmap that represents the different endpoint types and directions that this pipe can support. Possible values of the bitmap are:

Value

Description

USBD_EP_INFO_TYPE_CTRL

Pipe supports transfers of type Control.

USBD_EP_INFO_TYPE_ISOC

Pipe supports transfers of type Isochronous.

USBD_EP_INFO_TYPE_BULK

Pipe supports transfers of type Bulk.

USBD_EP_INFO_TYPE_INTR

Pipe supports transfers of type Interrupt.

USBD_EP_INFO_DIR_OUT

Pipe supports OUT (host-to-device) transfers.

USBD_EP_INFO_DIR_IN

Pipe supports IN (device-to-host) transfers.

.Nbr

Endpoint number.

.MaxPktSize

Maximum buffer size available for this pipe.

Listing - Example of endpoint description table in the USB Device Hardware Information page gives an example of an endpoint information table. In this case, the controller has four bi-directional endpoints. Three are capable of all transfer types, one is the default control pipe. Also, note the null entry at the end of the table.

Listing - Example of endpoint description table#
static USBD_DRV_EP_INFO BSP_USBD_EFM32_EP_InfoTbl[] = {
  { USBD_EP_INFO_TYPE_CTRL                                                                            | USBD_EP_INFO_DIR_OUT, 0u, 64u },
  { USBD_EP_INFO_TYPE_CTRL                                                                            | USBD_EP_INFO_DIR_IN, 0u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_OUT, 1u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_IN, 1u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_OUT, 2u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_IN, 2u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_OUT, 3u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_IN, 3u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_OUT, 4u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_IN, 4u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_OUT, 5u, 64u },
  { USBD_EP_INFO_TYPE_CTRL | USBD_EP_INFO_TYPE_ISOC | USBD_EP_INFO_TYPE_BULK | USBD_EP_INFO_TYPE_INTR | USBD_EP_INFO_DIR_IN, 5u, 64u },
  { DEF_BIT_NONE, 0u, 0u }
};

Hardware Driver Information#

The USB device driver requires information about the USB device controller on your MCU, which you provide using a structure of type USBD_DRV_INFO. This information can be found in the manual of your MCU.

Table - USBD_DRV_INFO structure in the USB Device Hardware Information page describes each configuration field available in this structure.

Table - USBD DRV INFO structure#

Field

Description

.BaseAddr

Base address of the USB device controller registers set. This corresponds to the address of the first register.

.MemAddr

Address of the dedicated memory to be used. Most of the time, this field is not used and can be set to 0.

.MemSize

Size of the dedicated memory to be used. Most of the time, this field is not used and can be set to 0.

.Spd

Maximum desired USB speed for this USB device controller. Possible values:

- USBD_DEV_SPD_FULL

- USBD_DEV_SPD_HIGH (if USB device controller supports it)

.EP_InfoTbl

Pointer to the endpoint information table created at step endpoint information table.

Listing - Example of driver information structure in the USB Device Hardware Information page shows an example of a driver hardware information structure.

Listing - Example of driver information structure#
static USBD_DRV_INFO BSP_USBD_EFM32_DrvInfoPtr = {
#if defined(USBC_MEM_BASE)
  .BaseAddr = USBC_MEM_BASE,
#else
  .BaseAddr = USB_MEM_BASE,
#endif
  .MemAddr = 0x00000000u,
  .MemSize = 0u,
  .Spd = USBD_DEV_SPD_FULL,
  .EP_InfoTbl = BSP_USBD_EFM32_EP_InfoTbl
};

BSP API Structure#

In order to provide a pointer to the BSP functions for the USB device controller driver, you have to create a structure of type USBD_DRV_BSP_API.

Table - USBD_DRV_BSP_API structure in the USB Device Hardware Information page describes each field available in this structure.

Table - USBD_DRV_BSP_API structure#

Field

Description

.Init

Pointer to the BSP initialization function.

.Conn

Pointer to the BSP connect function.

.Disconn

Pointer to the BSP disconnect function.

Listing - Example of BSP API structure in the USB Device Hardware Information page shows an example of a BSP API structure.

Listing - Example of BSP API structure#
static USBD_DRV_BSP_API BSP_USBD_USBHS_BSP_API_Ptr = {
     .Init    = BSP_USBD_EFM32_STK_Init,
     .Conn    = BSP_USBD_EFM32_STK_Conn,
     .Disconn = BSP_USBD_EFM32_STK_Disconn
};

Device Hardware Information#

The last step is to create the main device hardware information structure. This structure contains only pointers to other structures.

Table - USBD_DEV_HW_INFO structure in the USB Device Hardware Information page describes each configuration field available in this structure.

Table - USBD_DEV_HW_INFO structure#

Field

Description

.DrvAPI_Ptr

Pointer to the driver API structure you are using with your driver. Some drivers may provide more than one API structure.

.DrvInfoPtr

Pointer to the structure you created at step hardware driver information .

.BSP_API_Ptr

Pointer to the BSP API structure you created at step BSP API Structure .

USB Device Controller Registration to the Platform Manager#

Once the hardware information structure for your USB device controller is ready, it must be registered with the Platform Manager . This should normally be done using the BSP_OS_Init() function that is located in the file bsp_os.c.

There are two different macros located in the file usb_ctrlr.h that you can call to register a USB Device controller. Table - USB Device Controller Register Macros in the USB Device Controller Registration to the Platform Manager page describes these different macros.

Table - USB Device Controller Register Macros#

Macro

Description

USB_CTRLR_HW_INFO_REG()

Registers hardware information for a USB controller that has both Device and Host functionalities. Refer to USB Host Hardware Porting Guide for more information on the host side.

USB_CTRLR_HW_INFO_DEV_ONLY_REG()

Registers hardware information for a USB device controller.

Listing - Example of USB Controller Registration in the USB Device Controller Registration to the Platform Manager page shows an example of how to register a USB Device controller.

Listing - Example of USB Controller Registration#
#include  <rtos_description.h>
#include  <rtos/usb/include/usb_ctrlr.h>

#if defined(RTOS_MODULE_USB_HOST_AVAIL)                            (1)
BSP_HW_INFO_EXT(const  USBH_HC_HCD_HW_INFO, BSP_USBH_EFM32_PBHCI_HwInfo);
#endif

#if defined(RTOS_MODULE_USB_DEV_AVAIL)
BSP_HW_INFO_EXT(const  USBD_DEV_CTRLR_HW_INFO, BSP_USBD_EFM32_HwInfo);
#endif

void  BSP_OS_Init (void)
{

    /* ... */

                                            /* ------------- REGISTER USB CONTROLLERS ------------- */
#if defined(RTOS_MODULE_USB_DEV_AVAIL)
    USB_CTRLR_HW_INFO_DEV_ONLY_REG("usb0",                         (2)
                                   &BSP_USBD_EFM32_HwInfo);
#endif

#if defined(RTOS_MODULE_USB_DEV_AVAIL) || defined(RTOS_MODULE_USB_HOST_AVAIL)
    USB_CTRLR_HW_INFO_REG("usb1",                                  (3)
                          &BSP_USBD_EFM32_HwInfo,
                          &BSP_USBH_EFM32_PBHCI_HW_Info);
#endif
}

(1) Since the hardware information global variables are declared in another file, you must declare them as external in your bsp_os.c file. Always use the BSP_HW_INFO_EXT() macro.

(2) Registering a USB device-only controller with the tag "usb0". The tag will be used later on when calling the USBD_DevAdd() function.

(3) Registering a USB controller that implements both host and device functionalities. The controller name is "usb1". The tag will be used later on when calling the USBD_DevAdd() and/or USBH_HC_Add() function.