最近学习fpga,我使用verilog,基于小脚丫MAX10编写了一个串口收发模块。在串口助手发什么它会立刻回显什么。
仿真已通过,但是在上板的时候发现有字符缺失的现象,而且波特率越低,现象越严重。
波特率57600,可以接收79%的数据。
波特率115200,接收率89%。
而波特率调到2400时,即使发送单个字符也无法接收。
可以看到波特率的影响很大,所以我查看了源码中跟波特率有关的部分,发现只有将单比特数据持续时间转化为时钟数这一部分是相关的。
parameter BSP_CNT = TIME_1S / B_SPEED ;
reg[19:0] cnt;
wire add_cnt = flag;
wire end_cnt = add_cnt && cnt == BSP_CNT - 1;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt <= 20'd0;
end
else if(add_cnt)begin
if(end_cnt) begin
cnt <= 20'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
else begin
cnt <= cnt;
end
end
因为要用系统时钟计时,而根据公式,波特率越大,每次计时越短。因此我自己觉得可能是计数器的误差,导致不能够准确表示每一比特数据在串口数据序列中的持续时间。等计数到BSP_CNT/2的时候读取或发送某一比特时,实际数据早已发生变化。但是我不确定是不是这个原因。
我的源码在下面,希望大家指教 =(
//顶层模块
module my_uart #(parameter TIME_1S = 12000000 , B_SPEED = 460800)(
input clk ,
input rst_n ,
input dat_in ,
output dout
);
wire [7:0] dat_out ;
wire dout_vld ;
//接收模块
uart_rx#(.TIME_1S(TIME_1S) , .B_SPEED(B_SPEED)) u_uart_rx(
.clk (clk),
.rst_n (rst_n),
.dat_in (dat_in),
.dat_out (dat_out),
.dout_vld (dout_vld)
);
//回发模块
uart_tx#(.TIME_1S(TIME_1S) , .B_SPEED(B_SPEED)) u_uart_tx(
.clk (clk),
.rst_n (rst_n),
.din (dat_out),
.din_vld (dout_vld),
.dout (dout)
);
endmodule
```c
//接收模块
module uart_rx #(parameter TIME_1S = 12000000 , B_SPEED = 115200) (
input clk ,
input rst_n ,
input dat_in ,
output reg [7:0] dat_out ,
output reg dout_vld
);
//打拍,监测下降沿,并减小亚稳态
reg dat_in_2;
reg dat_in_3;
wire nedge;
wire podge;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dat_in_2 <= 1'b0;
dat_in_3 <= 1'b0;
end
else begin
dat_in_2 <= dat_in;
dat_in_3 <= dat_in_2;
end
end
assign nedge = ~dat_in_2 & dat_in_3;
assign podge = dat_in_2 & ~dat_in_3;//下降沿
wire add_bits;//数据比特计数条件
wire end_add_bits;//是否接收了全部数据
reg flag;//通讯标志,下降沿置1,接收完所有数据变成0
reg[3:0] rx_bits;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag <= 1'b0;
end
else begin
if(nedge)begin
flag <= 1'b1;
end
if(end_add_bits) begin
flag <= 1'b0;
end
end
end
parameter BSP_CNT = TIME_1S / B_SPEED ;//一比特数据持续的时钟周期数
reg[19:0] cnt;//计数每个比特的时钟周期数
wire add_cnt = flag;
wire end_cnt = add_cnt && cnt == BSP_CNT - 1;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt <= 20'd0;
end
else if(add_cnt)begin
if(end_cnt) begin
cnt <= 20'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
else begin
cnt <= cnt;
end
end
//rx_bits表示接受的数据的下标,8表示数据位全部接收到
assign add_bits = end_cnt;
assign end_add_bits = add_bits && rx_bits == 8;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
rx_bits <= 4'd0;
end
else if(add_bits) begin
rx_bits <= rx_bits + 1'b1;
if(end_add_bits)begin
rx_bits <= 4'd0;
end
end
else begin
rx_bits <= rx_bits;
end
end
reg [8:0] data;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data <= 9'b000000000;
end
else begin
if(flag && cnt == BSP_CNT/2)begin//在每个比特持续的中间时刻取值保存
data[rx_bits] <= dat_in_3;
end
else begin
data <= data;
end
end
end
//输出与数据有效标志
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
dat_out <= 8'b0;
end
else if(rx_bits == 8)begin
dat_out <= data[8:1];
end
else begin
dat_out <= 8'b0;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
dout_vld <= 1'b0;
end
else if(rx_bits == 8)begin
dout_vld <= 1'b1;
end
else begin
dout_vld <= 1'b0;
end
end
endmodule
//回发模块
module uart_tx #(parameter TIME_1S = 12000000 , B_SPEED = 115200)(
input clk ,
input rst_n ,
input [7:0] din ,//上位机发的串行数据
input din_vld ,
output reg dout
);
//打牌,监测有效标志上升沿
reg din_vld_2;
reg din_vld_3;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
din_vld_2 <= 1'b0;
end
else begin
din_vld_2 <= din_vld;
din_vld_3 <= din_vld_2;
end
end
wire nedge;
wire podge;
assign nedge = ~din_vld_2 && din_vld_3;
assign podge = din_vld_2 && ~din_vld_3;
parameter BSP_CNT = TIME_1S / B_SPEED;
reg flag;
reg [19:0] cnt_bsp;
wire add_cnt_bsp;
wire end_cnt_bsp;
assign add_cnt_bsp = flag;
assign end_cnt_bsp = add_cnt_bsp && cnt_bsp == BSP_CNT - 1;
reg [3:0] cnt_bit;
wire add_cnt_bit;
wire end_cnt_bit;
assign add_cnt_bit = end_cnt_bsp;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 10 - 1;
reg [9:0] data;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
data <= 10'd0;
end
else if (podge)begin
data <= {1'b1,din[7:0],1'b0};
end
else if(end_cnt_bit)begin
data <= 10'd0;
end
else begin
data <= data;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
flag <= 1'b0;
end
else if (podge)begin
flag <= 1'b1;
end
else if(end_cnt_bit)begin
flag <= 1'b0;
end
else begin
flag <= flag;
end
end
//每个比特的时钟计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_bsp <= 20'd0;
end
else if (add_cnt_bsp)begin
if (end_cnt_bsp)begin
cnt_bsp <= 20'd0;
end
else begin
cnt_bsp <= cnt_bsp + 1'b1;
end
end
else begin
cnt_bsp <= cnt_bsp;
end
end
//当前发送的数据下标
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_bit <= 4'd0;
end
else if (add_cnt_bit)begin
if (end_cnt_bit)begin
cnt_bit <= 4'd0;
end
else begin
cnt_bit <= cnt_bit + 1'b1;
end
end
else begin
cnt_bit <= cnt_bit;
end
end
//把数据串行发送出去
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
dout <= 1'b1;
end
else if (flag && cnt_bsp == BSP_CNT/2)begin
dout <= data[cnt_bit];
end
else begin
dout <= dout;
end
end
endmodule
将顶层模块的//顶层模块,_B_SPEED=460800修改为115200,并将串口调试助手固定以115200的波特率发送数据。
出现数据丢失,可能是波特率不匹配的问题。
module my_uart #(parameter TIME_1S = 12000000 , _B_SPEED = 460800****_)(
input clk ,
input rst_n ,
input dat_in ,
output dout
);