61

The standard is 9600 baud. That's just the standard. Using a Arduino Uno SMD R2, what is the highest practical baud rate I can achieve?

Bonus points for the audacious: how would you go about creating an error checking mechanism and then increasing the baud rate ridiculous high to get high transfer rates?

2
  • 2
    It's worth noting that Arduino boards that use FTDI USB-serial ICs can go REALLY fast. The common FT232 can go 3 Megabaud (that's 3,000,000 baud) without issues. The use of a ATmega16U2 is the limiting factor. Commented Feb 19, 2014 at 5:52
  • 1
    My clone Arduino Nano that I got from eBay maxed out at 1,099,999. Seriously. It did. Once it reached 1,100,000, the output was garbled. laqq`na`fca`fga`fga`bcngaah````iin`ha`a`a`bga`fga`bcqpahhqfq```fh`oopa`bca`fca. It uses a CH340 chip for USB comms.
    – Aloha
    Commented Sep 27, 2015 at 12:23

4 Answers 4

83
+50

There are several factors here:

  • How high of a baud-rate can the ATmega328P MCU achieve?
  • How high of a baud-rate can the USB-Serial interface achieve?
  • What is the oscillator frequency on the ATmega328P?
  • What is the oscillator frequency on the USB-serial interface (if it has one)?
  • How tolerant is the USB-serial interface of baud-rate mismatch?

All of these factors are relevant to determining the maximum achieveable baud rate. The ATmega328P uses a hardware divisor from it's clock-rate to generate the base-clock for the serial interface. If there is no integer ratio from the main clock to the bit-time of the desired baud rate, the MCU will not be able to exactly produce the desired rate. This can lead to potential issues, as some devices are much more sensitive to baud-rate mismatch then others.

FTDI-based interfaces are quite tolerant of baud-rate mismatch, up to several percent error. However, I have worked with specialized embedded GPS modules that were unable to handle even a 0.5% baud rate error.

General serial interfaces are tolerant of ~5% baud-rate error. However, since each end can be off, a more common spec is +-2.5%. This way, if one end is 2.5% fast, and the other is 2.5% slow, your overall error is still only 5%.


Anyways. The Uno uses a ATmega328P as the primary MCU, and a ATmega16U2 as the USB-serial interface. We're also fortunate here in that both these MCUs use similar harware USARTs, as well as 16 Mhz clocks.

Since both MCUs have the same harware and clock-rate, they'll both have the same baud-rate error in the same direction, so we can functionally ignore the baud error issue.

Anyways, the "proper" answer to this question would involve digging up the source for the ATmega16U2, and working out the possible baud-rates from there, but since I'm lazy, I figure simple, empirical testing will work.

A quick glance at the ATmega328P datasheet produces the following table:
enter image description here

So given the max stated baud-rate of 2 Mbps, I wrote a quick test program:

void setup(){};

void loop()
{

  delay(1000);
  Serial.begin(57600);
  Serial.println("\r\rBaud-rate = 57600");
  delay(1000);
  Serial.begin(76800);
  Serial.println("\r\rBaud-rate = 76800");
  delay(1000);
  Serial.begin(115200);
  Serial.println("\r\rBaud-rate = 115200");
  delay(1000);
  Serial.begin(230400);
  Serial.println("\r\rBaud-rate = 230400");
  delay(1000);
  Serial.begin(250000);
  Serial.println("\r\rBaud-rate = 250000");
  delay(1000);
  Serial.begin(500000);
  Serial.println("\r\rBaud-rate = 500000");
  delay(1000);
  Serial.begin(1000000);
  Serial.println("\r\rBaud-rate = 1000000");
  delay(1000);
  Serial.begin(2000000);
  Serial.println("\r\rBaud-rate = 2000000");
};

And then looking at the relevant serial port with a serial terminal:

enter image description here

So it appears the hardware can run at 2,000,000 baud without problems.

Note that this baud rate only gives the MCU 64 80 clock-cycles per byte, so it would be very challenging to keep the serial interface busy. While the individual bytes may be transferred very rapidly, there is likely to be lots of time when the interface is simply idle.


Edit: Actual Testing!

The 2 Mbps is real:
enter image description here
each bit-time is 500 ns, which matches exactly with what is expected.

Performance issues! Overall packet length:
500 Kbaud: enter image description here

1 Mbaud: enter image description here

2 Mbaud: enter image description here
Note: The noticeable overshoot is due to poor scope probe grounding practices, and is probably not real. I'm using the ground-clip-lead that's part of my scope probe, and the lead-inductance is likely the cause of the majority of the overshoot.

As you can see, the overall transmission length is the same for 0.5, 1 and 2 Mbaud. This is because the code that is placing the bytes in the serial buffer is poorly optimized. As such, you will never achieve anything better then an effective 500 Kbaud, unless you write your own serial libraries. The Arduino libraries are very poorly optimized, so it probably wouldn't be too hard to get a proper 2 Mbaud, at least for burst transmissions, if you spent a bit of time on it.

34
  • 5
    Nice illustration of the throughput limitation!
    – jippie
    Commented Feb 19, 2014 at 7:03
  • 1
    @jippie - I had the scope up, and was running the program in my answer that cycles through baud rates. It was very little additional work, and does illustrate the issue quite nicely. Also, the segmented memory on my scope is awesome. Commented Feb 19, 2014 at 7:05
  • 2
    @AnnonomusPerson - You'd need to swap both, or use a FTDI usb-serial interface with a 20 Mhz ATmega328P oscillator. The ATmega328P can't do 2.5 Mbps without a 20 Mhz crystal/resonator. The same is true for any ATmega16U2 interfaces. Commented Feb 20, 2014 at 2:35
  • 2
    Great answer! Just one small correction: at 2 Mb/s, each byte transmission takes 80 CPU cycles, not 64. This is because, time-wise, each byte is worth 10 bits (1 start, 8 data, 1 stop). Commented May 29, 2015 at 13:03
  • 2
    @GabrielStaples - You're missing the error I'm talking about. Basically, the way the ATmega UARTs work is they use an integer divider from the MCU clock to generate the serial timing. As such, some baud rates cannot be directly achieved, as the ratio between the baud rate and the system clock is not an integer. Generally, in this situation, the closest option is chosen, which results in the error I'm talking about here (abs(closest option - target baud) = err). This error will be matched between the two different parts. Commented Sep 11, 2015 at 18:56
9

The Arduino Serial Monitor window limits you to 115200, but that's not the highest baud rate capable. You can read the Atmel and the FT232 (or whatever you're using) datasheets to find out the maximum but I am able to successfully use 230400 (twice as fast as the largest the Arduino Serial Monitor supports) with no issues.

If you want to see the results in your computer, you will need another serial monitor that supports other baud rate options. I like CoolTerm and Termite.

Do note that this heavily depends on your clock speed as well.

Here's a calculator to help you with calculating what's possible.

3
  • As you start going faster and faster, the limitation becomes the Serial library - it's implementation isn't very efficient. Commented Feb 19, 2014 at 6:16
  • website of link is dead
    – Codebeat
    Commented Jul 18, 2018 at 1:30
  • "The Arduino Serial Monitor window limits you to 115200," - That's no longer true. It goes up to 2Mbps Commented Feb 5, 2020 at 20:53
3

This is probably one of the few aspects where el-Cheapo boards differ from original boards. The maximum serial transfer rate is pretty much only limited by the quality of the board and its layout. Once the serial data enters either AVR or USB interface chip, the data will be processed differently from the serial UART protocol.

Keep in mind though that the microcontroller has some basic hardware to shift in/out serial data to/from the IO pins, but the absolute maximum rate is limited to the 16MHz clock (for AVRs). Once a byte is moved to the serial buffer, the UART hardware will take over and push out / pull in the bits on its own. An AVR at best reaches 16M instructions per second and the interrupts used to fill the serial buffer have some overhead (at least 8 clock ticks for the interrupt handling + instructions to save current state + several instructions for actually filling the buffer). At a given bitrate, the protocol will run at a whopping n bits per second, but your controller needs more time to fill the serial buffer than it needs to actually output the data, resulting in a lower average throughput than you expect and the UART idling for a relatively long time. Disadvantage is the increased probability for bit errors.

Another effect to remember is that all the overhead required to push data out onto UART (or pull it in) cannot be spent in your actual program, again affecting the average practical throughput. You can only use every instruction cycle once, either for filling the buffer or for computing the main loop.

The maximum throughput is therefore dependent on the application you use (how fast is data generated/computed/ready to move to/from the serial buffer) and the actual 'physical' bitrate is only a small part of the design decision.

7
  • 1
    I really, REALLY doubt any of the boards out there have layout issues severe enough to prevent a 2 Mhz signal from working fine. 2 Mhz isn't exactly high frequency. Commented Feb 19, 2014 at 6:40
  • @FakeName At least one board on my desk here has increased BER when I push serial speed. I usually use 9600, that is more than enough for most applications and is robust.
    – jippie
    Commented Feb 19, 2014 at 6:44
  • No kidding! Huh. I wonder how bad the layout has to be to have that happen? I'd suspect it's not layout as much as poor-tolerance resonators/crystals, though. Commented Feb 19, 2014 at 6:49
  • 1
    High baud-rates, particularly if U2Xn = 1 in the USART, tend to get pretty cranky about mismatch. Commented Feb 19, 2014 at 6:51
  • @FakeName I'm a dinosaur, I kinda like "9600 8N1" for all the wrong legacy reasons you can think of ;o)
    – jippie
    Commented Feb 19, 2014 at 6:54
3

Error checking is actually very easy and there is an AVR lib that does this in a one liner.

Read up on util/crc16.h and you should be good to go in no time with the included examples.

CRC is quite robust and fast for simple applications.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.