on 2025-10-24 12:46 AM
This article is a tutorial on how to add the standalone version of USBX (without Azure RTOS) to an STM32 FreeRTOS™ project. This tutorial uses an STM32U5G9J-DK2 board and the same steps are applicable to any other STM32 MCU.
Currently in CubeMX, USBX and other Azure RTOS middleware are automatically disabled when FreeRTOS™ is activated. So, we need to create a separate "USBX only" project in CubeMX, configure only the USBX middleware + some basic project settings and generate the code. Afterwards, copy and paste the relevant generated code folders into our master project that has FreeRTOS™ and everything else our application needs (that is, NFC, UART, SPI, LCD, etc.).
For reference, see the attached STM32U5G9J-DK2 board "FreeRTOS + USBX" project (STM32U5G9J_DK2_USB_Device_HID_FreeRTOS_example_V1_project.zip file) at the end of this article. You can create your own “FreeRTOS + USBX” project by following this article.
In CubeMX, create a master project for your STM32 MCU that has all your project's peripheral and middleware configurations (that is, FreeRTOS™, USB, RCC, etc.) minus the USBX middleware configurations.
For now, just configure:
Refer to the attached "FreeRTOS + USBX" project for the specific configurations used on the STM32U5G9J-DK2 board.
Add a FreeRTOS™ USBTask and a couple other tasks for testing purposes.
In the NVIC configurations, make sure that you have enabled the interrupts that are necessary for your design.
Configure the code generation settings to NOT generate the MX_USB_..._Init() function and make sure that its visibility is NOT static. This is because we place this function call in our USB application code, which is outside of main.c.
Generate the code when finished with the configurations. Build the freshly generated project to make sure that it builds successfully.
In app_freertos.c for example purposes: Blink the user LEDs in the Task1 and Task2 FreeRTOS™ tasks, and add osDelay() values for all three FreeRTOS™ tasks.
Build the project and launch a debug session to verify that the application runs properly on your board. You should see the on-board or external LEDs toggling accordingly depending on the osDelay() value.
Now, we need to create a "USBX only" project that contains only the standalone USBX middleware configurations.
Create a new project in CubeMX for your specific STM32 MCU part number and configure the USB peripheral. Use the same USB peripheral configurations that you used in your FreeRTOS™ project in section 1 of this article. We are enabling and configuring the USB peripheral in this “USBX only” project only to ensure that we have all USBX middleware configuration options available to us.
Configure the USBX middleware’s mode and platform settings accordingly. The mode configurations shown below are for a USB HID mouse device. If your USB application requires something different, then make sure that you use the correct mode configurations for your specific USB application.
Configure the USBX middleware configurations as shown below.
Generate the code when finished. Build this "USBX only" project to make sure that it builds without errors.
Copy the following files/folders from the "USBX only" project into your "FreeRTOS + USBX" project.
Folder 1: USBX
Folder 2: usbx
Note: If your “FreeRTOS + USBX“ project does not have a Middlewares\ST folder, then create it.
In the "FreeRTOS + USBX" project, we need to add the compiler include paths for the files/folders we copied over.
Right click on the "USBX only" project→ Properties → C/C++ Build → Settings → Tool Settings → MCU/MPU GCC Compiler → Include paths. Copy all "../USBX/…" and "../Middlewares/ST/usbx/…" include paths that are listed.
Add them to the "FreeRTOS + USBX" project → Properties → C/C++ Build → Settings → Tool Settings → MCU/MPU GCC Compiler → Include paths.
For convenience, here’s a plain text version of the main compiler include paths you need to copy into your own “FreeRTOS + USBX” project:
Click [Apply], [Rebuild Index], then [Apply and Close] when done.
In the "FreeRTOS + USBX" project, we need to add the USBX related compiler preprocessor define symbols.
Right click on the "USBX only" project → Properties → C/C++ Build → Settings → Tool Settings → MCU/MPU GCC Compiler → Preprocessor. Copy all USBX / UX related compiler preprocessor define symbols that are listed.
Add them to the "FreeRTOS + USBX" project → Properties → C/C++ Build → Settings → Tool Settings → MCU/MPU GCC Compiler → Preprocessor.
For convenience, here is a plain text version of the main compiler preprocessor define symbol you need to copy into your own “FreeRTOS + USBX” project:
Click [Apply], [Rebuild Index], then [Apply and Close] when done. Build the "FreeRTOS + USBX" project to make sure that it builds without errors.
In the "FreeRTOS + USBX" project, we need to add the USBX folder to the source folders on the build path list.
Right click on the "FreeRTOS + USBX" project → Properties → C/C++ General → Paths and Symbols → Source Location. Add the /<FreeRTOS + USBX project root folder>/USBX folder.
Click [Apply], [Rebuild Index], then [Apply and Close] when done. Build the "FreeRTOS + USBX" project to make sure that it builds without errors.
In the "FreeRTOS + USBX" project, we need to add the USBX related includes to main.h and main.c.
In the "USBX only" project, copy all USBX related includes in main.h. Paste them into the "FreeRTOS + USBX" project → main.h file between the "USER CODE BEGIN Includes" and "USER CODE END Includes" labels.
Note: The app_usbx_device.h header file shown above is specific to USBX configured as a USB device. So if your USBX configurations are different, you may have different header file names. Make sure you copy all USBX related includes from your main.h file, not just the one shown above.
In the "USBX only" project, copy all USBX related includes in main.c. Paste them into the "FreeRTOS + USBX" project → main.c file between the "USER CODE BEGIN Includes" and "USER CODE END Includes" labels. Note: If a specific include is already in main.h, there is no need to put it in main.c.
Save and build the "FreeRTOS + USBX" project to make sure that it builds without errors.
Now, you need to add your USB application code to the "FreeRTOS + USBX" project.
In the "FreeRTOS + USBX" project, add your USB application code to the following files between "USER CODE BEGIN" and "USER CODE END" labels:
Note: Aside from main.h and main.c, these files are specific to USBX configured as a USB HID mouse device. So, if your USBX configurations are different, you will have different file names.
In main.c, you need to place the MX_USBX_Device_Init() function between the "USER CODE BEGIN 2" and "USER CODE END 2" labels.
Note: The MX_USBX_Device_Init() function is specific to USBX configured as a USB device. So if your USBX configurations are different, you may have a different MX USBX initialization function name.
Note: Aside from the MX_USBX_Device_Init() function, the rest of the code shown in main() is auto generated and is STM32 device specific and configuration specific. You may see different auto generated code in your main() function. Do not modify it with the auto generated code from the screenshot above.
When done, build the "FreeRTOS + USBX" project to make sure that there are no errors.
In the “FreeRTOS + USBX” project, we need to move the USBX_Device_Process(NULL) function from main() to the FreeRTOS USB task in app_freertos.c.
Note: The USBX_Device_Process(NULL) function is specific to USBX configured as a USB device. So, if your USBX configurations are different, you may have a different USB process start function name.
Note: StartUSBTask() is the name of the USB FreeRTOS task created in section 1 of this article. If you are using a different USB task start function name, then your StartUSBTask() function will have a different name.
When done, build the "FreeRTOS + USBX" project to make sure that there are no errors.
In the “FreeRTOS + USBX” project, launch a debug session and click Run / Resume to run the application on your board. Make sure that your second USB Type-C® cable is plugged into your PC and the application / user USB connector on your board (CN2 on the STM32U5G9J-DK2 board).
You should see the on-board or external LEDs toggling accordingly depending on the osDelay() values of the FreeRTOS tasks Task1 and Task2.
Every time you press the on-board or external user push button, your computer's mouse cursor moves.
FreeRTOS and USBX are now working together in the same STM32 project. At the end of this article, see the attached STM32U5G9J-DK2 board "FreeRTOS + USBX" project as an example. (STM32U5G9J_DK2_USB_Device_HID_FreeRTOS_example_V1_project.zip file)
WARNING 1
Before you re-generate code in your "FreeRTOS + USBX" project, ALWAYS backup / make copies of the following in case they get deleted or overwritten by the code generator:
WARNING 2
Every time you need to change your USBX configurations, you will have to do so in your "USBX only" project. Afterwards, copy over those newly generated USBX folders into your “FreeRTOS + USBX” project as instructed in Section 4 of this article. This overwrites all your “FreeRTOS + USBX” project files and application code in these folders. Make sure you back up or make copies of the following before copying over those newly generated USBX folders.