赞
踩
前文已经生成了MIG IP,本文将对其信号进行分析,并且仿真测试,最后上板验证MIG IP是否工作。
首先通过手册获取该IP的内部结构图,下图是该IP采用默认接口时的输入输出信号,ddr相关的信号与DDR3芯片的引脚直接相连,app开头的引脚是IP提供给用户的信号。
其中DDR3引脚相关的信号就不需要分析了吧,如果看过前面关于DDR演变的文章,这些引脚应该非常熟悉,大部分引脚与SDRAM的引脚一样。
下面是MIG IP的端口部分,生成的信号与上述框图中的信号基本保持一致。
mig_7series_0 u_mig_7series_0 (
// Memory interface ports
.ddr3_addr (ddr3_addr), // output [14:0] ddr3_addr
.ddr3_ba (ddr3_ba), // output [2:0] ddr3_ba
.ddr3_cas_n (ddr3_cas_n), // output ddr3_cas_n
.ddr3_ck_n (ddr3_ck_n), // output [0:0] ddr3_ck_n
.ddr3_ck_p (ddr3_ck_p), // output [0:0] ddr3_ck_p
.ddr3_cke (ddr3_cke), // output [0:0] ddr3_cke
.ddr3_ras_n (ddr3_ras_n), // output ddr3_ras_n
.ddr3_reset_n (ddr3_reset_n), // output ddr3_reset_n
.ddr3_we_n (ddr3_we_n), // output ddr3_we_n
.ddr3_dq (ddr3_dq), // inout [15:0] ddr3_dq
.ddr3_dqs_n (ddr3_dqs_n), // inout [1:0] ddr3_dqs_n
.ddr3_dqs_p (ddr3_dqs_p), // inout [1:0] ddr3_dqs_p
.init_calib_complete (init_calib_complete), // output init_calib_complete
.ddr3_cs_n (ddr3_cs_n), // output [0:0] ddr3_cs_n
.ddr3_dm (ddr3_dm), // output [1:0] ddr3_dm
.ddr3_odt (ddr3_odt), // output [0:0] ddr3_odt
// Application interface ports
.app_addr (app_addr), // input [28:0] app_addr
.app_cmd (app_cmd), // input [2:0] app_cmd
.app_en (app_en), // input app_en
.app_wdf_data (app_wdf_data), // input [127:0] app_wdf_data
.app_wdf_end (app_wdf_end), // input app_wdf_end
.app_wdf_wren (app_wdf_wren), // input app_wdf_wren
.app_rd_data (app_rd_data), // output [127:0] app_rd_data
.app_rd_data_end (app_rd_data_end), // output app_rd_data_end
.app_rd_data_valid (app_rd_data_valid), // output app_rd_data_valid
.app_rdy (app_rdy), // output app_rdy
.app_wdf_rdy (app_wdf_rdy), // output app_wdf_rdy
.app_sr_req (app_sr_req), // input app_sr_req
.app_ref_req (app_ref_req), // input app_ref_req
.app_zq_req (app_zq_req), // input app_zq_req
.app_sr_active (app_sr_active), // output app_sr_active
.app_ref_ack (app_ref_ack), // output app_ref_ack
.app_zq_ack (app_zq_ack), // output app_zq_ack
.ui_clk (ui_clk), // output ui_clk
.ui_clk_sync_rst (ui_clk_sync_rst), // output ui_clk_sync_rst
.app_wdf_mask (app_wdf_mask), // input [15:0] app_wdf_mask
// System Clock Ports
.sys_clk_i (sys_clk_i),
.sys_rst (sys_rst) // input sys_rst
);
为了与时序图一起讲解,将端口信号分为几部分进行讲解,首先是DDR3芯片引脚相关信号,如下表所示,后面表格中所有IO的方向都是针对MIG IP来说的。
信号名 | 位宽 | I/O | 含义 |
---|---|---|---|
ddr3_addr | 15 | O | 行、列地址线。 |
ddr3_ba | 3 | O | bank地址线。 |
ddr3_cas_n | 1 | O | 列选通信号,低电平有效。 |
ddr3_ck_n | 1 | O | 端口差分时钟的N端。 |
ddr3_ck_p | 1 | O | 端口差分时钟的P端。 |
ddr3_cke | 1 | O | 时钟使能引脚,高电平有效。 |
ddr3_ras_n | 1 | O | 行选通信号,低电平有效。 |
ddr3_reset_n | 1 | O | 复位信号,低电平有效。 |
ddr3_we_n | 1 | O | 写使能信号,低电平有效。 |
ddr3_dq | 16 | IO | 双向数据信号。 |
ddr3_dqs_n | 1 | IO | 数据选通差分信号的N端。 |
ddr3_dqs_p | 1 | IO | 数据选通差分信号的P端。 |
ddr3_cs_n | 1 | O | 片选信号,低电平有效。 |
ddr3_dm | 2 | O | 输入数据掩膜信号,高电平有效。 |
ddr3_odt | 1 | O | ODT引脚。 |
剩余端口信号都是提供给用户的端口,首先来查看指令和地址相关的引脚,MIG IP只支持读和写两种指令。
信号名 | 位宽 | I/O | 含义 |
---|---|---|---|
app_cmd | 3 | I | 为0时表示写指令,为1表示读指令。 |
app_addr | 29 | I | 读、写数据对应的地址。 |
app_en | 1 | I | 读写指令使能信号。 |
app_rdy | 1 | O | MIG IP空闲指示信号。 |
app_cmd这个信号其实只有一位有效,其余两位均为恒定电平,那为什么app_addr位宽为29?
在配置MIG IP时,选择地址使用如下模式,通过前文的MT41K256M16RE-125这颗芯片的框图可以知道列地址有10位,行地址有15位,bank地址有3位,加起来28位地址。而rank是针对内存条来说的,FPGA使用DDR时并不存在,也可以说为0,即使为0也需要一位数据表示吧,所以就多了一位,这一位实际可能没有作用。
注意MIG IP其实是把DDR3的存储单元按照这个地址排列起来了,对于用户来说就没有行、列地址了,只存在app_addr这一个地址。
当app_en信号拉高时并且app_rdy信号也为高电平时,读写命令和地址才会被写入到MIG IP内部的一个指令FIFO中。如果app_rdy为低电平,则app_en、app_addr和app_cmd需要保持状态,直到app_rdy变为高电平为止,对应时序图如下所示。
写数据相关的信号如下表所示,MIG IP数据和指令是分开的,可以不进行对齐。
信号名 | 位宽 | I/O | 含义 |
---|---|---|---|
app_wdf_data | 128 | I | 写数据。 |
app_wdf_end | 1 | I | 突发时写入最后一次数据。 |
app_wdf_wren | 1 | I | 写数据使能信号,高电平有效。 |
app_wdf_mask | 16 | I | 写数据掩膜信号。 |
app_wdf_rdy | 1 | O | MIG IP写数据空闲指示信号。 |
由于用户时钟频率为100MHz,MIG IP设置的DDR3端口时钟频率为400MHz,且双沿传输16位数据,那么MIG用户侧读写数据位宽则需要128位。数据掩膜信号1位可以控制8位数据的写入,一次写入MIG IP128位数据,所以需要16位的数据掩膜信号。
下图是非背靠背模式的写数据与写命令的时序图,写数据可以与写命令对齐,写数据也可以提前写命令,写数据也可以滞后写命令,写数据滞后写命令不应该超过2个时钟的限制。
app_wdf_wren与app_wdf_rdy也需要握手才表示数据写入到MIG IP内部的数据FIFO中,如果app_wdf_rdy为低电平,需要将app_wdf_wren和app_wdf_end以及有效的app_wdf_data保持,直到app_wdf_rdy为高电平位置。app_wdf_mask信号可以用来屏蔽要写入DDR3的字节数据。
需要注意个问题,当DDR3端口时钟频率与MIG IP的用户时钟频率比值为4:1且DDR3突发长度设置为8时,读写MIG IP数据位宽为128位,每次向MIG IP写入数据都是写入128位数据,就是写入一次突发传输的数据,那么每次写入的数据就是本次突发传输的最后一字节数据,所以app_wdf_wren和app_wdf_end应该保持一致,如下时序图所示:
注意上图中写入数据的地址每次加8,并不是加1,这是因为在图2计算内存地址时,认为每个地址存储8位数据,而每次写入MIG IP的是128位数据,所以每次加8。DDR3列地址为什么每次也是加8这在DDR3与DDR2区别的文章中有讲解,不再赘述。
如果DDR3端口时钟频率与MIG IP的用户时钟频率比值为2:1且DDR3突发长度设置为8时,那么读写MIG IP的数据位宽应该是64位,而突发读写DDR3中数据8次,需要传输128位数据,所以每次突发传输需要读写两次MIG IP中的数据,那么在写入数据时app_wdf_end只在第二次写入时位高电平,对应的时序图如下所示。
DDR3内存的读写操作可以分为两种模式:背靠背(Back-to-Back)和非背靠背(Non-Back-to-Back)。在背靠背模式下,读写操作连续进行,每个时钟周期都执行,没有间隔。而非背靠背模式则允许读写操作之间存在间隔。两种模式唯一的区别就是背靠背模式的写命令与写数据之间没有最大延迟限制, 背靠背模式下的写时序如下所示:
读数据相关的信号如下表所示,比较简单。
信号名 | 位宽 | I/O | 含义 |
---|---|---|---|
app_rd_data | 128 | O | 读数据。 |
app_rd_data_end | 1 | O | 突发时读出最后一次数据。 |
app_rd_data_valid | 1 | O | 读数据有效指示信号。 |
读时序如下图所示,当读命令发出后,等待读数据有效指示信号拉高,表示此时读数据线上的数据有效。
还剩下几个比较重要的信号,这几个信号单独拿出来讲解,不使用表格。
1、sys_clk_i是MIG IP的系统时钟输入信号,根据前面IP配置,这个时钟需要提供200MHz 时钟。
2、sys_rst是MIG IP的系统复位输入信号,低电平复位。
3、ui_clk是MIG IP提供给用户侧使用的时钟信号,DDR3端口时钟与ui_clk频率比值为4:1。
4、ui_clk_sync_rst是MIG IP提供给用户侧的同步复位信号,高电平有效。
5、init_calib_complete是DDR控制器对外部DDR3芯片初始化和校准完成信号,若该信号为高,表示DDR3初始化和校准完成,之后用户可往DDR3进行数据的读写操作了。
还剩下几个本地接口维护命令信号,如下表所示,这几个信号可以不用使用,输入信号直接给0,输出信号不连接其他信号。
信号名 | 位宽 | I/O | 含义 |
---|---|---|---|
app_sr_req | 1 | I | 保留信号,接低电平。 |
app_sr_active | 1 | O | 保留信号。 |
app_ref_req | 1 | I | 高电平表示请求MIG IP向DDR3发送刷新命令,高电平只能持续一个时钟周期,直到app_ref_ack信号被拉高。 |
app_ref_ack | 1 | O | 高电平表示确认刷新请求,并表示该命令已从存储器控制器发送到外部DDR3。 |
app_zq_req | 1 | I | 高电平表示请求MIG IP向DDR3发送ZQ校准命令,高电平只能持续一个时钟周期,直到app_zq_ack信号被拉高。 |
app_zq_ack | 1 | O | 高电平表示确Z校准请求,并表示该命令已从存储器控制器发送到外部DDR3。 |
MIG IP的所有端口信号就的含义就讲解完毕了,开放的用户接口其实还是比较简单的,如果理解了DDR3芯片的工作原理,与DDR3相关的所有引脚也基本上能记住。
在对MIG IP的所有端口讲解完毕之后,可以利用官方提供的例程对MIG IP进行仿真,通过仿真进一步查看读写时序。
如下图所示,在Hierarchy选项卡下,选中生成的MIG IP,然后鼠标右键点击Open IP Example Design。
之后会弹出以下选项卡,就是官方例程存储路径,直接点击OK即可。
之后就生成了一个可以用于测试的工程,如下图所示。
生成工程的RT视图如下所示,除了生成的MIG IP之外,还有一个控制模块。
鼠标点击Run Simulation,然后选择Run Behavioral Simulation开始仿真,如下图所示。
进入仿真界面后,默认会添加TestBench文件中的信号,但是我们需要查看的是MIG IP的接口时序,所以先停止仿真,把默认添加的信号先删除。然后选择MIG IP模块,右键添加所有信号,如下图所示。
之后把DDR3相关的引脚信号删除,因为本文主要是分析用户读写MIG IP的时序,所以不需要关注DDR3的接口时序,剩余信号如下图所示。
然后重新开始仿真,因为DDR3初始化需要一段时间,所以MIG IP的仿真时间比较长,下图是正在仿真的截图。
仿真完成的整体界面如下所示,可以看见天蓝色信号是初始化完成标志信号,过了很长一段时间才拉高,低电平时DDR3都在进行初始化和校准。直到初始化完成之后,读写指令相关信号才开始变化。
DDR3的初始化和校准是由MIG IP自动完成的,不需要用户干预,所以用户接口就没有相关的时序变化,如果需要了解,可以查看之前删除的DDR3相关信号的变化,分析起来也是比较复杂的,本文由于篇幅原因就不分析了,如果需要可以之后单独出一篇文章进行分析。
如下图所示,连续发出5个写命令,前4个写命令发出时,app_rdy为高电平,马上接收写命令,第5个写命令发出之后,app_rdy为低电平,表示第五个写命令没有被MIG IP接收,则写入地址app_addr和写命令使能信号app_en保持高电平,直到app_rdy变为高电平为止。
在写命令输入的同时,也一直在向MIG IP中写入数据,因为写数据空闲信号app_wdf_rdy一直为高电平,则会立即写入数据,所以一直在传输数据。因为这是背靠背写入数据,所以写数据和写命令之间没有最大延迟要求。
注意上述多位宽数据的显示方式为16进制,也就是说每次地址加8,前面也分析过原因。
继续查看写命令和写数据时序,如下图所示,app_rdy和app_wdf_rdy均有一段时间无效,对应的写地址和写数据相关信号就会保持不变,直到app_rdy、app_wdf_rdy变为高电平为止,仿真结果与前面的理论一致,没有问题。
当app_cmd为1时,表示读命令,下图是读命令和读数据的时序,读命令的时序与写命令的时序变化一致,区别在于app_cmd取值不同。当app_rd_data_vaild为高电平时表示读出数据,第一个读出的数据对应第一个读命令对应地址的数据。app_rd_data_end的原理与app_wdf_end的原理一致,不再赘述。
读写的数据时没有问题的,可以加入顶层模块的tg_compdata_error信号,如图20红色信号,如果读出的数据与写入数据不一致,该信号会变为高电平。当然也可以去对比写入数据和读出数据的值。
关于MIG IP的仿真就到此结束,有兴趣的可以自己创建工程,然后仿真查看,其实之后我们可以保留这个工程的顶层文件,然后自己去写读写控制模块,然后进行仿真,因为此工程提供了DDR3的仿真模型,能够模拟DDR3的初始化、校准和存储数据,所以还是比较好的,自己要是写DDR3的仿真模型估计不会简单。
有兴趣可以打开TestBench查看,包含很对延时之类的原语等等。
上述生成的测试工程可以用于上板测试,由于板载的晶振为100MHz,需要给MIG IP提供一路200MHz的时钟信号,需要添加一个锁相环IP倍频。
为了便于查看读写时序,还添加了一个ILA,抓取指令、读数据、写数据相关信号。
而init_calib_complete信号为高电平表示初始化完成,读写数据不一致时,会将tg_compdata_error变为高电平,我们可以使用这两个信号分别驱动一个LED,通过观察LED的状态变化,获取MIG IP初始化DDR3及读写数据的结果。开发板上LED相关原理图如下所示,高电平点亮LED。
综合工程后,需要对时钟信号、复位信号、指示信号分配对应管脚,init_calib_complete驱动LED2,tg_compdata_error驱动LED1。根据原理,在系统复位之后,LED2应该会熄灭一段时间后常亮,而LED3应该一直处于熄灭状态。
工程进行实现,然后下载到开发板上验证,按下复位按键后的运行结果如下所示,LED2会先熄灭一段时间,然后一直亮,表示初始化和校准完成后处于正常状态。而LED1一直处于熄灭状态,表示从DDR3读出的数据与写入DDR3的数据保持一致。
图24 DDR3读写测试
使用ILA抓取数据,结果如下所示。
ILA抓取的写数据指令,如下图所示,当app_en和app_rdy同时为高电平时,写数据命令才会被写入到MIG IP内部FIFO中。如果app_rdy为低电平时,app_en和app_addr的状态就必须保持不变,直到app_rdy为高电平为止。
ILA抓取写数据的时序如下所示,当app_wdf_wren和app_wdf_rdy同时为高电平时,写入数据app_wdf_wdata才会被写入到MIG IP内部FIFO中。如果app_wdf_rdy为低电平,则app_wdf_wren和app_wdf_wdata的状态保持不变,直到app_wdf_rdy为高电平为止。写入数据掩膜信号app_wdf_mask一直为低电平。
ILA抓取读数据指令时序如下图所示,与写数据命令时序基本一致,区别在于app_cmd的状态不同。
如下图所示,当向MIG IP发出读命令之后,需要等待读数据有效指示信号app_rd_data_vaild为高电平时,表示读出的数据app_rd_data有效。
app_rd_data_vaild第一个高电平读出的数据是第一个读数据命令的地址存储的数据,整个过程中tg_compare_error为低电平,表示读出的数据与写入的数据一致,与仿真结果一致。
本文对MIG IP默认的接口信号进行讲解,并且使用官方提供的工程对生成的IP进行仿真,最后添加锁相环和ILA后下载到开发板上验证仿真结果。
MIG IP其实已经对DDR3的接口信号进行简化了,比如将bank地址、行列地址合并为一个app_addr地址,但是还是需要rdy与en信号进行握手,其实可以通过封装继续简化读写操作。
本文的工程是官方的工程,本来不需要我提供的,但是为了我日后能够直接使用和验证,还是将工程上传网盘,需要工程的话可以在公众号后台回复“MIG IP验证工程”(不包括引号)。
如果对文章内容理解有疑惑或者对代码不理解,可以在评论区或者后台留言,看到后均会回复!
如果本文对您有帮助,还请多多点赞
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。