USBX

Revision as of 16:31, 30 September 2021 by Registered User (STM32 USB-USBX migration)

1 Introduction

Besides offering STMicroelectronics USB stack, USBX, the Azure® RTOS USB embedded stack is currently supported and offered with a set of applications running on STM32 MCUs.
The USB overview article, is a dedicated wiki page that provides a general overview of the Universal Serial Bus and its main features.
USBX is the Azure RTOS USB Host and USB Device embedded stack. It is tightly coupled with ThreadX. In some classes, it requires the FileX and NetX Duo stacks. It allows operation with USB devices with multiple configurations, composite devices, USB OTG, and supports USB power management.
USBX provides both USB Host and USB Device stacks with a large set of USB classes. The modular architecture makes porting onto different USB hardware IPs easier as soon as the low-level driver can answer the USBX requests.

All the STM32 USB IPs (Host, Device, OTG, high_speed, and full_speed) are supported transparently by USBX through the common STM32 HAL driver API.

Info white.png Information
The bare metal implementation is to be made available in the future (that is, using USBX without need for ThreadX).


USBX provides all common USB features and classes. The following figure provides the list of currently supported classes:

USBX supported classes


Info white.png Information
HUB class is to be made available in the future on specific products.


Besides ThreadX integration with USBX, the USB events are managed through interrupts.
The USBX stack has mainly three layers:

  • The lower layer is the controller layer that ensures interfacing with the Hardware USB peripheral, and for STM32 MCUs this layer is compatible with the HAL.
  • The middle layer ensures the USB stack processing and the interfacing requirements between the low and high layers.
  • The higher layer includes the different classes and ensures interfacing with the application layer.

The following figure provides an overview of the USBX three-layer architecture and main components.

USBX layers and components overeview

As presented in the following figure, the different layers can be easily found within the USBX folder.

USBX Folder architecture overview
Info white.png Information
For more details, please refer to Azure RTOS USBX documentation[1].


Info white.png Information
For frequently asked questions, please visit the general FAQ section in STM32CoreMW_overview.


2 USBX device for STM32

This section provides the main guidelines for use of the USBX Stack with the HAL on STM32 MCUs.

2.1 STM32 Device Porting layer

As described in the previous section, USBX is based on three layers that must be referenced within any application project. To be able to interface with the STM32 HAL, the project must integrate the STM32 device controllers. The drivers presented in the figure below include all the APIs allowing interfacing with the STM32 HAL.

USBX STM32 Device Controllers

2.2 How to customize

After referencing the required drivers, and depending on the class and application requirements, the following points must be verified:
1. Add the convenient Descriptors: the device descriptor, configuration descriptor, interface descriptor, endpoint descriptor and the Strings (Language ID, Product ID, and Vendor ID, manufacturer, and so on). The following figure shows some of the required definitions for the HID class:

Example of required definitions for HID application


Info white.png Information
For reference, all the required descriptors can be found in the ux_device_descriptors.c/.h files within the provided STM32 HID device application.


2. Add the Class parameters: every class needs to interface with the user application through some variables or functions. Thus, for every class, there is a structure that must be filled before registering the class. As an example for the HID application, the following structure must be filled in order to be able to register the class:

HID class required parameters

3. Customize the USBX build options by modifying the status of the different conditional compilation defines in ux_user.h, file such as: • USBX thread stack size
• The maximum class number that can be loaded by USBX
• The maximum number of devices that can be attached into one USB system
• Maximum number of endpoints
• The device used class(es)
• The device state side use

4. Depending on the application requirements, all required peripherals and resources (UART, I2C, and so on) must be initialized generally in the stm32XXxx_hal_msp.c file (XX is the family name, for example h7, f7).

Info white.png Information
To make sure that all the customized defines in the ux_user.h file are taken into consideration, the UX_INCLUDE_USER_DEFINE_FILE should be added within the preprocessor defined symbols.


When configuring the project using STM32CubeMX and the X-CUBE-AZRTOS-XX package, a list of variables can be customized through the interface before generating a device application.

USBX parameters definition

To see the role of every variable, just click on it and a little window shows the description. For instance, "USBD_DEVICE_FRAMEWORK_BUILDER" allows the device framework builder to be enabled or disabled.

Parameter information example

2.3 How to use the USBX Device stack to implement an application

1. To start the USBX application, ThreadX must be initialized as described in How to use ThreadX section.
2. Initialize the USBX controller data structures and allocate the required memory.

  /* Initialize USBX Memory & data structures */
  ux_system_initialize(pointer, USBX_MEMORY_SIZE, UX_NULL, 0);

3. Prepare the Device, string and LangID frameworks.

  /* Get_Device_Framework_High_Speed and get the length */
  device_framework_high_speed = USBD_Get_Device_Framework_Speed(USBD_HIGH_SPEED,
                                &device_framework_hs_length);

  /* Get_Device_Framework_Full_Speed and get the length */
  device_framework_full_speed = USBD_Get_Device_Framework_Speed(USBD_FULL_SPEED,
                                &device_framework_fs_length);

  /* Get_String_Framework and get the length */
  string_framework = USBD_Get_String_Framework(&string_framework_length);

  /* Get_Language_Id_Framework and get the length */
  language_id_framework = USBD_Get_Language_Id_Framework(&languge_id_framework_length);

Note: the descriptors must be implemented at application level to be provided as parameters when initializing the stack. For reference, all the required descriptors can be found in the ux_device_descriptors.c/.h files within every provided STM32 device application.
4. Initialize the USBX device stack with the prepared frameworks.

  /* The code below is required for installation of the device portion of USBX.
  in this application */
  ret =  ux_device_stack_initialize(device_framework_high_speed,
                                    device_framework_hs_length,
                                    device_framework_full_speed,
                                    device_framework_fs_length,
                                    string_framework,
                                    string_framework_length,
                                    language_id_framework,
                                    languge_id_framework_length, UX_NULL);

5. Initialize the device class parameters and register the class.

  /* Initialize the device class. The class is connected with interface 0 in this case */
  ret = ux_device_stack_class_register(_ux_system_slave_class_xxxx_name,
                                       ux_device_class_xxxx_entry, 1, 0, (VOID *)&class_xxxx_parameter);

6. Initialize the USB hardware peripheral and start the controller.
7. Implement the required applications tasks using Threads or Message Queue as explained in How to use ThreadX section.

Info white.png Information
The bare metal implementation is to be made be available in the future (ie. to make possibe the use of USBX without need for ThreadX).


2.4 USBX device applications

This section provides an overview of the USBX Device applications offered on STM32 MCUs.

2.4.1 USBX Device application architecture

The Following figure shows the project architecture and main application files.

USBX Application’s main files architecture

2.4.2 USBX device application overview

The following table provides an overview about the offered USBX Device applications:

USBX Device application Overview
HID Application This application makes the STM32 emulate a mouse USB device. When connected to a host through its USB peripheral, The STM32 is detected as an STM32 HID Mouse. The cursor moves automatically. For more details, please refer to the applications Readme file [2].

This application was implemented according to the Device Class Definition for Human Interface Device (HID) specification [3]

MSC application This application makes the STM32 emulate a Flash disc device. When connected to a host through its USB peripheral, the STM32 is detected as an STM32 mass storage device. The device can then be written, read and formatted. For more details, please refer to the application’s Readme file [4].

This application was implemented according to the Universal Serial Bus Mass Storage Class specification[5].

CDC ACM application This application makes the STM32 emulate an UART-USB Bridge. When connected to a host through its USB peripheral, The STM32 will be detected as an STM32 Virtual Com port. An HyperTerminal can be opened with the detected port and a communication can be established between the STM32 Virtual comport and the STM32 ST-link (UART) port. For more details, please refer to the application’s Readme file [6].

This application was implemented according to the Class definitions for Communication Devices specification[7].

Ux_Device_HID_CDC_ACM This application provides an example of Azure RTOS USBX stack usage on STM32H747I_Discovery board, it shows how to develop a composite USB Device communication Class "HID" and "CDC_ACM" based application. The application is designed to emulate an USB HID mouse device and USB-to-UART bridge following the Virtual COM Port (VCP) implementations.

For more details, please refer to the application’s Readme file [8].

CDC ECM application This application shows how to implement an application to run Web HTTP server stack over a USB interface using the CDC-ECM class. When an SD card is inserted into the STM32 board's SD-card reader and the board is powered up and connected to a DHCP-enabled Ethernet network, the green LED switches ON when Web HTTP server is successfully started. For further details, please refer to the application’s Readme file [9].


3 USBX Host for STM32

This section provides the main guidelines allowing use of the USBX Host Stack with the HAL on STM32 MCUs.

3.1 STM32 Host porting layer

As described in the previous section, the USBX stack is based on three layers that must referenced within any application project. To be able to interface with the STM32 HAL, the project must integrate the STM32 Host controllers interfacing with the HAL layer. The drivers presented in the figure below include all the APIs allowing interfacing with the STM32 HAL.

STM32 Host Controller drivers

3.2 How to customize


1. Customize the USBX build options by modifying the status of the different conditional compilation defines in the ux_user.h file, such as: • USBX thread stack size
• The maximum class number that can be loaded by USBX
• The maximum number of devices that can be attached into one USB system
• The maximum number of endpoint
• The host used class(es)
• The host state side use
2. Depending on the application requirements, the different peripherals and clocks should be correctly defined. Generally, the different peripheral IO initializations are done in the stm32XXxx_hal_msp.c (XX is the STM32 family that can be, for example, h7, f4, or f7).

Info white.png Information
To make sure that all the customized defines in the ux_user.h file are taken into consideration, the "UX_INCLUDE_USER_DEFINE_FILE" should be added within the preprocessor defined symbols.

When configuring the project using STM32CubeMX and the X-CUBE-AZRTOS-XX package, a list of variables can be customized through the interface before generating a host application.

USBX Host parameters definition

To see the role of every variable, just click on it and a little window shows the description.

3.3 How to use the USBX Host stack to implement an application

1. To start the USBX application, ThreadX must be initialized as described in How to use ThreadX section.
2. Initialize USBX’ different data structures to be used by the USB system.

  /* Initialize USBX memory. */
  if (ux_system_initialize(pointer, USBX_MEMORY_SIZE, UX_NULL, 0) != UX_SUCCESS)
  {
    ret = UX_ERROR;
  }

3. Register an error callback function to be able to get the error events at application level (this step is optional). This callback is called when an error occurs at thread level or at interrupt level. It can be called to inform the user of the error codes that can be related to the host controller, the device controller, the initialization, the class, the device stack, and so on.

  /* register a callback error function */
  _ux_utility_error_callback_register(&ux_host_error_callback);

4. Initialize the USB Host stack

  /* The code below is required for installing the host portion of USBX.  */
  if (ux_host_stack_initialize(ux_host_event_callback) != UX_SUCCESS)
  {
    status = UX_ERROR;
  }

Device status check: in fact, ux_host_stack_initialize() is the function that allows the initialization of the USB host stack, it takes a change event callback as a parameter, allowing the user application to determine whether the device status if defined. In fact this callback, if required, should be defined at application level. It is called when the device status is modified (inserted, removed, and so on) allowing the user to perform the required process following that event.
5. Register the class

  /* Register the convenient class. */
  if ((status =  ux_host_stack_class_register(_ux_system_host_class_xxxx_name,
                                              _ux_host_class_xxxx_entry)) != UX_SUCCESS)
  {
    status = UX_ERROR;
  }

6. Initialize the USB hardware peripheral.
7. Register all the available USB Host controllers with the USBX stack.

  /* Register all the USB host controllers available in this system. */
  if (ux_host_stack_hcd_register(_ux_system_host_hcd_stm32_name,
                                 _ux_hcd_stm32_initialize,
                                 USB_OTG_HS_PERIPH_BASE,
                                 (ULONG)&hhcd_USB_OTG_HS) != UX_SUCCESS)
  {
    status = UX_ERROR;
  }

7. Define and create the application required Threads or Message Queue.
8. Start the USB Host controller.

3.4 USBX Host applications

This section provides an overview of the offered USBX Device application.

3.4.1 USBX Host application architecture

The following figure shows the USB Host application main files and architecture.

USBX Host Application’s main files architecture

3.4.2 USBX Host application overview

The following table provides an overview of the offered USBX Device applications:

USBX Host application Overview
HID Application This application makes the STM32 emulate a USB HID Host that can enumerate and communicate with mice and keyboards. When an HID device (mouse or keyboard) is connected to a host through its USB peripheral, the STM32 detects it, recognizes its types and receives data in real time:
  • If a mouse device is connected, the pressed buttons, wheel movements and the modified cursor coordinates are detected and displayed.
  • If a keyboard device is connected, the pressed buttons are detected and displayed.

For further details, please refer to the application’s Readme file[10].

MSC Application This application makes the STM32 emulate a USB mass storage Host that can enumerate and communicate with Flash disk USB devices. When a Mass Storage is connected to the STM32 host through its USB peripheral, the STM32 detects the Device, enumerate it, create a file, write and read data and check the data integrity. For more details, please refer to the application’s Readme file[11].
Dual Class Application This application provides an example of Azure RTOS USBX stack usage. It shows how to develop a USB Host human interface "HID" and mass storage "MSC" that enumerates and communicates with:
  • A mouse or a keyboard.
  • A removable USB flash disk

For further details, please refer to the application’s Readme file [12].

CDC ACM Application This application provides an example of an STM32 USB Host CDC. When a CDC device is plugged into the STM32 Host board through an available port, a message is displayed on the UART HyperTerminal showing some information about the attached device. After the enumeration phase, the Host must be able to properly decode the CDC_ACM class request, and receive and send (from/to) the device.

For further details, please refer to the application’s Readme file[13].


4 STM32 USB-USBX migration

Commonly for all applications, it is up to the user to initialize the HAL layer through HAL_Init(), the MPU configuration (if required), the system clocks through SystemClock_Config(), and the different hardware peripherals that are used in the application (such as UART/USART, SD card, I2C and SPI).


4.1 Migration from USBD to USBX Device

USB Device framework builder:
For the STM32 USB applications that are based on the USB Device library, the user only has to register the convenient class in the application. All the class-dependent descriptors (such as configuration and device qualifier descriptors) are provided automatically when requested within the class layer.
For USBX-based applications, it is up to the user to build the required descriptors in the framework. Thus, a dedicated framework builder API has been implemented to make this task easier. In fact, this API ensures the implementation of the required USB descriptors at application level (such as Device descriptors, configuration descriptors and specific class descriptors).

The USB Device initialization and configuration are mainly ensured by calling, in the application layer, the APIs described in the table below:

Application based on STM32 USB Device stack Application based on USBX Device stack
USBD_Init () initializes the device stack and registers the class driver.

Before calling this API, the user must:

  • Overload USBD_LL_Init() in the application layer, to ensure the initialization of the low-layer driver (such as speed, DMA enable, low-power enable and PHY interface). This function is then automatically called in the core layer.
  • Overload HAL_PCD_MspInit () function at application level, to include the correct initialization (such as USB GPIOs, clock, interrupt enabling and correct priority configuration). This function is then automatically called in the HAL layer by HAL_PCD_Init().
ux_system_initialize() initializes USBX memory and data structures.

ux_device_stack_initialize() initializes the USB Device stack. This API takes as parameters the different frameworks that the user has to define in the application.
These two USBX APIs do not ensure the full initialization of the device HAL driver. The following remains to be done by the user:

  • Ensure the low-level driver parameter initialization (such as speed, DMA enable, low-power enable, PHY interface and Endpoints FIFO/PMA). For example, this can be done by implementing and calling a dedicated function in the application. In the provided USBX applications, MX_USB_OTG_HS_PCD_Init() (or MX_USB_OTG_FS_PCD_Init() ) was implemented and called for this purpose.
  • Overload HAL_PCD_MspInit () function in the application, to ensure the convenient initialization of USB GPIOs and clock, interrupt enabling and correct priority configuration.
  • Call HAL_PCD_Init() in the application to initialize the USB peripheral.
USBD_RegisterClass () links the class driver to the device core. The different common descriptors (configuration, qualifier and class descriptors) are provided within the class layer. The user must add the device descriptor. ux_device_stack_class_register() registers the convenient class with the convenient parameter structures for every class as explained in How to customize section.
USBD_Start () starts the USB device core including the device driver (no need to call HAL_PCD_Start() as this was already done inside the USBD_Start() function). ux_device_stack_pcd_register () initializes the USBX device stack with the prepared frameworks.

When the initialization is complete, the device driver must be started by calling HAL_PCD_Start() in the application.

4.2 Migration from USBH to USBX Host

The USB Host initialization and configuration is mainly ensured by calling, in the application layer, the APIs described in the table below:

Application based on STM32 USB Host stack Application based on USBX Host stack
USBH_Init () initializes the host library and loads the class driver. It includes the USB Host driver initialization by calling HAL_HCD_Init() which, in turn, ensures the USB hardware peripheral initialization by calling the HAL_HCD_MspInit (). This last HAL function must be overloaded by the user at application level, to include the correct initialization (such as USB GPIOs, clock, interrupt enabling and correct priority configuration).

USBH_Init () also ensures the low-level driver parameter initialization (such as speed, DMA enable, low-power enable and PHY interface) by calling USBH_LL_Init(). As a result, this last LL function must be overloaded at application level and then called in the core layer.

ux_system_initialize() initializes the USBX data structures to be used by the USB system.

ux_host_stack_initialize () initializes the USB Host stack. This API takes as parameter a pointer to the host events callback that must be defined by the user (if required).
These two USBX APIs do not ensure the full initialization of the host HAL driver. The following remains to be done by the application:

  • Ensure the low-level driver parameter initialization (such as speed, DMA enable, low-power enable and PHY interface). For example, this can be done by implementing and calling a dedicated function in the application. In the provided USBX applications, MX_USB_OTG_HS_HCD_Init() (or MX_USB_OTG_FS_HCD_Init() ) was implemented and called for this purpose.
  • Overload the HAL_HCD_MspInit () function to ensure the convenient initialization of USB GPIOs and clock, interrupt enabling and correct priority configuration. HAL_HCD_Init() must then be called to initialize the USB peripheral.
USBH_RegisterClass () links the class driver to the host core. ux_host_stack_class_register() registers the convenient class.
USBH_Start () starts the USB host core including the Host driver (no need to call HAL_HCD_Start() as this was already done inside the USBH_Start() function). ux_host_stack_hcd_register () registers all the available USB Host controllers with the USBX stack.

When the initialization is complete, the application must:

  • Ensure VBUS driving.
  • Start the Host driver by calling HAL_HCD_Start().
USBH_Process() must be called to manage the background process of the USB core. This process is currently managed through threads with ThreadX.

5 References