2024-12-01 10:04 PM - last edited on 2024-12-01 11:58 PM by SofLit
We are trying to send serial data from an ST microcontroller to a PC using CDC_Transmit_FS.
We can send data less than 16Kbyte (4096 * 4byte) without any problem, but when we try to send larger size, sometimes we get USBD_STATUS_CANCELED (confirmed by Wireshark + USBpcap).
Could you please tell us why the above behavior occurs?
2024-12-03 12:39 AM
Hi @pass3master
For bulk transfer in full speed, max packet size is 64. It is preferable to share your trace to understand better the error. Instead of sending a large chunk of data at once, split it into smaller chunks that fit within the endpoint buffer size (64bytes in FS mode).
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.
2024-12-03 12:47 AM
Thank you for your response. I see.
So, if I want to transfer 40Kbytes of data, I need to call CDC_Transmit_FS 625 times (40000 ÷ 64)?
2024-12-03 01:47 AM
Hi @pass3master
As explained in this article How to select suitable endpoints for your STM32 US... - STMicroelectronics Community, you can implement double buffering if available, to improve data throughput. Also, FIFO sizes can be adjusted to optimize performance and reduce CPU overhead. For example, to handle more data and reduce the frequency of FIFO overflows, bulk endpoints require large FIFOs to handle large data transfers efficiently. Otherwise, you can implement a timer to manage the transmission of large data chunks by generating periodic interrupts. Using this timer, you allow your STM32 perform other tasks in between transmission and reduce the risk of overwhelming the USB stack.
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.
2024-12-03 01:59 AM - edited 2024-12-03 02:05 AM
@pass3master wrote:Thank you for your response. I see.
So, if I want to transfer 40Kbytes of data, I need to call CDC_Transmit_FS 625 times (40000 ÷ 64)?
Actually 626 times, to send the ZLP after the last 64-byte packet. Hint: use TransmitComplete callback to send the next portion. Also, check if the USB stack you use appends ZLPs automatically. If so, don't use 64-byte portions as they will be transmitted as 2 packets.
Also, do NOT call Transmit from the main loop - it should be called from and ISR of the same priority as USB interrupt. That in fact may be the source of your original problem.
2024-12-03 05:11 PM
Why should I not call CDC_Transmit_FS from the main loop?
Is it because other interrupts may occur during transmission?
2024-12-04 03:18 AM
It was explained in few threads on USB. The HAL routines are not designed to be reentrant. If a USB interrupt is triggered during the execution of Transmit, there is a chance to store an incorrect value in one of USB peripheral register. This may easily lead to USB hangups or incorrect operation. So, either use software-generated interrupt to call Transmit (the priority must be the same as USB hw interrupt) or call transmit with interrupts disabled.
2024-12-04 03:59 PM
Thank you for your answer. I see. I understand.
I have one more question. Is it possible to disable only the USB interrupt? Also, how should I write this in the program?
2024-12-05 01:56 PM
Right, it's enough to disable USB int. Use NVIC_DisableIRQ() and NVIC_EnableIRQ().
2024-12-05 02:31 PM - edited 2024-12-06 08:29 AM
Except of one small thing: chance of priority inversion. If you raise the interrupt priority to the level of USB, all interrupts of lower priority will be blocked. If you just disable the USB interrupt, you remain at background/thread priority and can be preempted by interrupts of lower priority than the USB.