串口收发之RAM存储
前言
实现上位机通过串口发送数据到FPGA,FPGA接收到数据后将其存储在RAM的一段连续空间中,然后通过按键触发读出RAM数据,再通过串口发送到上位机。
整体设计
模块划分
1、串口接收模块;
2、按键消抖模块
3、创建RAM IP核模块
4、RAM IP核控制模块;
5、串口发送模块。
前面已经设计好了串口发送模块,串口接收模块和按键消抖模块,还剩RAM IP的创建和控制RAM模块的设计。
控制RAM读写的逻辑:
1、简易双端口RAM,有两组地址:写地址wraddress、读地址rdaddress;
2、只设置了写使能wren,没有设置读使能;
3、设置单时钟模式clock来控制所有寄存器,而且没有设置时钟使能 ;
4、data:要写入RAM的数据、q:RAM读出的数据。
1、控制写RAM
当需要写入数据时,把wren信号拉高的同时,给出写地址rdaddress和写数据data[7:0],数据就会按照指定的地址写入对应的存储单元;
具体而言,FPGA接收到数据后将其存储在双口RAM的一段连续空间中,需要设计wren写使能的同时给一个wraddress写地址自加的控制;
实现:在串口接收模块中,每接收一帧数据后会有一个时钟脉冲的标志信号Rx_Done表示数据接收完成,则Rx_Done作为写地址自加条件,同时作为写使能信号;写第一个字节时,直接写在地址0,然后出现Rx_Done信号,写地址wraddress加1,这样接收到的字节存储在一段连续空间中。
always@(posedge Clk or negedge Rst_n) if(!Rst_n) wraddress <= 8'b0; else if(Rx_Done) wraddress <= wraddress + 1'b1; else wraddress <= wraddress;
2、控制读RAM
当需要读出数据时,这里没有设置读使能信号,直接给出当前读地址rdaddress,输出端口q[7:0]就会根据当前指定的地址输出对应存储单元的数据。
如何将数据连续发送出去?
q始终连接串口发送模块的数据输入;
开始时读地址为0,输出端q为地址0对应的存储单元中的数据,第一次按键按下,Send_en使能将q端数据发送出去,然后触发Tx_Done,读地址加1,同时又作为Send_en的使能条件,将q对应的第二个字节发送出去,这样连续地读出RAM中数据。
串口使能发送Send_en的触发?
第一次按键按下,Send_en使能将q端数据发送出去;
后续Send_en使能是上一帧数据发送完成标注Tx_Done和按键状态Send_flag共同触发。
为什么读RAM时候可以连续的读?
连续的读也就说明Send_en信号持续有效。上面也说了Send_en使能是由当前按键状态和上一帧数据发送完成标志信号Tx_Done共同触发,当第一次按下按键Send_flag就持续有效,所以当第一帧发送完成出现Tx_Done,然后触发Send_en使能,接着就继续发送下一帧,发送完成又会出现Tx_Done,则连续的读。
为什么将Send_en的触发信号(Send_flag & !Tx_Done) 寄存两拍?
在对RAM IP进行仿真时,读出的数据总是延时对应的存储地址两拍。
RAM IP核
M9K存储器模块
通过对M9K存储器模块进行配置,可实现各种存储器功能:RAM、移位寄存器、ROM、FIFO。
下面是M9K存储器模块支持的模式:
- 单端口RAM
只有一组地址线,这组地址线控制着写数据端口和读数据端口;
支持从单一地址上的异时读写操作; - 简单双端口RAM
有两组地址线,分别控制着写数据端口和读数据端口;
支持不同位置的同时读写操作; - 真正双端口RAM
与简单双端口RAM相比,两个数据端口都可用做读/写;
真双端口模式支持两个端口操作的任意组合:在两个不同时钟频率上的两个读操作、两个写操作、一个读操作和一个写操作。
简单双端口RAM端口框图:
管脚说明:
data:RAM写数据端口
wraddress:RAM写地址端口
wren:写使能信号,高电平有效
bytenena:字节使能控制,该功能屏蔽了输入数据,这样仅写入数据中指定字节,未被写入的字节保留之前写入的值【创建IP这个功能可选】
wr_addressstall、rd_addressstall:地址使能控制,为高电平时,有效地址时钟会保持之前的地址【创建IP时可选】;
wrclock、rdclock:输入与输出时钟,输入时钟控制存储器模块的所有输入寄存器,包括data、wraddress、wren、rden寄存器;输出时钟控制数据q寄存器;
wrclocken、rdclocken:使能输入输出时钟;
rdaddress:RAM读地址端口;
rden:读使能信号,高电平有效;
q:RAM读数据端口;
aclr:异步复位信号,对RAM中数据进行清零操作,高电平有效。
这里创建的RAM非常简易,实现基本的读写操作即可
1、简易双端口RAM,有两组地址:写地址wraddress、读地址rdaddress;
2、只设置了写使能wren,没有设置读使能;
3、设置单时钟模式clock来控制所有寄存器,而且没有设置时钟使能 ;
4、data:要写入RAM的数据、q:RAM读出的数据。
创建RAM IP核
1、选择双端口RAM的IP
2、设置双端口RAM一个为读端口和一个为写端口【简单双端口RAM】
设置储存器大小的方式为按照字数确定
3、设置存储器容量;端口位宽为8【存储串口接收的一个字节数据】;
4、选择单时钟模式,即通过单时钟clock和一个时钟使能信号控制存储块所有的寄存器;
不创建读使能信号
5、对输出端口进行寄存;不创建时钟使能信号;不创建异步复位信号【是对RAM中的数据清零操作,本次实验不需要清零】
6、该页面指定在对RAM进行写操作时,读数据输出选择。
具体而言,写操作期间,RAM输出行为是可以配置的。如果在写操作期间激活了rden信号,则RAM输出端会显示相应地址上正在写入的数据【选择New Data】,或者原有的旧数据【Old memory contents appear】;如果在rden信号未激活的情况下执行写操作,那么RAM输出端将保留它们在最近的rden信号有效期间所保留的值。
本文没有使用rden信号,而且先把数据全部写入到RAM中,然后再一个字节一个字节的读出来,所以不考虑同时读写操作,就像选择了I do not care一样。那么如何读出对应地址上的存储单元中的数据呢?【具体看控制RAM读写模块设计】
7、创建RAM IP核,可以进行初始化也可以不进行;而创建ROM IP核必须进行初始化。
至此简易双端口RAM IP核已创建完毕,可以进行简单的测试.
IP核测试
输出q延时读地址两拍,所以在设计的时候要进行同步处理。
延时两拍的原因:
设计中使用锁存器的原因,会导致延时一拍;
创建IP核的时候,q被寄存了一拍,如下图,如果不勾选则只延时一拍。