Serial communication routine explanation
Based on many years of work experience, the FPGA design process has been summarized in a total of the above 12 steps, some of which can be omitted depending on the difficulty of the project. For example, for very simple projects, we can omit the steps in the dotted box, but our introductory course, no matter how simple it is, will be explained according to these 12 steps.
1. Interpretation of requirements
1.1 Requirements
Control 8 LED lights through the serial port with a baud rate of 9600. For example, if 8'h55 is sent through the serial port, 4 LED lights will be on and 4 LED lights will be off on the development board. At the same time, the serial port assistant will receive 8'h55
1.2 Knowledge background
Serial port is the abbreviation of "serial interface", that is, an interface that uses serial communication. Serial communication divides data bytes into bits and transmits them one by one on a data line. It is characterized by simple communication lines but slow transmission speed. Therefore, serial ports are widely used in embedded, industrial control and other fields where data transmission speed is not required.
Serial communication is divided into two methods: synchronous serial communication and asynchronous serial communication. Synchronous serial communication requires both communicating parties to transmit data synchronously under the control of the same clock; asynchronous serial communication means that both communicating parties use their own clocks to control the sending and receiving process of data.
UART is a universal asynchronous receiver-transmitter that uses asynchronous serial communication. When sending data, it converts parallel data into serial data for transmission, and when receiving data, it converts the received serial data into serial data. Data is converted into parallel data.
UART serial port communication requires two signal lines, one for serial port transmission and the other for serial port reception. A frame of data during UART transmission or reception consists of 4 parts, start bit, data bit, parity bit and stop bit. The specific timing is shown in Figure 1. Among them, the start bit marks the beginning of a frame of data, the stop bit marks the end of a frame of data, and the data bit is the valid data in a frame of data. The parity bits are divided into odd parity and even parity, which are used to check whether there are errors in the data during transmission. In odd parity, the sender should make the sum of the number of 1s in the data bits and the number of 1s in the check bits an odd number; when the receiver receives the data, it should check the number of 1s. If it is not an odd number, It means that there is an error in the data transmission process. Similarly, even parity checks whether the number of 1's is even.
The data format and transmission rate during UART communication can be set. For correct communication, both the sending and receiving parties should agree on and follow the same settings. The data bits can be selected as 5, 6, 7 or 8 bits, among which 8 data bits are the most commonly used. In practical applications, 8 data bits are generally selected; the parity bit can be odd parity, even parity or none. Check bit; stop bit can be selected from 1 bit (default), 1.5 or 2 bits. The rate of serial communication is represented by the baud rate, which represents the number of binary data transmitted per second, and the unit is bps (bits/second). Commonly used baud rates are 9600, 19200, 38400, 57600, and 115200.
After setting the data format and transmission rate, the UART is responsible for completing the serial-to-parallel conversion of the data, while the signal transmission is implemented by an external drive circuit. The transmission process of electrical signals has different level standards and interface specifications. The interface standards for asynchronous serial communication include RS232, RS422, RS485, etc., which define different electrical characteristics of the interface. For example, RS-232 is a single-ended input and output. RS-422/485 is differential input and output, etc.
The RS232 interface standard appeared earlier and can realize full-duplex working mode, that is, data sending and receiving can be carried out at the same time. When the transmission distance is short (no more than 15m), RS232 is the most commonly used interface standard for serial communication. This chapter mainly introduces UART serial communication for the RS-232 standard.
The most common interface type of the RS-232 standard serial port is DB9, as shown in Figure 2. Industrial computers used in the field of industrial control are generally equipped with multiple serial ports, and many old-fashioned desktop computers are also equipped with serial ports. However, laptops and newer desktop computers do not have serial ports. They generally use USB-to-serial cables (Figure 3) to achieve serial communication with external devices.
The DB9 interface definition and the function description of each pin are shown in Figure 16.1.4. We generally only use pins 2 (RXD), 3 (TXD), and 5 (GND). The other pins are generally used in normal serial port mode. Do not use.
1.3 Hardware design
1.4 Interface description
Signal name | direction | FPGA pin number | illustrate |
---|---|---|---|
CLK50M | enter | B10 | Clock signal, 50MHZ |
FPGA_RX | enter | H14 | Serial signal input |
FPGA_TX | output | F14 | Serial signal output |
Summary: Through the above description, the requirement can be interpreted as: the serial port assistant sends a number at a baud rate of 9600, and sends it to the FPGA through the serial port sending port. The FPGA parses the number according to the serial port timing, and then assigns this number to 8 LED will do. At the same time, the FPGA sends this number through the serial port sending port, so that the sent data can be displayed on the serial port assistant.
2. Draw theoretical waveform diagram
3. New TD project
In order to make the project look tidy and facilitate project transplantation. We create 4 new folders, namely Project, Source, Sim, and Doc.
Project — the project folder, which contains the TD project
Source — the source code folder, which contains the project source code (.v file or .vhd file)
Sim — the simulation folder, which contains the simulation-related files
Doc — stores relevant information , such as data manuals, requirements documents, etc.
4. Write code
4.1 Serial port receiving module code
///
//QQ:3181961725
//TEL/WX:13540738439
//作者:Mr Wang
//模块介绍:实现异步串口接收功能
///
module async_uart_rev(
input rst_n ,//复位信号,低电平有效
input clk ,//时钟信号,50MHZ
input rxd ,//串行接收数据
output reg [7:0] rev_data,//并行数据
output reg rev_dvld //并行数据有效标志
);
parameter baud_num=5207;//1/9600*1000000000/20
parameter IDLE =4'd0;
parameter START_ST =4'd1;
parameter STOP_ST =4'd2;
reg [12:0] baud_cnt;
reg baud_cnt_en;
wire sample_en;
reg [3:0] sample_num;
reg rxd_ff1;
reg rxd_ff2;
reg [3:0] curr_st;
//打两拍操作
always@(posedge clk)rxd_ff2<=rxd_ff1;
always@(posedge clk)rxd_ff1<=rxd;
assign sample_en=(baud_cnt==baud_num[12:1])?1'b1:1'b0;
//状态机跳转程序
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
curr_st<=IDLE;
else case(curr_st)
IDLE:begin
if(rxd_ff2==0)
curr_st<=START_ST;
else;
end
START_ST:begin
if(sample_num==8&&sample_en)
curr_st<=STOP_ST;
else;
end
STOP_ST:begin
if(rxd_ff2==1&&sample_en)
curr_st<=IDLE;
else;
end
default:;
endcase
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
baud_cnt<=0;
else if(curr_st==START_ST||curr_st==STOP_ST)begin
if(baud_cnt==baud_num)
baud_cnt<=0;
else
baud_cnt<=baud_cnt+1;
end else
baud_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
sample_num<=0;
else if(sample_en&&sample_num==9)
sample_num<=0;
else if(sample_en)
sample_num<=sample_num+1;
else;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
rev_data<=0;
else if(sample_en)
case(sample_num)
1:rev_data[0]<=rxd_ff2;
2:rev_data[1]<=rxd_ff2;
3:rev_data[2]<=rxd_ff2;
4:rev_data[3]<=rxd_ff2;
5:rev_data[4]<=rxd_ff2;
6:rev_data[5]<=rxd_ff2;
7:rev_data[6]<=rxd_ff2;
8:rev_data[7]<=rxd_ff2;
default:;
endcase
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
rev_dvld<=0;
else if(sample_num==9&&sample_en)
rev_dvld<=1;
else
rev_dvld<=0;
end
endmodule
4.2 Serial port sending module code
///
//QQ:3181961725
//TEL/WX:13540738439
//作者:Mr Wang
//模块介绍:实现异步串口发送功能
///
module async_uart_tran(
input rst_n ,//复位信号,低电平有效
input clk ,//时钟,50MHZ
input [7:0] tran_data ,//输入的并行数据
input tran_dvld ,//输入的并行数据有效标志
output reg txd //串行输出数据
);
parameter baud_num=5207;//1/9600*1000000000/20
parameter IDLE =4'd0;
parameter DATA_ST =4'd1;
parameter START_ST =4'd2;
parameter STOP_ST =4'd3;
reg [12:0] baud_cnt;
reg baud_cnt_en;
wire sample_en;
reg [3:0] sample_num;
reg [3:0] curr_st;
assign sample_en=(baud_cnt==baud_num)?1'b1:1'b0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
curr_st<=IDLE;
else case(curr_st)
IDLE:begin
if(tran_dvld==1)
curr_st<=START_ST;
else;
end
START_ST:begin
if(sample_en==1)
curr_st<=DATA_ST;
end
DATA_ST:begin
if(sample_en&&sample_num==8)
curr_st<=STOP_ST;
else;
end
STOP_ST:begin
if(sample_en==1)
curr_st<=IDLE;
else;
end
default:;
endcase
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
baud_cnt<=0;
else if(curr_st==START_ST||curr_st==DATA_ST||curr_st==STOP_ST)begin
if(baud_cnt==baud_num)
baud_cnt<=0;
else
baud_cnt<=baud_cnt+1;
end else
baud_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
sample_num<=0;
else if(curr_st==IDLE)
sample_num<=0;
else if(sample_en)
sample_num<=sample_num+1;
else;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
txd<=1;
else if(sample_en)
case(sample_num)
0:txd<=1'b0;
1:txd<=tran_data[0];
2:txd<=tran_data[1];
3:txd<=tran_data[2];
4:txd<=tran_data[3];
5:txd<=tran_data[4];
6:txd<=tran_data[5];
7:txd<=tran_data[6];
8:txd<=tran_data[7];
9:txd<=1'b1;
default:txd<=1;
endcase
end
endmodule
4.3 Top-level module code
///
//QQ:3181961725
//TEL/WX:13540738439
//作者:Mr Wang
//模块介绍:顶层模块,例化接收和发送模块
///
module async_uart_top(
input clk ,//时钟,50MHZ
input rst_n ,//复位信号,低电平有效
input rxd ,//串行接收数据
output txd ,//串行发送数据
output [7:0] led
);
wire [7:0] rev_data;
wire rev_dvld;
assign led=rev_data;
async_uart_rev Uasync_uart_rev(
.rst_n (rst_n),
.clk (clk),
.rxd (rxd),
.rev_data (rev_data),
.rev_dvld (rev_dvld)
);
async_uart_tran async_uart_tran(
.rst_n (rst_n),
.clk (clk),
.tran_data (rev_data),
.tran_dvld (rev_dvld),
.txd (txd)
);
endmodule
5. Write simulation test stimulus file
Simulation test stimulus file (TB file)
`timescale 1ns/1ns
module async_uart_top_tb;
reg clk ;
reg rst_n ;
wire rxd ;
wire tran_dvld;
reg [17:0] cnt=0;
initial
begin
clk = 0;
rst_n=0;
#1000
rst_n=1;
end
always #10 clk=~clk;
always@(posedge clk)cnt<=cnt+1;
assign tran_dvld=(cnt==100)?1'b1:1'b0;
async_uart_tran Uasync_uart_tran(
.rst_n (rst_n),
.clk (clk),
.tran_data (8'h55),
.tran_dvld (tran_dvld),
.txd (rxd)
);
async_uart_top async_uart_top(
.clk (clk),
.rst_n (rst_n),
.rxd (rxd),
.txd (),
.led ()
);
endmodule
6.Modelsim simulation
There are generally two methods for Modelsim simulation:
-
Graphical interface simulation means that all operations are completed on the Modelsim software interface. The advantage of this method is that it is easy to learn and suitable for simple projects. The disadvantage is that the operation steps are cumbersome.
-
Batch simulation , this method requires writing corresponding script files before simulation. The advantage of this method is that the simulation can be completed with one click, saving time and effort. The disadvantage is that script files need to be written in the early stage. The first two lectures use graphical interface simulation; in order to be closer to engineering reality, starting from the third lecture, we use batch processing simulation. For specific operation steps, please refer to our video tutorial.
The simulated waveform is shown below:
7. Compare waveforms
Compare the theoretical waveform diagram drawn in the second step with the waveform diagram simulated by Modelsim in the sixth step. The results are consistent, indicating that our logic design is correct. If the comparison results are found to be inconsistent, you need to find the reason for the inconsistency, and ultimately ensure that the comparison results are consistent. By comparison, the theoretical waveform is consistent with the simulated waveform, indicating that the function meets the design requirements.
8 Add .v file
9 Bind the pins and save the constraint file (.adc)
10 Compile and synthesize the BIT file
11. Download BIT file
After the download is successful, you can observe the experimental phenomena on the development board. If the experimental phenomena match the design requirements, it means that there is no problem with our design, and we can proceed to the next step of solidifying the configuration file.
12 solidification configuration file
FPGA has a characteristic that the configuration information will be lost after power failure, so we need to store the configuration information in the configuration chip (FLASH). After the development board is powered on, the FPGA will read the configuration information in the configuration chip, so the development The board can still work normally after powering off and on again.
After the curing is successful, power off the development board and then power it on again. It can be observed that the development board can still perform the functions just now.