热门标签 | 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


推荐阅读
  • 探讨ChatGPT在法律和版权方面的潜在风险及影响,分析其作为内容创造工具的合法性和合规性。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 基于机器学习的人脸识别系统实现
    本文介绍了一种使用机器学习技术构建人脸识别系统的实践案例。通过结合Python编程语言和深度学习框架,详细展示了从数据预处理到模型训练的完整流程,并提供了代码示例。 ... [详细]
  • 本文介绍如何使用SAS根据输入数据集自动生成并执行SQL查询,其中CASE语句依据另一个数据集中的观测值动态调整。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 深入理解Vue.js:从入门到精通
    本文详细介绍了Vue.js的基础知识、安装方法、核心概念及实战案例,帮助开发者全面掌握这一流行的前端框架。 ... [详细]
  • 探讨 HDU 1536 题目,即 S-Nim 游戏的博弈策略。通过 SG 函数分析游戏胜负的关键,并介绍如何编程实现解决方案。 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • This post discusses an issue encountered while using the @name annotation in documentation generation, specifically regarding nested class processing and unexpected output. ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 优化SQL Server批量数据插入存储过程的实现
    本文介绍了一种改进的SQL Server存储过程,用于生成批量插入语句。该方法不仅提高了性能,还支持单行和多行模式,适用于SQL Server 2005及以上版本。 ... [详细]
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
  • 本文介绍了如何在PHP Magento模型中自定义主键,避免使用默认的自动递增主键,并提供了解决方案和代码示例。 ... [详细]
  • 本文详细介绍了如何使用 HTML 和 CSS 创建一个功能齐全的联系我们表单,包括布局和样式设计。 ... [详细]
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社区 版权所有