UART Framing and Baud Rate Error

By Anatolie · Updated 2026-09-03

UART is the "serial port" — two wires, TX and RX, no shared clock. Because there's no clock line, both ends must be told the bit rate in advance and must agree on it closely. Two things follow from that: a framing structure that lets the receiver find each byte, and a tolerance for how far the two clocks can drift apart.

The frame on the wire

The line idles high. Each byte is wrapped in a frame:

[ start bit ][ data bits, LSB first ][ optional parity bit ][ 1 or 2 stop bits ]
idle start 8 data bits, LSB first stop
The line idles high; the start bit's falling edge is what the receiver syncs to before sampling each following bit at a fixed interval.
  • Start bit — one bit-time low. Its falling edge is what the receiver uses to synchronise; it then samples the following bits at fixed intervals.
  • Data bits — usually 8, sent least-significant first.
  • Parity — optional. One bit set so the total number of 1s is even (even parity) or odd (odd parity). Detects any single-bit error in the frame.
  • Stop bit(s) — one or two bit-times high, guaranteeing a return to idle so the next start bit's edge is unambiguous.

The shorthand 8N1 means 8 data bits, No parity, 1 stop bit. 7E1 (7 data, Even parity, 1 stop) is the classic alternative from older equipment.

Why 8N1 gives only 80% throughput

An 8N1 frame is 10 bits on the wire for 8 bits of data: 1 start + 8 data + 1 stop. So at 9600 baud you move 9600 ÷ 10 = 960 bytes per second, not 1200. Add a parity bit (11 bits/frame) and it drops to ~873 bytes/s; two stop bits, lower still. When you're budgeting how long it takes to send a message, count 10 (or 11) bits per byte. The UART baud rate calculator works out frame time and effective throughput for any format.

Baud rate error, and why it corrupts data

A microcontroller makes its bit clock by dividing its main clock by an integer:

divisor = round(Fclk ÷ (oversample × baud)) − 1

Because the divisor has to be a whole number, the actual baud rate is slightly off the target. The receiver samples each bit near its middle, counting bit-times from the start edge. A small per-bit timing error accumulates across the frame, so by the last data bit the sampling point has drifted. Once it drifts past the edge of a bit cell, that bit is read wrong.

The combined error of transmitter and receiver needs to stay under roughly ±2–3% for a standard 8-bit frame. More stop bits and fewer data bits give a little more margin; 9-bit data gives less.

Worked example

16 MHz clock, 16× oversampling, target 115200:

divisor = round(16000000 ÷ (16 × 115200)) − 1 = round(8.68) − 1 = 8
actual baud = 16000000 ÷ (16 × (8+1)) = 111111
error = (111111 − 115200) ÷ 115200 = −3.5%

That's over the limit — this combination is unreliable, which is why you see communication that "works at 9600 but garbles at 115200". A 14.7456 MHz crystal divides evenly into every standard baud rate and gives 0% error; that's the whole reason such an odd frequency exists.

Practical checklist when serial data is garbled

  • Both ends set to the same baud, data bits, parity, and stop bits?
  • Baud rate error under ~2% at both ends for the chosen clock? (Check with the calculator.)
  • TX of one device to RX of the other (not TX–TX)?
  • Common ground between the two devices?
  • Voltage levels compatible (3.3 V logic vs 5 V, or true RS-232 levels needing a transceiver)?

For the register values on a specific board, the Arduino serial timing calculator. For other embedded timing, the PWM duty cycle calculator.