Maximizing USB bulk transfer throughput

Author
peplin
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2011/10/26 07:12:06
  • Location: 0
  • Status: offline
2011/10/26 07:18:08 (permalink)
0

Maximizing USB bulk transfer throughput


Hello,

I'm just getting started with USB programming using the recently released Microchip library on the chipKIT board with the network shield. I've tried to learn as much as I can about proper USB programming and it's been good for the most part - however, I'm stuck at a ~75KB/s bulk transfer speed. I apologize for the cross-post on the chipKIT forums if you read both - I'm thinking there is a wider audience here, and I think this question has more to do with the Microchip library.

Some quick background - I need to create a simple USB device that spits on discrete messages to the host PC as fast as possible. The current strategy is to use minified JSON delimited by newlines sent via a bulk transfer endpoint. (of course this could be made faster using plain binary, but this will do for now).

I've trimmed down the GenericUSB example to test the maximum transfer rate, and created a Python receiver (wrapping libusb) for the host. The code is posted here if someone with more experience has a minute to take a look: 
< Argh, I can't post URLs to the forum.  The code is available at https://github.com/openxc...-transfer-benchmarking

On the chipKIT side, the main loop is pretty simple and is basically this:



// using our own loop seems faster than using the arduino's          
while(true) {                                                                                          
    while(usb.HandleBusy(handleInput));                                                                                                    
    handleInput = usb.GenWrite(DATA_ENDPOINT, messageBuffer, messageSize);   


In Python it's a similar thing, a look that requests a read of some size until it hits 10MB transferred. This is the actual read function that gets called:


def _read(self):
        return self.device.read(self.endpoint, self.message_size)


If you download the benchmarkUSB.pde sketch to the chipKIT, then run "python receiver.py" it will read 10MB from the device with various "read request" sizes ranging from 64 bytes (one packet) to 1KB. 

It's my understanding that requesting more data from the host at a time will increase throughput as messaging overhead drops - for some reason, this isn't the case for my code. You'll see as the request size increases the throughput actually drops from 75KB/s to even lower numbers.

Any help would be greatly appreciated, as I'm stumped at this point. I don't think the problem is in the Python code, because I've also tried this benchmark from Java (on Android) and had similar results. That code is also in the Github repository - like the Python it's a pretty simple benchmark, it just does a bulk read of a certain size until it hits 10MB.

(Another thing I've noticed is that the
#define USB_SPEED_OPTION USB_FULL_SPEED
line in usb_config.h seems to have no effect. Whether I define low or full speed, the throughput is the same measly 75KB/s.)


post edited by peplin - 2011/10/26 07:27:12
#1

7 Replies Related Threads

    Antipodean
    Super Member
    • Total Posts : 1556
    • Reward points : 0
    • Joined: 2008/12/09 10:19:08
    • Location: Didcot, United Kingdom
    • Status: offline
    Re:Maximizing USB bulk transfer throughput 2011/10/26 08:55:33 (permalink)
    0
    I get the feeling that there is a lack of understanding of some of USBs underlying limits.

    Get a copy of Jan Axelsons "USB Complete" to see what the speed limits for the various modes are, and the requirements of the modes.


    Do not use my alias in your message body when replying, your message will disappear ...

    Alan
    #2
    peplin
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2011/10/26 07:12:06
    • Location: 0
    • Status: offline
    Re:Maximizing USB bulk transfer throughput 2011/10/26 09:00:04 (permalink)
    0
    Thanks for the tip - I think I have a pretty good understanding of the limits of the various modes. Correct me if this is wrong, but full-speed USB 1.1 is limited to 64-byte packets and the maximum actual throughput should be on the order of 700-1000 KB/s. I'd be happy with half of that, 300KB/s, but all I can get is less than 100 KB/s.
    #3
    chinzei
    Super Member
    • Total Posts : 2250
    • Reward points : 0
    • Joined: 2003/11/07 12:39:02
    • Location: Tokyo, Japan
    • Status: offline
    Re:Maximizing USB bulk transfer throughput 2011/10/26 10:31:24 (permalink)
    0
    I get the feeling that there is a lack of understanding of ChipKit of me Smile
    Please teach me.
     
    On both types of ChipKit board, a FTDI chip sits near the USB connector.
    http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,892,893&Prod=CHIPKIT-UNO32
    http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,892,894&Prod=CHIPKIT-MAX32
     
    Are you connecting the board over this chip?
    Hum, where is the schematic of the board?
     
    Tsuneo
    post edited by chinzei - 2011/10/26 10:33:30
    #4
    chinzei
    Super Member
    • Total Posts : 2250
    • Reward points : 0
    • Joined: 2003/11/07 12:39:02
    • Location: Tokyo, Japan
    • Status: offline
    Re:Maximizing USB bulk transfer throughput 2011/10/26 21:07:21 (permalink)
    0

    Ok, found schematics.
    You are using the on-chip USB device engine of PIC32 over the USB connector on the Network Shield?
    I couldn't imagine that Network Shield has USB connectors, until I see the schematic.wink

    chipKIT UNO32 schematic
    http://digilentinc.com/Da...T%20Uno32_bysa_sch.pdf

    chipKIT Max32 schematic
    http://digilentinc.com/Da...T%20Max32_bysa_sch.pdf

    chipKIT Network Shield schematic
    http://digilentinc.com/Da...twork%20Shield_sch.pdf


    Next, the source code of your implementation.
    The code is available at https://github.com/openxc...-transfer-benchmarking

    Where is the source of your usb.HandleBusy() and usb.GenWrite()?
    Quick search on your arduino-transfer-benchmarking and mpide-0022-windows-20110822.zip ( https://github.com/chipKI..chipKIT32-MAX/downloads ) doesn't hit anything.

    Point the implementation file more exactly.
    How can we comment without knowing what these functions do in background?

    Tsuneo
    post edited by chinzei - 2011/10/26 21:17:01
    #5
    peplin
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2011/10/26 07:12:06
    • Location: 0
    • Status: offline
    Re:Maximizing USB bulk transfer throughput 2011/10/27 11:29:12 (permalink)
    0
    Tsuneo, thanks for looking into it - I'm sorry, I should have made it more clear that I am using the Microchip USB libraries provided via chipKIT at the bottom of this page: http://digilentinc.com/Products/Detail.cfm?NavPath=2,719,943&Prod=CHIPKIT-NETWORK-SHIELD

    That library is where the GenWrite function is implemented, and I believe this is the standard Microchip application library with perhaps a few modifications for the specific hardware.

    You are also correct about the USB controller - I am using the USB port on the network shield (I agree, bad name!) that is not an FTDI controller. 
    #6
    peplin
    New Member
    • Total Posts : 7
    • Reward points : 0
    • Joined: 2011/10/26 07:12:06
    • Location: 0
    • Status: offline
    Re:Maximizing USB bulk transfer throughput 2012/02/06 12:47:03 (permalink)
    0
    I wanted to follow up here because I believe I've solve the problem.

    I've summarized the whole issue here (http://christopherpeplin..../bulk-usb-throughput/) and copied the solution below:

    The problem ended up being much simpler and had more to do with one of the core design principles of USB. After shelving this issue for a few months, I revisited the problem and something caught my eye.

    No matter how many bytes were requested on the host, from 64 to 4096, the read operation only every returned 45 bytes - one message. USB uses 64 byte packets, and it uses a less than 64 byte packet (traditionally but not limited to a zero length packet) to indicate the end of a transfer. Were we causing a lot of extra overhead by ending every transfer after 45 byets?

    I padded out the 45 byte test message I was using to 64 bytes, and now it is much faster (70KB/s from Python to 650+ KB/s). Previously, we requested 1024 bytes but got 45, which is less than a full 64 byte packet so of course, the transfer was closed.

    In hindsight this seems like a pretty important thing to know about USB, but being new to driver development, it wasn't obvious and I couldn't find any references to how the less-than-max length packet can effect performance elsewhere.

    #7
    chinzei
    Super Member
    • Total Posts : 2250
    • Reward points : 0
    • Joined: 2003/11/07 12:39:02
    • Location: Tokyo, Japan
    • Status: offline
    Re:Maximizing USB bulk transfer throughput 2012/02/06 20:40:01 (permalink)
    0

    I couldn't find any references to how the less-than-max length packet can effect performance elsewhere.

    Short transaction (less-than-max length packet) terminates USB transfer.
    As you said, it is the first hurdle on understanding USB transfer.
    I wrote a brief explanation on this issue.
    http://www.cygnal.org/ubb/Forum9/HTML/001627.html

    Tsuneo
    #8
    Jump to:
    © 2018 APG vNext Commercial Version 4.5