How fast is Software-USB
How fast is Software-USB
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.
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.
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.
I think i tried this already:
I send data to the AVR with:
in mybuffer is the data I send (254 byte).
In the AVR is this:
Without the 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 ?
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;
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 ?
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.
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.
I tried:
and in the main:
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.
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.
Code: Select all
uchar usbFunctionWrite(uchar *data, uchar len)
{
return 1;
}
and in the main:
Code: Select all
int main(void)
{
for(;;){
usbPoll();
}
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
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.
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.
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.
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.
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.
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.
You can find the sources and the circuit i used here:
http://www.geocities.com/tcsstebach/
http://www.geocities.com/tcsstebach/