Loading header...

UART: Universal Asynchronous Receiver-Transmitter

UART is a simple asynchronous serial link used for debug consoles, GPS receivers, modems, Bluetooth modules, bootloaders, and factory test ports. It sends one bit stream per direction with no separate clock wire. Both ends agree on baud rate and frame format before communication starts.

UART is easy to bring up, but it is also easy to miswire. Most failures come from the lowest layer: crossed pins, missing ground, wrong voltage level, wrong baud rate, or inverted RS-232 signaling.

Learning Objectives

By the end of this lesson, you should be able to:

  • explain why UART is asynchronous and how the receiver finds each byte;
  • decode an 8N1 UART frame;
  • calculate bit time, frame time, and approximate throughput;
  • wire TX, RX, and GND correctly between two logic-level devices;
  • choose level shifting when voltage levels are incompatible;
  • debug baud, framing, parity, overrun, and wiring faults.

Core Idea: Shared Speed, No Clock Wire

Synchronous buses such as SPI send a clock. UART does not. The transmitter and receiver are configured to the same baud rate, and each side uses its own local clock.

flowchart LR A["Device A UART\nTX and RX pins\nbaud 115200"] W["Crossed serial link\nA TX to B RX\nB TX to A RX\nGND to GND"] B["Device B UART\nTX and RX pins\nbaud 115200"] A --- W --- B

The idle line is logic HIGH for normal TTL or CMOS UART. A frame begins when the transmitter pulls TX LOW for a start bit. The receiver uses that falling edge to align its sampling points near the middle of each bit.

UART Frame Format

The most common format is 8N1: eight data bits, no parity bit, and one stop bit.

flowchart TD IDLE["Idle HIGH"] START["Start LOW"] DATA["Data bits\nD0 to D7\nLSB first"] PARITY["Optional parity"] STOP["Stop HIGH"] NEXT["Next frame or idle"] IDLE --> START --> DATA --> PARITY --> STOP --> NEXT
Field Logic level or content Purpose
Idle HIGH no byte being transmitted
Start LOW marks the beginning of a frame
Data 5 to 9 bits, commonly 8 byte payload, least significant bit first
Parity optional simple odd/even error check
Stop HIGH for 1, 1.5, or 2 bit times gives the receiver a clean frame end

For the ASCII character A, the byte is 0x41, binary 0100 0001. UART sends it least significant bit first: 1, 0, 0, 0, 0, 0, 1, 0.

title "UART 8N1 example, byte 0x41"
time start=0 end=10 unit=bit divisions=10
TX: square label="TX line, illustrative bits" low=0 high=1 duty=50 cycles=5 unit=logic color=#2563eb
marker START at=1 label="start low" color=#dc2626
marker STOP at=9 label="stop high" color=#16a34a

The waveform is illustrative. A real oscilloscope trace would show each bit value held for one bit time, with rise/fall time and noise from the actual circuit.

Baud Rate, Bit Time, And Throughput

For ordinary UART, one symbol is one bit, so baud rate is approximately bits per second.

$$
t_{bit} = \frac{1}{baud}
$$

For an 8N1 frame:

$$
bits_{frame} = 1 + 8 + 1 = 10
$$

$$
bytes/s \approx \frac{baud}{10}
$$

Baud rate Bit time 8N1 frame time Approximate payload
9,600 104.17 us 1.04 ms 960 bytes/s
57,600 17.36 us 173.6 us 5,760 bytes/s
115,200 8.68 us 86.8 us 11,520 bytes/s
1,000,000 1.00 us 10.0 us 100,000 bytes/s

UART tolerates only limited clock error because the receiver samples a whole frame based on the start edge. A common design target is to keep total transmitter plus receiver baud error within a few percent, then verify on real hardware.

Wiring Rules

UART TX and RX are crossed:

  • device A TX connects to device B RX;
  • device B TX connects to device A RX;
  • grounds are connected, unless the link uses isolation;
  • never connect two push-pull TX outputs together.
flowchart LR MCU["MCU\nTX\nRX\nGND"] MOD["Module\nRX\nTX\nGND"] MCU -- "TX to RX" --> MOD MOD -- "TX to RX" --> MCU MCU ---|"GND reference"| MOD

For short board-level links, a direct connection is often enough when voltage levels match. For cables, noisy machines, long distance, or multi-drop networks, use a physical layer designed for that environment, such as RS-232, RS-485, CAN, USB, or Ethernet.

Voltage Levels And RS-232

UART describes framing. It does not guarantee that two connectors use compatible voltages.

Interface style Typical logic levels Notes
3.3 V CMOS UART LOW near 0 V, HIGH near 3.3 V common on modern MCUs
5 V TTL UART LOW near 0 V, HIGH near 5 V common on older boards
RS-232 negative voltage for logic 1, positive voltage for logic 0 inverted and higher voltage

Never drive a non-5-V-tolerant 3.3 V input from a 5 V TX pin. Use a level shifter or at least a checked resistor divider for the receive direction. RS-232 needs a transceiver such as MAX3232; it is not directly compatible with MCU pins.

Firmware Flow

UART hardware shifts bits automatically. Firmware usually interacts with data and status registers, FIFOs, interrupts, or DMA.

flowchart TD INIT["Configure baud, frame, pins"] TXWAIT["Transmit path\nwait for TX buffer empty"] TXWRITE["write byte or FIFO"] RXIRQ["Receive path\nRX interrupt or poll flag"] RXREAD["read byte before overrun"] PARSE["append to parser buffer"] INIT --> TXWAIT --> TXWRITE INIT --> RXIRQ --> RXREAD --> PARSE

Minimal blocking pseudocode:

void uart_putc(uint8_t b) {
    while (!uart_tx_ready()) {
        ;
    }
    UART_TX_REG = b;
}

bool uart_getc(uint8_t *b) {
    if (!uart_rx_ready()) {
        return false;
    }
    *b = UART_RX_REG;
    return true;
}

Production firmware usually uses interrupts or DMA so slow serial I/O does not block time-critical control loops.

Error Flags

Common UART hardware status flags:

Flag Meaning Typical cause
Framing error stop bit was not sampled HIGH wrong baud, wrong polarity, noise, line break
Parity error parity bit does not match wrong parity setting or corrupted bit
Overrun new byte arrived before old byte was read firmware too slow or interrupts disabled
Break detect line stayed LOW longer than a frame intentional break, short to ground, stuck transmitter

Always read the microcontroller reference manual because flag-clearing sequences differ. Some MCUs clear errors only after reading status and then data in a required order.

Worked Example

A GPS module sends NMEA sentences at 9,600 baud, 8N1. One frame is 10 bits.

$$
t_{frame} = \frac{10}{9600} = 1.0417 ms
$$

If a sentence is 80 characters, transmit time is approximately:

$$
t_{sentence} = 80 \times 1.0417 ms = 83.3 ms
$$

At one sentence per second this is easy. At many sentences per second, or if firmware blocks interrupts for long periods, the receive buffer can overflow.

Practical Debug Checklist

  1. Confirm both devices share a voltage reference or use isolation.
  2. Confirm voltage level compatibility with a meter or oscilloscope.
  3. Cross TX to RX, not TX to TX.
  4. Match baud rate, data bits, parity, stop bits, and polarity.
  5. Verify idle is HIGH for logic-level UART.
  6. Send a known byte such as 0x55, which produces alternating bits.
  7. Check framing and overrun flags before blaming the parser.
  8. Reduce baud rate to see whether the problem is timing or signal integrity.

Common Mistakes

  • Using an RS-232 adapter directly on MCU UART pins.
  • Forgetting GND on a two-board link.
  • Assuming a 5 V TX pin is safe for a 3.3 V RX pin.
  • Matching baud rate but not parity or stop bits.
  • Reading received data too slowly and losing bytes to overrun.
  • Printing from inside a high-rate UART interrupt until the system stalls.
  • Connecting two transmitters to the same line without a proper bus transceiver.

Summary

UART sends framed bytes over separate TX and RX lines without a shared clock. The receiver locks onto each start bit, samples data bits at the configured baud rate, and checks the stop bit. Reliable UART links require correct wiring, compatible voltage levels, matching frame settings, and firmware that services receive data before buffers overflow.

Further Reading

  • Microchip USART peripheral chapters in AVR and PIC data sheets.
  • STMicroelectronics STM32 USART reference manual chapters.
  • Texas Instruments application notes on logic-level translation.
  • Analog Devices and Maxim Integrated RS-232 transceiver data sheets.

Mind Map

mindmap root((UART)) Core concept Async serial No clock wire Start edge sync 8N1 common Frame Idle high Start low LSB first Optional parity Stop high Calculations tbit equals 1 over baud 8N1 equals 10 bits bytes per s near baud over 10 clock error few percent Wiring TX to RX RX to TX Shared ground Level shifter RS232 transceiver Practical checks Baud match Frame settings Idle polarity Error flags 0x55 test byte Common mistakes TX to TX Missing GND Five volt damage Overrun ignored RS232 direct

Next: SPI: Serial Peripheral Interface