Skip to content
This repository

The reason why 250000 baud is so problematic in Linux... #205

thantik opened this Issue July 25, 2012 · 21 comments

8 participants

thantik daid Ian Jackson nothinman toybuilder ErikZalm whosawhatsis hgroover

250000 baud is not a standard baud rate. Instead of having to recompile things, or go through these configuration changes trying to get a non-standard baud rate to work, the baud in marlin needs to be 230400. Setting it to that made all my linux machines work magically. This needs to be the default baud rate in marlin instead of 250000.

daid commented July 25, 2012

No it doesn't. There is a good reason why 250000 is used, as it has a much lower bit error rate then 230400. On 16Mhz Arduinos.

As you need you configure the firmware anyhow when you build it, so you can configure the baudrate yourself. Or use the Marlin builder:

What really should be done is fixing PySerial so it uses "termios2" and TCSETS2, which is the new kernel interface to set custom baudrates and makes 250000 work under linux. Also, it depends on your distro if 250000 works, because in Fedora it seems to work fine, while Ubuntu fails to use 250000.

(A comment could be added at the baudrate setting that the 250000 default has some troubles under Linux)


The reason why it has a lower bit error rate and less jitter is purely because it's a faster speed. There are standards for a reason. 250,000 baud is not standard. Nowhere in any documentation anywhere does anyone mention 230400 vs 250000. Yet, 230400 works with current, unaltered software, 250000 does not.

daid commented July 25, 2012

The reason why it has a lower error rate is because the divider of the UART of the AVR used in the Arduino can create 250000 without an error, while 230400 has a 3.5% error in clock.

So how is a datasheet for documentation for you?

ATMega2560 datasheet page 231. Table 21-12: fosc = 16.0000 MHz
Baudrate - Error
230.4K: -3.5%
250.0K: 0.0%
(And this is assuming the Arduino software is smart enough to use the U2X bit, else the error increases to 8.5%)

Also, experiments on the Ultimaker have shown that 250000 gives less errors.

Ian Jackson

I think Linux systems are making this unnecessarily difficult TBH and I consider this a bug. The kernel seems to have supported nonstandard baud rates since 2006 or so but the libc is getting in the way.

I have filed a bug against the distro I use, Debian, here:
In practice I think it will be difficult to fix this in reprap host software that's not written in C/C++ until the underlying layers are fixed.

So in the meantime I would recommend that Linux users use a standard baud rate.

daid commented August 04, 2012

A quick thought on the subject. Any reason why people aren't using say 1Mb/1.25Mb instead of 115k/250k? My atmega1284p supports it, and ft232 supports it...


The ArduinoMega2560 doesn't use the TFDI chip, but an ATMega8U, which most likely also support it. However, the higher the bitrates, the higher the chance some random EMI disrupts a bit. And you'll get the same software support issues as 250k, and you'll most likely run into the low speed USB limits.


@daid Well, not true. I've been happily using 1Mb serial since I posted (a month ago) and everything works fine. AVRs support it, and my FTDI chip supports it too. It's USB full speed, so it's 12Mb. Even if it was low speed, it would be 1.5Mb. There's no slower USB.
In regards to the EMI, etc -- 1Mb is not fast. I consider it very slow. There are no problems with EMI, etc. Chip is a UART to USB transceiver and it does all the filtering magic for you. It just works.
I'm also not sure why are people having trouble with "non-standard" baud rates on linux. It's working fine for me on Ubuntu and Windows. I would consider it a driver issue rather than a kernel bug. But I can be wrong on this one.

@thantik Standards were there for a reason. The reason was simple -- even clock division. And by having both devices using defined speed you could always guarantee communication.
But if you set UART on AVR to 1Mb and you transceiver to 1Mb, it will work nicely. If you set both sides to 219kbit it will also work nicely. FTDI chip does all the conversion, because USB, regardless of your UART speed, will always be running at 12Mbps.



@nothinman: The ArduinoMega2560 R2 or R3 doesn't have an FTDI chip but an ATMega8U doing the USB-Serial.
Also, USB has considerable overhead when doing USB-Serial, so you cannot convert USB speeds directly to serial speeds.
1MBit is fast for boards and cables not designed for it. Especially in a noisy environment with the steppers in a RepRap.

The reason people have trouble with none-standard baudrates on Linux is because the kernel developers created 2 different interfaces to set none-standard baudrates and not all drivers/kernel version support both, and not all serial libraries support both. In this case, PySerial does not support Termios2.


@daid: I understand some don't use FTDI transceiver. For those it may not work indeed.
There's no cables. RXD and TXD from AVR is connected on PCB to FTDI chip. The only cable is the USB cable.
Overhead is meaningless here, because USB is much faster than the serial speeds AVR/FTDI support...

Appreciate the comment regarding the kernel. Wasn't aware of it. One could write a software-based serial driver based on timer interrupts and could therefore use any baud rate.
Well, I'm happy mine works. I suggest people get FTDI chips :-)


I'm not sure that I'd worry about the <4% error -- unless the UART state machine is poorly designed, it should be able to handle framing drifts by aligning to the Stop/Start bit transition.

Keep in mind that UART's are designed to drift. Oscillators on different machines can easily vary by several 100s of ppm, and since the machines aren't clock-sync'ed, You will eventually have a misalignment if that framing logic was not in place.

Reading a really old datasheet from the 1980's or before on the 8250 describing the state machine and how it oversamples the input to align the link to framing drift would probably be very instructive. IIRC, I think it was an 8x or 16x oversampling. So I would expect that a rate difference up to 6% wouldn't matter. I would expect other UART designs to be comparable.

In fact, a quick look at StackOverflow more-or-less confirms what I just said:


@toybuilder You theory is ok. But with 250000 I get no communication errors. And with 115200 I get errors. The print will not stop. But you can see some artifacts in your printed object.


Do the errors appear as framing errors? Or is the problem caused by underruns from not feeding the controller fast enough with additional Gcode data? If there's actual line corruption from the rate mismatch, you would expect the print to come out plainly wrong, as swaths of gcode would get mangled.

I apologize that I haven't dug into the source code to see what's going on under the hood on the Arduino side of the equation.

230.4K seems to be a widely supported "standard" bit rate, and close to 250K, so that one expects less problems running at that speed. I guess the bigger question is how well the USB->Serial converter is honoring the speed selection.

What would be helpful is if there was a way to be able to select the comm speed through a manual switch of some kind -- I know, jumpers are so last century, but it could be a simple solution to this problem.


It seems like auto-discovery should be possible. What if the firmware and host agreed to first attempt to connect at some very common bitrate, say 9600, sent a list of their acceptable baud rates, and then disconnected and reconnected at the highest rate on both lists.

To make the transition easier, you could add an M code to Marlin that would list acceptable baud rates and another that would cause it to disconnect and restart its serial at a specified baud rate, then host support would be optional. Since 115200 seems to be pretty universally supported (it's the highest rate allowed by the serial terminal in the Arduino IDE, and the highest rate aside from 250000 listed in pronterface's dropdown), that should probably be the default, but the addition of these M codes would allow the host to renegotiate the baud rate after connecting at 115200.


I've had baudrate discovery in Cura for more then half a year now. Didn't even require cooperation from the firmware. But a command to set the baudrate would be useful in any case.


That's cool, but it doesn't help if the problem is that the host system isn't compatible with the baudrate set in the firmware. One side really has to be able to get a list of the other's acceptable baud rates and choose the highest one that matches its own list, then get the other to change baudrates with it.

Thinking about it a bit more, it could really be done with only one M code. With no arguments, the code causes the firmware to echo a list of its available baud rates, and the same code followed by S250000 would trigger a switch to that baudrate.


The firmware doesn't care much for which baudrate you use, it can set the baudrate to any value you want, but some will be more accurate then others. The whole baudrate issue is 2 fold. First, not every hardware design handles noise pretty well, and thus some baudrates cause issues on a hardware level. Secondly, Linux. The kernel developers added a nice interface for setting custom baudrates (with TCSET2), however, for some reason this is hardly anywhere exposed by the kernel-header packages in common distributions, so pyserial also didn't pick up on it. This interface is nothing new, and was introduced a few years ago.


Perhaps a better way to handshake in "fall back mode" is to use a combination of hardware handshake lines and a line break while turning on/resetting the controller...


The handshake lines do not reach the controller and are stopped at the USB interface. So no use there.


Looks like the issue of using termios2 in PySerial for custom bitrates was recently addressed:

On Ubuntu 12.04 I was able to just replace the distro's pyserial by building from source:
(apt-get install subversion, all the python setup prerequisites covered setting up printrun, skeinforge et al)
svn checkout svn:// pyserial-code
cd pyserial-code
wget -O pyserial.patch
patch -p0 < pyserial.patch
cd pyserial
python build
sudo python install

I've verified this works with the pronterface gui.

daid commented August 22, 2013

Note that that pyserial patch breaks backwards compatibility and thus won't be accepted by the maintainer. Real shame.

I just added this patch to Cura, which I hope solves the issue for Cura:
I would rather see it solved in pyserial. But after half a year I don't see the patch being included in pyserial any time soon.

thantik thantik closed this November 04, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.