FPGA – serial transceiver

The three commonly used low-speed serial communication are UART, SPI, and IIC. Here FPGA is used to realize UART communication. UART communication has only two wires, one is to send data tx, and the other is to receive data rx. PC and PFGA realize data communication through two wires.


Complete the transceiver design of the FPGA part to realize the serial communication.

RS232
1. RS232 is a kind of UART, there is no clock line, only two data lines, namely rx and tx, both of which are 1bit wide. Where rx is the line for receiving data and tx is the line for sending data.
2. The rx bit width is 1 bit. When the PC sends 8-bit data to the FPGA through the serial port debugging assistant, the FPGA receives the data one by one through the rx serial port line, from the lowest bit to the highest bit, and finally the bits are spliced into 8 bits in the FPGA. bit data.
3. The tx bit width is 1 bit. When the FPGA sends 8-bit data to the PC through the serial port, the FPGA transmits the 8-bit data to the PC bit by bit through the tx line, and sends them sequentially from the lowest bit to the highest bit, and finally the host computer passes the serial port. According to the RS232 protocol, the assistant splices the data bit by bit into 8bit data.
4. The sending and receiving of serial port data is based on the frame structure, that is, sending and receiving data frame by frame. In addition to the 8-bit valid data in the middle of each frame, there must be a start bit at the beginning of each frame, which is fixed to 0; at the end of each frame, there must also be a stop bit, which is fixed to 1. That is, the most basic frame structure (excluding checksum etc.) has 10 bits. In the case of not sending or receiving data, rx and tx are in an idle state. At this time, both rx and tx lines remain high. If there is a data frame transmission, there will be a start bit first, and then 8bit data Bit, followed by a 1-bit stop bit, then rx and tx continue to enter the idle state, and then wait for the next data transmission. Figure 28-7 shows the most basic RS232 frame structure.

1bit represents one bit of 1or0 in binary. A binary symbol (1or0) can carry 1bit of information (1or0). An octal code unit can carry 3 bits of information.
The baud rate of the s232 serial port is also the symbol transmission rate. 9600Baud/s. means that 9600 symbols are transmitted per second. bit (bps) bit rate = (Bps) baud number The binary corresponding to a single modulation state, the above picture is 9600/1. Ps: The serial port sends or receives a data time in baud. The serial port baud rate is 9600Bps, so one baud time is 1/9600s. If the system clock is 50Mhz, then at 9600 baud, one baud is equivalent to 1/9600s and then divided by 20ns=5208 system cycles. That is, every time the serial port transmits a bit of information, the system clock must maintain 5208 cycles.
FPGA Accept Module

module uart_rx
#(
parameter UART_BAUD = 'd9600, //baud rate
parameter CLK_FRE = 'd50_000_000 //system clock
)
(
input wire sys_clk,
input wire sys_rst_n,
input wire rx ,//serial data sent by the assistant
\t
\t
\t
output reg [7:0] po_data ,//Outgoing parallel data
output reg po_flag //flag signal for data transmission
);

parameter BAUD_MAX = CLK_FRE/UART_BAUD;//Transmission time required for each bit data transmission

reg rx_reg1;//Three beats to reduce the influence of metastable state
reg rx_reg2;//Because the signal reaches the register, the setup time and hold time do not meet the requirements
reg rx_reg3;//so a metastable state is generated
reg start_nedge;
reg work_on;
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt;
reg [7:0] rx_data;
reg rx_flag;

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;
//When the falling edge of rx_reg is detected, a high level of a clock is generated. When detecting the falling edge, the signal can be delayed
//A clock, and then extract a flag signal as follows.
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if((rx_reg2 == 1'b0) & amp; & amp; (rx_reg3 == 1'b1) & amp; & amp; (work_on == 1'b0))
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;
// An enable signal can be determined by the extracted flag signal. Use the enable signal to determine the sampling range of the data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_on <= 1'b0;
else if(start_nedge == 1'b1)
work_on <= 1'b1;
else if(bit_flag == 1'b1 & amp; & amp; bit_cnt == 4'd8)
work_on <= 1'b0;
else
work_on <= work_on;
//The baud rate counter counts, the time required for one bit information. 50_000_000/9600=5208
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'd0;
else if(baud_cnt == BAUD_MAX - 1 || work_on == 1'b0)
baud_cnt <= 13'd0;
else if(work_on == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//When the counter counts to the middle, the sampled data is the most stable
//At this time, a flag message is pulled high to indicate that the data can be taken away
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_MAX/2 - 1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//The counter of the number of valid data, 8 valid data (excluding start bit 0 and stop bit 1)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'd0;
else if(bit_cnt == 4'd8 & amp; & amp; bit_flag == 1'b1)
bit_cnt <= 4'd0;
else if(bit_flag == 1'b1)
bit_cnt <= bit_cnt + 1'b1;
//Input data to shift
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_data <= 8'h00;
else if(bit_cnt >= 4'd1 & amp; & amp; bit_cnt <= 4'd8 & amp; & amp; bit_flag == 1'b1)
rx_data <= {<!-- -->rx_reg3,rx_data[7:1]};
//When the input data is completed, pull up the level of a clock
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if(bit_cnt == 4'd8 & amp; & amp; bit_flag == 1'b1)
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
//Complete the output of 8-bit valid data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_data <= 8'h00;
else if(rx_flag == 1'b1)
po_data <= rx_data;
//Output data valid flag bit
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_flag <= 1'b0;
else
po_flag <= rx_flag;




endmodule



FPGA sending module

module uart_tx
#(
parameter UART_BPS = 'd9600,//serial port baud rate
parameter CLK_FRE = 'd50_000_000//clock frequency
)
(
input wire sys_clk,
input wire sys_rst_n,
input wire [7:0] pi_data ,//8bit data input by the module
input wire pi_flag ,//Valid flag signal for parallel data
\t
\t
output reg tx //Serial to parallel 1bit data
);


parameter BAUD_CNT = CLK_FRE/UART_BPS;//

reg work_on;
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt;



always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_on <= 1'b0;
else if(pi_flag == 1'b1)
work_on <= 1'b1;
else if(bit_flag == 1'b1 & amp; & amp; bit_cnt == 4'd9)
work_on <= 1'b0;
else
work_on <= work_on;

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 0;
else if(baud_cnt == BAUD_CNT - 1 || work_on == 1'b0)
baud_cnt <= 0;
else if(work_on == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
\t\t
\t\t
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == 0 & amp; & amp; work_on == 1'b1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 0;
else if(bit_cnt == 4'd9 & amp; & amp; bit_flag == 1'b1)
bit_cnt <= 4'd0;
else if(bit_flag == 1'b1 & amp; & amp; work_on == 1'b1)
bit_cnt <= bit_cnt + 1'b1;

always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
tx <= 1'b1;
else if(bit_flag == 1'b1)
begin
case(bit_cnt)
0: tx <= 1'b0;
1: tx <= pi_data[0];
2: tx <= pi_data[1];
3: tx <= pi_data[2];
4: tx <= pi_data[3];
5: tx <= pi_data[4];
6: tx <= pi_data[5];
7: tx <= pi_data[6];
8: tx <= pi_data[7];
9: tx <= 1'b1;
default: tx <= 1'b1;
end case
end



endmodule

Top level module

module rs232
(
input wire sys_clk,
input wire sys_rst_n,
input wire rx ,
\t
output wire tx
);

wire [7:0] po_data;
wire po_flag;





uart_rx
#(
.UART_BAUD(9600), //baud rate
.CLK_FRE(50_000_000) //system clock
)
uart_rx_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.rx (rx),//serial data sent by the assistant

.po_data (po_data), //Outgoing parallel data
.po_flag (po_flag) //Flag signal for data transmission
);


uart_tx
#(
.UART_BPS(9600),
.CLK_FRE(50_000_000)
)
uart_tx_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.pi_data (po_data),
.pi_flag (po_flag),


.tx (tx)
);




endmodule

Simulation results

Serial port assistant debugging results