cancel
Showing results for 
Search instead for 
Did you mean: 

USB CDC device receive fails on transmit

JD1800
Associate II
Posted on March 31, 2017 at 23:39

I am using the USB CDC library on a STM32F746 as created with CubeMX and have run into a problem when the MCU transmits at the same time that it is receiving over USB.  I had a PC bursting data to the MCU.  The data is packetized, so for test purposes I had the MCU send a single byte each time it received a full packet.  If the PC sent one packet at a time, this worked fine, but when it sent a burst of packets back to back, the MCU would receive the first packet and part of the next, then it would stop receiving data.  This was with 262 byte packets, but when I reduced the packet size to about 200 bytes, which would change the timing of the transmit relative to the receive stream, the MCU would receive all of the packets.

On further digging, I found that when the reception failed, the CDC receive end point was disabled (EPENA cleared in DOEPCTL).  The code calls USBD_CDC_ReceivePacket every time in the CDC_Receive_FS callback, but when this happened, I would need to call

USBD_CDC_ReceivePacket again to get reception started again.

It seems that somehow, when CDC data is transmitted at a certain point during CDC reception, it causes the receive end point to be disabled.  I assume it is happening in the HAL_PCD_IRQHandler ISR, but I have not been able to capture when or how it happens.  For now, I have implemented a brute force fix where the main loop keeps checking if the Rx end point is enabled, and if not it calls USBD_CDC_ReceivePacket again.

Has anyone else seen this issue or know how or why it happens?  I would very much like if I could have this work properly.

#end-point #cdc_receive_fs #cdc #usb #usbd_cdc_receivepacket
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on April 11, 2017 at 14:03

It looks like the fix described in

https://community.st.com/0D50X00009XkfIBSAZ

byarnold.rene

solves to problem

Do this :

'For those of you, who are interested in a solution: We have fixed it now by surrounding all code from HAL_LOCK until HAL_UNLOCK (including those 2 macro 'calls') of function HAL_PCD_EP_Transmit() in file stm32f4xx_hal_pcd.c by a critical section, so it can no longer be preempted by the interrupt, that raises, when the USB device receives data from the host (in other words: HAL_PCD_EP_Transmit() and HAL_PCD_EP_Receive() must not preempt each other, or at least the code between LOCK and UNLOCK must not be preempted). Though you have to be aware of the fact, that Cube overwrites this code, when code is re-generated.'

That is, Add

HAL_NVIC_DisableIRQ(USB_IRQn);

just before

__HAL_LOCK(hpcd);

and add

HAL_NVIC_EnableIRQ(USB_IRQn);

just after

__HAL_UNLOCK(hpcd);

it is now running stable longer than ever.

View solution in original post

3 REPLIES 3
CHABIN.Laurent
Associate II
Posted on April 10, 2017 at 20:00

I also have right now something that looks like that. Spent a lot of time on it. Stuck.

Using USB Custom HID. Bulk transfers. 1ms IN, 10 ms OUT

Code generated with STM32CubeMX, on STM32F072RB on Discovery board. Even updated today the libs and regenerated the code : no progress

If I only transmit from PC, OK. Never blocks

If I only receive from PC, OK. Never Blocks

Now,

If I have IN reports at about every 16ms, and OUT reports about every 20ms, after some random time, really random, but never much more than 30 seconds, the OUT reports are stuck, that is, the transaction never completes.

After that, the IN reports can continue with no problem. I never have problems on the IN reports.

If I restart my PC application, I even can still enumerate, but cannot send any OUT report. A WriteFile() produces a ERROR_IO_PENDING than never ends.

Now 

Here is the IMPORTANT information : if I disconnect the 'USB User' from the board, (still running thanks to the other USB connector for the supply and debug), then reconnect (which calls USBD_LL_Reset() among other things) , IT WORKS again, the OUT reports go through (at least for another 30sec...). 

For me, this is the PROOF that it is a low level problem in ST's firmware.

I have even tried to activate double buffering : even worse. Can't make it work at all in double buffer.

Posted on April 11, 2017 at 14:03

It looks like the fix described in

https://community.st.com/0D50X00009XkfIBSAZ

byarnold.rene

solves to problem

Do this :

'For those of you, who are interested in a solution: We have fixed it now by surrounding all code from HAL_LOCK until HAL_UNLOCK (including those 2 macro 'calls') of function HAL_PCD_EP_Transmit() in file stm32f4xx_hal_pcd.c by a critical section, so it can no longer be preempted by the interrupt, that raises, when the USB device receives data from the host (in other words: HAL_PCD_EP_Transmit() and HAL_PCD_EP_Receive() must not preempt each other, or at least the code between LOCK and UNLOCK must not be preempted). Though you have to be aware of the fact, that Cube overwrites this code, when code is re-generated.'

That is, Add

HAL_NVIC_DisableIRQ(USB_IRQn);

just before

__HAL_LOCK(hpcd);

and add

HAL_NVIC_EnableIRQ(USB_IRQn);

just after

__HAL_UNLOCK(hpcd);

it is now running stable longer than ever.

JD1800
Associate II
Posted on April 11, 2017 at 17:21

Thanks Chabin for finding this.  I tried it in my test code and it does resolve the issue.  It's unfortunate that ST has not fixed this yet as it has been almost 2 years since it was first noted.