Page 1 of 2

How fast is Software-USB

Posted: Sat Nov 11, 2006 5:12 pm
by chefpro
In the Project i am on, I can get about 4-5 kbyte Transferspeed max. Is there a way to make it faster ? It will be a USB-gLCD interface for a t6963 Display. So, the framebuffer is about 4kbyte and 1fps wouldn't be enough.

Posted: Sun Nov 12, 2006 12:09 am
by christian
I don't have figures at hand, but the driver can be much faster. As far as I remember, it gets close to the theoretical limit of low speed USB (which is MUCH less than the 1.5 Mbit low level transfer rate).

For optimum performance, please use control transfers of at least 128 bytes in size. Although they are still split down to 8 byte transactions, the split is done at a lower protocol level, allowing for faster transfers.

When you increase the transfer size, please note that the driver has a limit at 254 bytes.

Posted: Sun Nov 12, 2006 7:55 pm
by chefpro
I think i tried this already:

I send data to the AVR with:

Code: Select all

int ret = usb_control_msg(device, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_CMD_T6963_STREAM, 0xff, 0xff, (char *)mybuffer, bufferlen, 5000);

in mybuffer is the data I send (254 byte).

In the AVR is this:

Code: Select all

uchar usbFunctionWrite(uchar *data, uchar len) { ... return 1; }

Without the

Code: Select all

return 1;
usb_control_msg dont come back until the timeout occurs on the host.

In the "USBasp - Programmer for Atmel AVR Controllers" Doku is written that he could do 5kByte max.

Maybee this is the limit ?

So what to do now, to speed this up ?

Posted: Sun Nov 12, 2006 10:15 pm
by Guest
OK. I've looked up the data in the USB spec.

The theoretical limit is at 24 kbytes/s (192 kbits/s) for control transfers of infinite size. This limit is reached with 3 transactions per frame. See USB 1.1 spec section 5.5.4.

The theoretical limit can be reached if the device never responds with a NAK when the host tries to send/receive data. Assuming that you send data to the device, I'll only talk about the device's receive system in the following text. The device sends a NAK as long as a message is in the receive buffer. If the host receives a NAK, it pauses for some time and then retries the transaction.

Your effective transfer rate depends on several factors:

(1) How fast you can empty the receive buffer. This buffer is freed when usbFunctionWrite() completes. And usbFunctionWrite() is called from within usbPoll(). You must therefore make sure that you poll as often as possible and be as fast as possible in usbFunctionWrite().

(2) How long the host controller waits when it receives a NAK. This behavior is probably defined in the USB spec, but I don't know the timing.

(3) The total size of the control transfer. This determines the ratio of payload to setup data.

I currently don't have a device with a dummy application to test the transfer rate limits. If you have such a device and the transfer rate is much slower than expected, you can probably debug it with a storage scope. You see transactions as data bursts on the D+/D- lines. By watching the timing you should be able to see whether a NAK was sent and how long the host waits for a retry.

Regarding the return value of usbFunctionWrite(): The spec clearly states that you must return 1 if the last transaction of the transfer was received and 0 otherwise. See usbdrv.h for details. Always returning 1 works in many cases, but violates the spec.

Posted: Tue Nov 14, 2006 6:54 am
by chefpro
I tried:

Code: Select all

uchar   usbFunctionWrite(uchar *data, uchar len)
  return 1;

and in the main:

Code: Select all

int main(void)
    return 0;

which should result in fastest transfer.
But it dont goes over the 5kByte/s transfer speed limit.

I think now this is the limit.

And I think the reason is the transfer size of one transfer.
The theoretical limit is at 24 kbytes/s

:idea: I think the problem is caused by the max transfer size, which should be maximum about 1300 byte ( I dont read the spec, but as I know with my little knowledge :) ).
This is about 5 times bigger than 254 byte.
And surprisingly the max speed of control transfers is 24 kbytes/s, which is also 5 times faster than my 5 kByte/s.

So, I think the count of control transfers is limited, too. Which would make it imposible to speed this up without enhancing the transfer size.

Posted: Tue Nov 14, 2006 10:11 am
by christian
OK, then this is probably the practical limit with the software driver. Maybe you get more with a different host operating system or driver, maybe not.

If anybody gets better results, please post them here!

Posted: Tue Nov 14, 2006 11:17 pm
by chefpro
Ok, thats it. I think I have reached the knowledge that I have to use another interface. Maybee I use the USART which could do the 1Mbit and use one of this USB-Serial adapters. :(

But my last thouth is:

It could be posible to drive the avr with 18Mhz or 24Mhz. ( I know it would be outside Spec ) But some avr could do at least 18Mhz (ex: mega16). Then there is some spare time to do the bigger tranfser size.
For a USB 1.1 compatible low-speed device, a bit stream of 1.5 Mbit/s must be decoded. For a processor clocked at 12 MHz, this means that we have 8 CPU cycles for each bit.

So, with 18Mhz there are 4 more CPU cycles and at 24Mhz there are double CPU cycles.

With this it sould be posible to do the transferbuffer in short int adressing instead of byte. :) Which would result in max transfer size, and 24Kbyte/s troughput.

Posted: Tue Nov 14, 2006 11:38 pm
by christian
You don't need a higher clock rate to lift the 254 bytes limit. That's only an optimization to save code size since we can store the message size in a byte.

However, increasing the message size won't buy you much. Currently, assuming that you do 254 byte transfers, the number of transactions is 1 x Setup + 32 x Out = 33 transactions with 8 bytes each. That's effectively 33/254 = 0.13 transactions per byte.

If you increase the message size to (say) 65534, that would be 1 x Setup + 8192 x Out = 8193 transactions, effectively 8193 / 65534 = 0.125 transactions per byte.

As you can see, the benefit is minimal.

In my opinion, the time is lost when we can't get the data out of the buffer fast enough. Even if you call usbPoll() at maximum frequency, much of the code in usbdrv.c must run before the buffer is freed. That's probably too long.

Posted: Thu Nov 23, 2006 6:16 pm
by Guest
I acheive around 7850 Bytes per Second in Payload-Data on Control-In using usbFunctionRead (and atm a fairly slow one) and a request size
of 0x600 (with a modified usbdrv.c of course so the larger blocksize is supported)

Posted: Thu Nov 23, 2006 6:24 pm
by christian
Thanks for that information!

Can you confirm that this is due to the increased transfer size, or do you get similar results with 254 byte transfers?

Posted: Thu Nov 23, 2006 9:04 pm
by Guest
7910 B/s with 0x700 blocksize
7710 B/s with 0x200 blocksize
7490 B/s with 0x100 blocksize
6980 B/s with 0xfe blocksize
6550 B/s with 0x80 blocksize
5450 B/s with 0x40 blocksize

I'm currently drawing a nice looking schematic
so i can publish the whole materials later.

Best regards,

Posted: Thu Nov 23, 2006 11:24 pm
by Guest
You can find the sources and the circuit i used here:

Posted: Fri Nov 24, 2006 8:05 pm
by christian
As far as I can see, increasing the transfer size limit would buy us at maximum 7910 vs 6980 = 13% performance increase. I think that this is not worth the increased code size and complexity.

Posted: Fri Dec 14, 2007 7:07 pm
by kattoaster
chefpro write his programm to test the data transfer rate between ┬Ác and the pc. but how can i measure the speed now? does he increase a counter and read this counter out after a few minutes?

perhaps has somebody a user program to test the data transfer rate?

Posted: Fri Dec 14, 2007 7:25 pm
by christian
Send a couple of kB to the device and measure the time it takes. The quotient gives the transfer rate, the more kB, the more precise it will be.