Why UART Prints Garbage: Baud Rate, Voltage Levels, and Ground

Series navigation: Episode 1: The Roadmap · Episode 7: Reading Arduino Pin-Current Specifications · Episode 8

The problem: A terminal shows random symbols even though both devices say “UART.”
The goal: Understand what must match electrically and logically before bytes become readable text.
The result: A debugging order for TX/RX, ground, voltage, baud rate, frame format, buffering, and signal capture.

A microcontroller connected to a USB serial adapter for UART debugging

AI-generated illustration of a low-voltage UART bench. It is not a measurement record or exact wiring guide.

The terminal opened, but the text looked broken

UART is often the first communication interface I use on a board. It prints boot messages, accepts commands, connects two controllers, or talks to a GPS, modem, Bluetooth module, serial display, or USB-to-serial adapter.

Then the terminal shows this:

��H�l�

The program may be sending Hello, but UART does not transmit software strings. It places timed voltage levels on a wire. The receiver must agree about voltage, timing, direction, and frame format before those levels become the same byte.


What 9600 8N1 means

Asynchronous UART has no shared clock wire. Both ends agree on a baud rate and reconstruct a frame from its edges.

A UART 8N1 frame and the layers that must match

9600 8N1 means 9,600 symbols per second, eight data bits, no parity, and one stop bit. A typical character uses ten bit times: one start, eight data, and one stop. At 9,600 baud, one bit lasts about 104 ยตs and framing limits the theoretical rate to roughly 960 characters per second before protocol overhead.

The line normally idles HIGH. A LOW start bit begins the frame, data bits commonly arrive least-significant bit first, and the stop bit returns HIGH.


Wire direction before code

Device A TX → Device B RX
Device A RX ← Device B TX
Device A GND — Device B GND

TX crosses to RX. The shared ground gives both devices the reference used to decide HIGH and LOW. Never connect two actively driven TX outputs together.

Also, “serial” does not identify the electrical standard:

Interface Difference
3.3 V or 5 V logic UART Single-ended logic; voltage compatibility must be checked
RS-232 Different, often bipolar levels; requires a transceiver
RS-485 Differential bus; requires a transceiver and bus design
USB Packet-based differential interface; a bridge converts it to UART

RS-232 connected directly to GPIO can cause damage. A 5 V TX can exceed a 3.3 V input rating. Check both data sheets.


Debug from electricity upward

1. Identify both endpoints

Record the board or chip, UART instance, pin mapping, I/O voltage, idle polarity, baud rate, data bits, parity, stop bits, and flow control.

2. Check ground and idle voltage

TX should normally idle HIGH. Verify the ground path and voltage compatibility. If TX never changes, confirm that firmware selected the correct peripheral and pin multiplexer.

3. Send a known pattern

Repeated U characters (0x55) create alternating bits that are easy to recognize. Avoid debugging a complex binary protocol and the physical link simultaneously.

4. Match the complete frame

A 115200 terminal cannot decode a 9600 transmitter. Baud, character size, parity, and stop bits must all match.

5. Measure one bit

A logic analyzer decodes frames and flags errors. An oscilloscope reveals actual voltage, bit time, slow edges, ringing, and noise. If a 9,600-baud bit is far from about 104 ยตs, inspect the clock and baud configuration.

6. Check software buffering

Only after the electrical frame is valid, investigate receive-buffer overflow, blocking code, binary-versus-text interpretation, delimiters, and packet framing.


Common symptoms

Symptom Likely cause First check
Nothing received TX/RX direction, wrong pin, no ground, or no transmission Probe the transmitting TX pin
Consistent garbage Baud or frame mismatch, inverted signal Measure bit time and idle polarity
First characters missing Receiver starts late or resets Capture boot and reset timing
Works one direction only One wire, input level, or receiver configuration Test directions separately
Fails at high baud Clock error, wiring, noise, or slow level shifter Lower baud and inspect edges
Bytes disappear under load Buffer overrun or blocking firmware Count errors and service RX promptly

Adding a delay may change the symptom, but it does not prove that timing or voltage is valid.

Make diagnostic output useful

BOOT rev=3 reset=power_on
UART baud=115200 format=8N1
COUNT 0001
COUNT 0002

A counter reveals missing or duplicated messages. Firmware revision and reset cause distinguish corruption from an unexpected restart.

For chip-to-chip binary data, add a frame boundary, length, message type, sequence number, and integrity check appropriate to the risk. UART carries bytes; it does not define the packet protocol.

Completion checklist

  • [ ] TX crosses to RX and both endpoints share a valid reference.
  • [ ] I verified logic UART versus RS-232, RS-485, or USB.
  • [ ] Voltage levels and input limits are compatible.
  • [ ] Baud rate, data bits, parity, and stop bits match.
  • [ ] I can estimate and measure one bit time.
  • [ ] I use a logic analyzer for frames and a scope for electrical quality.
  • [ ] I inspect buffering only after the wire-level frame is valid.

Next experiment

UART needs no shared clock. An SPI LCD adds a clock, chip select, command/data state, and controller-specific startup sequence. Next, I will debug why a powered display can remain completely white.


References

Comments

Popular posts from this blog

Phrase Hero 1.1.0: Review Only the Phrasal Verbs You Missed

Simple Side Note: Never Lose a Note Again

Phrase Hero 1.2.0: Five Worlds and 100 English Expressions