Go Down

Topic: Faster SerialUSB read (Read 628 times) previous topic - next topic

BluePill

Jul 30, 2015, 09:51 pm Last Edit: Jul 30, 2015, 09:55 pm by BluePill
Because the transfer rates of SerialUSB.readBytes are slow (I transfer pixel data for a 240x400 px touchscreen from my PC and get less than one full frame per second), I decided to write my own read function which has almost eight times faster transfer rates (with an average of around 1270 KB/s compared to readBytes with around 160 KB/s). If I actually transfer the data to the screen, I end up with around 620 KB/s which is enough for more than 2 frames per second. [EDIT : I am talking about 192 KB per transfer]
The difference is mostly caused by the amount of function calls. SerialUSB.accept calls USDB_Recv for each byte.
A disadvantage of it is that it sometimes seems to skip or corrupt bytes but I couldn't find out why. Adding acknowledge data which the PC waits for seems to make it less likely.

Here's the code :
Code: [Select]

void WaitReadUSB(void *data, uint32_t len)
{
  uint32_t i = 0;
  if (len > 0)
  {
    while (!USBD_Available(CDC_RX)){}
    while (i < len)
    {
      i += USBD_Recv2(CDC_RX, &((byte*)data)[i], min(len-i,16));
      if (!USBD_Available(CDC_RX))
      {
        udd_ack_fifocon(CDC_RX);
        if (i < len)
        {
          while (!USBD_Available(CDC_RX))
          {}
        }
      }
    }
  }
}

USBD_Recv2 is a modified USBD_Recv that only calls UDD_Recv one. I inserted it into USBCore.cpp from the Arduino Due package (and the declaration into USBAPI.h).
Code: [Select]

uint32_t USBD_Recv2(uint32_t ep, void* d, uint32_t len)
{
if (!_usbConfiguration)
return -1;

LockEP lock(ep);
len = min(UDD_FifoByteCount(ep & 0xF),len);
uint8_t* dst = (uint8_t*)d;
UDD_Recv(ep & 0xF, dst, len);
if (len && !UDD_FifoByteCount(ep & 0xF)) // release empty buffer
UDD_ReleaseRX(ep & 0xF);

return len;
}


Even if the data isn't used, SerialUSB.accept still is called by an interrupt handler in USBCore.cpp which results in loss of data until the buffer is filled. I just added an additional parameter to Serial_::begin that specifies whether Serial_::accept should just return immediately (it is in CDC.cpp and the header is USBAPI.h).

Go Up