功能
接收并行数据,将数据转成并行数据,依次发出。
和发送端的区别:
- 发送端只需要按照规范或标准进行设计;
- 接收端不仅要按照规范或标准进行设计,而且需要考虑很多异常处理设计,比如发送端没有按照约定发送怎么办,比如链路上有干扰怎么办
接口
信号名 | 方向 | 含义 |
BAUD_RATE | parameter/input | parameter类型,波特率 |
clk | input | 模块工作时钟 |
reset_n | input | 模块复位信号 |
uart_rxd | input | 接收的串行数据 |
rx_data[7:0] | output | 解析出的并行数据 |
rx_dv | output | 接收数据有效指示信号,因为端口是clk,这个信号是clk的时钟域,一个时钟宽度 |
时序图
实现思路
对串行线上进行16倍波特率的过采样(upsampling)(即1位数据采样16次),这样可以避免线上干扰,收发时钟skew的问题,通过过采样的数据判断起始位,数据位,还是停止位。
起始位判断这里有个技术细节:从哪一次开始计数到16次,这里需要边沿检测,检测到边沿后开始计数。
沿检测的方法:上一个时钟采样到1,下一个时钟采样到0(下降沿),这个时钟用哪个有不同的区别,这里选择与数据判断一致的16倍波特率时钟
每解析出一位数据位,将这一位数据存在寄存器中,等停止位判断正确后,将rx_dv拉高一个时钟周期。
如果停止位不对,就舍弃这8位数据,重新等待起始位。
这次rx的难度明显比tx大,其中一个关键点,就是多了一个时钟,如果觉得复杂,是否可以拆分成更小的module,每个module使用一个时钟
将rx分成如下几个部分:
Baud_rate_clk产生部分:输入系统时钟,输出预期波特率16倍的时钟
位检测处理部分:输入波特率16倍的时钟,输入串行数据,输入串行数据有效标志,输出位检测结果,并伴随数据有效信号
——这部分相对独立,可以考虑将其封装成一个module
调试过程中总结
- 写代码脑中一片空白,不知道从而写起,就把各个部分的核心语句以伪代码的形势先想出来,可以写在这个word中
- 养成赋值#1的习惯
- 这次rx的难度明显比tx大,其中一个关键点,就是多了一个时钟,如果觉得复杂,是否可以拆分成更小的module,每个module使用一个时钟
- 每个always块最好只对一个变量幅值
- 为了减少状态机,不使用中间变量negedge_detect,这样使得state能够和数据对应,而不会晚一拍
module uart_rx
#(parameter SYSCLK = 50_000_000, BAUDRATE = 115200)
(
clk,
reset_n,
uart_rxd,
rx_data,
rx_dv
);
input clk;
input reset_n;
input uart_rxd;
output reg [7:0] rx_data;
output reg rx_dv;
wire baud_clk_16;
reg uart_rxd_r;
wire sdata;
reg sdata_valid;
wire bit;
wire bit_valid;
parameter IDLE = 4'b0000;
parameter START_BIT = 4'b0001;
parameter RXD_BIT0 = 4'b0010;
parameter RXD_BIT1 = 4'b0011;
parameter RXD_BIT2 = 4'b0100;
parameter RXD_BIT3 = 4'b0101;
parameter RXD_BIT4 = 4'b0110;
parameter RXD_BIT5 = 4'b0111;
parameter RXD_BIT6 = 4'b1000;
parameter RXD_BIT7 = 4'b1001;
parameter STOP_BIT = 4'b1010;
reg [3:0] state;
reg [7:0] temp_data;
reg [3:0] rxd_bit_cnt;
//产生波特�??16倍的时钟
baud_clk_gen
#(SYSCLK, BAUDRATE)
baud_clk_gen_inst
(
.clk(clk),
.reset_n(reset_n),
.baud_clk_16(baud_clk_16)
);
//起始位下降沿�??�??
always@(posedge baud_clk_16)
begin
uart_rxd_r <= #1 uart_rxd;
end
//状�?�机
//主状态机的输�??
always@(posedge clk or negedge reset_n)
begin
if(!reset_n)
begin
rx_dv <= #1 0;
rx_data <= #1 8'b0;
temp_data <= #1 8'b0;
end
else
begin
case(state)
RXD_BIT0:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {temp_data[7:1],bit};
end
RXD_BIT1:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {temp_data[7:2],bit,temp_data[0]};
end
RXD_BIT2:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {temp_data[7:3],bit,temp_data[1:0]};
end
RXD_BIT3:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {temp_data[7:4],bit,temp_data[2:0]};
end
RXD_BIT4:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {temp_data[7:5],bit,temp_data[3:0]};
end
RXD_BIT5:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {temp_data[7:6],bit,temp_data[4:0]};
end
RXD_BIT6:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {temp_data[7],bit,temp_data[5:0]};
end
RXD_BIT7:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
if(bit_valid)
temp_data <= #1 {bit,temp_data[6:0]};
end
STOP_BIT:
begin
if(bit_valid & (1 == bit) & (0 ==rx_dv))
begin
rx_dv <= #1 1;
rx_data <= #1 temp_data;
end
else
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
end
temp_data <= #1 temp_data;
end
default:
begin
rx_dv <= #1 0;
rx_data <= #1 rx_data;
temp_data <= #1 temp_data;
end
endcase
end
end
//状�?�机的跳转条�??
always@(posedge baud_clk_16 or negedge reset_n)
begin
if(!reset_n)
state <= #1 IDLE;
else if((IDLE == state) & (1 == uart_rxd_r) & (0 == uart_rxd))
state <= #1 START_BIT;
else if((START_BIT == state) & bit_valid & (0 == bit))
state <= #1 RXD_BIT0;
else if((START_BIT == state) & bit_valid & (1 == bit))
state <= #1 IDLE;
else if((RXD_BIT0 == state) & bit_valid)
state <= #1 RXD_BIT1;
else if((RXD_BIT1 == state) & bit_valid)
state <= #1 RXD_BIT2;
else if((RXD_BIT2 == state) & bit_valid)
state <= #1 RXD_BIT3;
else if((RXD_BIT3 == state) & bit_valid)
state <= #1 RXD_BIT4;
else if((RXD_BIT4 == state) & bit_valid)
state <= #1 RXD_BIT5;
else if((RXD_BIT5 == state) & bit_valid)
state <= #1 RXD_BIT6;
else if((RXD_BIT6 == state) & bit_valid)
state <= #1 RXD_BIT7;
else if((RXD_BIT7 == state) & bit_valid)
state <= #1 STOP_BIT;
else if((STOP_BIT == state) & bit_valid)
state <= #1 IDLE;
else
state <= #1 state;
end
//位数据采�??
assign sdata = uart_rxd_r;
bit_sample bit_sample_inst
(
.baud_clk_16(baud_clk_16),
.reset_n(reset_n),
.sdata(sdata),
.sdata_valid(sdata_valid),
.bit(bit),
.bit_valid(bit_valid)
);
always@(posedge baud_clk_16 or negedge reset_n)
begin
if(!reset_n)
sdata_valid <= #1 0;
else if((IDLE == state) & (1 == uart_rxd_r) & (0 == uart_rxd))
sdata_valid <= #1 1;
else if(IDLE == state)
sdata_valid <= #1 0;
else if((START_BIT == state) & bit_valid & (0 == bit))
sdata_valid <= #1 1;
else if((START_BIT == state) & bit_valid & (1 == bit))
sdata_valid <= #1 0;
else if((STOP_BIT == state) & bit_valid)
sdata_valid <= #1 0;
else
sdata_valid <= #1 1;
end
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/09/18 17:13:49
// Design Name:
// Module Name: baud_clk_gen
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
// 产生期望的波特率×16倍的时钟,这个期望通过parameter传递,这个期望的波特率BAUDRATE需要小于等于SYSCLK/32
// 如SYSCLK = 50MHz,BAUDRATE = 1.5625Mbps,640ns per bit,baud_clk_16=25MHz,50ns per bit
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module baud_clk_gen
#(parameter SYSCLK = 50_000_000, BAUDRATE = 115200)
(
clk,
reset_n,
baud_clk_16
);
input clk;
input reset_n;
output reg baud_clk_16;
reg [7:0] cnt;
always@(posedge clk or negedge reset_n)
begin
if(!reset_n)
baud_clk_16 <= #1 1;
else if((SYSCLK/BAUDRATE/16/2 -1) == cnt)
baud_clk_16 <= #1 ~ baud_clk_16;
else
baud_clk_16 <= #1 baud_clk_16;
end
always@(posedge clk or negedge reset_n)
begin
if(!reset_n)
cnt <= #1 8'b0;
else if((SYSCLK/BAUDRATE/16/2-1) == cnt)
cnt <= #1 8'b0;
else
cnt <= #1 cnt + 1'b1;
end
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/09/18 21:28:06
// Design Name:
// Module Name: bit_sample
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
// 每个bit位的采集。对16个采样值进行划分,前4不用,后3不用,
// 选中间的9个值,9个值中,1的个数超过一半,即大于等于5,就算这一位是1;
// 如果0的个数超过一半,即大于等于5,就算这一位是0。
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module bit_sample
(
baud_clk_16,
reset_n,
sdata,
sdata_valid,
bit,
bit_valid
);
input baud_clk_16;
input reset_n;
input sdata;
input sdata_valid;
output reg bit;
output reg bit_valid;
reg [3:0] cnt;
always@(posedge baud_clk_16 or negedge reset_n)
begin
if(!reset_n)
cnt <= #1 4'b0;
else if(4'b1111 == cnt)
cnt <= #1 4'b0;
else if(1 == sdata_valid)
cnt <= #1 cnt + 1;
else
cnt <= #1 cnt;
end
reg [3:0] temp;
always@(posedge baud_clk_16 or negedge reset_n)
begin
if(!reset_n)
temp <= #1 4'b0;
else if(4'b0000 == cnt)
temp <= #1 4'b0;
else if((4'b0100 <= cnt) & (4'b1100 >= cnt))
temp <= #1 temp + sdata;
else
temp <= #1 temp;
end
always@(posedge baud_clk_16 or negedge reset_n)
begin
if(!reset_n)
begin
bit <= #1 0;
bit_valid <= #1 0;
end
else if(4'b1110 == cnt)
begin
bit <= #1 (temp >= 5) ? 1 : 0;
bit_valid <= #1 1;
end
else
begin
bit <= #1 bit;
bit_valid <= #1 0;
end
end
endmodule