Day 70: Peripheral: UART TX/RX with oversampling
Peripheral: UART TX/RX with oversampling
A UART sends bytes over one wire asynchronously: an idle-high line, a start bit (falling edge), 8 data bits (LSB first), an optional parity bit, and a stop bit. The transmitter is a PISO shift register (Stage 0) clocked at the baud rate. The receiver is harder: with no shared clock, it must oversample (typically 16×) to find the start-bit edge and then sample each bit at its center.
// 16x oversampling receiver, simplified
// baud_tick pulses 16x the baud rate
always @(posedge clk) begin
case (state)
IDLE: if (!rx) begin state <= START; os_cnt <= 0; end // falling edge
START: if (baud_tick) begin
if (os_cnt == 7) begin // mid of start bit
if (!rx) begin state <= DATA; os_cnt<=0; bit_i<=0; end
else state <= IDLE; // false start -> reject
end else os_cnt <= os_cnt + 1;
end
DATA: if (baud_tick) begin
if (os_cnt == 15) begin // sample at bit center
shreg <= {rx, shreg[7:1]}; // LSB first
os_cnt <= 0;
if (bit_i == 7) state <= STOP; else bit_i <= bit_i + 1;
end else os_cnt <= os_cnt + 1;
end
STOP: if (baud_tick && os_cnt==15) begin valid<=1'b1; state<=IDLE; end
endcase
endWhy oversample, and baud tolerance
Oversampling at 16× lets the receiver locate the start edge to within 1/16 of a bit and sample each bit near its center, tolerating a few-percent baud mismatch between sender and receiver before the sample point drifts off the bit. 'Whiteboard a UART receiver, including baud-error tolerance' is a named Stage-2 interview checkpoint — this is it.
Key terms
- UART
- Universal asynchronous receiver/transmitter — serial framing with start/data/parity/stop bits over one wire.
- Baud rate
- Symbols per second on the line (e.g. 115200); both ends must agree within tolerance.
- Oversampling
- Sampling the RX line many times per bit (e.g. 16×) to find the start edge and bit centers.
- Start / stop bit
- Framing bits marking the beginning (falling edge) and end (idle-high) of a character.
Ship for Day 70
Why does a UART receiver oversample the RX line (e.g. at 16×) rather than sampling once per bit?