cancel
Showing results for 
Search instead for 
Did you mean: 

Virtual_COM_Port (USB CDC) - Throughput

budde
Associate II
Posted on November 10, 2010 at 11:06

Virtual_COM_Port (USB CDC) - Throughput

4 REPLIES 4
budde
Associate II
Posted on May 17, 2011 at 14:14

I think this was a problem in the Linux Kernel. After using a newer Linux version, the throughput looks much better. So the OUT transfers are working now.

But I have still problems with double buffering and IN transfers.

I always receive some additional characters on the PC, which I have not sent.

To fix this problem I have changed the reset code from

  SetEPDblBuffCount(ENDP1, EP_DBUF_IN, 64);

to

  SetEPDblBuffCount(ENDP1, EP_DBUF_IN, 0);

My interrupt handler looks like this:

-------------------------------------------------------------------------

void Usb::HandleTxInternal (bool sof)

{

  uint8_t   buf[VIRTUAL_COM_PORT_DATA_SIZE];

  uint32_t  cnt;

  if (sof == false)

    m_tx_pending--;

  while (m_tx_pending < 2)

  {

    if (m_buf_tx.IsEmpty() == true)

      break;

    if (m_buf_tx.GetCount() < VIRTUAL_COM_PORT_DATA_SIZE)

      cnt = m_buf_tx.GetCount();

    else

      cnt = VIRTUAL_COM_PORT_DATA_SIZE;

 

    for (uint32_t i=0; i < cnt; i++)

    {

      buf[i] = m_buf_tx.GetItem();

      m_buf_tx.RemoveItem();

    }

 

    if (GetENDPOINT (ENDP1) & EP_DTOG_RX)

    {

      UserToPMABufferCopy (buf, ENDP1_TXADDR1, cnt);

      SetEPDblBuf1Count (ENDP1, EP_DBUF_IN, cnt);

    }     

    else

    {

      UserToPMABufferCopy (buf, ENDP1_TXADDR0, cnt);

      SetEPDblBuf0Count (ENDP1, EP_DBUF_IN, cnt);

    }

   

    FreeUserBuffer(ENDP1, EP_DBUF_IN);

    m_tx_pending++;

    if (GetEPTxStatus (ENDP1) == EP_TX_NAK)

      SetEPTxStatus(ENDP1, EP_TX_VALID);

  }

}

-------------------------------------------------------------------------

I call this method from the endpoint and the SOF callbacks.

The first buffer is always send twice.

Even after reading the manual of ST several times, I still do not understand how to implement double buffering correctly.

tsuneo
Senior
Posted on May 17, 2011 at 14:14

> At the moment I can reach only a throughput of around 32 kByte/s. I am using Linux for testing:

 

> dd if=/dev/zero of=/dev/ttyACM0 bs=2048 count=10

 

Ummm, too slow.

I have doubt that dd (or dev/tty) really passes 2048 bytes block at a time to the PC host controller.

Check the low-level USB system call using usbmon. What is the real transfer size of each bulk transfer?

USB sniffing on linux - using usbmon and WireShark

http://biot.com/blog/usb-sniffing-on-linux

Tsuneo

tsuneo
Senior
Posted on May 17, 2011 at 14:14

> Even after reading the manual of ST several times, I still do not understand how to implement double buffering correctly.

Surely, the reference manual is complicated for the double buffer.

The reason is that this table leads you misunderstanding.

''Table 167. Bulk double-buffering memory buffers usage''

This table is fine just when a hardware interrupt occurs on the endpoint (EP). ie. just when you apply this logic in the EP callback, it works as expected. At IN EP interrupt, at least one buffer is empty. At OUT EP interrupt, at least one buffer is occupied. It is the reason why the table doesn't have the conditions, ''both buffers are occupied'' for IN, ''both buffers are empty'' for OUT.

When you apply this logic at SOF interrupt, you may fail, because you can't tell if there is any empty IN buffer or not. You need another semaphore for SOF interrupt, which is set in the IN EP callback to tell the number of empty buffer.

Tsuneo

budde
Associate II
Posted on May 17, 2011 at 14:14

Hi,

thanks a lot for your answer.

I think I already have this semaphore (called ''m_tx_pending'' in my code).

The strange this is: if I but e.g. 7 bytes into my TX buffer (m_buf_tx) and send them from the SOF interrupt (using ''HandleTxInternal (true)''), the data is transmitted correctly to the PC, but this is done twice. So I receive 14 bytes on the PC. And ''EP1_IN_Callback'' is called twice, too.

When should I call ''FreeUserBuffer(ENDP1, EP_DBUF_IN)'' the first time? Directly after putting the first data into the USB buffer? Or should I call it after receiving the first ''EP1_IN_Callback()''.