自从发布《轻松设计SDRAM控制器》这一系列教程的第一讲之后,不知道大家对于这套教程中所讲的这个小练习的设计思路是否理解透了呢?理解透了是好事,完全没有理解也没关系,我们会在这套教程的后续部分一步一步的给大家讲解这个小练习各个模块的设计思想,相信讲到最后,爱学习的你一定会对咱们讲解的这个小项目有充分的了解。
现在进入到《轻松设计SDRAM控制器》的第二讲内容,主要内容如下: - 介绍RS232协议;
- 讲解RS232接收模块的设计思路;
- 介绍RS232接收模块的仿真技巧。
通过这一讲的学习,Kevin希望大家能彻底掌握RS232协议的内容,并能够在本节所讲设计思想的基础上,设计其他波特率的串口接收模块。
一、RS232协议简单介绍
上面的图片是一个不“完整”RS232协议时序图,我们以第一讲中的那个演示为例。
当PC机未给FPGA通过串口发送数据时,串口的发送端处于空闲状态,而串口发送端是以高电平来表示空闲状态,也就是说,当串口未发送数据时,其发送端是一直处于高电平。
当PC端需要开始发送数据时,首先需要给一个起始位来表示从空闲状态转变为忙碌状态。起始位发送完后,接着就是发送一个字节数据的最低位,然后依次发送直至发送完最高位。
一个完整的RS232协议,在发送完数据的最高位之后,还有1bit的校验位。但在本套教程中,我们未使用校验位,所以在发送完数据最高位之后,直接给了停止位。
好了,RS232协议还是比较简单的,我们就先介绍到这。
二、串口接收模块设计思路讲解在讲解设计思路之前,先说一下几个参数,串口的波特率为9600,FPGA使用的系统时钟为50MHz.
在了解了RS232的协议之后,怎么来设计我们的这个串口接收模块呢?首先第一点大家要明确,我们来检测串口上的数据,肯定是在每一位的最中间进行的,这样才能保证检测到的串口数据是在稳定之后的。
既然这样,那我们是不是可以产生一个计数器,这个计数器的计数范围就是串口数据1bit所占用的时间,然后在该计数器计到最大值的一半时,进行检测串口上的数据。OK了,想到这一点接下来就好办了。
大家请看我们的这个时序图:
- rx 表示 PC 端的串口发送端( 对于 FPGA 端, 为串口的接收端), 在串口空闲状态时, rx 一直处于高电平。 若 PC 端需要通过串口发送数据, 则需要将 rx 从高拉低,表示串口发送的起始位,接着依次发送 8bit 的数据 ( 最低位优先), 发送完最后 1bit 数据, rx 保持高电平( 无校验位);
- 由于 PC 端与 FPGA 端处于两个时钟域, 所以在 FPGA 端需要进行跨时钟域处理, 即对 rx 进行打两拍处理( rx_t, rx_tt), rx_ttt 是 rx 的 3 级寄存器;
- rx_flag 是串口处于接收状态的标志信号, rx_flag 拉高的条件是 rx 从空闲状态发送起始位的下降沿, 拉低条件是接收完一帧串口数据( 8bit);
- baud_cnt 为波特率计数器, FPGA 使用时钟为 50MHz, 所以串口发送 1bit的数据占用的时钟周期为:( 1/9600) x109÷20≈5208, 该计数器自加的条件为 rx_flag 为高, 当计数满 5207 时, 自动清零;
- bit_flag 为检测 rx 上串口数据的标志信号, 只有当 baud_cnt 计数到 2603时, bit_flag 才会拉高。 选在 baud_cnt 计数器的中间值来检测串口数据,是为提高检测数据的可靠性;
- bit_cnt 为已接收一帧串口数据的 bit 数, 其自加条件为 bit_flag, 当计数到 8, 即表示接收完一帧数据后清零;
- rx_data 是接收串口数据的寄存器, 位宽为 8, 该寄存器使用了位拼接操作, 其目的是对接收到的串口数据进行移位, 将接收到的 1bit 数据构造成 8bit 的数据, 也可以理解成串转并的一个操作;
- po_flag 为接收完一帧串口数据的标志信号, 用于提供给外部模块检测接收到的串口数据, 即 rx_data 寄存器的值。
根据时序图,写出来的代码如下(建议大家先尝试自己把代码写出来):
三、串口接收模块仿真文件编写
写完了串口接收模块的代码,那接下来就是编写我们的仿真文件了。对于仿真,大家首先要想清楚我们仿真的目的是什么?在我们的TB文件中需要编写什么内容?想清楚了这些,才能知道如何下手编写代码。 在这里,我们是需要对我们的串口接收模块仿真,而我们在tb文件中所要做的,就是模拟串口发送的时序。 模拟串口的发送时序,最简单的中做法,就是只在一个initial块中完全使用延时的方法来产生我们想要的串口发送时序。 但在这,Kevin教大家一种稍微复杂一点的方法,这种方法编写的代码稍微多一点:
对于该tb文件,Kevin不对其解释,由大家自行消化。 写完tb文件后,大家就可以使用modelsim对其进行仿真了。对于如何仿真,Kevin不再作详细的演示,由大家自行完成。 在这一讲中,Kevin贴出了所写模块的代码,只是想让大家更加深入地理解这个模块的设计思路,并且如何根据设计的时序图来编写代码。 好了,我们第二讲的内容就到此结束,希望本节内容能对大家有所帮助。
在后续章节中,Kevin将不会把全部代码贴出。如果对后续课程中的内容有所疑惑,您可以结合我们的视频教程进行学习,也可以加入开源骚客FPGA交流群:312109973,当然也可以加Kevin个人微信(微信号:opensoc888)进行讨论。
特别提醒#1
|