2026-02-05 2:53 AM
Hi everyone,
I’m working on an STM32U5G9 using USBX + ThreadX.
I was able to make the device work as:
MSC only
CDC-ACM only
MSC + CDC-ACM simultaneously
That part is fine. What I need now is more dynamic behavior: start the device as MSC, and when a button is pressed, stop USB, change the class to CDC-ACM and restart it (long term I’d like to switch arbitrary combinations of classes, but for now switching from MSC to CDC-ACM is the goal.)
From what I understand, I must stop USB so the host will re-enumerate using the new device descriptor, and I’m OK with that. However, every approach I tried ends in a HardFault when I restart with the other class. I suspect I’m missing a call or doing things in the wrong order.
How I start the device (this works):
/* Start device with MSC only (initial boot) */
/* First I insert CLASS_TYPE_MSC is "UserClassInstance" variable in ex_device_descriptors.c (not shown here), then: */
ux_device_stack_initialize(...);
/* Register MSC-only */
ux_device_stack_class_register(...);
HAL_PCD_Init(...);
/* Then I set the RX an TX Fifo for both MSC and CDC classes, even if only the MSC Is active */
HAL_PCDEx_SetRxFiFo(...);
HAL_PCDEx_SetTxFiFo(...);
ux_dcd_stm32_initialize(...);
HAL_PCD_Start(...);
How I try to switch to CDC-ACM (this leads to HardFault):
/* Stop device and remove old class */
HAL_PCD_Stop(...);
_ux_dcd_stm32_uninitialize(...);
HAL_PCD_DeInit(...);
ux_device_stack_class_unregister(...);
ux_device_stack_uninitialize(...);
ux_system_uninitialize(...);
/* change UserClassInstance to CLASS_TYPE_CDC_ACM in the ex_device_descriptors.c (not shown here) */
/* Restart with CDC-ACM */
ux_system_initialize(...);
ux_device_stack_initialize(...);
ux_device_stack_class_register(...); // CDC-ACM
HAL_PCD_Init(...);
HAL_PCDEx_SetRxFiFo(...);
HAL_PCDEx_SetTxFiFo(...);
ux_dcd_stm32_initialize(...);
HAL_PCD_Start(...);
At this point the device always ends up in the HardFault handler, but I suspect I’m missing a call or doing things in the wrong order.
Can anyone give advice, point out what is wrong in the sequence above, or share an example showing how to correctly stop and restart USBX with a different device class?
Thank you very much for your help.
Solved! Go to Solution.
2026-03-02 6:50 AM
Thanks @Gyessine for the reply. I managed to get the system working, but using a different approach.
In your code, each time USB_Device_ReInit_For_Mode is called, you also run ux_device_stack_initialize without first calling ux_device_stack_deinitialize. In my case, I need to deinitialize first, otherwise ux_device_stack_initialize doesn’t complete successfully. Even with that change, though, I was still hitting an error.
What ultimately fixed it was reinitializing to zero the USBD_DevClassHandleTypeDef variables USBD_Device_FS and USBD_Device_HS in ux_device_descriptors.c every time. Doing that, along with reinitializing the device stack and memory, and modifying uint8_t UserClassInstance[USBD_MAX_CLASS_INTERFACES] made the system work.
2026-02-26 5:09 AM
Hello @Eagle
Sorry for the late reply.
There are various possible root causes that may lead to failure in the class switch, which cannot be identified through the provided code. However, I attempted to replicate your case and created a project that switches from the HID device class to the CDC device class using the B-U585I-IOT02A board (which features an STM32U585 microcontroller).
I will attach the project so you can use it as a reference to understand the mechanism used for the class switch. I have added comments throughout the project to facilitate understanding.
Hope this helps you solve your issue
Gyessine
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2026-03-02 6:50 AM
Thanks @Gyessine for the reply. I managed to get the system working, but using a different approach.
In your code, each time USB_Device_ReInit_For_Mode is called, you also run ux_device_stack_initialize without first calling ux_device_stack_deinitialize. In my case, I need to deinitialize first, otherwise ux_device_stack_initialize doesn’t complete successfully. Even with that change, though, I was still hitting an error.
What ultimately fixed it was reinitializing to zero the USBD_DevClassHandleTypeDef variables USBD_Device_FS and USBD_Device_HS in ux_device_descriptors.c every time. Doing that, along with reinitializing the device stack and memory, and modifying uint8_t UserClassInstance[USBD_MAX_CLASS_INTERFACES] made the system work.