2010-11-10 02:06 AM
Virtual_COM_Port (USB CDC) - Throughput
2011-05-17 05:14 AM
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.2011-05-17 05:14 AM
> 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
2011-05-17 05:14 AM
> 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
2011-05-17 05:14 AM
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()''.