cancel
Showing results for 
Search instead for 
Did you mean: 

USB CDC flow contol

trevor23
Associate III
Posted on February 22, 2013 at 10:48

I’m using a slightly modified version of the USB CDC example on STM32F205. The modification is that I’m terminating the STM32 end with a simple command line rather than tunnelling to and from a UART. This is a full speed (FS) device (not OTG). All works well if receiving small amounts of data. However when the PC sends more data to the device there seems to be no flow control implemented i.e. unless we can consume the data in the USB receive interrupt as fast as it arrives we lose data.

I can’t (and don’t want to) wait around in the USB receive interrupt until all the data has been processed as sometimes the data needs to be saved to external flash which isn’t quick. I need to process the data in another task i.e. not in the interrupt. The root of the problem is that the data is arriving much faster than it can be dealt with. So I need some way of “holding the data back� from the sender -- like a flow control mechanism.

I need some way of “telling� the sending USB end that I’m getting near the limit of what I can receive so that it can stop sending more data - just like what would happen with hardware handshaking over a normal serial port.

Anyone else come accross this issue? Any ideas?

Interestingly on our STM32103 projects this works fine  --  I think because with that USB library you have to poll for new data and if you don’t poll fast enough there is some form of flow control.

Regards

Trevor

My setup:

Rowley Crossworks for ARM 2.3.0

Windows 7

STM32F205

ARM-USB-TINY JTAG

1 REPLY 1
tsuneo
Senior
Posted on February 26, 2013 at 09:38

> However when the PC sends more data to the device there seems to be no flow control implemented

USB already has this flow control on the hardware - NAKing. For the OTG_FS core, defer the ''arm'' of the bulk OUT EP, until the firmware finishes the process of the last packet. While the bulk OUT EP is not armed, the EP returns NAKs to the host, which means ''try the transaction again later''. On the STM32_USB-Host-Device_Lib_V2.1.0, DCD_EP_PrepareRx() arms the bulk OUT EP.

STM32_USB-Host-Device_Lib_V2.1.0\Libraries\STM32_USB_Device_Library\Class\cdc\src\usbd_cdc_core.c
static uint8_t usbd_cdc_DataOut (void *pdev, uint8_t epnum)
{ 
uint16_t USB_Rx_Cnt;
/* Get the received data buffer and update the counter */
USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count;
/* USB data will be immediately processed, this allow next USB traffic being 
NAKed till the end of the application Xfer */
APP_FOPS.pIf_DataRx(USB_Rx_Buffer, USB_Rx_Cnt);
/* Prepare Out endpoint to receive next packet */
DCD_EP_PrepareRx(pdev,
CDC_OUT_EP,
(uint8_t*)(USB_Rx_Buffer),
CDC_DATA_OUT_PACKET_SIZE);
return USBD_OK;
}

Modify above routine, as follows. If APP_FOPS.pIf_DataRx() process would take long time, this callback raises a flag, instead of doing actual process. And then usbd_cdc_DataOut() returns without calling DCD_EP_PrepareRx(). In the main loop, picking up this flag, the process of received packet is done. When this process finishes, the main-loop task calls DCD_EP_PrepareRx(), for the next packet. Tsuneo