Hard · Counters & Timers · Finite State Machines
Design a UART receiver for the 8N1 format (8 data bits, LSB first, no parity, 1 stop bit). The line rx idles high. A frame is a start bit (0), data bits d0 (LSB) ... d7 (MSB), and a stop bit (1); each bit lasts CLKS_PER_BIT clock cycles.
A robust receiver does not trust edges. It finds the middle of the start bit, checks that the line is still low there (otherwise the falling edge was just a glitch), and then samples every following bit once, in its middle.
| Parameter | Default | Meaning |
|---|---|---|
CLKS_PER_BIT | 8 | Clock cycles per bit, 4 <= CLKS_PER_BIT <= 65535. Your design must work for every value in this range (odd ones too): the hidden tests also use non-default values, including the smallest. |
Let H = CLKS_PER_BIT / 2 (integer division; H = 4 for the default).
| Port | Dir | Width | Meaning |
|---|---|---|---|
clk | input | 1 | Clock. |
rst | input | 1 | Synchronous, active-high reset (takes effect only at a rising edge of clk). |
rx | input | 1 | Serial line. It is already synchronized to clk; use it directly. |
data | output | 8 | Received byte. Only required to be correct while valid = 1. |
valid | output | 1 | One-cycle pulse: a frame was received correctly (registered). |
frame_error | output | 1 | One-cycle pulse: the stop bit was 0 (registered). |
rx is sampled at every rising edge of clk. The receiver only looks at the samples listed below; all other samples are ignored.
rx = 0. Call the edge where it sees thisfirst 0 edge t0.
rx = 1 there, the low pulse was a glitch:the receiver returns to idle, produces no output, and can detect a new start bit from edge t0 + H + 1 on. If rx = 0, reception continues.
d[i] (i = 0..7) is the sample at edge t0 + H + (i+1)·CLKS_PER_BIT.rx = 1: the frame is good. In the cycle right after edge ts, valid = 1 anddata = {d7, ..., d0}. The receiver is idle again starting with edge ts + 1 (that edge may already be the t0 of the next frame).
rx = 0: framing error. In the cycle right after edge ts, frame_error = 1 andvalid = 0. The receiver then waits until it samples rx = 1 (at some edge ≥ ts + 1); only at the edges after that one can it detect a new start bit. This keeps a "break" (line held low) from being received as a stream of 0x00 frames.
valid and frame_error are 0 in every other cycle (each is a pulse of exactly onecycle per frame, and they are never both 1).
rst = 1): any reception in progress is abandoned; valid = 0,frame_error = 0; the receiver is idle (the first edge with rst = 0 can be a t0). Reset is synchronous: raising rst during a cycle in which valid or frame_error is 1 does not cut that pulse short; it ends at the next rising edge as usual.
A transmitter with the same CLKS_PER_BIT that starts its start bit just before edge t0 produces CLKS_PER_BIT samples per bit, so the sample points above fall in the middle of each bit. Back-to-back frames (the next start bit immediately after a stop bit) are received without loss.
CLKS_PER_BIT = 8, H = 4, receiving 8'h35 = 0011_0101)| what | edge (relative to t0) | rx sampled |
|---|---|---|
| first 0 (t0) | 0 | 0 |
| start check | 4 | 0 |
d0 ... d7 | 12, 20, 28, 36, 44, 52, 60, 68 | 1, 0, 1, 0, 1, 1, 0, 0 |
| stop | 76 | 1 → valid = 1, data = 8'h35 in the next cycle |
A low glitch that is sampled as 0 for at most H consecutive edges is ignored (its sample at t0 + H is 1).
The diagram below illustrates the sample points with a smaller CLKS_PER_BIT = 4 (H = 2) so that it fits: the start bit, d0 = 1 and d1 = 0. t0 is the edge at the end of the first low cycle; the marked cycles end at the sampling edges t0 + 2 (start check), t0 + 6 (d0) and t0 + 10 (d1).
Sign up free to solve UART Receiver (8N1) with Glitch Filter and Framing Error in your browser.