2012-11-19 02:17 AM
I want to use the CDC example to send ADC data to a PC in a fast way.
My problem is that I seem to be losing data erratically, especially if I send more data. I changed the usbd_cdc_VCP.c file in the following way (see code below): - when DataRx is called (when a character comes in) it will set a counter (StartSend) - I added a SOF callback that is called from usbd_cdc_core.c on each SOF In this callback, the counter is decremented and a 250 char block is sent. This is repeated this the counter hits zero If I set StartSend to values below 8 (2000 chars, spread over 8 frames) then I get the right number of characters in the RealTerm terminal program that I am using in 95 % of cases In the other 5% I first get 976 chars and 3024 on the next character that I send. If I set StartSend to higher values (9 for example), I get even more problems: 202,202,202,2250,202,202,202,... chars received on each 2250 chars send. If I set the circular buffer (APP_Rx_Buffer) size from 2048 to 2148 bytes long. then this changes to: ..., 102,102,102,2250,102,102,102,... So in both cases, the number of disappeared chars seems to be equal to the buffer size (APP_RX_DATA_SIZE) The code changes are here below: Does anybody have an idea of what might be going wrong here? static uint16_t RP700_DataRx (uint8_t* Buf, uint32_t Len) { uint32_t i,n; uint8_t Buffer[APP_RX_DATA_SIZE]; STM_EVAL_LEDToggle(LED3); StartSend=4; return USBD_OK; } static uint16_t RP700_DataBufTx (uint8_t* Buf, uint32_t Len) { uint32_t i; for (i = 0; i < Len; i++) { APP_Rx_Buffer[APP_Rx_ptr_in] = i; APP_Rx_ptr_in++; if(APP_Rx_ptr_in == APP_RX_DATA_SIZE) { APP_Rx_ptr_in = 0; /* To avoid buffer overflow */ STM_EVAL_LEDToggle(LED4); // Blue led } } return USBD_OK; } static uint16_t RP700_SOF () { uint32_t i,n; uint8_t Buffer[APP_RX_DATA_SIZE]; STM_EVAL_LEDToggle(LED2); // top RED LED if (StartSend) { RP700_DataBufTx (Buffer, 250); StartSend--; } // 20x 250 chars return USBD_OK; } #endpoint-interrupts #usb-lib #usb-lib-cdc2012-11-19 08:06 PM
> I changed the usbd_cdc_VCP.c file in the following way
Ah, you are working on STM32_USB-Host-Device_Lib_V2.1.0 The ''USB_Device_Examples\VCP'' is customized for USB-UART, in which UART RX input comes asynchronously. This requirement makes the firmware a little complicated. For the transfer of ADC data, you may simplify it, without SOF process. There are a couple of implementation of ADC data transfer, for example, a) Streaming type Host sends ''start ADC'' command to the virtual COM port. The device streams ADC data over the COM port, until host puts ''stop ADC'' command. b) Block tranfer type Host sends ''Take ADC data'' command, with sampling period figure. When the sampling finishes, the device returns the data block. etc. The modification of the device firmware depends on your requirement. Which one do you like? My recommendation is, Starting with b) Block Transfer, clean up the example code to delete unused UART procedures. In this process, you'll get better perspective of the code. In this model, the timing of ADC and USB are separated. It results in simple sequence of control structure. And then, move to a) Streaming type, in which the timing of ADC and USB closely relates. This requirement introduces more extension over the b) approach, such as cyclic buffer. Tsuneo2012-11-20 07:05 AM
Hello Tsuneo
Thanks for the reply. I have got one problem solved now: the CDC_IN_FRAME_INTERVAL Framecounter loop was only responding to 1/40 SOF. I removed the loop so I always call Handle_USBAsynchXfer(pdev) on each SOF I still get problems after some (random number) of data sends though: I am still sending numbers 0...250, in a fixed memory buffer in High Speed mode. Each time I receive a character, I do this for 40 consecutive SOF's. Wat I get back is 10000 chars most of the time (so OK) but after a few successful sends, I receive less than the 40 frames and the output communication hangs. Using LED toggles I can see that, after hanging, The frimware still receives the trigger char from the PC, and Handle_USBAsynchXfer is still called, but usbd_cdc_DataIn stops being called (so no IN endpoint interrupts any more) I printed the endpoint status to the LCD in the Handle_USBAsynchXfer function using: USB_status=DCD_GetEPStatus(pdev ,CDC_IN_EP); sprintf(statString,''%d '',USB_status); LCD_UsrLog(statString); This shows that is is 48 (decimal) and does not change before or after hanging. The code is below, Do you have any idea what could make it hang? Thank you, Bart static uint16_t RP700_Init(void) { uint8_t i=0; for (i = 0; i < 250; i++) APP_Rx_Buffer[i] = i; return USBD_OK; } static uint16_t RP700_SOF () { if (StartSend) { APP_Rx_ptr_in = 250; StartSend--; } // 20x 250 chars return USBD_OK; } static uint8_t usbd_cdc_SOF (void *pdev) { static uint32_t FrameCount = 0; APP_Rx_ptr_out = 0; APP_Rx_ptr_in = 0; USB_Tx_State = 0; /* signal to RP700 layer that PC requested data packet */ APP_FOPS.pIf_SOF(); Handle_USBAsynchXfer(pdev); return USBD_OK; } static void Handle_USBAsynchXfer (void *pdev) { uint16_t USB_Tx_ptr; uint16_t USB_Tx_length; if(USB_Tx_State != 1) { if (APP_Rx_ptr_out == APP_RX_DATA_SIZE) { APP_Rx_ptr_out = 0; } if(APP_Rx_ptr_out == APP_Rx_ptr_in) { USB_Tx_State = 0; return; } if(APP_Rx_ptr_out > APP_Rx_ptr_in) /* rollback */ { APP_Rx_length = APP_RX_DATA_SIZE - APP_Rx_ptr_out; } else { APP_Rx_length = APP_Rx_ptr_in - APP_Rx_ptr_out; } #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED APP_Rx_length &= ~0x03; #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ 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; } USB_Tx_State = 1; STM_EVAL_LEDToggle(LED2); // top RED LED DCD_EP_Tx (pdev, CDC_IN_EP, (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr], USB_Tx_length); } } static uint8_t usbd_cdc_DataIn (void *pdev, uint8_t epnum) { uint16_t USB_Tx_ptr; uint16_t USB_Tx_length; STM_EVAL_LEDToggle(LED4); // Blue led 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-11-21 12:40 AM
I downloaded Advanced USB port monitor, and get the following last logs when the crash happens..
Version:0.9 StartHTML:-1 EndHTML:-1 StartFragment:000081 EndFragment:002318[192] URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (SUCCESS/0x00000000) 20121121091277 (+0)
Pipe handle: 0x876883F4 Transfer flags: 0x00000003 (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) Transfer buffer: 0x8538E0042012-11-21 07:59 AM
I seem to have solved my problem by lowering the data rate.
The FrameCounter that was used in the SOF function before seems to have a reason: If you send to many bytes on each SOF then the datarate becomes to high and the connection hangs. Problem was solved by reintroducing the FrameCounter (see below) and setting the number of byte sent (DATAQUANTUM) to 300 and CDC_IN_FRAME_INTERVAL to 10. This results in about 80Kbytes /sec although I am sure that everything is configured for High Speed USB (I checked via USB port monitor). If you try to go faster by increasing DATAQUANTUM or decreasing CDC_IN_FRAME_INTERVAL then the connection stops (as documented above) Might this be a problem with ST PC-side driver, or maybe the RealTerm program that I use on the PC slows things down? Which Brings me back to my original question: is there a way to check (at the VCP level) if the PC-side buffer has overrun, recover and re-send the data?static uint16_t RP700_Init(void)
{ uint16_t i=0,MSB; for (i = 0; i < DATAQUANTUM; i+=2) { // APP_Rx_Buffer[i] = i; MSB=i/256; APP_Rx_Buffer[i] = MSB; APP_Rx_Buffer[i+1] = i-MSB*256; } return USBD_OK; } static uint16_t RP700_SOF () { static uint32_t FrameCount = 0; if (StartSend) if (FrameCount++ == CDC_IN_FRAME_INTERVAL) { FrameCount = 0; StartSend--; APP_Rx_ptr_in = DATAQUANTUM; } return USBD_OK; }2013-01-15 10:53 AM
Hi Van,
Can U share your code for ADC data with USB.2014-02-07 05:33 AM
Hi
I`ve found you question and maybe I can help. I`ve customized ST`s CDC for my own (adding FreeRTOS semaphores for FIFO operation) and now I can achieve maximum speed of CDC over FS USB. My hints for you are: - use SOF as kick-out mechanism to start transactions over bulk EP - the rest do in callback - enqueue data in fifo And remember to achieve max speed of CDC only full size packet have to be send (64bytes in FS USB). If not USB limitations occur. Also I don`t like ST`s implementation of circular buffer. It`s buggy and extrimly difficult to resolve. I`ve rewrite it all, starting from SOF handler and .._DataOut handler up. My app use CDC to perform crypto operation. Data are send to STM32, encrypt and send back. Max speed is required for it. I hope it help.2014-02-08 04:49 AM
Hi Krutecki,
But how do you handle packets that are not 64 bytes. For example, if you receive only 1 byte or 2 bytes, do you padd it to 64?2014-02-08 04:49 AM
Hi Krutecki,
But how do you handle packets that are not 64 bytes. For example, if you receive only 1 byte or 2 bytes, do you padd it to 64?2014-02-18 01:10 PM
Hi
I don`t understand :( Receiving (data send from host to device) is over you control. You just got pointer to data and data length. Then I`m pushing to FIFO and counting semaphore is updated. It`s easy, no to much to improve here.I was talking about opposite situation - sending data from device to host.Chris