Skip to main content
Logo image

Section 18.3 UART system design

Transmitter.

The transmitter datapath is simple. A block diagram is shown in Figure 18.3.1.
described in detail following the image
Block diagram
Figure 18.3.1. A UART transmitter consists of a 10-bit shift register for parallel-to-serial conversion, a bit time counter to mark the time between shifts, and a controller (state machine).
The controller is diagrammed in Figure 18.3.2. The state machine is normally in a loop governed by the timer, which is designed to assert TC for one clock cycle, and restart itself, every bit time. When it times out, the register is shifted by asserting tx_shift_tick for one clock cycle. When idle, the output of the shift register is ’1’. To initiate a transmission, the user sets up the tx_data byte and asserts the tx_start signal for one clock cycle. This causes the state machine to assert tx_load_tick for one clock cycle and also reset the timer. The state machine then returns to the normal shift loop. The load operation immediately places the start bit on the tx line, and subsequent assertions of tx_shift_tick shift the data bits and, finally, the stop bit, out of the register. The register is then shifting ’1’s out until the next load.
described in detail following the image
State diagram
Figure 18.3.2. State machine for the UART transmitter controller.

Checkpoint 18.3.3. UART bit timer.

If the system clock is 10MHz, how high does the bit timer have to count for a 115,200 baud rate?
Answer.
\(N = \dfrac{10,000,000}{115,200} \approx 87\)

Receiver.

Receivers are more complex than transmitters, because they don’t know what’s coming at them or when it’s coming. The receiver’s datapath is straightforward, just a 10-bit serial-to-parallel shift register, an 8-bit parallel-load output register, and a double-flop synchronizer, because the input stream is asynchronous to the receiver’s clock, Figure 18.3.4. The shift register is equipped with an rx_shift_tick control (and optionally, a clear control), and the output register has an rx_data_load control. Additionally, the controller outputs a signal rx_done_tick when a byte has been completely received.
described in detail following the image
Block diagram
Figure 18.3.4. Block diagram of the UART receiver.
The interesting part is the controller. We assume that the receiver knows the transmitter’s baud rate. The controller has a timer that divides the clock down to the bit time. It also has a counter to keep track of how many times the register has been shifted (how many bits have been received in the current packet). The controller’s state machine moves through these steps:
  1. Watch the serial input line, waiting for it to drop from ’1’ to ’0’, signifying the arrival of the start bit. While in this state, the shift counter and the bit timer are held in reset.
  2. Find the center of the start bit. This is done by having the timer count for half a bit time (see Figure 18.2.1).
  3. Assert rx_shift_tick for one clock cycle, bringing the start bit into the register.
  4. Wait for the timer to count one full bit time, then assert rx_shift_tick to bring the first data bit into the register. Repeat this step until the stop bit is shifted into the register (count the shifts).
  5. After ten shifts, the middle eight bits of the register (8 down to 1) contain the data byte. Transfer this byte into the output register, rx_data by asserting rx_data_load. This second register ensures that the output remains steady while the next packet is being received.
  6. Assert the rx_done_tick pulse for one clock cycle to signal that the data byte is available, then return to the initial state and wait for the next start bit.
When a long line connects the transmitter and receiver, noise can corrupt the received signal and cause the receiver not to function properly. A common error check that can be build into a UART is to make sure that the received start bit is, in fact, ’0’, confirming that the state machine didn’t just react to a glitch on the line. Another is to observe the final contents of the shift register to make sure that the LSB is ’0’ and the MSB is ’1’. If this is not observed, then a framing error has occurred.

Exercises Exercises

1. UART transmitter design.

Convert the UART transmitter block diagram, Figure 18.3.1, and state diagram, Figure 18.3.2, into a VHDL model, write a testbench, and confirm that the model works correctly.

2. UART receiver design.

Draw a state diagram for the UART receiver. Convert the block diagram, Figure 18.3.4, and the state diagram to a VHDL model, write a testbench, and confirm that the model works correctly. You may also use your transmitter model to generate a simulated bitstream and test the combination end-to-end.

3. UART prototype.

Take your transmitter and receiver designs through synthesis and implementation. Test your FPGA prototype in one of two ways (or both):
  • Set up a data byte for the transmitter with slide switches, and use a pushbutton to assert the tx_start signal. Wire the transmitter output to the receiver input (this is called a “loopback”) and display the rx_data on LEDs.
  • Set up a terminal emulator, like PuTTy, and use it to send bytes from a computer to the UART receiver and receive them from the UART transmitter (another loopback). You will need to uncomment the entries for the RsRx and RsTx ports in the XDC file, which map to the USB-to-serial interface on the Basys3 board. Loop rx_data back to tx_data, and use rx_done_tick to trigger tx_start. Check that what you type into PuTTy is displayed in the terminal window via the UART loopback.