0
0
VerilogHow-ToBeginner · 4 min read

Verilog Code for UART Transmitter: Syntax and Example

A UART transmitter in Verilog sends serial data by shifting bits out one at a time using a clock. The uart_tx module typically includes a state machine to handle start, data, parity, and stop bits, controlled by a baud rate clock.
📐

Syntax

The basic UART transmitter module in Verilog includes inputs for clock, reset, data to send, and a start signal. Outputs include the serial transmit line and a busy flag. Internally, it uses a state machine to send start bit, data bits, optional parity, and stop bit.

  • clk: System clock input.
  • rst: Reset signal to initialize the transmitter.
  • tx_start: Signal to start transmission.
  • tx_data: 8-bit data to transmit.
  • tx_serial: Output serial data line.
  • tx_busy: Indicates transmitter is busy sending data.
verilog
module uart_tx(
    input wire clk,
    input wire rst,
    input wire tx_start,
    input wire [7:0] tx_data,
    output reg tx_serial,
    output reg tx_busy
);

    // Baud rate generator and state machine signals
    // ... (implementation details)

endmodule
💻

Example

This example shows a complete UART transmitter module that sends 8-bit data serially with 1 start bit and 1 stop bit at a fixed baud rate. It demonstrates how to use a baud rate counter and a state machine to control the transmission.

verilog
module uart_tx(
    input wire clk,          // System clock
    input wire rst,          // Reset signal
    input wire tx_start,     // Start transmission
    input wire [7:0] tx_data,// Data byte to send
    output reg tx_serial,    // UART transmit line
    output reg tx_busy       // Busy flag
);

    // Parameters for baud rate generation
    parameter CLK_FREQ = 50000000; // 50 MHz clock
    parameter BAUD_RATE = 9600;
    localparam BAUD_COUNTER_MAX = CLK_FREQ / BAUD_RATE;

    reg [15:0] baud_counter = 0;
    reg baud_tick = 0;

    // State machine states
    typedef enum reg [2:0] {
        IDLE = 3'b000,
        START_BIT = 3'b001,
        DATA_BITS = 3'b010,
        STOP_BIT = 3'b011
    } state_t;

    state_t state = IDLE;
    reg [3:0] bit_index = 0;
    reg [7:0] tx_shift_reg = 8'b0;

    // Baud rate generator
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            baud_counter <= 0;
            baud_tick <= 0;
        end else begin
            if (baud_counter == BAUD_COUNTER_MAX - 1) begin
                baud_counter <= 0;
                baud_tick <= 1;
            end else begin
                baud_counter <= baud_counter + 1;
                baud_tick <= 0;
            end
        end
    end

    // UART transmitter state machine
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            state <= IDLE;
            tx_serial <= 1'b1; // Idle line is high
            tx_busy <= 0;
            bit_index <= 0;
            tx_shift_reg <= 8'b0;
        end else if (baud_tick) begin
            case (state)
                IDLE: begin
                    tx_serial <= 1'b1; // Line idle high
                    tx_busy <= 0;
                    if (tx_start) begin
                        tx_busy <= 1;
                        tx_shift_reg <= tx_data;
                        state <= START_BIT;
                    end
                end
                START_BIT: begin
                    tx_serial <= 1'b0; // Start bit is low
                    state <= DATA_BITS;
                    bit_index <= 0;
                end
                DATA_BITS: begin
                    tx_serial <= tx_shift_reg[bit_index];
                    if (bit_index == 7) begin
                        state <= STOP_BIT;
                    end else begin
                        bit_index <= bit_index + 1;
                    end
                end
                STOP_BIT: begin
                    tx_serial <= 1'b1; // Stop bit is high
                    state <= IDLE;
                    tx_busy <= 0;
                end
            endcase
        end
    end

endmodule
Output
No direct console output; tx_serial line outputs UART serial data stream at 9600 baud.
⚠️

Common Pitfalls

Common mistakes when writing a UART transmitter include:

  • Not generating the correct baud rate clock, causing timing errors.
  • Forgetting to set the transmit line high when idle, which can cause framing errors.
  • Not handling the tx_busy flag properly, leading to data overwrites.
  • Incorrect bit order when shifting data out (LSB first is standard).

Always test with a known baud rate and verify the output with a logic analyzer or serial terminal.

verilog
/* Wrong: tx_serial line left low when idle */
// tx_serial <= 0; // Incorrect idle state

/* Right: tx_serial line high when idle */
// tx_serial <= 1; // Correct idle state
📊

Quick Reference

  • Start bit: Always 0 (low) to signal start of transmission.
  • Data bits: Usually 8 bits, sent LSB first.
  • Stop bit: Always 1 (high) to signal end of transmission.
  • Baud rate: Controls timing; must match receiver.
  • Idle line: Always high when not transmitting.

Key Takeaways

Generate a precise baud rate clock to time UART bits correctly.
Send a low start bit, then data bits LSB first, and a high stop bit.
Keep the transmit line high when idle to avoid framing errors.
Use a busy flag to prevent starting a new transmission before the current one finishes.
Test your UART transmitter with a serial terminal or logic analyzer.