cancel
Showing results for 
Search instead for 
Did you mean: 

problems with USB lib CDC example

bart239955
Associate II
Posted on November 19, 2012 at 11:17

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-cdc
9 REPLIES 9
tsuneo
Senior
Posted on November 20, 2012 at 05:06

> 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.

Tsuneo

bart239955
Associate II
Posted on November 20, 2012 at 16:05

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;

}

bart239955
Associate II
Posted on November 21, 2012 at 09:40

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: 0x8538E004

bart239955
Associate II
Posted on November 21, 2012 at 16:59

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;

}

mahapushpa
Associate II
Posted on January 15, 2013 at 19:53

Hi Van,

Can U share your code for ADC data with USB.

krutecki
Associate II
Posted on February 07, 2014 at 14:33

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.

lowpowermcu
Associate II
Posted on February 08, 2014 at 13:49

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?

lowpowermcu
Associate II
Posted on February 08, 2014 at 13:49

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?

krutecki
Associate II
Posted on February 18, 2014 at 22:10

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