2025-05-07 11:06 AM - edited 2025-05-07 4:32 PM
Hello,
I am trying to enable the USB IP DMA mode on an STM32U5A5. Without DMA, I have it working as a USB device and it transmits and receives data without apparent issues. To start using DMA, my understanding is that all I need to do, in CubeMX, is change the "Enable IP DMA" setting for the USB OTG HS peripheral to ENABLED. From there I expect the USB peripheral to take care of itself.
Unfortunately, in DMA mode, the device transmits exactly three 512-byte packets and then hangs.In my short test, I request four packets. The fourth one never moves. The PC host receiver never gets the fourth packet. The first three arrive intact. I tried tests where the buffer containing the transmit data is set to either 512 bytes long, 1024 bytes long or 2048 bytes long. Each test moves 3*512 bytes and stops.
[After posting the above, I did some additional tests by breaking the data into small chunks, as small as 4 bytes at time. The magic limit of the number of bytes is about 1700. Every permutation stopped somewhere near 1700 bytes sent. Data always arrives at the receiver in perfect condition. (The last test made 425 sends at 4 bytes at a time.) What is special about that number?]
What am I missing in my configuration?
Thanks, Erik
Solved! Go to Solution.
2025-05-10 4:52 PM
The issue is resolved.
In a nutshell, I neglected to define the depth of the command FIFO which, is on EP2.
The last config in this excerpt was missing (see usbd_conf.c):
HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200); // 2048 bytes
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, USBD_MAX_EP0_SIZE / 4); // was 0x10 (words)
// This is in words and must represent 512 bytes to get the maximum packet size.
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, USBD_CDCACM_EPIN_HS_MPS / 4); // 2048 bytes
// The ThreadX example sets space for this FIFO, in addition to the three above.
// The descriptor indicates an enpoint 2, not sure why this setting was dropped.
// Here it is added back in. With this setting missing, the driver appears to work
// but it does not support IP DMA mode (the interface hangs after ~1700bytes).
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 2, USBD_CDCACM_EPINCMD_HS_MPS / 4); // 8 bytes
Why? The example I based my driver on (https://github.com/STMicroelectronics/stm32u5-classic-coremw-apps), only had the first three settings. I found the fourth configuration in the newer, ThreadX-based example. Adding it cleared up the DMA issue. The defines and their values were all taken from the ThreadX example.
I cannot provide an explanation about why the the DMA worked up to ~1700 bytes.
2025-05-08 3:48 AM
2025-05-08 5:02 PM - edited 2025-05-13 9:18 AM
Hi FBL,
Yes, it the Nucleo-U5A5ZJ-Q to be exact. I also put my test case up on GitHub. That may be more convenient. I sent you the link as a direct message. The repo is private, but if you send me your GitHub user ID I can add you.
Please let me know how you want to proceed.
Thanks,
Erik
2025-05-10 4:52 PM
The issue is resolved.
In a nutshell, I neglected to define the depth of the command FIFO which, is on EP2.
The last config in this excerpt was missing (see usbd_conf.c):
HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200); // 2048 bytes
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, USBD_MAX_EP0_SIZE / 4); // was 0x10 (words)
// This is in words and must represent 512 bytes to get the maximum packet size.
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, USBD_CDCACM_EPIN_HS_MPS / 4); // 2048 bytes
// The ThreadX example sets space for this FIFO, in addition to the three above.
// The descriptor indicates an enpoint 2, not sure why this setting was dropped.
// Here it is added back in. With this setting missing, the driver appears to work
// but it does not support IP DMA mode (the interface hangs after ~1700bytes).
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 2, USBD_CDCACM_EPINCMD_HS_MPS / 4); // 8 bytes
Why? The example I based my driver on (https://github.com/STMicroelectronics/stm32u5-classic-coremw-apps), only had the first three settings. I found the fourth configuration in the newer, ThreadX-based example. Adding it cleared up the DMA issue. The defines and their values were all taken from the ThreadX example.
I cannot provide an explanation about why the the DMA worked up to ~1700 bytes.
2025-05-24 9:27 PM
I was asked about this driver in a private message. Here is my reply:
Depending on the task, I've been seeing at least 35E6bits per second. I haven't finished testing and my test does a lot of computation for each packet. I expect that moving raw data should be able to go faster.
STM used "classic" to describe this driver, so I'm sticking with it. I think of the Thread-X based middle ware as the modern way to implement a USB device, but we wanted something that could work without an RTOS.
I basically copied from two examples. Most of the code came directly from this example:
https://github.com/STMicroelectronics/stm32u5-classic-coremw-apps.git
This one was used as reference:
git@github.com:STMicroelectronics/stm32-mw-usb-device.git
What I share is basically the first code base stripped down to just files necessary for my task. It is essentially STM code with bug fixes and a little customization. There is another driver that sits on top of the one I'm providing. Most of what that does is simple loading/unloading of Tx/Rx buffers.
2025-05-27 2:16 AM
Thank you @Erik16 for your feedback.
About the limit of 1700 bytes before hanging likely correlates with the cumulative size of the FIFO buffers before EP 2's buffer overflowed or is already unavailable. Without proper configuration, the DMA controller couldn't manage the data flow beyond this point.
The example provided here doesn't use interrupt endpoint and CDC_Itf_Control().
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.