Draft preview. Lessons are being written and reviewed.

Digital Design / Module 12: Projects and interview preparation

64. Minor project: UART transmitter and receiver

Build a real serial link.

Lecture coming soon

Lab: Protocol waveforms

The goal

Build a UART transmitter and receiver, the classic first real interface. It needs no shared clock, just an agreed bit rate. This project combines counters, , an FSM and a .

The frame

The line sits high when idle. One frame is a start bit (low), then 8 data bits with LSB first, then a stop bit (high). At 115200 baud, each bit lasts about 8.68 µs. Use the protocol lab above to see the waveform for any byte.

Transmitter

  • Baud generator: a counter that pulses once per bit.
  • A shift register that loads {stop, data, start} when a send is requested.
  • An FSM, or just a bit counter, to know when the frame is complete.

Register the TX output, so that it can't . Remember the receiver is watching this line for a falling edge.

Receiver

  • Synchronize RX first. It comes from outside your .
  • Oversample, commonly at 16 times the baud rate.
  • On a falling edge, wait half a bit, and confirm it's still low. This filters out noise.
  • Then sample once per bit at about the middle, shifting into a register.
  • Check that the stop bit is high. Otherwise, raise a framing error.

Why oversampling helps

The two ends use different oscillators, so the bit rates differ a little. Sampling in the middle of each bit tolerates that mismatch: the error accumulates across the 10-bit frame, and the middle sample has margin in both directions.

Requirements for your project

  • Parameterised clock frequency and baud rate
  • A valid/ready interface to the user logic
  • A self-checking loopback testbench, using random bytes
  • Tests with baud mismatch of about 2%, a false start bit, and a bad stop bit

Common mistake

Calculating the divisor with integer truncation, which adds rate error that you never checked. For 100 MHz and 115200 baud, 100,000,000 / 115,200 = 868.06, so the small error is fine here. At high baud rates, or with slow clocks, it can matter. Always compute the actual baud error.

Key ideas

  • Baud generator, framing, and oversampled receive.
  • Synchronize RX before use.
  • Test with loopback.

Your exercise

Complete UART TX and RX with a self-checking testbench.

Find the bug

This code has one deliberate bug. Read the symptom, then click the line you think is wrong.

What goes wrong: The receiver gets the wrong byte: every value arrives with its bits reversed, so 0x01 arrives as 0x80.

Interview questions

coreWhy oversample UART RX?

basicA UART runs at 9600 baud with 8 data bits, no parity and one stop bit. How long is one frame, and what is the maximum byte rate?

basicSketch the line levels for sending 0x41 over a UART, from idle to idle.

coreA 50 MHz system clock drives a UART at 115200 baud with 16 times oversampling. What tick divisor do you use, and what is the actual baud error?

coreWhy does the receiver synchronize RX first, and then check the start bit again half a bit after the falling edge?

coreA loopback test that only ever sends 0xA5 passes, but real traffic arrives wrong. The transmitter's data bit line is shown. What is the bug, and why did the test miss it?

always @(*)
  case (state)
    IDLE:    line_d = 1'b1;
    START:   line_d = 1'b0;
    DATA:    line_d = data[7 - idx];   // idx counts 0 to 7
    default: line_d = 1'b1;            // STOP
  endcase

coreIf the line is held low for a long time, a break condition, what should your receiver do?

advancedWith 16 times oversampling, the receiver finds the start edge up to one tick late and samples the stop bit about 9.5 bits after the edge. Roughly how much clock mismatch can it tolerate?

advancedA 10 MHz system clock must run a UART at 921,600 baud. Can it use 16 times oversampling?

Practise these 9 questions with animations