How to get the maximum possible bandwidth using LUFA?

88 views
Skip to first unread message

esakaf...@gmail.com

unread,
Jan 22, 2016, 2:57:32 AM1/22/16
to LUFA Library Support List
I'm writing an application for an AT90USB646 microcontroller that will communicate with a host PC using LUFA and libusb. If possible, I would like to get at least 1 Mbps. I decided to give BulkVendor Demo a try, since as far as I know, Bulk transfers can use almost all the exceeding bus capacity (as long as it is not being used for other kind of transfers) and are the ones used with devices that do not have strict latency requisites, but demand the most bandwidth (e.g. hard disks).

On the PC, I'm using libusb to communicate with the device. The demo runs OK, but I'm getting an extremely poor bit rate (about 32 Kbps!). I suppose there must be a trick to achieve higher bit rates, but I cannot get it. I know it should be possible to get 1 Mbps on a full speed link, because I do 921600 bps with a CP2102 full speed chip that has almost the same configuration that I'm using. This is the output of lsusb for the CP2102:

$ lsusb -vd10c4:

Bus 001 Device 004: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x10c4 Cygnal Integrated Products, Inc.
  idProduct          0xea60 CP210x UART Bridge / myAVR mySmartUSB light
  bcdDevice            1.00
  iManufacturer           1
  iProduct                2
  iSerial                 3
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      0
      bInterfaceProtocol      0
      iInterface              2
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0


And this is the output when polling my device:

$ lsusb -vd10c4:

Bus 001 Device 004: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x10c4 Cygnal Integrated Products, Inc.
  idProduct          0xea60 CP210x UART Bridge / myAVR mySmartUSB light
  bcdDevice            1.00
  iManufacturer           1
  iProduct                2
  iSerial                 3
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      0
      bInterfaceProtocol      0
      iInterface              2
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0


Both configurations use 64 byte bulk endpoints to do the transfers!

What should I do to maximize speed? Any suggestions?

Thanks in advance!

Dean Camera

unread,
Jan 23, 2016, 8:38:39 PM1/23/16
to lufa-s...@googlegroups.com
Hi Eska (?),

Try changing the last parameter of the Endpoint_ConfigureEndpoint() calls here:

void EVENT_USB_Device_ConfigurationChanged(void)
{
    bool ConfigSuccess = true;

    /* Setup Vendor Data Endpoints */
    ConfigSuccess &= Endpoint_ConfigureEndpoint(VENDOR_IN_EPADDR,  EP_TYPE_BULK, VENDOR_IO_EPSIZE, 1);
    ConfigSuccess &= Endpoint_ConfigureEndpoint(VENDOR_OUT_EPADDR, EP_TYPE_BULK, VENDOR_IO_EPSIZE, 1);

    /* Indicate endpoint configuration success or failure */
    LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
}

To the value "2", which will use two physical endpoint DPRAM banks. That should allow the AVR core a little more time to re-fill an endpoint bank as the host can read out the previous bank data while the new bank is being filled. Unfortunately the USB AVR8s weren't really designed for speed, so the above combined with a) tight loops to pump the data into endpoint bank as soon as it becomes ready and b) a 16MHz core clock is pretty much the most favourable configuration. At the very least, enabling double-buffering via the above should improve throughput quite a bit.

- Dean
--
You received this message because you are subscribed to the Google Groups "LUFA Library Support List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lufa-support...@googlegroups.com.
To post to this group, send email to lufa-s...@googlegroups.com.
Visit this group at https://groups.google.com/group/lufa-support.
For more options, visit https://groups.google.com/d/optout.

esakaf...@gmail.com

unread,
Jan 24, 2016, 7:02:08 AM1/24/16
to LUFA Library Support List
Thanks a lot Dean for the great LUFA and for the support!

I already got with the solution before reading your reply, and got about 2 Mbps transfer speeds!. Enabling dual endpoints increased throughput a bit, but what really made the big difference was changing the way I read data using libusb. Previously I was reading one endpoint at a time. Changing read length to 8 times endpoint length did the trick! E.g:

ret = libusb_bulk_transfer(handle, ENDPOINT_IN_ADDR, buff, 8 * ENDPOINT_IN_LENGTH, &size, timeout);

BTW, I have tested with shorter and larger read lengths, and it looks like 8 is the optimum parameter: greater values don't increase throughput, but shorter ones decrease it.

Again, thanks!!!

esakaf...@gmail.com

unread,
Jan 25, 2016, 5:12:20 AM1/25/16
to LUFA Library Support List
Unfortunately it looks like I spoke too soon... Even though IN transfers work perfect, I don't know why I cannot get OUT transfers to work. This is how I send data using libusb:

r = libusb_bulk_transfer(handle, ENDPOINT_OUT, data, length, &sent, REGULAR_TIMEOUT);

And this is how I receive data using LUFA:

            // Read data test
            while (TRUE)
            {
                do {
                    USB_USBTask();
                } while (!Endpoint_IsOUTReceived());
                if (Endpoint_Read_Stream_LE(bigBuf, VENDOR_IO_EPSIZE, NULL) != ENDPOINT_RWSTREAM_NoError)
                    LEDs_TurnOffLEDs(LEDS_LED1);
                Endpoint_ClearOUT();
            }


Using the code above, LED1 never turns off, so it looks like Endpoint_Read_Stream_LE() does not report errors. Having a look with libusb debug info enabled, and also with Wireshark sniffer, it looks like 2 64 byte endpoints are sent, but then libusb hangs until it times out (3 seconds on my current code).

I have tried using different values for the transfer lengths (64 bytes and bigger) always with the same result: 128 bytes are transferred and then


esakaf...@gmail.com

unread,
Jan 25, 2016, 5:14:55 AM1/25/16
to LUFA Library Support List
and then it looks like LUFA hangs and is not able to receive data anymore.

Having a look to kernel messages (dmesg) doesn't show anything wrong either...

Any suggestions?

esakaf...@gmail.com

unread,
Jan 25, 2016, 5:22:36 AM1/25/16
to LUFA Library Support List
OK, I have found the problem, I was missing the Endpoint_SelectEndpoint() call. It looks like transfers work now (will have to optimize speed though).

Sorry for being so dumb!
Reply all
Reply to author
Forward
0 new messages