在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 505|回复: 1

[原创] 孩子都能学会的FPGA:第六课——用计数器实现UART协议的接收模块

[复制链接]
发表于 2023-11-21 13:41:23 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 chdaj58 于 2023-11-21 13:44 编辑

原创声明:该文是作者的原创,面向对象是FPGA入门者,后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门作者不光让大家知其然,还要让大家知其所以然!每个工程作者都搭建了全自动化的仿真环境,只需要双击top_tb.bat文件就可以完成整个的仿真(前提是安装了modelsim),降低了初学者的门槛。如果需要整个工程请加微信15092150280索要即可,不收任何费用,但是仅供参考,不建议大家获得资料后从事一些商业活动!

有了第五课的uart发送模块,那uart接收模块相对就简单多了。还是需要两个计数器就可以实现,一个计数器用于一次uart传输位数的计数,一个计数器用于uart一位数据宽度的控制,就是波特率的设置。

uart接收模块的计数器和发送模块的计数器功能是完全相同的,那接收模块的设计要点在哪儿?我们知道uart是异步串行通信,就是只有数据线,没有同步时钟线。发送模块有数据就可以发送,那接收模块什么时候接收呢?这时候就能看出来uart起始位的作用了。我们知道,uart的数据线在空闲状态下是高电平,而起始位是低电平,所以FPGA应该时刻监控uart数据线上的状态,如果前一个时刻还是高电平,下一个时刻就是低电平了(暂时不考虑线上有干扰),说明有新的数据要发送过来了,做好接收数据的准备。

判断出来起始位,那后面的数据位,结束位就能顺理成章的能判断出来。每一位用100MHz的时钟可以计数868次,那我们在哪个点从线上取数据呢?发送端是在bandrate_cnt计数为0的时候把数据放到线上,实际生效是在bandrate_cnt计数为1的时候,持续到bandrate_cnt下次计数为0为止。对于接收端,理论来说在bandrate_cnt0计数到867的每一点都可以,但是bandrate_cnt的计数值在0附近表明线上的信号刚发生了变化,此时从线上取数据可能会取到错误的数据,所以一般在数据最稳定的地方取数据,即bandrate_cnt的计数值是433的时候。

如下所示,与uart发送模块类似,设置了一个接收标志寄存器recv_domain,当有新的数据要接收时拉高,当一次10位的传输完成后拉低;byte_cnt和bandrate_cnt计数器的功能和uart发送模块的完全一样,新增了一个标志信号get_data_point,在计数为433的时候拉高一个时钟周期,用于uart线上数据的采集。


v2-7652cfe1c2773c8e7cfef03729068c02_720w.png


知道了上面的两个设计要点,下面我们来分析一下uart_byte_rx模块的设计。首先输入信号clkrst_n是时钟和复位。rx_signaluart线上的信号,dout_vld是接收数据dout的有效指示信号。


v2-4fdbca689ab50767a565033072fc982b_720w.png

增加了一个GET_DATA_CNT的参数,用于指示在波特位的中间位置采集数据,用wire类型的信号get_data_point来指示数据采集点。recv_domain来标志数据采集区域,所有控制信号在recv_domain拉高的区域变化。增加了rx_sync0/rx_sync1/rx_sync2这几个信号,作用有两个,一个对其它时钟域的信号rx_signal进行打拍同步,二是通过打拍实现对rx_signal信号的下降沿进行检测。信号rx_detect用于指示rx_signal信号的下降沿,即uart接收数据的开始。寄存器end_ok用来检测停止位是否正确。


v2-75a7377ba4638e9c944dd31310e059fb_720w.png

首先对rx_signal信号进行打拍同步,因为rx_signal信号和本模块的clk一般不是同一个时钟域。我们都知道,uart一般都是对外的接口,所以FPGA收到的rx_signal这个信号是同其它芯片发过来的,和FPGA的主时钟clk不是同一个时钟域。这个地方的信号打拍就涉及到不同时钟域的信号同步问题,信号同步的方法后面会有课时专门讲述,这个地方先大体说一下打拍为什么管用。

用一个例子解释一下大家就明白了,假设两趟地铁在站点X可以进行换乘,已知如下的信息:

地铁A每7分钟一趟;

地铁B每5分钟一趟;

同一站点换乘时间是2-5分钟(考虑人流的密度)。

假设你乘坐的地铁A到站的时间是7点3分,而最近的一辆地铁B1的发车时间是7点5分,下一辆地铁B2的发车时间是7点10分下一辆地铁B3的发车时间是7点15分,然后地铁B4的发车时间是7点20分,那就可以分析一下,你直接去赶地铁,有可能赶上地铁B1(人流量小的时候),也有可能赶不上地铁B1(人流量大的时候),但是不出意外的话一般可以赶上地铁B2。

但是你朋友是坐的地铁A是7点10分到站点X,他提前打电话让你等他一块去做地铁B,这样你和朋友一定赶不上地铁B2,不出意外可以赶上地铁B3,但是一定可以赶上B4。

所以信号的寄存器打拍就和地铁换乘一样,打拍越多,留给信号的处理时间裕量就越大,同步也就越好,但是花的时间也就越多。一般而言,打两到三拍能解决绝大多数的同步问题。rx_detect是采样rx_signal信号的下降沿,也就是上一个时刻是高电平,当前时刻是低电平,这就是下降沿。


v2-7e87aed65450942fc4b4c4d271d39708_720w.png

接收标志寄存器recv_domain,有新的数据要接收时拉高,一次uart传输完成拉低,有这个信号的好处是其它的控制信号都在recv_domain高电平的时候变化,在recv_domain低电平的时候清零或者默认值即可。


v2-4bf6ffe511caa7a5ea130b80f2d4a3cc_720w.png
下面是两个计数器的实现,与uart发送模块的计数器实现方式完全一样,只不过把send_domain改为了recv_domain。


v2-2a3a2dfcd62ab97ded4b406f35fac929_720w.png

然后就可以在期望的点(get_data_point)进行uart线上的数据的采集了,由于uart线上是先发的低位,再发的高位,所以这儿采用右移的方式来存储采集的数据,数据先存储在寄存器dout_tmp中。同理采集结束位的信号,保存在寄存器stop_ok中,用于线上数据的校验


v2-6f81b9eabcca43a798eb6664de66a9f0_720w.png

最后完成数据的接收后,如果停止位检测正确,那就可以输出采集的uart线上数据dout,同时用dout_vld信号来标识dout信号的有效。


v2-1e2e5cfc837161bb915c719cee040572_720w.png

在仿真模块中,将uart_byte_rx模块和上节课的uart_byte_tx模块一起例化仿真。


v2-8765d6272fd13ce52d557cdda92805ef_720w.png

由仿真结果可以看出来,发送端把8bit的信号转换成了单bit的串行信号,接收端把串行的单bit信号又转变成了8bit的信号,发送数据和接收数据一致,功能设计正确。


v2-9b7b863b6b150a62c04f523417491c88_720w.png

这节课实现了uart接收的基本功能,和上接课的模块一起就可以完成uart最基本的通讯功能。我们知道很多uart还需要奇偶校验位,那我们下节就进一步完善uart的通讯功能。


发表于 2023-11-21 16:56:31 | 显示全部楼层
謝謝樓主整理圖片 和筆記技術文章 感恩
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条

×

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-5-13 06:05 , Processed in 0.030647 second(s), 9 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表