SparkRoad Review (7) - FPGA Serial Port Test
[Copy link]
Anlu's development board is equipped with a USB2UART module, which is connected to the USB-to-serial port through the microcontroller on the board. It is not possible to open the built-in routine 6_uart_loopback and run it by itself. Because the default pin is not connected to the UART2USB line, the pin must be set to the pin specified by USB2UART.
1. Open the project uart.al, file mini_EG4S20BG256.adc
2. Modify the specified resources of the file. uart_tx E16, uart_rx F16
set_pin_assignment {ext_clk_25m} { LOCATION = K14; }
set_pin_assignment {ext_rst_n} { LOCATION = L12; } ##KEY_C
##set_pin_assignment {uart_tx} { LOCATION = C11; }
##set_pin_assignment {uart_rx} { LOCATION = B15; }
set_pin_assignment {uart_tx} { LOCATION = E16; }
set_pin_assignment {uart_rx} { LOCATION = F16; }
3. After synthesizing the project, burn it into the board and you can experiment.
This is an explanation of the project files in the experiment. The speed_setting.v file is used to modify the baud rate. There are two files corresponding to the two settings of sending and receiving.
module speed_setting
#(
parameter BPS_SET = 96, //波特率
parameter CLK_PERIORD = 40 //时钟周期40ns(25MHz)
)
(
input clk, //25MHz主时钟
input rst_n, //低电平复位信号
input bps_start, //接收到数据后,波特率时钟启动信号置位
output clk_bps //clk_bps的高电平为接收或者发送数据位的中间采样点
);
`define BPS_PARA (10_000_000/CLK_PERIORD/BPS_SET) //10_000_000/`CLK_PERIORD/96;
`define BPS_PARA_2 (`BPS_PARA/2) //BPS_PARA/2;
reg [12:0] cnt; //分频计数
reg clk_bps_r; //波特率时钟寄存器
reg [2:0] uart_ctrl; //uart波特率选择寄存器
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 13'd0;
else if((cnt == `BPS_PARA) || !bps_start)
cnt <= 13'd0; //波特率计数清零
else
cnt <= cnt + 1'b1; //波特率时钟计数启动
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_bps_r <= 1'b0;
else if(cnt == `BPS_PARA_2)
clk_bps_r <= 1'b1; //clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点
else
clk_bps_r <= 1'b0;
end
assign clk_bps = clk_bps_r;
endmodule
Just modify parameter BPS_SET = 96, //96 in the baud rate, the actual parameter line is: `define BPS_PARA (10_000_000/CLK_PERIORD/BPS_SET) //10_000_000/`CLK_PERIORD/96;
Don't touch anything else. In fact, the main thing is a "divider"
Next, let's analyze the serial port sending file, my_uart_tx.v
module my_uart_tx
(
input clk,
input rst_n,
input [7:0] rx_data,
input rx_int,
output uart_tx,
input clk_bps,
output bps_start
);
//---------------------------------------------------------
reg rx_int0,rx_int1,rx_int2; //rx_int信号寄存器
wire neg_rx_int; //rx_int下降沿标志位
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rx_int0 <= 1'b0;
rx_int1 <= 1'b0;
rx_int2 <= 1'b0;
end
else
begin
rx_int0 <= rx_int;
rx_int1 <= rx_int0;
rx_int2 <= rx_int1;
end
end
assign neg_rx_int = ~rx_int1 & rx_int2; //捕捉到下降沿后,neg_rx_int拉高保持一个主时钟周期
//---------------------------------------------------------
reg [7:0] tx_data; //待发送数据的寄存器
reg bps_start_r;
reg tx_en; //发送数据使能信号,高有效
reg [3:0] num;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
bps_start_r <= 1'bz;
tx_en <= 1'b0;
tx_data <= 8'd0;
end
else if(neg_rx_int)
begin //接收数据完毕,准备把接收到的数据发回去
bps_start_r <= 1'b1;
tx_data <= rx_data; //把接收到的数据存入发送数据寄存器
tx_en <= 1'b1; //进入发送数据状态中
end
else if(num == 4'd10)
begin //数据发送完成,复位
bps_start_r <= 1'b0;
tx_en <= 1'b0;
end
end
assign bps_start = bps_start_r;
//---------------------------------------------------------
reg uart_tx_r;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
num <= 4'd0;
uart_tx_r <= 1'b1;
end
else if(tx_en)
begin
if(clk_bps)
begin
num <= num+1'b1;
case (num)
4'd0: uart_tx_r <= 1'b0; //发送起始位
4'd1: uart_tx_r <= tx_data[0]; //发送bit0
4'd2: uart_tx_r <= tx_data[1]; //发送bit1
4'd3: uart_tx_r <= tx_data[2]; //发送bit2
4'd4: uart_tx_r <= tx_data[3]; //发送bit3
4'd5: uart_tx_r <= tx_data[4]; //发送bit4
4'd6: uart_tx_r <= tx_data[5]; //发送bit5
4'd7: uart_tx_r <= tx_data[6]; //发送bit6
4'd8: uart_tx_r <= tx_data[7]; //发送bit7
4'd9: uart_tx_r <= 1'b1; //发送结束位
default: uart_tx_r <= 1'b1;
endcase
end
else if(num == 4'd10)
num <= 4'd0;
end
end
assign uart_tx = uart_tx_r;
endmodule
This file is a bit confusing, mainly because there is an extra step in it, which is the process of transferring the received data to tx_data. This process should not be written into this module. My suggestion is to write it into the state machine in the top-level file.
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
bps_start_r <= 1'bz;
tx_en <= 1'b0;
tx_data <= 8'd0;
end
else if(neg_rx_int)
begin //接收数据完毕,准备把接收到的数据发回去
bps_start_r <= 1'b1;
tx_data <= rx_data; //把接收到的数据存入发送数据寄存器
tx_en <= 1'b1; //进入发送数据状态中
end
else if(num == 4'd10)
begin //数据发送完成,复位
bps_start_r <= 1'b0;
tx_en <= 1'b0;
end
end
Next comes the main part of the output.
//---------------------------------------------------------
reg uart_tx_r;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
num <= 4'd0;
uart_tx_r <= 1'b1;
end
else if(tx_en)
begin
if(clk_bps)
begin
num <= num+1'b1;
case (num)
4'd0: uart_tx_r <= 1'b0; //发送起始位
4'd1: uart_tx_r <= tx_data[0]; //发送bit0
4'd2: uart_tx_r <= tx_data[1]; //发送bit1
4'd3: uart_tx_r <= tx_data[2]; //发送bit2
4'd4: uart_tx_r <= tx_data[3]; //发送bit3
4'd5: uart_tx_r <= tx_data[4]; //发送bit4
4'd6: uart_tx_r <= tx_data[5]; //发送bit5
4'd7: uart_tx_r <= tx_data[6]; //发送bit6
4'd8: uart_tx_r <= tx_data[7]; //发送bit7
4'd9: uart_tx_r <= 1'b1; //发送结束位
default: uart_tx_r <= 1'b1;
endcase
end
else if(num == 4'd10)
num <= 4'd0;
end
end
assign uart_tx = uart_tx_r;
This program uses a counter instead of a standard state machine. This depends on personal preference. The advantage of a counter is that it takes up less resources, but it is not very flexible and has poor configurability. The disadvantage of a state machine is that it has a complex structure. This is up to your preference. This test ends here. I hope you can correct me.
|