FPGA module – serial port sending and receiving module

FPGA module – serial port module

  • Send code
  • receive code
  • Pin constraints

Send code

1. Use the sending module

Using this module requires outputting a sending port
output uart_txd, //UART send port
/*-------------------------------------------------*/


wire uart_rx_done = 1'b1; //UART receives completion signal
wire[7:0] rx_data;

assign rx_data = 8'b11111111; //Data to be sent

//parameter define
parameter CLK_FREQ = 50000000; //Define the system clock frequency
parameter UART_BPS = 115200; //Define the serial port baud rate

//wire define



//Serial port sending module
uart_tx #(
    .CLK_FREQ (CLK_FREQ),
    .UART_BPS (UART_BPS)
    )
    u_uart_tx(
    .clk (sys_clk),
    .rst_n (sys_rst_n),
    .uart_tx_en (uart_rx_done),
    .uart_tx_data (rx_data ),
    .uart_txd (uart_txd ),
    .uart_tx_busy ( )
    );
   


2. The bottom layer of serial port sending
Add a uart_tx.v file

module uart_tx(
    input clk, //system clock
    input rst_n, //System reset, low effective
    input uart_tx_en, //UART transmission enable
    input [7:0] uart_tx_data, //Data to be sent by UART
    output reg uart_txd , //UART sending port
    output reg uart_tx_busy //Send busy status signal
    );

//parameter define
parameter CLK_FREQ = 50000000; //system clock frequency
parameter UART_BPS = 115200; //Serial port baud rate
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //To obtain the specified baud rate, count the system clock BPS_CNT times

//reg define
reg [7:0] tx_data_t; //Send data register
reg [3:0] tx_cnt; //Send data counter
reg [15:0] baud_cnt; //Baud rate counter

//************************************************ *****
//** main code
//************************************************ *****

//When uart_tx_en is high, register the input parallel data and pull the BUSY signal high
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        tx_data_t <= 8'b0;
        uart_tx_busy <= 1'b0;
    end
    //When sending is enabled, register the data to be sent and pull the BUSY signal high
    else if(uart_tx_en) begin
        tx_data_t <= uart_tx_data;
        uart_tx_busy <= 1'b1;
    end
    //When counting reaches the end of the stop bit, stop the sending process
    else if(tx_cnt == 4'd9 & amp; & amp; baud_cnt == BAUD_CNT_MAX - BAUD_CNT_MAX/16) begin
        tx_data_t <= 8'b0; //Clear the send data register
        uart_tx_busy <= 1'b0; //and pull down the BUSY signal
    end
    else begin
        tx_data_t <= tx_data_t;
        uart_tx_busy <= uart_tx_busy;
    end
end

//Counter assignment of baud rate
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        baud_cnt <= 16'd0;
    //When in the sending process, the baud rate counter (baud_cnt) performs loop counting
    else if(uart_tx_busy) begin
        if(baud_cnt < BAUD_CNT_MAX - 1'b1)
            baud_cnt <= baud_cnt + 16'b1;
        else
            baud_cnt <= 16'd0; //The count is cleared after reaching one baud rate cycle
    end
    else
        baud_cnt <= 16'd0; //The counter is cleared at the end of the sending process
end

//tx_cnt assigns value
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        tx_cnt <= 4'd0;
    else if(uart_tx_busy) begin //tx_cnt is counted only when it is in the sending process
        if(baud_cnt == BAUD_CNT_MAX - 1'b1) //When the baud rate counter counts to one baud rate cycle
            tx_cnt <= tx_cnt + 1'b1; //Send data counter plus 1
        else
            tx_cnt <= tx_cnt;
    end
    else
        tx_cnt <= 4'd0; //The counter is cleared at the end of the sending process
end

//Assign a value to the uart sending port based on tx_cnt
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        uart_txd <= 1'b1;
    else if(uart_tx_busy) begin
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0; //Start bit
            4'd1: uart_txd <= tx_data_t[0]; //The lowest bit of data bits
            4'd2 : uart_txd <= tx_data_t[1];
            4'd3: uart_txd <= tx_data_t[2];
            4'd4 : uart_txd <= tx_data_t[3];
            4'd5 : uart_txd <= tx_data_t[4];
            4'd6: uart_txd <= tx_data_t[5];
            4'd7 : uart_txd <= tx_data_t[6];
            4'd8: uart_txd <= tx_data_t[7]; //Highest data bit
            4'd9: uart_txd <= 1'b1; //Stop bit
            default : uart_txd <= 1'b1;
        endcase
    end
    else
        uart_txd <= 1'b1; //The sending port is high level when idle
end

endmodule

Receive code

1. Use the receiving module

To use this module, you need to enter a receiving port
input uart_rxd //UART receiving port
/*------------------------------------------------ ----*/
//parameter define
parameter CLK_FREQ = 50000000; //Define the system clock frequency
parameter UART_BPS = 115200; //Define the serial port baud rate

//wire define
wire uart_rx_done; //UART receives completion signal
wire [7:0] uart_rx_data;
reg [7:0] rx_data;

initial flag <= 1'b0;
//Check the received data
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
       flag <= 1'b1;
    end
    else begin
        rx_data<=uart_rx_data;
         if(rx_data==8'b1111_1110)begin
                flag <= ~flag ;
         end
    
    end


end

//Serial port receiving module
uart_rx #(
    .CLK_FREQ (CLK_FREQ),
    .UART_BPS (UART_BPS)
    )
    u_uart_rx(
    .clk (sys_clk),
    .rst_n (sys_rst_n),
    .uart_rxd (uart_rxd ),
    .uart_rx_done (uart_rx_done),
    .uart_rx_data (uart_rx_data)
    );

2. The bottom layer of the receiving module
Add a uart_rx.v file

module uart_rx(
    input clk, //system clock
    input rst_n, //System reset, low effective

    input uart_rxd, //UART receiving port
    output reg uart_rx_done, //UART reception completion signal
    output reg [7:0] uart_rx_data //Data received by UART
    );

//parameter define
parameter CLK_FREQ = 50000000; //system clock frequency
parameter UART_BPS = 115200; //Serial port baud rate
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //To obtain the specified baud rate, count the system clock BPS_CNT times

//reg define
reg uart_rxd_d0;
reg uart_rxd_d1;
reg uart_rxd_d2;
reg rx_flag; //Receive process flag signal
reg [3:0] rx_cnt; //Receive data counter
reg [15:0] baud_cnt; //Baud rate counter
reg [7:0 ] rx_data_t; //Receive data register

//wire define
wire start_en;

//************************************************ *****
//** main code
//************************************************ *****
//Capture the falling edge (start bit) of the receiving port and get a pulse signal of one clock cycle
assign start_en = uart_rxd_d2 & amp; (~uart_rxd_d1) & amp; (~rx_flag);

//Synchronous processing of asynchronous signals
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;
        uart_rxd_d2 <= 1'b0;
    end
    else begin
        uart_rxd_d0 <= uart_rxd;
        uart_rxd_d1 <= uart_rxd_d0;
        uart_rxd_d2 <= uart_rxd_d1;
    end
end

//Assign a value to the receiving flag
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        rx_flag <= 1'b0;
    else if(start_en) //Start bit detected
        rx_flag <= 1'b1; //During the reception process, the flag signal rx_flag is pulled high
    //When the stop bit is halfway, that is, the receiving process ends, the flag signal rx_flag is pulled low
    else if((rx_cnt == 4'd9) & amp; & amp; (baud_cnt == BAUD_CNT_MAX/2 - 1'b1))
        rx_flag <= 1'b0;
    else
        rx_flag <= rx_flag;
end

//Counter assignment of baud rate
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        baud_cnt <= 16'd0;
    else if(rx_flag) begin //When in the receiving process, the baud rate counter (baud_cnt) performs loop counting
        if(baud_cnt < BAUD_CNT_MAX - 1'b1)
            baud_cnt <= baud_cnt + 16'b1;
        else
            baud_cnt <= 16'd0; //The count is cleared after reaching one baud rate cycle
    end
    else
        baud_cnt <= 16'd0; //The counter is cleared at the end of the receiving process
end

//Assign value to the received data counter (rx_cnt)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        rx_cnt <= 4'd0;
    else if(rx_flag) begin //rx_cnt counts only when it is in the receiving process
        if(baud_cnt == BAUD_CNT_MAX - 1'b1) //When the baud rate counter counts to one baud rate cycle
            rx_cnt <= rx_cnt + 1'b1; //Receive data counter plus 1
        else
            rx_cnt <= rx_cnt;
    end
    else
        rx_cnt <= 4'd0; //The counter is cleared at the end of the receiving process
end

//Register the data of the rxd port according to rx_cnt
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        rx_data_t <= 8'b0;
    else if(rx_flag) begin //When the system is in the receiving process
        if(baud_cnt == BAUD_CNT_MAX/2 - 1'b1) begin //Determine whether baud_cnt counts to the middle of the data bits
           case(rx_cnt)
               4'd1: rx_data_t[0] <= uart_rxd_d2; //Register the lowest bit of data
               4'd2 : rx_data_t[1] <= uart_rxd_d2;
               4'd3 : rx_data_t[2] <= uart_rxd_d2;
               4'd4 : rx_data_t[3] <= uart_rxd_d2;
               4'd5 : rx_data_t[4] <= uart_rxd_d2;
               4'd6 : rx_data_t[5] <= uart_rxd_d2;
               4'd7 : rx_data_t[6] <= uart_rxd_d2;
               4'd8: rx_data_t[7] <= uart_rxd_d2; //Register the high and low bits of data
               default : ;
            endcase
        end
        else
            rx_data_t <= rx_data_t;
    end
    else
        rx_data_t <= 8'b0;
end

//Assign values to the reception completion signal and received data
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        uart_rx_done <= 1'b0;
        uart_rx_data <= 8'b0;
    end
    //When the received data counter counts to the stop bit and baud_cnt counts to the middle of the stop bit
    else if(rx_cnt == 4'd9 & amp; & amp; baud_cnt == BAUD_CNT_MAX/2 - 1'b1) begin
        uart_rx_done <= 1'b1; //Pull high the reception completion signal
        uart_rx_data <= rx_data_t; //Assign the data received by UART
    end
    else begin
        uart_rx_done <= 1'b0;
        uart_rx_data <= uart_rx_data;
    end
end

endmodule

Pin constraints

#Timing constraints
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]

#IO pin constraints
#----------------------System Clock------------------------- --
set_property -dict {<!-- -->PACKAGE_PIN R4 IOSTANDARD LVCMOS33} [get_ports sys_clk]

#----------------------System Reset------------------------- --
set_property -dict {<!-- -->PACKAGE_PIN U2 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]

#---------------------USB UART------------------------- --
set_property -dict {<!-- -->PACKAGE_PIN U5 IOSTANDARD LVCMOS33} [get_ports uart_rxd]
set_property -dict {<!-- -->PACKAGE_PIN T6 IOSTANDARD LVCMOS33} [get_ports uart_txd]