I'm trying to send data at a pretty high transmission rate( ~1Mbaud) from an Arduino Micro to the PC. I read that people achieved high data rates using the Uno, but information regarding the Micro seems scarce. Given the 16 Mhz clock and the "full speed USB 2.0" connection (http://arduino.cc/en/pmwiki.php?n=Main/ArduinoBoardMicro) I guess it should be possible?
I'd like to transmit 14 Bytes per message (=one measurement) and up to 5000 messages per second (=5kHz sampling rate). Transmitting one byte actually takes 10 bits, so we end up with 14 * 10 * 5000 = 700kBit/s.
As I couldn't get anywhere near those bit rates, I reduced my sketch to the following
void setup()
{
Serial.begin(115200); // initialize serial communication
}
void loop()
{
PORTC = PORTC | B10000000; // Set Pin13 (LED) HIGH
Serial.println("*12345~98765#"); // takes ~78µs without monitoring serial data on PC and ~256 µs with an serial console open
PORTC = PORTC & B01111111; // Set Pin13 (LED) LOW
}
I'm using an oscilloscope to measure the duration of the high state (=time needed to execute the data transmission). I found two things I can't explain to myself:
The baud rate I'm using in the statement
Serial.begin(115200);
doesn't seem to have an effect on the time needed to transmit one message ("*12345~98765#"'\r''\n'). I tried 9600 buad, 115200 baud and 1000000 baud and get always the same values.
2) The time needed to execute
Serial.println("*12345~98765#");
once depends on the programs I'm running on my PC. When I'm using any serial console (Arduino IDE SerialMonitor, Putty, Termite) it gets substantially longer than without monitoring the transmission. It takes ~78µs without monitoring serial data on PC and ~256 µs with an serial console open.
Let's assume that one needs 10 bits for transmitting 1 byte as with serial transmission. I'm sending 13 data bytes + two bytes from println(). That is 15 * 10 bits = 150 bits. It takes ~ 260µs, so I get 150 bits / 260 µs = 578 kbit/s. That's a long way from 12 Mbps.
Is there any chance to speed things up? If the host controls the the transmission speed, where would one start looking?
The Micro presents itself as a Virtual serial port, but the Baudrate doesn't affect transmission speed...I'm kinda lost here as I don't understand what's happening "within" the emulated COM-Port and how to influence that
pepe:
For instance, you can speed up using a program on the PC much faster than the serial monitor (I've already managed to send data over Serial/USB at 1 Mbaud).
That sounds promising, could you please give a little more detail how you achieved that? I already tried opening the serial port at higher baud rates (e.g. 1Mbip) using Putty and Termite, but the transmission still takes ~260µs.
pepe:
To achieve a 1Mbps transmission, I haven't used a terminal display on the PC, but a program just storing the data into a file, without displaying.
I tried this as well, using LabVIEW VISA to read the data from the serial port as fast as possible and write it to the disk. But I still got the same transmission rate Could anyone give me a hint where I can look up what is happening "under the hood" when working with Virtual Com Ports?
pepe:
And on the Arduino, I haven't used the println() function, but directly sent a buffer already containing the bytes.
Could you please give an code example for this? I experimented with for loops sending data by using Serial.write() instead of Serial.println() but couldn't achieve faster transmission. Thank you very much for your help!
Thanks a lot for the example code, this is neat! Unfortunately, it doesn't compile on Arduino 1.0.5. Which version are you using? I get the error
serial_speed_test_2:30: error: invalid conversion from 'char*' to 'const uint8_t*'
serial_speed_test_2:30: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
refering to the line
Serial.write(buff, len);
When changing the buffer definition to
uint8_t buff[1024];
the code compiles, but the transmission speed is still lower than expected (~500kBit/s). I tried with and without an USB Hub, same results. I also seem to get some false readings (additional '0's on the beginning of some lines).
pepe:
You should try this test sketch, which sends data packets of different sizes :
....SNIP....
The results are in bytes per second, so you have to multiply by 8 and 10 to get bits/s and bauds.
On Arduino Leonardo (with direct USB interface, as on Arduino Micro) :
• the average transmission speed over the whole test (including delays) is more or less 1 Mbits/s.
• the transmission speed can be higher than 10 Mbits/s, especially when sending more or less 64 bytes (i.e. the USB buffer size) at one time.
• adding a 1 ms delay in the test loop can lead to better and more stable results.
I must try this.
My tests with high baud rates on an Uno suggest that the best round-trip time is about 4 msecs regardless of the size of the data transfer (11 bytes to 88 bytes) and I attribute this to the USB system overhead. By "round-trip" I mean the sequence in which the Arduino sends "" and the PC program responds with some data.
It had occurred to me that the baud rate is pretty meaningless on a Leonardo - but I hadn't thought to check it.
Comparing the two outputs, it becomes clear that the transmission speed is going up as the numer of bytes transmitted is getting closer to 64 bytes (=the USB buffer size). That wasn't the case when compiled with Arduino 1.0.5. I even found mentioning of that in the release notes of Arduino 1.5.7. BETA:
pepe:
This test is not intended to be run on an Arduino with a separate USB link such as Uno, Due, Mega or Nano. In this case, the results are inconsistent.
On an Arduino whose application MCU integrates the USB interface (Micro, Leonardo or Yún), the maximum theorical speed is 12 Mbit/s. So reading an average speed of 8.6 Mbit/s is reasonable.
I can see the logic of your last sentence (above) but I am not at all convinced that your tests on the Leonardo are consistent in the way you seem to think. Why, for example, is the max data rate at 64/65 bytes? Why don't you get the same rate at any multiple of 64?
I think to be more useful your program should run several hundred iterations at each data size and average the time.
When I run my own test (requesting a byte and then receiving data) the turnaround time on a Leonardo is about 3msecs compared to 4msecs on an Uno.
pepe:
you would have known it was possible to run the USB link twice as fast as that.
Sorry, I'm not clear what you mean by the word "that" in the phrase "as fast as that".
Have you tried my version of the code and have you managed to get a throughput greater than 60,000 bytes per sec? Change the length of data transmission to optimize your result.
I believe my version gives consistent results on an Uno and a Leonardo.
I am interested in this because I am building a project in which I want to maximize throughput.
pepe:
I've run your test on a Leonardo without changing anything, and I get 5 to 7 times as fast as that speed :
Thanks for taking the trouble. Your results are very interesting.
I have been using 1.5.6 and I think your results are with 1.5.7 - so I must try that (tomorrow).
Edit to add ....
I have now tried this with 1.5.7Beta and my 60,000 bytes/sec has gone up to 300,000 - huge improvement!
As expected there was no significant change on the Uno where the speed is dictated by the baudrate.
From a more practical point of view the turnaround time (on the Leonardo) in my other test has fallen to about 2 msecs - half what it is on an Uno and 33% better on the Leonardo than 1.5.6r2.