由于之前学习FPGA的过程中,没有做一个良好的记录,以及已学知识的扩展,所以从今天开始每一个实验例程和扩展应用,都要做文档记录。本实验,是基于正点原子达芬奇xc7a35tfgg484-2开发板。开发板时钟为50Mhz,采用RS232的通信协议。
1.UART串口通信简介
串口数据的发送与接收都是基于帧结构的,即一帧一帧的发送与接收数据。每一帧除了中间包含8bit有效数据外,还在每一帧的开头都必须要有一个起始位,且固定为0;在每一帧的结束时,也必须要有一个停止位,且固定为1,即最基本的帧结构(不包括校验等)有10bit。在不发送或不接收数据的情况下,rx和tx处于空闲状态,此时rx和tx都保持高电平。
后续则在上述实验原理的基础下,完成以下两个实验。
2.实验一:回环测试
输入回环测试,即输入即输出。当上位机通过串口调试工具发送数据给FPGA,FPGA再通过串口接收数据并将接收到的数据返送给上位机,完成串口数据回环。
2.1.串口接收模块
串口发送模块将输入的8位并行数据进行串行输出。串口发送模块uart_rx代码如下:
module uart_rx
#(
parameter UART_BPS = 'd19200,
parameter CLK_FREQ = 'd50_000_000
)
(
input wire sys_clk,
input wire sys_rst_n,
input wire rx,
output reg [7:0] Po_data,
output reg Po_flag
);
parameter BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
reg rx_reg1;
reg rx_reg2;
reg rx_reg3;
reg start_nedge;
reg work_en;
reg [15: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)begin
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if(rx_reg2 == 1'b0 && rx_reg3 == 1'b1)
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
work_en <= 1'b0;
else if(start_nedge == 1'b1)
work_en <= 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
baud_cnt <= 16'd0;
else if((baud_cnt == BAUD_CNT_MAX - 1'b1) || (work_en == 1'b0))
baud_cnt <= 16'd0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_CNT_MAX/2 - 1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
bit_cnt <= 4'd0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd8))
bit_cnt <= 4'd0;
else if(bit_flag == 1'b1)
bit_cnt <= bit_cnt + 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
rx_data <= 8'd0;
else if((bit_cnt >= 4'd1) && (bit_cnt <= 4'd8) && (bit_flag == 1'b1))
rx_data <= {rx_reg3,rx_data[7:1]};
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
Po_data <= 8'b0;
else if(rx_flag == 1'b1)
Po_data <= rx_data;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
Po_flag <= 1'b0;
else
Po_flag <= rx_flag;
end
endmodule
验证仿真tb_ uart_rx.v如下所示
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/06/12 19:20:12
// Design Name:
// Module Name: tb_uart_rx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_uart_rx();
reg sys_clk ;
reg sys_rst_n ;
reg rx ;
wire [7:0] Po_data ;
wire Po_flag ;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
rx <= 1'b1;
#20
sys_rst_n <= 1'b1;
end
initial begin
#200
rx_bit(8'd0);
rx_bit(8'd1);
rx_bit(8'd2);
rx_bit(8'd3);
rx_bit(8'd4);
rx_bit(8'd5);
rx_bit(8'd6);
rx_bit(8'd7);
end
always #10 sys_clk = ~sys_clk;
task rx_bit(input [7:0] data);
integer i;//定义一个常亮
for(i=0;i<10;i=i+1)begin
case(i)
0 : rx <= 1'b0;
1 : rx <= data[0];
2 : rx <= data[1];
3 : rx <= data[2];
4 : rx <= data[3];
5 : rx <= data[4];
6 : rx <= data[5];
7 : rx <= data[6];
8 : rx <= data[7];
9 : rx <= 1'b1;
endcase
#(5208 * 20); // 每发送1位数据延时5208个时钟周期
end
endtask
uart_rx uart_rx_inst(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.rx (rx ),
.Po_data (Po_data ),
.Po_flag (Po_flag )
);
endmodule
2.2.串口接收模块
串口接收模块将串行的8位数据转化为并行的8位数据进行输出。串口接收模块uart_rx代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/06/12 16:13:31
// Design Name:
// Module Name: uart_tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_tx
#(
parameter UART_BPS = 'd9600,
parameter CLK_FREQ = 'd50_000_000
)
(
input wire sys_clk ,
input wire sys_rst_n,
input wire [7:0] Po_data ,
input wire Po_flag ,
output reg tx
);
parameter BAUD_CNT_MAX = CLK_FREQ / UART_BPS;
reg [15:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt;
reg work_en;
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
baud_cnt <= 16'd0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 16'd0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
work_en <= 1'b0;
else if(Po_flag == 1'b1)
work_en <= 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == 16'd1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
bit_cnt <= 4'd0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
bit_cnt <= 4'd0;
else if((bit_flag == 1'b1) && (work_en == 1'b1))
bit_cnt <= bit_cnt + 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)begin
if(sys_rst_n == 1'b0)
tx <= 1'd1;
else if(bit_flag == 1'b1)
case(bit_cnt)
4'd0 : tx <= 1'b0;
4'd1 : tx <= Po_data[0];
4'd2 : tx <= Po_data[1];
4'd3 : tx <= Po_data[2];
4'd4 : tx <= Po_data[3];
4'd5 : tx <= Po_data[4];
4'd6 : tx <= Po_data[5];
4'd7 : tx <= Po_data[6];
4'd8 : tx <= Po_data[7];
4'd9 : tx <= 1'b1;
default : tx <= 1'b1;
endcase
end
endmodule
2.3.顶层模块
顶层模块即将uart_rx.v和uart_tx.v两个连接起来即可。
module rs232
(
input wire sys_clk,
input wire sys_rst_n,
input wire rx,
output wire tx
);
wire [7:0] Po_data;
wire Po_flag;
parameter UART_BPS = 16'd19200 ;
parameter CLK_FREQ = 26'd50_000_000 ;
uart_rx
#(
.UART_BPS (UART_BPS ),
.CLK_FREQ (CLK_FREQ )
)
uart_rx_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.rx (rx ),
.Po_data (Po_data ),
.Po_flag (Po_flag )
);
uart_tx
#(
.UART_BPS (UART_BPS ),
.CLK_FREQ (CLK_FREQ )
)
uart_tx_inst
(
.sys_clk (sys_clk) ,
.sys_rst_n (sys_rst_n) ,
.Po_data (Po_data) ,
.Po_flag (Po_flag) ,
.tx (tx)
);
endmodule
3.实验二:检测字符
当上位机通过串口调试工具发送数据给FPGA,FPGA进行检测识别,发现传送的数据为Hello Word时,串口返回ni hao,并点亮led灯;否则,串口返回no,Led熄灭;
2.1.串口发送和接收模块
串口的发送和接收模块都和之前的模块保持一致,直接调用之前的模块即可。
2.3.控制模块
控制模块uart_ctrl用于控制串口通信发送使能和发送数据信号,当检测到上位机串口调试工具助手发送数据给FPGA时,FPGA接收模块接收数据后与Hello Word进行对标,发现一致,将ni hao发送到上位机,并点亮led灯;当接收到的数据不一致时,测返回no,并熄灭led灯。控制模块uart_ctrl代码如下:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)