A UART transmitter turns a byte into a timed bit stream on one wire. It uses a small FSM, a baud counter, a shift register, and a valid/ready handshake.
5 lessons, about 28 min
10 bit-times × 16 clocks = 160 cycles (start + 8 data + stop).
The whole topic on one page, taken from each lesson's Remember box. Read it before an interview, or print it.
Framing and Timing
8N1 is 10 bit-times per byte: start, 8 data bits (least significant first) and stop.
CLKS_PER_BIT is the clock divided by the baud rate, rounded. The rounding gives a period error and a baud error.
The TX and RX baud rates must match closely. Compare B_TX / B_RX - 1 at opposite oscillator corners.
Rule of thumb: make CLKS_PER_BIT a parameter, so the same RTL runs at 4 clocks per bit in simulation and 434 on the board.
The UART TX FSM
tick is baud_cnt == CLKS_PER_BIT - 1 with the counter reset at every bit boundary, so each bit lasts exactly CLKS_PER_BIT clocks.
STOP can return to START at once when a byte waits and CTS allows it, so frames run with no idle gap.
tx_ready depends on the baud counter. Keep one side of the producer handshake registered.
Rule of thumb: start the start bit on the accept edge and reset the counter on the same edge.
Cycle-by-Cycle Walkthrough
The line carries 0x96 as 0, 1, 1, 0, 1, 0, 0, 1 (least significant bit first), after the start bit.
A frame is 10 bits at 4 clocks each, so it runs for 40 clocks, from cycle 2 to cycle 41.
Equal neighbouring bits give no line edge, so a receiver counts bit times and does not watch for edges.
Rule of thumb: test with a byte whose bit order is not symmetric.
Verification and Integration
Check every clock of every frame, data order, no lost or extra frames, valid/ready stability and back-to-back spacing.
Mutations prove the bench: a wrong tick compare and an MSB-first transmitter both make it fail.
Drive the pin from a flop in the UART's own clock domain, and cross whole bytes into that domain.
Rule of thumb: never test only against a receiver you wrote.
Mini Project: an SPI Master
Mode 0: SCLK idles low, MOSI changes only when SCLK falls, both sides sample on the rising edge, most significant bit first.
The FSM moves only on the divider's tick; the bit position lives in a counter, not in sixteen states.
busy low must mean a start is taken now. Test with a producer that starts in the done cycle.
Rule of thumb: derive busy from the same condition that takes the start, so the two can never disagree.
Code lab: Build a UART transmitter FSM
Practice question: FSM verification strategy: coverage and assertions for corner cases
Code lab: UART TX byte
Interview: run a mock interview on this topic