fast SerialUSB for Arduino DUE

Hi guys! Does anybody know fast SerialUSB library for Arduino DUE?
Current SerialUSB read data at 1Mbit/s but can be at 10Mbit/s easily.

I DO get about 10mbit.... over 1MB per second......

It is down to what payload you transfer.

Regards,

Graham

Hi Graham! I used in PC the following python script:

import serial
import sys

ser = serial.Serial(
port = '/dev/ttyACM0',
baudrate = 115200,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS
)

if ser.isOpen() == False :
ser.open()
if ser.isOpen() == False :
print "Can't open serial port"
sys.exit(1)

for i in range(100000) :
ser.write('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')

In Arduino Due:

char buffer[48];

void setup() {
SerialUSB.begin(115200);
}

void loop() {
if (SerialUSB.available() > 0) {
SerialUSB.readBytes(buffer, 48);
}
}

Speed of read is around 1Mbit/s

How to make 10Mbit/s ? What's wrong may be in my scripts?

Try lifting your read buffer to 256....

Regards,

Graham

I did test. This is my results:

buffer 48: 121kByte/s=0,95Mbit/s
buffer 256: 129kByte/s=1Mbit/s

So, reading speed of SerialUSB is not very good.

You can look at comparing test results from the Internet:

It's very terrible that Arduino Due has so powerful hardware and so not optimal libraries.
Guys, let's fix it pls.

I found one solution here Faster SerialUSB read - Arduino Due - Arduino Forum
But I haven't so deeply knowledge to change libraries and provide it for all.
Can anybody from Arduino's experts optimize SerialUSB for fast reading?
Thanks in advance!

The data rate is determined FAR more by the HOST device than the target device....

Regards,
Ray L.

it's 100% arduino's problem. I connected USB-RS485 adapter to PC and used the same python script. Speed was 2,5Mbit/s (and can be higher I think).
With arduino - max 1Mbit/s.

Can anybody pls help to optimize SerialUSB.read?

Sorry sined23 for misleading you, my write speed is >10mb, my read speed is comparable with yours (133174 bytes/second). :frowning:

I will see if I can make sense of the link you gave.

Regards,

Graham

Graham, thank you! I will wait :slight_smile:

Actually I also got write speed >10Mbit, even 40Mbit. But read speed is low :frowning:

I connected USB-RS485 adapter to PC and used the same python script. Speed was 2,5Mbit/s (and can be higher I think).

Same Driver? I believe the Due uses Windows built-in CDC driver, which is reported to be "not that great." If your USB/RS485 driver has an FTDI or other chip that has its own driver, direct comparisons could be invalid.

Could be fun to poke at the Due code and see what changes have any effects...

@westfw,

You have previously mentioned the thesycon driver, have you personally tried it?

@sined123,

The link you sent with those changes to USBcore etc, I tried what he suggested, and the difference is amazing, BUT it makes the received data unreliable.... Not suitable if your data is critical.

Regards,

Graham

Graham, but is it possible to increase read speed without bit error?
I think it must be some way.

Hi sined,

Yes it should be, but I am thinking this is over my head too..... Take a look at this document from Atmel, I think the problem is a poorly implemented USB/CDC core by the Arduino gang.... I am just reading it now to see if I can make head or tail of it... :o

Regards,

Graham

Graham, oh, it would very cool if you can deal with it

BTW: I found author of the usb libraries. It's Peter Barrett.
Also there are contributors:


222222.png

Do you know somebody from them? May be they can join us?

Perhaps my knowledge was enough :slight_smile:
I increased USB read speed up to 8Mbit/s.
Speed can be increased more, but need optimize libraries more.

Pls, help to test it.

unzip fast_usbread.zip into hardware/sam/1.6.7/cores/arduino

after that you can use SerialUSB.readBlock(buffer, length) with high read speed

P.S. fast_usbread.zip is updated again

fast_usbread.zip (20.7 KB)

Read speed is increased up to 12Mbit/s !!! (using buffer 500 Bytes in SerialUSB.readBlock)
Use updated fast_usbread.zip

fast_usbread.zip (20.7 KB)

Hi Sined,

I have been quite busy with my own stuff(UTFT_GHL) but I am very interested to test your improvements to DUE read speed, however, what changes have you made to stream and uartclass? I understand the need for changes to usbcore, usbapi and cdc.... A little more info would be good.

Also I am using 1.6.5 as I had issues with both 1.6.7 and 1.6.8, so unsure if I can just overwrite these files....

Regards,

Graham

Hi Graham! Arduino Due has CDC buffer 512 bytes (it's configurable).
When data comes from PC, Arduino Due runs accept function from CDC.cpp.
Accept get only one byte and write it into the buffer.
You can see CDC.cpp (Serial_::accept):

c = USBD_Recv(CDC_RX);
buffer->buffer[buffer->head] = c;

And when you run USBSerial.readBytes(array, len), Arduino Due fill in array from CDC buffer only one by one byte.
You can see Streem.cpp (Stream::readBytes):

int c = timedRead();
if (c < 0) break;
*buffer++ = (char)c;

timedRead runs read() function, only it uses timeout feature.

Becouse of it read speed is slow.
I decided to write bytes into CDC buffer as many as possible () and get from CDC buffer full length of array.
I wanted to change readBytes function but decided to create new one and called readBlock.
Actually it's possible to modify only readBytes and don't create readBlock.

So, I added new function readBlock in Stream.cpp and Stream.h
readBlock can't use read() from Streem.cpp becouse read() get only one byte.
So, I created readb in CDC. int Serial_::readb(char *c, size_t length)
readb should be declared in several places.
In UARTClass as well. But it will not work in UART :slight_smile: Becouse it's specially for USB.
In UARTClass.cpp I just added

int UARTClass::readb(char *c, size_t length)
{
	return 0;
}

Now about readb in CDC.cpp:

unsigned int d = min((buffer->head - buffer->tail) % CDC_SERIAL_BUFFER_SIZE, length); // know how many bytes we can get from CDC buffer
 
unsigned int i;
for (i = 0; i < d; i++) *c++ = buffer->buffer[(buffer->tail + i) % CDC_SERIAL_BUFFER_SIZE]; // get bytes
buffer->tail = (unsigned int)(buffer->tail + d) % CDC_SERIAL_BUFFER_SIZE; // change tail as tail+d

About accept in CDC.cpp:

uint8_t c[CDC_SERIAL_BUFFER_SIZE]; // create temp array
uint32_t k = USBD_Recv(CDC_RX, &c, (buffer->tail - i) % CDC_SERIAL_BUFFER_SIZE); // recieve bytes as many as possible into temp array c. k - count of recorded bytes
uint32_t j;
for (j=0;j<k;j++) buffer->buffer[(buffer->head + j) % CDC_SERIAL_BUFFER_SIZE] = c[j]; // write k bytes into CDC buffer

buffer->head = (buffer->head + k) % CDC_SERIAL_BUFFER_SIZE; // change head as head+k

Actually it's hard to explain all. I spend 2,5 days to get it :slight_smile:
If you have some questions pls ask.

One more thing. I changed USBD_Recv in USBCore.cpp

before it used:

while (n--)
                *dst++ = UDD_Recv8(ep & 0xF);

to get data from USB.

But now it uses:

UDD_Recv(ep & 0xF, dst, len);

It really increases read speed as well.

You can backup your files and copy mine.
About changes you can use compare tools to find exact changes.

When you finish your tests pls tell me results. It's interesting for me :slight_smile:

Total Time taken to transfer 20971520 bytes =15335852(us)

Bytes per second =1367483.2
MB per second =1.3041337

:slight_smile: 8)

Well done!!

Regards,

Graham