UART with Verilog Part One: Receiver

Hasitha Algewatta
5 min readJun 23, 2019

UART, which stands for Universal Asynchronous Receiver/Transmitter is a circuit for sending parallel data through a serial line. In this article we will look at how we can implement a simplified version of the receiver in verilog which would hopefully help you understand verilog and the protocol itself a bit more clearly.

When the system is in idle and there is no data to be send, the receiver will see logic HIGH at its input. The transmitter starts communciation with the receiver by sending a start bit. This is signalled by lowering the signal from logic HIGH to logic LOW (Figure 1).

Figure 1: Data Feed to Receiver

The start bit is followed by the data bits (in this example we assume an 8 bit transfer). An optional parity bit can be sent after the data bits for error correction purposes. Transmission ends with stop bits which are logic HIGH.

That’s the high level view of the receiver. It does not look that hard now does it?

So how are we going to model this in Verilog?

Before that we need to dig deeper into how the receiver actually performs. In UART there is no clock synchronization between the transmitter(Tx) and the receiver(Rx). This means they have to agree beforehand to a clock frequency. This is done by setting the baud rate for Rx and Tx.

Since the there is no clock synchronisation done at the start of the transmission there needs to be a way to make sure the bits are read when they are stable not when they are changing. Oversampling is used to achieve this. In the implementation we will be doing a bit will be sampled 16 times. So the idea is to read every eighth sample from the start of the bit which is bound to be near the middle thus would be stable. Even though receiver has no idea when exactly the start bit will occur its estimation will be off only by at most 1/16.

So what signals do the Rx need to decipher the transmission?

  • Receive signal from Tx (let’s say rx)
  • Sampling signal or ticks (s_tick)
  • Reset (reset)

Then it will output the following

  • Data read (dout)
  • Read completed signal (rx_done_tick)

rx_done_tick signals that data is ready and stable to be read from Rx

Figure 2: How ticks are used to approximate the middle of a signal

So this is how our module would look like

module uart_rx(
rx,
s_tick,
dout,
rx_done_tick,
reset
);
input rx;
input s_tick;
output reg [7:0] dout;
output reg rx_done_tick;

Now we need to add our sampling logic. In the following code snippet, we look at how it is done. Mind you this has intentionally being made simple and can be written down in a more compact form as we will see later.

First we define the following ‘states’.

localparam [4:0]
IDLE = 4'd0,
DATA0 = 4'd1,
DATA1 = 4'd2,
DATA2 = 4'd3,
DATA3 = 4'd4,
DATA4 = 4'd5,
DATA5 = 4'd6,
DATA6 = 4'd7,
DATA7 = 4'd8;
STOP = 4'd9;

We need two registers to keep track of what’s happening. One for how many ticks (counter) and one for the current state (state).

reg [4:0] counter;
reg [2:0] state;

Now to the implementation of the logic. Once a HIGH to LOW transition is detected by the reciever we start incrementing the counter every sampling tick until it is 7. This is means we are likely at the middle of the start bit or at least surely somewhere very near it. Here we reset the counter to 0 and start incrementing it every sampling tick. When the counter is at 15 then it is sampling the middle of the first data bit. Then we reset the counter to 0 and do this again until data bits are exhausted.

Here is how the code could look like (without the stop bit)

always@(posedge s_tick) begin
case(state)
IDLE:
if(rx == 0 && counter == 4'd7) begin
rx_done_tick <= 0;
state <= DATA0;
counter <= 0;
dout <= 0;
end else begin
counter <= counter + 1;
end
DATA0:
if(counter == 4'd15) begin
state <= DATA1;
counter <= 0;
dout[0] <= rx;
end else begin
counter <= counter + 1;
end
DATA1:
if(counter == 4'd15) begin
state <= DATA2;
counter <= 0;
dout[1] <= rx;
end else begin
counter <= counter + 1;
end
DATA2:
if(counter == 4'd15) begin
state <= DATA3;
counter <= 0;
dout[2] <= rx;
end else begin
counter <= counter + 1;
end
DATA3:
if(counter == 4'd15) begin
state <= DATA4;
counter <= 0;
dout[3] <= rx;
end else begin
counter <= counter + 1;
end
DATA4:
if(counter == 4'd15) begin
state <= DATA5;
counter <= 0;
dout[4] <= rx;
end else begin
counter <= counter + 1;
end
DATA5:
if(counter == 4'd15) begin
state <= DATA6;
counter <= 0;
dout[5] <= rx;
end else begin
counter <= counter + 1;
end
DATA6:
if(counter == 4'd15) begin
state <= DATA7;
counter <= 0;
dout[6] <= rx;
end else begin
counter <= counter + 1;
end
DATA7:
if(counter == 4'd15) begin
state <= IDLE;
counter <= 0;
dout[7] <= rx;
rx_done_tick <= 1;
end else begin
counter <= counter + 1;
end
endcase
end

Now if you look closely you may have realised that all states from DATA0 to DATA6 practically does the samething. So we can refactor this to be much shorter and needed lesser ‘states’ by introducing a new register to keep track of the data bit being read

reg [3:0] bit_count;

And the code change to reflect this (after adding STOP as well)

always@(posedge s_tick) begin
case(state)
IDLE:
if(rx == 0 && counter == 4'd7) begin
rx_done_tick <= 0;
state <= DATA;
counter <= 0;
bit_count <= 0;
dout <= 0;
end else begin
counter <= counter + 1;
end
DATA:
if(counter == 4'd15) begin
state <= DATA;
dout <= {rx, dout[7:1]};
bit_count <= bit_count + 1;
counter <= counter + 1;
if(bit_count == 3'd7) begin
state <= STOP;
bit_count <= 0;
rx_done_tick <= 0;
end
end else begin
counter <= counter + 1;
end
STOP:
if(counter == 4'd15) begin
rx_done_tick <= 1;
state <= IDLE;
counter <= 0;
end else begin
counter <= counter + 1;
end
endcase
end

Here a clever shifting of bits has been used to dramatically reduce the number of ‘states’ needed.

Next we add the reset logic to complete our design. I’ve used an asynchronous reset here as I did not feed the clock to the design to make it simpler.

always@(negedge reset) begin
state <= IDLE;
counter <= 4'b0;
rx_done_tick <= 1;
end

For a sample test bench with see https://bitbucket.org/hmalgewatta/uart/src/master/uart_rx/

Hope this helped you get some idea about the workings of UART!

--

--