【逻辑学习笔记】uart_rx模块-verilog

本文详细介绍了UART接收端的设计,包括其功能、接口描述和实现思路。接收端不仅需要遵循协议,还需处理异常情况,如数据错误和链路干扰。通过16倍波特率的过采样来提高抗干扰能力,并使用状态机进行数据位的检测和解析。在调试过程中,作者分享了将复杂问题分解为小模块、使用伪代码预先规划和养成良好编程习惯的经验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

功能

接收并行数据,将数据转成并行数据,依次发出。

和发送端的区别:

  1. 发送端只需要按照规范或标准进行设计;
  2. 接收端不仅要按照规范或标准进行设计,而且需要考虑很多异常处理设计,比如发送端没有按照约定发送怎么办,比如链路上有干扰怎么办

接口

信号名

方向

含义

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

调试过程中总结

  1. 写代码脑中一片空白,不知道从而写起,就把各个部分的核心语句以伪代码的形势先想出来,可以写在这个word中
  2. 养成赋值#1的习惯
  3. 这次rx的难度明显比tx大,其中一个关键点,就是多了一个时钟,如果觉得复杂,是否可以拆分成更小的module,每个module使用一个时钟
  4. 每个always块最好只对一个变量幅值
  5. 为了减少状态机,不使用中间变量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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值