目录

  • 1. IDLE:等待并数据到来
    • 1.1. valid&ready 的Slave写握手
    • 1.2. 异步FIFO 的Master读握手
  • 2. TRANS:并串转换
    • 2.1. 打包tx_data_frm
    • 2.2. 并串转换
    • 2.3. 发送完毕标志
  • 3. 基于valid&ready握手 的UART_TX代码
  • 4. 基于异步FIFO 的UART_TX代码

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


还是先从外围模块开始,UART_TX模块的功能比较简单,将多bit数据按照波特率解构成单bit发送到tx上即可。

由于tx端每一拍的数据都不同,即当前tx输出会与之前tx_data有关,因此输出输入是时序逻辑关系,此处使用状态机进行设计。

状态设计两种:IDLE和TRANS。咱先用语言描述每个状态要干啥 以及状态转移条件,再翻译成时序图,最终形成代码

IDLE状态下,一直等待要发送的数据出现,出现了就转入TRANS状态

TRANS状态下,将待发送的数据按照帧格式和波特率单bit发送,发完了转回IDLE。

状态转换图如下:

1. IDLE:等待并数据到来

IDLE状态什么都不用做,只需找到一个条件判断有待发送数据即可进入TRANS状态。

1.1. valid&ready 的Slave写握手

UART_TX的接口都给出了tx_data、tx_data_valid和tx_ready,摆明了告诉你将UART_TX当作Slave通过写握手判断数据到来。

标准握手时序

然后就是常见的写握手套路了,tx发完单bit数据了,就把tx_ready拉高,等待tx_data_valid有效时缓存tx_data

所以IDLE本来就是等待数据到来,所以IDLE与ready的时序对齐即可,如下图

红色箭头就表示将tx_data直接按照帧格式缓存,并转入TRANS状态。

绿色箭头表示tx_data_val拉低,所以在此之后tx_data可能发生了变化

这样的话,状态机就变成了

进入TRANS状态UART_TX要单bit发数据了,ready应该是一直拉低的,那么此时Master写过来数据那只能展宽等待了,效率不高。

解决办法是,咱就别缓存成一个tx_data_r变量了,咱直接一个异步FIFO缓存。

1.2. 异步FIFO 的Master读握手

如果中间弄个异步FIFO那么,UART_TX就不是被写的Slave了,而变成了Master与FIFO进行读握手!

那么进入IDLE状态后,rd_en一直拉高,直到empty为低,表示异步FIFO必定会读出数据,这时候拉低rd_en,并进入TRANS状态。

按照标准Master读握手时序,应该是rd_en一直拉高,直到ready为高,则表示数据必会被读出,在下一拍获取数据。只不过此处的ready变成了empty非
使用异步FIFO后,Master与UART_TX的时钟就可以不同了

时序图如下,注意empty为空时要延长rd_en

所以异步FIFO方案的状态机变成:

2. TRANS:并串转换

OK现在有要发送的数据了,TRANS这边需要作一下几个工作:

  1. 获取tx_data值,计算奇偶校验位,并根据帧结构打包成tx_data_frm

  2. 根据波特率和tx_clk频率,实现tx_data_frm到tx的并串转换

  3. 确定发送完毕条件,返回IDLE状态

由于我们提出了握手和FIFO两种方案,因此将分别做出解释。

2.1. 打包tx_data_frm

如果使用的valid&ready 握手的话,那么在检测到tx_data_val && ready就直接将tx_data打包成tx_data_frm,这个之前已经讲到了。

如果使用异步FIFO的话,在TRANS状态下检测到valid有效,就可以缓存数据了

这个FIFO的valid标志只拉高一拍,要确认

奇偶校验位直接按位异或即可,结果为1表示有rdata有奇数个1,否则为偶数个。

2.2. 并串转换

在之后TRANS的时间内,要通过tx_data_frm移位的方式实现单bit发送

别忘了波特率!波特率其实就是tx数据更新的频率!需对tx_clk计数的来判断什么时候移位1次

一般来说tx_clk频率远高于波特率,所以一定可以计数的。

那么什么时候开始计数呢?

无论是ready握手还是异步FIFO,计数器的时序要与tx_data_frm对齐,所以开始计数的条件与tx_data_frm更新的条件 相同即可

ready握手时序图如下

异步FIFO的时序图如下

细节就是baud_cnt什么时候开始+1?如果是ready握手,那么baud_cnt+1的条件是cur_state == TRANS。如果是异步FIFO,TRANS下第二拍才能开始+1。

2.3. 发送完毕标志

完成TX_DATA_WIDTH+3个位发送,就可以转入IDLE状态了。

我们怎么知道发送了这么多个bit?看来我们还需要另一个计数器bit_cnt计算发了多少bit,显然是baud_cnt加完一轮bit_cnt再加1。

以每16拍tx变换一次为例,时序图如下,所以说TRANS返回IDLE的条件就是bit_cnt == 10 && baud_cnt == 15

最终得到UART_TX的ready握手状态机如下:


异步FIFO的状态机如下

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

代码写的可能有点冗杂,但是逻辑是清晰的,并且相信DC综合。

module uart_tx_handshake#(parameter BAUD_RATE        = 115200,                  //bit per secondparameter TX_CLK_FREQ       = 50000000,                    //HZparameter TX_DATA_WIDTH     = 16,parameter ASYNC_FIFO_DEPTH    = 4096)(input                          rstn,input                          tx_clk,input    [TX_DATA_WIDTH-1:0]     tx_data,input                           tx_data_val,output                          tx_ready,output                         tx);localparam IDLE     = 1'b0;
localparam TRANS    = 1'b1;localparam FRAME_WIDTH = TX_DATA_WIDTH + 3;
localparam BIT_CNT_WIDTH = $clog2(FRAME_WIDTH);                //if FRAME_WIDTH == 16 but width of bit_cnt is 4localparam TX_RATE = TX_CLK_FREQ/BAUD_RATE;
localparam BAUD_CNT_WIDTH = $clog2(TX_RATE);reg                            cur_state;
reg                             nxt_state;
reg     [FRAME_WIDTH-1:0]       tx_data_frm;
reg     [BIT_CNT_WIDTH-1:0]     bit_cnt;
reg     [BAUD_CNT_WIDTH-1:0]    baud_cnt;
reg                             tx_ready_r;
wire                            parity;always@(posedge tx_clk) beginif(!rstn)cur_state <= IDLE;else cur_state <= nxt_state;
endalways@(*) begincase(cur_state)IDLE:if(tx_ready_r && tx_data_val)nxt_state = TRANS;elsenxt_state = IDLE;TRANS:if(bit_cnt == FRAME_WIDTH-1 && baud_cnt == TX_RATE-1)           nxt_state = IDLE;elsenxt_state = TRANS;default:   nxt_state = IDLE;endcase
endalways@(posedge tx_clk) beginif(!rstn)tx_ready_r <= 1'b1;else if(cur_state == IDLE) beginif(tx_ready_r && tx_data_val)tx_ready_r <= 1'b0;endelse if(cur_state == TRANS) beginif(bit_cnt == FRAME_WIDTH-1 && baud_cnt == TX_RATE-1)tx_ready_r <= 1'b1;end
endassign tx_ready = tx_ready_r;always@(posedge tx_clk) beginif(!rstn)tx_data_frm <= 'b1;else if(cur_state == IDLE) beginif(tx_ready_r && tx_data_val)tx_data_frm <= {1'b1,parity,tx_data,1'b0};endelse if(cur_state == TRANS) beginif(baud_cnt == TX_RATE-1)tx_data_frm <= {1'b1,tx_data_frm[FRAME_WIDTH-1:1]};end
endassign parity = (tx_ready_r && tx_data_val)?(^tx_data+1'b1):1'b0;assign tx = tx_data_frm[0];always@(posedge tx_clk) beginif(!rstn)baud_cnt <= 'b0;else if(cur_state == IDLE)baud_cnt <= 'b0;else if(cur_state == TRANS) beginif(baud_cnt < TX_RATE-1)baud_cnt <= baud_cnt + 1'b1;elsebaud_cnt <= 'b0;end
endalways@(posedge tx_clk) beginif(!rstn)bit_cnt <= 'b0;else if(cur_state == IDLE)bit_cnt <= 'b0;else if(cur_state == TRANS) beginif(baud_cnt == TX_RATE-1) beginif(bit_cnt == FRAME_WIDTH-1) bit_cnt <= 1'b0;elsebit_cnt <= bit_cnt + 1'b1;end   end
endendmodule

4. 基于异步FIFO 的UART_TX代码

module uart_tx_fifo#(parameter BAUD_RATE         = 115200,                  //bit per secondparameter TX_CLK_FREQ       = 50000000,                    //HZparameter TX_DATA_WIDTH     = 16,parameter ASYNC_FIFO_DEPTH    = 4096)(input                          rstn,input                          user_clk,           //FIFO WRITE CLKinput                           tx_clk,input    [TX_DATA_WIDTH-1:0]     tx_data,input                           tx_data_val,output                          tx_ready,output                         tx);localparam IDLE     = 1'b0;
localparam TRANS    = 1'b1;localparam FRAME_WIDTH = TX_DATA_WIDTH + 3;
localparam BIT_CNT_WIDTH = $clog2(FRAME_WIDTH);localparam TX_RATE = TX_CLK_FREQ/BAUD_RATE;
localparam BAUD_CNT_WIDTH = $clog2(TX_RATE);reg                            cur_state;
reg                             nxt_state;
reg     [FRAME_WIDTH-1:0]       tx_data_frm;
reg     [BIT_CNT_WIDTH-1:0]     bit_cnt;
reg     [BAUD_CNT_WIDTH-1:0]    baud_cnt;
wire                            parity;wire                         fifo_full;
reg                             fifo_rd_en;
wire    [TX_DATA_WIDTH-1:0]     fifo_rdata;
wire                            fifo_rdata_val;
wire                            fifo_empty;always@(posedge tx_clk) beginif(!rstn)cur_state <= IDLE;else cur_state <= nxt_state;
endalways@(*) begincase(cur_state)IDLE:if(fifo_rd_en && !fifo_empty)nxt_state = TRANS;elsenxt_state = IDLE;TRANS:if(bit_cnt == FRAME_WIDTH-1 && baud_cnt == TX_RATE-1)           //if FRAME_WIDTH == 16 but width of bit_cnt is 4nxt_state = IDLE;elsenxt_state = TRANS;default: nxt_state = IDLE;endcase
endalways@(posedge tx_clk) beginif(!rstn)fifo_rd_en <= 1'b0;else if(cur_state == IDLE) beginif(fifo_rd_en && !fifo_empty)fifo_rd_en <= 1'b0;endelse if(cur_state == TRANS) beginif(bit_cnt == FRAME_WIDTH-1 && baud_cnt == TX_RATE-1)fifo_rd_en <= 1'b1;end
endalways@(posedge tx_clk) beginif(!rstn)tx_data_frm <= 'b1;else if(cur_state == IDLE)tx_data_frm <= tx_data_frm;else if(cur_state == TRANS)  beginif(fifo_rdata_val)tx_data_frm <= {1'b1,parity,fifo_rdata,1'b0};else if(baud_cnt == TX_RATE-1)tx_data_frm <= {1'b1,tx_data_frm[FRAME_WIDTH-1:1]};end
endassign parity = (fifo_rdata_val)?(^fifo_rdata+1'b1):1'b0;assign tx = tx_data_frm[0];always@(posedge tx_clk) beginif(!rstn)baud_cnt <= 'b0;else if(cur_state == IDLE)baud_cnt <= 'b0;else if(cur_state == TRANS) beginif(fifo_rdata_val)baud_cnt <= 'b0;else if(baud_cnt < TX_RATE-1)baud_cnt <= baud_cnt + 1'b1;elsebaud_cnt <= 'b0;end
endalways@(posedge tx_clk) beginif(!rstn)bit_cnt <= 'b0;else if(cur_state == IDLE)bit_cnt <= 'b0;else if(cur_state == TRANS) beginif(fifo_rdata_val)bit_cnt <= 'b0;else if(baud_cnt == TX_RATE-1)bit_cnt <= bit_cnt + 1'b1;end
endasync_fifo#(.ASYNC_FIFO_WIDTH            (TX_DATA_WIDTH),.ASYNC_FIFO_DEPTH           (ASYNC_FIFO_DEPTH)) u_async_fifo(.rstn      (rstn),.wclk        (user_clk),.wr_en       (tx_data_val),.wdata        (tx_data),  .full       (fifo_full),.rclk       (tx_clk),.rd_en     (fifo_rd_en),.rdata     (fifo_rdata),.valid     (fifo_rdata_val),.empty     (fifo_empty)
);assign tx_ready = !fifo_full;endmodule

UART的RTL逻辑设计部分 - uart_tx相关推荐

  1. UART的RTL逻辑设计部分 - uart_rx

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

  2. FPGA逻辑设计回顾(12)RAM以及ROM的RTL设计及其验证

    前言 本文首发:FPGA逻辑设计回顾(12)RAM以及ROM的RTL设计及其验证 RAM以及ROM在FPGA中的实现大体有两种方式,一种是使用IP核定制,一种是RTL设计. 也许有人会反驳,那原语呢? ...

  3. 逻辑设计中复位的稳妥处理方法?

    前言 看别人的好设计,能让自己从细节上提升,所谓好的设计,除了从各种指标上评判,我们都知道,设计的兼容性(参数化),可读性,可扩展性等等,可是既然是学习,我们本身就不知道什么样的才是好的,这些指标也分 ...

  4. FPGA逻辑设计回顾(11)FPGA以及PC中的RAM与ROM

    文章目录 前言 RAM以及ROM在计算机中的应用 什么是存储器? 什么是硬盘驱动器? 其他类型的存储器 什么是RAM? RAM的类型 SRAM DRAM 什么是ROM? ROM的类型 掩膜ROM PR ...

  5. FPGA逻辑设计回顾(8)单比特信号的CDC处理方式之Toggle同步器

    文章目录 前言 脉冲反馈展宽同步器技术补充说明 RTL代码 行为仿真 低电平脉冲的展宽处理 切换同步器的原理与实现 RTL实现 前言 本文首发自:FPGA逻辑设计回顾(8)单比特信号的CDC处理方式之 ...

  6. FPGA逻辑设计回顾(9)DDR的前世今生以及演变过程中的技术差异

    文章目录 前言 DDR的前世SDRAM DDR的今生以及演变版本:DDR/DDR2/DDR3 DDR/DDR2/DDR3/DDR4之间简单对比 速度对比 电压对比 延迟对比 预取差异 电阻端接对比 物 ...

  7. FPGA逻辑设计回顾(1)新手易犯的逻辑综合错误之always块

    前言 注:本文首发自FPGA逻辑设计回顾(1)新手易犯的逻辑综合错误之always块 本文中用到了如下的小标题: "心中有路"与综合推断 "心中无路"与无从推断 ...

  8. FPGA逻辑设计回顾(3)多比特信号上升沿检测的设计方式与陷阱?

    前言 注:本文首发自FPGA逻辑设计回顾(3)多比特信号上升沿检测的设计方式与陷阱? 在总结本文最后的多比特上升沿检测之前,我们先把备用知识讲清楚,摊开来,以免造成模糊不清的默许! 逻辑运算符与位元运 ...

  9. 串行外设接口(Serial Peripheral Interface, SPI)逻辑设计部分 - spi_master

    目录 1. baud_clk_gen 1.1. 代码 2. spi_master 2.1. IDLE:等待写入 2.2. WAIT_CS:等待选通 2.3. TRANS:传输 (CPOL ^ CPHA ...

最新文章

  1. windowsclient开发--为你的client进行国际化
  2. 批命令 set /a与set /p有哪些区别
  3. SAP HU 序列号里的Sales Order号码不一致导致PGI失败问题之对策
  4. macaca web(4)
  5. python之decorator理解
  6. jq获取页面高度_JQuery获取页面高度宽度
  7. Angular2-路由重定向的办法
  8. “朝三暮四”与“BPO”
  9. Prototype.js 1.4中文使用手册PDF版下载
  10. 服务器上怎么安虚拟主机呀,上线虚拟主机产品步骤
  11. 爱荷华大学计算机科学专业,爱荷华大学计算机科学本科.pdf
  12. OSG 场景图(Scene Graph) 类图
  13. 计算机毕业设计JAVA二手物品置换平台mybatis+源码+调试部署+系统+数据库+lw
  14. 永恒之蓝漏洞攻击完整步骤
  15. echarts r 地图_用R与Stata绘制地图,让文稿shinly起来
  16. 推荐到Oracle YEP计划
  17. 论文解读:SuperPoint: Self-Supervised Interest Point Detection and Description
  18. 1652:牡牛和牝牛
  19. C++中你不知道的namespace和using的用法
  20. linux设置nexus开机自启动_linux nexus自启动

热门文章

  1. html-day07垂直对齐定位
  2. pve虚拟机和openstack虚拟机的区别
  3. [附源码]java毕业设计新闻发布和评论管理系统
  4. HTTP-FLV协议
  5. 百度绿萝算法公告的内容
  6. 纹理、贴图、材质的区别
  7. css和ctl,亲身体验诉说ctl4100和ctl672有啥区别?哪个好?内情必看测评
  8. 大学图书馆计算机房,图书馆计算机房与整体方案设计.doc
  9. 玩转腾讯首发Linux内核源码《嵌入式开发笔记》
  10. UVa 10697 - Firemen barracks