热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

UART的RTL逻辑设计部分uart_rx

目录1.IDLE:等待串数据到来2.REC:串并转换3.ARB:裁决校验位3.1.valid&ready的Slave读握手3.2.异步FI

目录

  • 1. IDLE:等待串数据到来
  • 2. REC:串并转换
  • 3. ARB:裁决校验位
    • 3.1. valid&ready 的Slave读握手
    • 3.2. 异步FIFO 的Master写握手
  • 3. 基于valid&ready握手 的UART_RX代码
  • 4. 基于异步FIFO 的UART_RX代码

当UART完成了模块分解和输出之后,就可以开始设计逻辑了,设计好了再写代码!!!!


接受模块的流程应该是这样的:先是空闲,然后rx出现低电平表示单bit数据来了,开始串转并,转好之后判断校验位,未通过直接丢掉,通过了就等待下级的ready信号,当ready为高就发出去,

可以看到整个过程包含了三个状态

IDLE:等待rx低电平到来

REC:串并转换过程

ARB:根据校验位裁决收到的数据是否有效,有效就等待ready将收集的数据发出,否则直接抛弃。

转换图如下:

在这里插入图片描述

可不可以在等待发送rx_data的时候进行新的串并转换呢?可以,但你无法保证新的串并转换之后rx_data还未发送。所以UART_RX也分两种方式——valid&ready写握手 和 异步FIFO


其实将ARB纳入到REC也是可以的,UART_TX那边不把计算校验位纳入到TRANS里了嘛


1. IDLE:等待串数据到来

刚开始闲着,等待rx那边低电平出现,出现了就说明来数据了,然后转入REC阶段开始接受。

但是这里要注意一个点:rx来信号是不是跨时钟域的?

虽然说商议好了波特率,即我方UART_RX.rx和对方UART_TX.tx连线上信号的变化频率相同,但是时钟很可能不同

UART常用于芯片级模块通信,时钟都不同源,必然跨时钟域
UART_TX就不用考虑跨时钟域问题,因为UART_TX的Master一般与UART_TX是同时钟,要是异时钟直接上异步FIFO

那么想到单bit跨时钟域问题,由于rx_clk频率一般会远高于波特率,所以一定满足“3个沿”条件,故直接打两拍完事

异步时钟亚稳态 的解决方案——单bit信号

所以说开始串转并,或进入REC状态的条件则是rx_d2为低,如下时序图

在这里插入图片描述

2. REC:串并转换

这个阶段就是不断的收集rx_d2,组成一个多bit并数据rx_data,并获取校验位。

那么在什么时候将rx_d2的值拼入rx_data呢?

还得依靠俩计数器baud_cnt和bit_cnt,为了采样到稳定的rx_d2,可每一bit的中间时刻计入rx_data,这样一般是稳定的电平。

采样脉冲就是这样,采样脉冲头和尾都容易因为电压太低采成逻辑0,所以应该采中间。

假设rx_data宽度是8、rx每16拍变化一次,时序图如下

在这里插入图片描述

所以baud_cnt一开始一直是0,当检测到rx_d2为低时开始+1,在bit_cnt为1~8时记录串并转换成数据,
在bit_cnt为9时记录校验位,在bit_cnt为10时为终止位

实际上在bit_cnt为9时(此时rx为校验位)且校验位被记录下来就可以进入ARB状态了,这里为了让综合的电路简单一点所以就让终止位存在

而rx_d2拼入rx_data的时刻是bit_cnt为1~8且baud_cnt为7时,此时对应rx_d2每个bit的中间时刻。

此时状态机更新为

在这里插入图片描述

3. ARB:裁决校验位

这个部分要做的就是根据收取的校验位核验收取的并数据是否是正确的,如果是就与外界握手发出去,否则扔掉。

实际上,在baud_cnt == 7 && bit_cnt == 9的那一拍直接看rx_d2和rx_data校验对不对就行,如果不对直接进入IDLE,否则就握手去。

握手传输rx_data又是套路。

3.1. valid&ready 的Slave读握手

这回是UART_RX被外部读,UART_RX是Slave。所以校验过了之后,就将rx_ready拉高,等待外部的读请求信号rx_req,当其为高时驱动rx_data,并将rx_data_val拉高一拍,时序图如下:

在这里插入图片描述

其实UART_RX也可以改成Master写握手,那么就要去掉rx_req,将rx_ready变成输入
时序就是进入ARB时直接拉高rx_data_val,等待对方的rx_ready,为高时认为写成功并转入IDLE


3.2. 异步FIFO 的Master写握手

时序和上图类似,不过就是将rx_data_val连接到FIFO的wr_en端,把rx_ready变成!empty即可。当rx_data_val && !empty时表示成功写入,转入IDLE状态。

状态机最终变成

在这里插入图片描述

3. 基于valid&ready握手 的UART_RX代码

module uart_rx_handshake#(parameter BAUD_RATE = 115200, //bit per secondparameter RX_CLK_FREQ = 50000000, //HZparameter RX_DATA_WIDTH = 16,parameter ASYNC_FIFO_DEPTH = 4096)(input rstn,input rx_clk,input rx,input rx_req,output rx_ready,output [RX_DATA_WIDTH-1:0] rx_data,output rx_data_val);localparam IDLE = 2'b00;
localparam REC = 2'b01;
localparam TRANS = 2'b11;localparam FRAME_WIDTH = RX_DATA_WIDTH + 3;
localparam BIT_CNT_WIDTH = $clog2(FRAME_WIDTH);localparam RX_RATE = RX_CLK_FREQ/BAUD_RATE;
localparam BAUD_CNT_WIDTH = $clog2(RX_RATE);reg [1:0] cur_state;
reg [1:0] nxt_state;
reg rx_d1;
reg rx_d2;
reg rx_ready_r;
reg rx_parity;
reg [RX_DATA_WIDTH-1:0] rx_data_r;
reg rx_data_val_r;
reg [BIT_CNT_WIDTH-1:0] bit_cnt;
reg [BAUD_CNT_WIDTH-1:0] baud_cnt;always&#64;(posedge rx_clk) beginif(!rstn) beginrx_d1 <&#61; 1&#39;b1;rx_d2 <&#61; 1&#39;b1;endelse beginrx_d1 <&#61; rx;rx_d2 <&#61; rx_d1;end
endalways&#64;(posedge rx_clk) beginif(!rstn)cur_state <&#61; IDLE;else cur_state <&#61; nxt_state;
endalways&#64;(*) begincase(cur_state)IDLE:if(!rx_d2)nxt_state &#61; REC;elsenxt_state &#61; IDLE;REC:if(bit_cnt &#61;&#61; FRAME_WIDTH-1 && baud_cnt &#61;&#61; RX_RATE-1) beginif(rx_parity &#61;&#61; ^rx_data &#43; 1&#39;b1) //parity checknxt_state &#61; TRANS;elsenxt_state &#61; IDLE;endelsenxt_state &#61; REC;TRANS:if(rx_data_val)nxt_state &#61; IDLE;elsenxt_state &#61; TRANS;default: nxt_state &#61; IDLE;endcase
endalways&#64;(posedge rx_clk) beginif(!rstn)rx_data_r <&#61; &#39;b0;else if(cur_state &#61;&#61; REC) beginif(bit_cnt >&#61; &#39;d1 && bit_cnt <&#61; FRAME_WIDTH-3 && baud_cnt &#61;&#61; (RX_RATE-1)/2)rx_data_r <&#61; {rx_d2,rx_data_r[RX_DATA_WIDTH-1:1]};end
endassign rx_data &#61; rx_data_r;always&#64;(posedge rx_clk) beginif(!rstn)rx_parity <&#61; &#39;b0;else if(cur_state &#61;&#61; REC) beginif(bit_cnt &#61;&#61; FRAME_WIDTH-2 && baud_cnt &#61;&#61; (RX_RATE-1)/2)rx_parity <&#61; rx_d2;end
endalways&#64;(posedge rx_clk) beginif(!rstn)baud_cnt <&#61; &#39;b0;else if(cur_state &#61;&#61; IDLE) beginif(!rx_d2)baud_cnt <&#61; &#39;b1;endelse if(cur_state &#61;&#61; REC) beginif(baud_cnt &#61;&#61; RX_RATE-1)baud_cnt <&#61; &#39;b0;elsebaud_cnt <&#61; baud_cnt &#43; &#39;b1; end
endalways&#64;(posedge rx_clk) beginif(!rstn)bit_cnt <&#61; &#39;b0;else if(cur_state &#61;&#61; IDLE && !rx_d2)bit_cnt <&#61; &#39;b0;else if(cur_state &#61;&#61; REC && baud_cnt &#61;&#61; RX_RATE-1)bit_cnt <&#61; bit_cnt &#43; 1&#39;b1;
endalways&#64;(posedge rx_clk) beginif(!rstn)rx_ready_r <&#61; 1&#39;b0;else if(cur_state &#61;&#61; REC) beginif(bit_cnt &#61;&#61; FRAME_WIDTH-1 && baud_cnt &#61;&#61; RX_RATE-1 && (rx_parity &#61;&#61; ^rx_data &#43; 1&#39;b1))rx_ready_r <&#61; 1&#39;b1;endelse if(cur_state &#61;&#61; TRANS && rx_req)rx_ready_r <&#61; 1&#39;b0;
endassign rx_ready &#61; rx_ready_r;always&#64;(posedge rx_clk) beginif(!rstn)rx_data_val_r <&#61; 1&#39;b0;else if(cur_state &#61;&#61; TRANS) beginif(rx_req && rx_ready_r)rx_data_val_r <&#61; 1&#39;b1;elserx_data_val_r <&#61; 1&#39;b0;end
endassign rx_data_val &#61; rx_data_val_r;endmodule

4. 基于异步FIFO 的UART_RX代码

module uart_rx_handshake#(parameter BAUD_RATE &#61; 115200, //bit per secondparameter RX_CLK_FREQ &#61; 50000000, //HZparameter RX_DATA_WIDTH &#61; 16,parameter ASYNC_FIFO_DEPTH &#61; 4096)(input rstn,input user_clk,input fifo_rd_en,input rx_clk,input rx,input rx_ready,output [RX_DATA_WIDTH-1:0] rx_data,output rx_data_val);localparam IDLE &#61; 2&#39;b00;
localparam REC &#61; 2&#39;b01;
localparam TRANS &#61; 2&#39;b11;localparam FRAME_WIDTH &#61; RX_DATA_WIDTH &#43; 3;
localparam BIT_CNT_WIDTH &#61; $clog2(FRAME_WIDTH);localparam RX_RATE &#61; RX_CLK_FREQ/BAUD_RATE;
localparam BAUD_CNT_WIDTH &#61; $clog2(RX_RATE);reg cur_state;
reg nxt_state;
reg rx_d1;
reg rx_d2;
reg rx_parity;
reg [RX_DATA_WIDTH-1:0] fifo_wdata;
reg fifo_wr_en;
reg [BIT_CNT_WIDTH-1:0] bit_cnt;
reg [BAUD_CNT_WIDTH-1:0] baud_cnt;
wire fifo_empty;
wire fifo_full;always&#64;(posedge rx_clk) beginif(!rstn) beginrx_d1 <&#61; 1&#39;b1;rx_d2 <&#61; 1&#39;b1;endelse beginrx_d1 <&#61; rx;rx_d2 <&#61; rx_d1;end
endalways&#64;(posedge rx_clk) beginif(!rstn)cur_state <&#61; IDLE;else cur_state <&#61; nxt_state;
endalways&#64;(*) begincase(cur_state)IDLE:if(!rx_d2)nxt_state &#61; REC;elsenxt_state &#61; IDLE;REC:if(bit_cnt &#61;&#61; FRAME_WIDTH-1 && baud_cnt &#61;&#61; RX_RATE-1) beginif(rx_parity &#61;&#61; ^rx_data &#43; 1&#39;b1) //parity checknxt_state &#61; TRANS;elsenxt_state &#61; IDLE;endelsenxt_state &#61; REC;TRANS:if(fifo_wr_en && !fifo_full)nxt_state &#61; IDLE;elsenxt_state &#61; TRANS;default: nxt_state &#61; IDLE;endcase
endalways&#64;(posedge rx_clk) beginif(!rstn)fifo_wdata <&#61; &#39;b0;else if(cur_state &#61;&#61; TRANS) beginif(bit_cnt >&#61; &#39;d1 && bit_cnt <&#61; FRAME_WIDTH-3 && baud_cnt &#61;&#61; (RX_RATE-1)/2)fifo_wdata <&#61; {rx_d2,fifo_wdata[RX_DATA_WIDTH-1:1]};end
endalways&#64;(posedge rx_clk) beginif(!rstn)rx_parity <&#61; &#39;b0;else if(cur_state &#61;&#61; REC) beginif(bit_cnt &#61;&#61; FRAME_WIDTH-2 && baud_cnt &#61;&#61; (RX_RATE-1)/2)rx_parity <&#61; rx_d2;end
endalways&#64;(posedge rx_clk) beginif(!rstn)baud_cnt <&#61; &#39;b0;else if(cur_state &#61;&#61; IDLE) beginif(!rx_d2)baud_cnt <&#61; &#39;b1;endelse if(cur_state &#61;&#61; REC) beginif(baud_cnt &#61;&#61; RX_RATE-1)baud_cnt <&#61; &#39;b0;elsebaud_cnt <&#61; baud_cnt &#43; &#39;b1; end
endalways&#64;(posedge rx_clk) beginif(!rstn)bit_cnt <&#61; &#39;b0;else if(cur_state &#61;&#61; IDLE && !rx_d2)bit_cnt <&#61; &#39;b0;else if(cur_state &#61;&#61; REC && baud_cnt &#61;&#61; RX_RATE-1)bit_cnt <&#61; bit_cnt &#43; 1&#39;b1;
endalways&#64;(posedge rx_clk) beginif(!rstn)fifo_wr_en <&#61; 1&#39;b0;else if(cur_state &#61;&#61; REC) beginif(bit_cnt &#61;&#61; FRAME_WIDTH-1 && baud_cnt &#61;&#61; RX_RATE-1 && (rx_parity &#61;&#61; ^rx_data &#43; 1&#39;b1))fifo_wr_en <&#61; 1&#39;b1;endelse if(cur_state &#61;&#61; TRANS) beginif(fifo_wr_en && fifo_full)fifo_wr_en <&#61; 1&#39;b0;end
endasync_fifo#(.ASYNC_FIFO_WIDTH (RX_DATA_WIDTH),.ASYNC_FIFO_DEPTH (ASYNC_FIFO_DEPTH)) u_async_fifo(.rstn (rstn),.wclk (rx_clk),.wr_en (fifo_wr_en),.wdata (fifo_wdata), .full (fifo_full),.rclk (user_clk),.rd_en (fifo_rd_en),.rdata (rx_data),.valid (rx_data_val),.empty (fifo_empty)
);assign rx_ready &#61; !fifo_empty;endmodule


推荐阅读
  • 在本篇学习笔记中,我们将继续深入探讨RISC架构下存储程序机的电路设计。通过详细分析关键组件的工作原理和设计方法,旨在为读者提供更全面的技术理解和实践指导。本部分将重点讨论指令执行流程、数据通路设计以及控制单元的优化策略,进一步提升系统的性能和效率。 ... [详细]
  • 通过采用JSON数据格式,能够高效且精确地获取用户的实时地理位置信息,为各类位置服务应用提供可靠的数据支持。该方法不仅简化了数据交换流程,还提高了地理信息处理的准确性和效率,适用于移动应用、导航系统及物联网设备等多种场景。 ... [详细]
  • PAT甲级 1068 寻找更多硬币 (30分) 01背包问题与路径优化
    PAT甲级 1068 寻找更多硬币 (30分) 01背包问题与路径优化 ... [详细]
  • C/C++利用栈和队列实现停车场管理系统【C++教程】
    数据结构的课程设计一般都不是很好理解,今天小编为大家总结了一下c和c++版本的常见栈和队列的的停车场管理程序,需要 ... [详细]
  • 深入解析Android中图像资源的内存占用问题及其优化策略
    在Android开发过程中,图像资源的内存占用是一个值得关注的问题。本文将探讨图像内存占用与哪些因素相关,包括设备性能的影响,并提供一系列优化策略,帮助开发者有效管理图像资源,提升应用性能。 ... [详细]
  • wxPython 中的 GDI 画刷技术深入解析(第三部分)
    在 wxPython 中,GDI 画刷技术是实现图形区域填充的关键工具。本文深入探讨了画刷的多种属性,如颜色和样式,并详细介绍了如何通过 `dc.SetBackground(brush)` 方法设置控件的背景色,确保其与父窗口背景的一致性。此外,文章还扩展讨论了画刷在复杂图形绘制中的应用,提供了丰富的代码示例和实践技巧。 ... [详细]
  • 本文详细介绍了如何使用PHP进行MySQL数据库操作,从基础概念到实际应用。首先,通过示例代码展示了如何在本地建立与MySQL服务器的连接,例如使用 `mysql_connect('localhost', 'root', 'xxxxxx')` 函数。此外,文章还涵盖了数据查询、插入、更新和删除等常见操作,并提供了丰富的代码示例和最佳实践,帮助读者快速掌握PHP与MySQL的交互技巧。 ... [详细]
  • 本文深入探讨了Google Guava库中的Optional类,详细解析了其设计原理和使用方法,并结合实际应用场景展示了如何有效避免空指针异常,提高代码的健壮性和可读性。通过具体示例,文章还介绍了Optional类在数据处理、函数式编程等方面的优势,为开发者提供了实用的参考。 ... [详细]
  • 深入解析 Go 语言中的位操作技术 ... [详细]
  • 算术表达式分析与解析技术初探
    本文初步探讨了算术表达式的分析与解析技术,针对作者在职业转型过程中发现自身算法基础薄弱的问题,决定在接下来的三个月内,系统地学习和掌握常用数据结构与算法,以提升个人技术能力。研究内容不仅涵盖了基本的算术表达式解析方法,还深入讨论了其在实际应用中的优化策略,为相关领域的进一步研究奠定了基础。 ... [详细]
  • 如何在Linux系统上部署MySQL 5.7.28
    本文详细介绍了在Linux系统上部署MySQL 5.7.28的具体步骤。通过官方下载页面获取最新安装包后,按照提供的指南进行配置和安装。文章内容实用性强,适合初学者和有经验的管理员参考。 ... [详细]
  • 在《数据库技术深度解析:Oracle与SQL优化系列之第五篇》中,我们对Oracle数据库的SQL优化进行了阶段性总结。本文继续探讨了使用UNION ALL替代UNION的优化策略,特别是在可能的情况下,以提高查询性能和效率。此外,还深入分析了这一变更对数据完整性和查询结果的影响,提供了多个实际案例和测试结果,帮助读者更好地理解和应用这些优化技巧。 ... [详细]
  • 本文介绍了如何利用摄像头捕捉图像,并将捕获的图像数据保存为文件。通过详细的代码示例,展示了摄像头调用的具体实现方法,适用于多种应用场景,如安全监控、图像处理等。 ... [详细]
  • 本文旨在构建一个JavaScript函数,用于对用户输入的电子邮件地址和密码进行有效性验证。该函数将确保输入符合标准格式,并检查密码强度,以提升用户账户的安全性。通过集成正则表达式和条件判断语句,该方法能够有效防止常见的输入错误,同时提供即时反馈,改善用户体验。 ... [详细]
  • 利用注解在Spring框架中实现面向切面编程(AOP)
    本文探讨了如何在Spring框架中通过注解实现面向切面编程(AOP)。具体介绍了使用`@Retention(RetentionPolicy.RUNTIME)`和`@Target({ElementType.TYPE, ElementType.METHOD})`等注解来定义切面,以及如何配置Spring AOP以实现对业务逻辑的增强和解耦。通过实例代码,详细展示了注解驱动的AOP在实际项目中的应用,为开发者提供了实用的参考。 ... [详细]
author-avatar
手机用户2502863161
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有