UART baud rate error
How a UART generates the baud by dividing the clock, why an error appears, how the tolerance budget is derived (3.95% for 8N1 at 16×) and the role of the fractional divisor.
Configuring a UART looks trivial until a 115200-baud link, on a board that works perfectly at 9600, starts dropping characters. The cause is almost always one thing: the baud rate error. This tool computes it; this page explains where it comes from and when it becomes a problem.
How a UART generates the baud
A UART has no dedicated baud oscillator: it derives it by dividing the clock of the peripheral. A generator samples each bit several times — the oversampling, typically 16× or 8× — and a divisor brings the clock down to the desired rate:
The receiver uses the oversampling to find the centre of each bit: it detects the start-bit edge, counts ticks and samples mid-window, where the signal is most stable.
Why the error appears
The catch is that the ideal divisor is almost always fractional, but the integer divisor must be an integer. Rounding it, the actually generated baud departs from the target.
The classic example: 16 MHz, 115200 baud, 16× oversampling. The ideal divisor is 16,000,000 / (16 · 115200) = 8.68. Rounded to 9 it gives an actual baud of 16,000,000 / (16 · 9) = 111,111 baud, i.e. −3.5%. The same clock at 9600 baud gives a divisor of ~104, rounded to 104 with near-zero error: this is why the same board “works at 9600 but not at 115200”.
Same baud, different clocks
At 115200 baud and 16× oversampling, the error depends entirely on how close the ideal divisor is to an integer — that is, on the clock:
| Clock | ideal div | integer div | integer baud | integer error | 1/16 div | 1/16 error |
|---|---|---|---|---|---|---|
| 3.6864 MHz | 2.0000 | 2 | 115 200 | 0.000 % | 2.0000 | 0.000 % |
| 8.0000 MHz | 4.3403 | 4 | 125 000 | +8.507 % | 4.3125 | +0.644 % |
| 12.0000 MHz | 6.5104 | 7 | 107 143 | −6.994 % | 6.5000 | +0.160 % |
| 14.7456 MHz | 8.0000 | 8 | 115 200 | 0.000 % | 8.0000 | 0.000 % |
| 16.0000 MHz | 8.6806 | 9 | 111 111 | −3.549 % | 8.6875 | −0.080 % |
| 18.0000 MHz | 9.7656 | 10 | 112 500 | −2.344 % | 9.7500 | +0.160 % |
| 24.0000 MHz | 13.0208 | 13 | 115 385 | +0.160 % | 13.0000 | +0.160 % |
| 25.0000 MHz | 13.5634 | 14 | 111 607 | −3.119 % | 13.5625 | +0.006 % |
| 48.0000 MHz | 26.0417 | 26 | 115 385 | +0.160 % | 26.0625 | −0.080 % |
| 72.0000 MHz | 39.0625 | 39 | 115 385 | +0.160 % | 39.0625 | 0.000 % |
The 8 MHz clock is the worst: with such a small integer divisor, a single rounding step is worth 8.5 %. As the clock rises the divisor grows and each rounding unit weighs less; with the 14.7456 MHz “serial” crystal the error vanishes entirely.
Where the threshold comes from, computed
A UART frame is start + 8 data bits + stop = 10 bits. The receiver synchronises on the start edge and then samples “blind”, counting the following bits at the rate of its own clock. The difference in rate between the two ends builds up bit after bit across the frame, and the threshold follows from that rather than being assumed.
The receiver samples bit k at (k − 0.5) of its own bit periods after the detected start edge, and that sample must land inside the transmitter’s bit-k window, one bit period wide. There is also an initial error: the start edge is detected with the resolution of one oversampling tick, that is 1/S of a bit. To first order, with e the combined error between the two ends and n the number of bits in the frame counting start and stop:
where q = 1/S if the decision is taken on a single sample, and q = 2/S if it is taken by majority over three consecutive samples — the normal case, which needs one more tick of margin on the side you are drifting towards.
| Format | n bits | 16× (single sample) | 16× (majority) | 8× (single sample) | 8× (majority) |
|---|---|---|---|---|---|
| 7N1 | 9 | 5.15 % | 4.41 % | 4.41 % | 2.94 % |
| 8N1 | 10 | 4.61 % | 3.95 % | 3.95 % | 2.63 % |
| 8N1 + parity | 11 | 4.17 % | 3.57 % | 3.57 % | 2.38 % |
| 9N1 | 11 | 4.17 % | 3.57 % | 3.57 % | 2.38 % |
| 9 bits + parity | 12 | 3.80 % | 3.26 % | 3.26 % | 2.17 % |
The number to remember is the 3.95% on the 8N1 row at 16× with majority decision: it is the total budget, the one that has to cover everything together — the transmitter’s baud generator, the receiver’s, the tolerance of both source clocks, jitter.
Where the sample lands, bit by bit
The same arithmetic read as accumulated drift on the last bit of an 8N1 frame at 16× (9.5 bit periods from the start edge, plus 0.125 bit of start quantization):
| Combined error | Drift on the last bit | Plus the start | Sample |
|---|---|---|---|
| 0.5 % | 0.048 bit | 0.172 bit | inside |
| 1.0 % | 0.095 bit | 0.220 bit | inside |
| 2.0 % | 0.190 bit | 0.315 bit | inside |
| 3.0 % | 0.285 bit | 0.410 bit | inside |
| 4.0 % | 0.380 bit | 0.505 bit | OUTSIDE |
| 5.0 % | 0.475 bit | 0.600 bit | OUTSIDE |
The half bit runs out between 4% and 5%, not at 5%: at 4% the sample already sits 0.505 bit from the centre, that is just past the edge. This is also the most useful reading of why baud failures are intermittent: the bit that gives way first is always the stop, and a frame that gets the stop wrong raises a framing error, not a silently corrupted byte. If the error is larger, the drift reaches the data bits too, and then wrong bytes arrive with no flag at all.
One thing the accumulation does not do is carry across frames: every start edge resets the count, so the error does not grow with message length. A 3% error breaks one frame in many, at random, and does not “get worse as it goes”.
The budget splits between the two ends
If both ends stay within 2% but in opposite directions, the difference is 4%: beyond the 3.95% budget. That is what the tool’s colours really mean — green below 2% is not caution, it is the most that can be allocated to one end assuming the other is essentially exact. The amber 2–3% band is where the link works if the other end is good, and red past 3% leaves no margin for anybody.
And the baud generator is not the only consumer: ahead of it sits the source-clock tolerance, counted twice because there are two ends.
| Clock source at both ends | Summed tolerance | Left to the baud generator |
|---|---|---|
| TCXO ±2.5 ppm | 0.0005 % | 3.95 % |
| crystal ±50 ppm | 0.010 % | 3.94 % |
| trimmed internal RC ±1 % | 2.000 % | 1.95 % |
| internal RC ±2 % | 4.000 % | −0.05 % |
The last row is why a crystal-less board talks at 9600 and not at 115200 even with zero generator error: two untrimmed internal RC oscillators at ±2% consume the entire budget by themselves. With a crystal, on the other hand, practically all of the budget is left to the generator — and that is the case the tool measures.
16× versus 8× oversampling
At 16× each bit is observed over 16 ticks and the decision is taken by majority around the centre: maximum robustness to noise and jitter. At 8× the divisor can halve, so with the same clock higher bauds are reached — but with half the sampling margin. The rule of thumb: 16× by default, 8× only when you need to squeeze out the last factor of two of speed.
The exact price is in the table above, on the 8N1 row: the budget goes from 3.95% to 2.63%, a third of the tolerance gone. In exchange the maximum baud doubles — at 48 MHz a minimum divisor of 1 gives 3 Mbaud at 16× and 6 Mbaud at 8×. It is a reasonable trade only on a short link with crystal clocks: putting 8× on an internal RC means asking for a 2.63% budget from a chain that already spends 2% on tolerance alone.
The fractional divisor
Many modern peripherals (for example the STM32 USART) do not use an integer divisor but a mantissa plus a fraction on 4 bits, i.e. steps of 1/16. Quantizing the fractional part of the ideal divisor to 1/16, the actual baud gets very close to the target.
In the 16 MHz / 115200 case: the ideal divisor 8.68 is represented as 8 + 11/16 = 8.6875, which gives a baud of 115,108 — an error of −0.08% instead of −3.5%. The fractional divisor is the standard cure when the clock cannot be chosen freely.
The cure has a quantifiable limit, though, and not the one usually assumed. Quantizing to 1/16, the residual error on the divisor is at most half a step, 1/32, and in relative terms that half step weighs less the larger the divisor is:
| Baud (48 MHz clock) | ideal div | Bound 1/(32·div) | actual 1/16 error |
|---|---|---|---|
| 9600 | 312.5000 | ±0.010 % | 0.000 % |
| 115 200 | 26.0417 | ±0.120 % | −0.080 % |
| 460 800 | 6.5104 | ±0.480 % | +0.160 % |
| 921 600 | 3.2552 | ±0.960 % | +0.160 % |
| 2 000 000 | 1.5000 | ±2.083 % | 0.000 % |
So the fractional divisor is at its most effective where the divisor is large (low bauds) and stops being enough exactly where it is needed most: at 2 Mbaud on 48 MHz the ideal divisor is 1.5 and the theoretical bound is already ±2.08%, inside the amber band. The “actual” columns are often much better than the bound — if the ideal divisor happens to fall near a multiple of 1/16 the error is zero — but the bound is what to use when deciding whether a baud is robustly reachable or only reachable by arithmetic luck.
Choosing the right clock
The “magic” clocks for serial are integer multiples of (baud · oversampling). At 16× a clock of 14.7456 MHz gives zero error across the whole 9600–921600 family, because 14,745,600 / 16 = exactly 921,600, and 921600 is a multiple of every standard baud. These are the odd-looking crystals (3.6864 / 7.3728 / 14.7456 / 22.1184 MHz) that exist specifically for serial. If the clock is constrained by something else (48 MHz USB, a system PLL), the fractional divisor recovers the margin.
Limitations
- The fractional quantization here is 1/16 (4 bits), the most common case; some peripherals have different resolution or extra constraints (in 8× mode the least-significant fraction bit is handled separately).
- It considers only the baud-generator error: the source-clock tolerance (crystal or PLL) and jitter are not modelled, and they add up, eating part of the ±2–3% margin.
- Demonstrative tool: real configuration relies on the UART reference manual and its registers (BRR, OVER8, mantissa/fraction fields).
References
- UART/USART peripheral reference manual — the document that defines the divisor calculation, the baud-rate register fields, the oversampling and any fractional divisor for that MCU. It is the operational reference.
- Related tool — the UART baud error calculator puts this page into practice: enter clock, baud, oversampling and fractional and read the divisor, actual baud, error and the standard-bauds table.
A similar project?
Acoustics, embedded, calculation tools: if you have a related use case, let’s talk.