Abstract: Verilog UART 设计
同步发布于个人博客
更新记录
当前为 v4 版本
解决了之前版本连续收发时丢数据的问题
模块代码
Rx 部分
// UART 接收模块 可选波特率 可选数据位 仅支持一位停止位
module UART_Rx_module #(
parameter CLK_FREQ_MHZ = 27,
parameter BAUD_RATE = 9600,
parameter DATA_WIDTH = 8 // 数据位宽
) (
input in_sys_clk,
input in_rst_n,
input in_rx_ready, // 准备好接受串口数据
input in_rx_pin,
output [DATA_WIDTH-1:0] out_rx_data, // 接收到的串口数据 rx_data_ready和rx_data_valid均为高时送出
output out_rx_data_valid // 接收到的串口数据有效
);
localparam BAUD_CNT_THRESHOLD = CLK_FREQ_MHZ * 1000000 / BAUD_RATE; // 波特率计数最大值
localparam BAUD_CLK_CNT_THRESHOLD = (DATA_WIDTH + 2); // 波特率时钟计数最大值 数据位+起始位+结束位
wire w_rx_negedge;
wire w_rx_done; // 接收接收标识
wire w_sample_signal;
wire w_bit_rev_done;
reg r_rx_pin_t0, r_rx_pin_t1;
reg r_rx_state; // 接收状态
reg [$clog2(BAUD_CNT_THRESHOLD)-1:0] r_baud_rate_cnt; // 波特率计数器
reg [$clog2(BAUD_CLK_CNT_THRESHOLD)-1:0] r_baud_rate_clk_cnt; // 波特率时钟计数
reg [BAUD_CLK_CNT_THRESHOLD-1:0] r_rx_data_frame_byte; // 完整数据帧
assign w_rx_negedge = (r_rx_pin_t1 && ~r_rx_pin_t0);
assign w_rx_done = (r_baud_rate_clk_cnt==BAUD_CLK_CNT_THRESHOLD-1) && (r_baud_rate_cnt==BAUD_CNT_THRESHOLD/2+2); // 不判断完整的结束位
assign w_sample_signal = (r_baud_rate_cnt==BAUD_CNT_THRESHOLD/2);
assign w_bit_rev_done = (r_baud_rate_cnt==BAUD_CNT_THRESHOLD-1);
assign out_rx_data = (out_rx_data_valid && in_rx_ready)? r_rx_data_frame_byte[BAUD_CLK_CNT_THRESHOLD-2:1] : 'd0;
assign out_rx_data_valid = w_rx_done;
//****输入数据同步****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_rx_pin_t0 <= 1'b0;
r_rx_pin_t1 <= 1'b0;
end
else begin
r_rx_pin_t0 <= in_rx_pin;
r_rx_pin_t1 <= r_rx_pin_t0;
end
end
//********//
//****接收状态逻辑****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_rx_state <= 1'b0;
end
else begin
if (w_rx_negedge && ~r_rx_state) begin // 下降沿到来
r_rx_state <= 1'b1;
end
else if (w_rx_done) begin // 接收完成
r_rx_state <= 1'b0;
end
else if (r_baud_rate_clk_cnt=='d1 && r_rx_data_frame_byte[0]=&