0
0
VerilogHow-ToBeginner · 4 min read

Verilog Code for UART Receiver: Syntax and Example

A UART receiver in Verilog reads serial data bits and converts them into parallel data. The uart_rx module typically uses a baud rate clock, start bit detection, data bit sampling, and stop bit verification to receive data correctly.
📐

Syntax

The basic UART receiver module includes inputs for the serial data line and clock, and outputs the received byte and a data valid signal. It uses a state machine to detect the start bit, sample data bits at the baud rate, and check the stop bit.

  • clk: System clock input.
  • rx: Serial data input line.
  • data_out: 8-bit parallel output data.
  • data_valid: Signal indicating data reception complete.
verilog
module uart_rx(
    input wire clk,
    input wire rx,
    output reg [7:0] data_out,
    output reg data_valid
);

// Parameters for baud rate generation and sampling
parameter CLKS_PER_BIT = 434; // Example for 115200 baud with 50MHz clock

// State machine states
localparam IDLE = 0, START = 1, DATA = 2, STOP = 3;

reg [9:0] clk_count = 0;
reg [3:0] bit_index = 0;
reg [1:0] state = IDLE;
reg [7:0] rx_shift_reg = 0;

always @(posedge clk) begin
    case(state)
        IDLE: begin
            data_valid <= 0;
            clk_count <= 0;
            bit_index <= 0;
            if (rx == 0) // Start bit detected
                state <= START;
        end
        START: begin
            if (clk_count == (CLKS_PER_BIT-1)/2) begin // Mid bit sample
                if (rx == 0) begin
                    clk_count <= 0;
                    state <= DATA;
                end else
                    state <= IDLE; // False start bit
            end else
                clk_count <= clk_count + 1;
        end
        DATA: begin
            if (clk_count < CLKS_PER_BIT - 1) begin
                clk_count <= clk_count + 1;
            end else begin
                clk_count <= 0;
                rx_shift_reg[bit_index] <= rx;
                if (bit_index < 7) begin
                    bit_index <= bit_index + 1;
                end else begin
                    bit_index <= 0;
                    state <= STOP;
                end
            end
        end
        STOP: begin
            if (clk_count < CLKS_PER_BIT - 1) begin
                clk_count <= clk_count + 1;
            end else begin
                if (rx == 1) begin // Stop bit should be high
                    data_out <= rx_shift_reg;
                    data_valid <= 1;
                end
                state <= IDLE;
                clk_count <= 0;
            end
        end
    endcase
end

endmodule
💻

Example

This example shows a complete UART receiver module that receives 8-bit data at 115200 baud with a 50 MHz clock. It outputs the received byte and a data valid pulse when a byte is received.

verilog
module uart_rx_example(
    input wire clk,      // 50 MHz clock
    input wire rx,       // UART serial input
    output reg [7:0] data_out,
    output reg data_valid
);

parameter CLKS_PER_BIT = 434; // 50MHz / 115200 baud

localparam IDLE = 0, START = 1, DATA = 2, STOP = 3;

reg [9:0] clk_count = 0;
reg [3:0] bit_index = 0;
reg [1:0] state = IDLE;
reg [7:0] rx_shift_reg = 0;

always @(posedge clk) begin
    case(state)
        IDLE: begin
            data_valid <= 0;
            clk_count <= 0;
            bit_index <= 0;
            if (rx == 0) // Detect start bit
                state <= START;
        end
        START: begin
            if (clk_count == (CLKS_PER_BIT-1)/2) begin
                if (rx == 0) begin
                    clk_count <= 0;
                    state <= DATA;
                end else
                    state <= IDLE;
            end else
                clk_count <= clk_count + 1;
        end
        DATA: begin
            if (clk_count < CLKS_PER_BIT - 1) begin
                clk_count <= clk_count + 1;
            end else begin
                clk_count <= 0;
                rx_shift_reg[bit_index] <= rx;
                if (bit_index < 7) begin
                    bit_index <= bit_index + 1;
                end else begin
                    bit_index <= 0;
                    state <= STOP;
                end
            end
        end
        STOP: begin
            if (clk_count < CLKS_PER_BIT - 1) begin
                clk_count <= clk_count + 1;
            end else begin
                if (rx == 1) begin
                    data_out <= rx_shift_reg;
                    data_valid <= 1;
                end
                state <= IDLE;
                clk_count <= 0;
            end
        end
    endcase
end

endmodule
⚠️

Common Pitfalls

Common mistakes when writing a UART receiver in Verilog include:

  • Incorrect baud rate clock division causing wrong sampling timing.
  • Not sampling data bits in the middle of the bit period, leading to errors.
  • Ignoring the stop bit check, which can cause framing errors.
  • Not resetting state machine variables properly after each byte.

Always verify the clock frequency and baud rate match your hardware setup.

verilog
/* Wrong: Sampling data bits at start of bit period */
always @(posedge clk) begin
    if (clk_count == 0) begin
        rx_shift_reg[bit_index] <= rx; // Sampling at start, may cause errors
    end
    // ... rest of code
end

/* Right: Sampling data bits at middle of bit period */
always @(posedge clk) begin
    if (clk_count == (CLKS_PER_BIT-1)/2) begin
        rx_shift_reg[bit_index] <= rx; // Sample at middle for stability
    end
    // ... rest of code
end
📊

Quick Reference

  • Start bit: Detect low (0) on RX line to begin reception.
  • Data bits: Sample 8 bits at baud rate intervals, mid-bit.
  • Stop bit: Check for high (1) to confirm byte end.
  • Baud rate clock: Generate clock enable to sample bits correctly.
  • State machine: Use states IDLE, START, DATA, STOP for control flow.

Key Takeaways

Sample UART data bits at the middle of each bit period for reliable reception.
Use a state machine with states IDLE, START, DATA, and STOP to manage UART reception.
Verify your clock frequency and baud rate to calculate correct clock cycles per bit.
Check the stop bit to detect framing errors and confirm valid data.
Reset counters and state variables properly after each received byte.