2012-08-16 11:52 AM
Hello!
Looks like there is a subtle bug in the USB CDC device implementation. I played recently with STM32F4DISCOVERY board. In order to test USB operation in VCP mode I've created simple code which just echo everything back. At the host side I've launched test application writing the sequence of random bytes with random length to the port and reading the sequence back. What I've found rather quickly is that the read from the port hung occasionally in the state where the ARM is thinking the data is sent but application still can't receive them. After 2 days of thinking and experimenting I've found the solution - see the attached diff. In short - the receiver is detecting the end of the message by looking at the size of the last received chunk. If it is equal to the maximum transfer size it may expect more data coming and refuse to return the buffered data to application. So in case the last transaction size is a multiple of the maximum transfer size we have to transmit zero sized packet just to indicate that we have no more data to transmit. Regards, Oleg. --- STM32_USB_Device_Library\Class\cdc\src\usbd_cdc_core.c.1 Fri Oct 28 10:31:18 2011 +++ STM32_USB_Device_Library\Class\cdc\src\usbd_cdc_core.c Thu Aug 16 22:29:38 2012 @@ -624,7 +624,17 @@ { if (APP_Rx_length == 0) { - USB_Tx_State = 0; + if (((USB_OTG_CORE_HANDLE*)pdev)->dev.in_ep[epnum].xfer_len != CDC_DATA_IN_PACKET_SIZE) + { + USB_Tx_State = 0; + return USBD_OK; + } + /* Transmit zero sized packet in case the last one has maximum allowed size. Otherwise + * the recipient may expect more data coming soon and not return buffered data to app. + * See section 5.8.3 Bulk Transfer Packet Size Constraints + * of the USB Specification document. + */ + USB_Tx_length = 0; } else { @@ -643,13 +653,12 @@ APP_Rx_ptr_out += APP_Rx_length; APP_Rx_length = 0; } - - /* Prepare the available data buffer to be sent on IN endpoint */ - DCD_EP_Tx (pdev, + } + /* Prepare the available data buffer to be sent on IN endpoint */ + DCD_EP_Tx (pdev, CDC_IN_EP, (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr], USB_Tx_length); - } } return USBD_OK; #stm32-usb-library #!bug #cdc-device2012-08-16 12:47 PM
What version of the library is this from?
The current V2.1.0 from March 2012 looks like followsstatic uint8_t usbd_cdc_DataIn (void *pdev, uint8_t epnum)
{
uint16_t USB_Tx_ptr;
uint16_t USB_Tx_length;
if (USB_Tx_State == 1)
{
if (APP_Rx_length == 0)
{
USB_Tx_State = 0;
}
else
{
if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE){
USB_Tx_ptr = APP_Rx_ptr_out;
USB_Tx_length = CDC_DATA_IN_PACKET_SIZE;
APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE;
APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE;
}
else
{
USB_Tx_ptr = APP_Rx_ptr_out;
USB_Tx_length = APP_Rx_length;
APP_Rx_ptr_out += APP_Rx_length;
APP_Rx_length = 0;
}
/* Prepare the available data buffer to be sent on IN endpoint */
DCD_EP_Tx (pdev,
CDC_IN_EP,
(uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr],
USB_Tx_length);
}
}
return USBD_OK;
}
2012-08-17 01:05 AM
Yes, I'm using v2.1.0. The patch is the diff to it that fixing the problem.
2012-12-17 03:00 AM
Hi, Oleg
I also encountered similar problem on ST32F2 series. Echo was not working when I sent packets equal ar larger than 512 bytes (FIFO size) Unfortunately, your code did not help. How did you realised ECHO? In my case I modified in file ''usbd_cdc_vcp.c'' function VCP_DataRx() as follows: static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len) { VCP_DataTx (Buf, Len); return USBD_OK; } May be, this is incorrect echo style? In my case I traced functions writing into DIEPCTL, DIEPTSIZ and into FIFO IN buffer. Data was written in due order, but without activity on USB. Best regads, Serafim