FPGA UART Transmission Module – Detailed Analysis with Code

Welcome to leave a message, each message will be selected, and I will reply on the same day. Any errors in the article will also be updated in the reply.

#FPGA #UART Transmission #Volatility Generation #Timing Logic

The Verilog code is at the bottom of the article.

1. Design File <span>uart_byte_tx</span> Function Analysis

This module is a UART transmission module that converts byte data into serial signals (start bit, data bits, stop bit). The key logic is as follows:

  1. Parameter Definition:

  • <span>MCNT_baudset</span> Baud rate (9600bps) corresponding to the frequency divider counter threshold (assuming system clock is 50MHz, <span>50_000_000 / 9600 ≈ 5208</span>).
  • <span>MCNT_bitset</span> Maximum value of bit counter (1 byte + 1 start bit + 1 stop bit = 10 bits, counting from 0 to 9).
  • <span>MCNT_dalaycnt</span> Delay counter threshold (originally designed for 1s, redefined in Testbench as 10ms).
  • Core Logic:

    • <span>delay_cnt</span> Delay counter, used to control the sending interval.
    • <span>send_en</span> Send enable signal, activated after the delay counter is full.
    • <span>baud_div_cnt</span> Baud rate division counter, generates bit period signal.
    • <span>bit_cnt</span> Bit counter, tracks the current sending bit (start bit, data bits, stop bit).
    • <span>data_byte_reg</span> Data register, temporarily stores the byte to be sent.
    • <span>uart_tx</span> UART transmission logic, outputs the corresponding bit based on <span>bit_cnt</span> (start bit <span>0</span>, data bits, stop bit <span>1</span>).
    • <span>led</span> Flips once after sending a byte, indicating transmission completion.

    2. Testbench File <span>uart_byte_tx_tb</span> Analysis

    1. Instantiation and Parameter Redefinition:

    • Instantiate the <span>uart_byte_tx</span> module.
    • Redefine <span>MCNT_dalaycnt = 50_000_0 - 1</span> to shorten the sending interval from 1s to 10ms.
  • Stimulus Generation:

    • Generate a 50MHz clock (period 20ns).
    • After reset, first send <span>8'b01010101</span> (0x55), then after a delay of 30ms send <span>8'b10101010</span> (0xAA).

    3. Simulation Waveform Analysis

    FPGA UART Transmission Module - Detailed Analysis with Code

    • <span>clk</span> 50MHz clock, green square wave.
    • <span>reset_n</span> Initially low reset, then pulled high.
    • <span>data_byte</span> First <span>01010101</span> (0x55), then <span>10101010</span> (0xAA).
    • <span>uart_tx</span>
      • When sending <span>0x55</span>: start bit <span>0</span> → sequentially send <span>01010101</span> (LSB first) → stop bit <span>1</span>.
      • When sending <span>0xAA</span>: start bit <span>0</span> → sequentially send <span>10101010</span> (LSB first) → stop bit <span>1</span>.
    • <span>led</span> Flips once after sending a byte, consistent with the design condition <span>(bit_cnt == MCNT_bitset) && (baud_div_cnt == MCNT_baudset)</span><span>.</span>

    4. Summary

    This design implements the UART byte transmission function. The Testbench shortened the sending interval by redefining parameters, and the simulation waveform verified the logical correctness:

    • The order of start bit, data bits, and stop bit is correct.

    • The LED accurately indicates the completion of byte transmission.

    • The baud rate division and bit counting logic meet expectations (at 9600bps, each bit period is approximately 104μs, corresponding to the division counter 5208).

    <span>5. Verilog Code</span><span>1. Design file uart_byte_tx.v code</span>

    module uart_byte_tx # (    parameter MCNT_baudset = 5208 -1,//Baud rate 9600 corresponding frequency divider counter threshold    parameter MCNT_bitset = 10-1,    parameter MCNT_dalaycnt = 50_000_000 - 1//Delay counter to 1s)(    input clk,//Global clock signal    input reset_n,//Reset signal    input [7:0]data_byte,//Input byte-level data    output reg uart_tx,//Data to be sent (bit-level)    output reg led//Flips once after one byte transmission completed);    reg [12:0] baud_div_cnt;//Baud rate division counter    reg [3:0]bit_cnt;//Bit counter    reg [7:0]data_byte_reg;//Input data register    reg send_en;//Bit send enable signal    reg [25:0]delay_cnt;//Delay counter, sending 1 byte requires 1s/9600*10=1.04ms, far less than 1s, the time from 1ms to 1s does not require sending data, so a delay counter is needed//Delay counter logic, delay_cntalways@(posedge clk or negedge reset_n)begin    if(!reset_n)        delay_cnt <= 0;    else if(delay_cnt == MCNT_dalaycnt) //Count full reset to 0        delay_cnt <= 0;    else        delay_cnt <= delay_cnt + 1'b1;end//Bit send enable signal logic, send_enalways@(posedge clk or negedge reset_n)begin    if(!reset_n)        send_en <= 1'b0;    else if(delay_cnt == MCNT_dalaycnt) //Count full set to 1        send_en <= 1'b1;    else if((bit_cnt == MCNT_bitset)&&(baud_div_cnt == MCNT_baudset))//One byte transmission completed        send_en <= 1'b0;end//Baud rate division counter logicbaud_div_cntalways@(posedge clk or negedge reset_n)begin    if(!reset_n)        baud_div_cnt <= 0;    else if(send_en) begin//Enable signal triggered        if(baud_div_cnt == MCNT_baudset)            baud_div_cnt <= 0;        else            baud_div_cnt <= baud_div_cnt + 1'b1;        end    else//No enable signal, no reset signal        baud_div_cnt <= 0;end//Bit counter logicbit_cntalways@(posedge clk or negedge reset_n)begin    if(!reset_n)        bit_cnt <= 0;    else if(baud_div_cnt == MCNT_baudset)begin//Division counter full reset to 0        if(bit_cnt == MCNT_bitset)            bit_cnt <= 0;        else            bit_cnt <= bit_cnt +1;    endend//Data register logicdata_byte_regalways@(posedge clk or negedge reset_n)begin    if(!reset_n)        data_byte_reg <= 0;    else if(delay_cnt == MCNT_dalaycnt)//1s delay reached, enable signal to send the next byte        data_byte_reg <= data_byte;    else        data_byte_reg <= data_byte_reg;end//Bit send logicuart_txalways @ (posedge clk or negedge reset_n) begin    if(!reset_n)        uart_tx <= 1'b1;    else if(send_en == 1) begin        case(bit_cnt)            0:uart_tx <= 1'b0;            1:uart_tx <= data_byte_reg[0];            2:uart_tx <= data_byte_reg[1];            3:uart_tx <= data_byte_reg[2];            4:uart_tx <= data_byte_reg[3];            5:uart_tx <= data_byte_reg[4];            6:uart_tx <= data_byte_reg[5];            7:uart_tx <= data_byte_reg[6];            8:uart_tx <= data_byte_reg[7];            9:uart_tx <= 1'b1;            default:uart_tx <= uart_tx;        endcase    end    else        uart_tx <= 1'b1;end//LED flip logicalways@(posedge clk or negedge reset_n)begin    if(!reset_n)        led <= 0;    else if((bit_cnt == MCNT_bitset) &&(baud_div_cnt == MCNT_baudset))//One byte data transmission completed        led <= !led;    else        led <= led;endendmodule

    2. Simulation file uart_byte_tx_tb.v code:

    `timescale 1ns / 1psmodule uart_byte_tx_tb();//Declare reg type signals as stimulus sources, wire type signals connect to the output of the module under test    reg clk;//Global clock signal    reg reset_n;//Reset signal    reg [7:0]data_byte;//Input byte-level data    wire uart_tx;//Data to be sent (bit-level)    wire led;//Flips once after one byte transmission completed//Instantiate    uart_byte_tx uart_byte_tx(        .clk(clk),        .reset_n(reset_n),        .data_byte(data_byte),        .uart_tx(uart_tx),        .led(led)    );//Redefine parameter MCNT_dalaycnt, shorten time from 1s to 10ms, that is, send data (byte level) every 10ms    defparam uart_byte_tx.MCNT_dalaycnt = 50_000_0 -1;//Generate clock    initial clk = 1;    always #10 clk=~clk;//Generate test data    initial begin        reset_n = 0;        #201;        reset_n = 1;        data_byte = 8'b01010101;        # 30_000_000;//Send data three times, 30_000_000ns = 30_000 μs = 30 ms        data_byte = 8'b10101010;        # 30_000_000;//Send data three times, 30_000_000ns = 30_000 μs = 30 ms        $stop;    endendmodule

    Leave a Comment