概述
Uart串口收发回环验证
- 接受模块
- 发送模块
- 波特率设置模块
- 顶层模块
- TB
- Modelsim仿真结果
- 板级验证
- 总结
本次所做的项目比较复杂(对我本人来讲),设计一个Uart IP核,在其基础,封装axi接口,使其成为面向AXI口的IP,再例化个microblaze作为主机,使microblaze与Uart之间通过AXI总线进行通信。具体模块图如下,包含主机microblaze,主接口模块,从接口模块,从机Uart。
本文首先介绍Uart基本模块。该顶层模块包含接受模块、发送模块、发送波特率设置模块、接受波特率设置模块。为了方便验证,我们将接受模块与发送模块连接,采用回环的形式。
接受模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2019/05/24 16:58:41
// Design Name:
// Module Name: uart_rx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_rx(
clk,
rst_n,
Rs232_rx,
bps_clk,
rx_data,
rx_int,
bps_start
);
input clk;
input rst_n;
input bps_clk;
input Rs232_rx;
output [7:0] rx_data;
output reg rx_int;
output reg bps_start;
reg Rs232_rx0,Rs232_rx1,Rs232_rx2,Rs232_rx3;
wire neg_edge;
reg [3:0] num;
reg [7:0] rx_data_t1;
reg [7:0] rx_data_t2;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
Rs232_rx0 <= 1'b1;
Rs232_rx1 <= 1'b1;
Rs232_rx2 <= 1'b1;
Rs232_rx3 <= 1'b1;
end
else begin
Rs232_rx0 <= Rs232_rx;
Rs232_rx1 <= Rs232_rx0;
Rs232_rx2 <= Rs232_rx1;
Rs232_rx3 <= Rs232_rx2;
end
assign neg_edge = Rs232_rx3 & Rs232_rx2 & ~Rs232_rx1 & ~Rs232_rx0;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
bps_start <= 1'b0;
rx_int <= 1'b0;
end
else if (neg_edge) begin
bps_start <= 1'b1;
rx_int <= 1'b1;
end
else if (num == 4'd10) begin
bps_start <= 1'b0;
rx_int <= 1'b0;
end
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
rx_data_t1 <= 8'd0;
rx_data_t2 <=8'd0;
num <= 4'd0;
end
else if(rx_int) begin
if (bps_clk) begin
num <= num+1'b1;
case(num)
4'd1: rx_data_t1[0] <= Rs232_rx;
4'd2: rx_data_t1[1] <= Rs232_rx;
4'd3: rx_data_t1[2] <= Rs232_rx;
4'd4: rx_data_t1[3] <= Rs232_rx;
4'd5: rx_data_t1[4] <= Rs232_rx;
4'd6: rx_data_t1[5] <= Rs232_rx;
4'd7: rx_data_t1[6] <= Rs232_rx;
4'd8: rx_data_t1[7] <= Rs232_rx;
default:;
endcase
end
end
else if(num >= 4'd9) begin
num <= 4'd0;
rx_data_t2 <= rx_data_t1;
end
assign rx_data = rx_data_t2;
endmodule
发送模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2019/05/24 15:39:09
// 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(
clk,
rst_n,
tx_int,
rx_data,
bps_clk,
Rs232_tx,
bps_start
);
input clk;
input rst_n;
input tx_int;
input [7:0] rx_data;
input bps_clk;
output Rs232_tx;
output bps_start;
reg tx_int0;
reg tx_int1;
reg tx_int2;
wire neg_edge;
(* keep = "true" *) reg en;
reg [3:0] num;
reg bps_start_t;
//reg [7:0] rx_data_t;
reg Rs232_tx_t;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
tx_int0 <= 1'b0;
tx_int1 <= 1'b0;
tx_int2 <= 1'b0;
end
else begin
tx_int0 <= tx_int;
tx_int1 <= tx_int0;
tx_int2 <= tx_int1;
end
assign neg_edge = tx_int2 & ~tx_int1;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
en <= 1'b0;
bps_start_t <= 1'b0;
end
else if (neg_edge) begin
en <= 1'b1;
bps_start_t <= 1'b1;
//rx_data_t <= rx_data;
end
else if (num == 4'd10) begin
en <= 1'b0;
bps_start_t <= 1'b0;
end
assign bps_start = bps_start_t;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
Rs232_tx_t <= 1'b1;
num <= 12'd0;
end
else if (en) begin
if (bps_clk) begin
case (num)
4'd0: Rs232_tx_t <= 1'b0;
4'd1: Rs232_tx_t <= rx_data[0];
4'd2: Rs232_tx_t <= rx_data[1];
4'd3: Rs232_tx_t <= rx_data[2];
4'd4: Rs232_tx_t <= rx_data[3];
4'd5: Rs232_tx_t <= rx_data[4];
4'd6: Rs232_tx_t <= rx_data[5];
4'd7: Rs232_tx_t <= rx_data[6];
4'd8: Rs232_tx_t <= rx_data[7];
4'd9: Rs232_tx_t <= 1'b1;
default: Rs232_tx_t <= 1'b1;
endcase
num <= num +1'b1;
end
end
else if(num == 4'd10) begin
num <= 1'b0;
end
assign Rs232_tx = Rs232_tx_t;
endmodule
波特率设置模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2019/05/24 15:06:47
// Design Name:
// Module Name: speed_set
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module speed_set(
bps_start,
clk,
rst_n,
bps_clk
);
input bps_start;
input clk;
input rst_n;
output reg bps_clk;
(* keep = "true" *) reg [12:0] cnt;
`define BPS_NUM 5207
`define BPS_NUM_2 2306
always@(posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 13'd0;
else if (cnt == `BPS_NUM || !bps_start)
cnt <= 13'd0;
else
cnt <= cnt + 1'b1;
always@(posedge clk or negedge rst_n)
if(!rst_n)
bps_clk <= 1'b0;
else if (cnt == `BPS_NUM_2)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
endmodule
顶层模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2019/05/27 10:00:56
// Design Name:
// Module Name: uart_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_top(
clk_p,
clk_n,
rst_n,
Rx,
Tx
);
input clk_p;
input clk_n;
input rst_n;
input Rx;
output Tx;
wire clk_50m;
wire bps_clk_tx;
wire bps_clk_rx;
wire bps_start_tx;
wire bps_start_rx;
wire [7:0] rx_data;
wire int;
clk_wiz_0 instance_name
(
// Clock out ports
.clk_50m(clk_50m), // output clk_50m
// Status and control signals
.resetn(rst_n), // input resetn
// Clock in ports
.clk_in1_p(clk_p), // input clk_in1_p
.clk_in1_n(clk_n)); // input clk_in1_n
speed_set speed_tx(
.bps_start(bps_start_tx),
.clk(clk_50m),
.rst_n(rst_n),
.bps_clk(bps_clk_tx)
);
uart_tx uart_tx(
.clk(clk_50m),
.rst_n(rst_n),
.tx_int(int),
.rx_data(rx_data),
.bps_clk(bps_clk_tx),
.Rs232_tx(Tx),
.bps_start(bps_start_tx)
);
speed_set speed_rx(
.bps_start(bps_start_rx),
.clk(clk_50m),
.rst_n(rst_n),
.bps_clk(bps_clk_rx)
);
uart_rx uart_rx(
.clk(clk_50m),
.rst_n(rst_n),
.Rs232_rx(Rx),
.bps_clk(bps_clk_rx),
.rx_data(rx_data),
.rx_int(int),
.bps_start(bps_start_rx)
);
endmodule
TB
`timescale 1ns / 1ps
`define clock_period 20
//
// Company:
// Engineer:
//
// Create Date: 2019/05/27 10:38:22
// Design Name:
// Module Name: uart_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module Uart_tb;
reg clk_p;
reg clk_n;
reg rst_n;
reg Rx;
wire Tx;
uart_top uart_top(
.clk_p(clk_p),
.clk_n(clk_n),
.rst_n(rst_n),
.Rx(Rx),
.Tx(Tx)
);
initial clk_p = 0;
always #2.5 begin
clk_p = ~clk_p;
clk_n = ~clk_p;
end
initial begin
Rx = 1'b1;
rst_n = 1'b0;
#(`clock_period*20);
rst_n = 1'b1;
#(`clock_period*52080);
//起始位
Rx = 1'b0;
#(`clock_period*5208);
//数据位
Rx = 1'b1;
#(`clock_period*5208);
Rx = 1'b0;
#(`clock_period*5208);
Rx = 1'b0;
#(`clock_period*5208);
Rx = 1'b0;
#(`clock_period*5208);
Rx = 1'b1;
#(`clock_period*5208);
Rx = 1'b0;
#(`clock_period*5208);
Rx = 1'b0;
#(`clock_period*5208);
Rx = 1'b0;
#(`clock_period*5208);
//停止位
Rx = 1'b1;
#(`clock_period*5208);
Rx = 1'b1;
#(`clock_period*52080);
end
endmodule
Modelsim仿真结果
板级验证
总结
本项目Uart设计没有什么难度,基本原理在看完Uart之后spe之后基本了解,再加上之前有点底子,在代码表写上很快完成。但由于Vivado工具使用不熟练,导致花费大量时间,尤其在debug调试之后生成ILA核,抓取的波形不知道怎么看,自己摸索始终不会,最终还是在 老同志的帮助下知道了怎么回事,一方面感谢,另一发方面感概其其奇妙之后,感觉在数字芯片这么难之下下,我们工程师(妄称)还是要多多交流,这样才能共同进步。终极学习法费曼学习法不是说了吗,学习最快的途径是教会一个外行人,你教别人的同时自己也在快速成长。另外自身而言,实在琢磨不出在,还是问问别人,又是你半天搞不出来,一问就回了,提高效率不是。
扯哪去了,回归正题。在前期写好代码之后,兴致勃勃地仿真还通过了,感觉没啥问题,直接上板子烧入,之后崩了,没有结果。前期以为串口工具有问题,想不到还真有问题,板子上USB口接错了,COM口出错,小白尽是犯这种低级错误啊。改完之后重新烧入,还是不行,心态有点炸。实在没办法请教了大神,让我用debug来找出代码那不对,刚开始我始终不以为意,认为仿真通过我写的代码肯定没问题,肯定是其他硬件问题。再加上我debug不会用,浪费了大量时间。在慢慢琢磨与请教之后,发现了问题(前方高能):
1.我在一个always进程中对一个变量赋值之前,没有对其进行复位(TX模块的bps_start_t),导致仿真出现红线未知态。不过这不是主要问题
2.也是tx模块中我竟然多num信号在两个进程中同时对其赋值,明显不过的代码错误,但是综合尽然通过了,什么鬼
总结:
在那个alway进程中间对所有变量赋值之前,现在Rst中对所有进行复位
不要感觉没有错误仿真通过就感觉代码没问题,万事大吉EDA也不是万能的,错误看完的看看警告。
对变量进行暂存再赋值是将reg型变量变为wire型。如果其他进程用到了就不需要转变,只是偶尔输出时需要转变。
最后
以上就是玩命板栗为你收集整理的Uart串口收发回环验证的全部内容,希望文章能够帮你解决Uart串口收发回环验证所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复