借用之前在优快云看到的一位仁兄分享的博客内容,再来详细分析和解释一下在学习DDR3过程中的理解与体会。仁兄文章的链接不知道是啥了,在这里说声不好意思哈!
一、mig_7series_0 IP核例化模块接口代码如下:
mig_7series_0 u_mig_7series_0 (
// Memory interface ports
.ddr3_addr (ddr3_addr), // output [14:0]
.ddr3_ba (ddr3_ba), // output [2:0]
.ddr3_cas_n (ddr3_cas_n), // output
.ddr3_ck_n (ddr3_ck_n), // output [0:0]
.ddr3_ck_p (ddr3_ck_p), // output [0:0]
.ddr3_cke (ddr3_cke), // output [0:0]
.ddr3_ras_n (ddr3_ras_n), // output
.ddr3_reset_n (ddr3_reset_n), // output
.ddr3_we_n (ddr3_we_n), // output
.ddr3_dq (ddr3_dq), // inout [63:0]
.ddr3_dqs_n (ddr3_dqs_n), // inout [7:0]
.ddr3_dqs_p (ddr3_dqs_p), // inout [7:0]
.init_calib_complete (init_calib_complete), // output
.ddr3_cs_n (ddr3_cs_n), // output [0:0]
.ddr3_dm (ddr3_dm), // output [7:0]
.ddr3_odt (ddr3_odt), // output [0:0]
// Application interface ports
.app_addr (app_addr), // input [28:0]
.app_cmd (app_cmd), // input [2:0]
.app_en (app_en), // input
.app_wdf_data (app_wdf_data), // input [511:0]
.app_wdf_end (app_wdf_end), // input
.app_wdf_wren (app_wdf_wren), // input
.app_rd_data (app_rd_data), // output [511:0]
.app_rd_data_end (app_rd_data_end), // output
.app_rd_data_valid (app_rd_data_valid), // output
.app_rdy (app_rdy), // output
.app_wdf_rdy (app_wdf_rdy), // output
.app_sr_req (app_sr_req), // input
.app_ref_req (app_ref_req), // input
.app_zq_req (app_zq_req), // input
.app_sr_active (app_sr_active), // output
.app_ref_ack (app_ref_ack), // output
.app_zq_ack (app_zq_ack), // output
.ui_clk (ui_clk), // output
.ui_clk_sync_rst (ui_clk_sync_rst), // output
.app_wdf_mask (app_wdf_mask), // input [63:0]
// System Clock Ports
.sys_clk_i (sys_clk_i),
.sys_rst (sys_rst) // input
);
这段代码就是举个例子,例化的接口代码用于下面讲解时的参考对照,按照需求设计的IP核不同,接口引脚也不太一样,但是相差不大。
二、例化IP核
1. 打开IP Catalog然后搜索mig,如下图所示:
2. 如下图所示,首先是确认工程的信息,主要是芯片信息和编译环境的信息,如果没什么问题,直接点击“Next”。
3. 如下图所示,选择“Create Design”,在“Component Name”一栏设置该 IP 元件的名称,这里取默认软件的名称,再往下选择控制器数量,默认为“1”即可。最后关于 AXI4 接口,因为本工程不去使用AXI4 接口,所以不勾选。配置完成点击“Next”。
4. 如下图所示,该页主要是选择可以兼容的芯片,本工程默认不勾选,即不需要兼容其他的 FPGA芯片。配置完成点击“Next”。
5. 如下图所示,因为我们要用 DDR3 芯片,所以选择第一个选项“DDR3 SDRAM”,配置完成后点击“Next”。
6. 如下图所示,从这页开始,就开始正式配置MIG IP 核的各个参数了。
- Clock Period:DDR3 物理芯片使用的运行时钟,ddr芯片会以这个时钟采数据。这个参数的范围和 FPGA 的芯片类型以及具体类型的速度等级有关。我这里选择2500ps,对应 400M。注意这个时钟是 MIG IP 核产生,并输出给 DDR3物理芯片使用的(时钟管脚ddr3_ck_n,ddr3_ck_p),该时钟与DDR3 芯片具体的运行带宽相关。若DDR3 芯片的数据位宽总共为16位,则由于DDR3双沿数据采样,运行带宽可达到12.8Gb/s(800M*16bit)。
- VCCAUX_IO: FPGA 高性能 bank(High Performance bank)的供电电压,HR(High Range)bank不使用这个IO电压,默认设置为1.8V。它的设置取决于 Clock Period这个参数的设置。通过K7 data sheet可知,如下图按(-2)这个级别的芯片来说,当DDR3器件连接在HP bank时,当VCCAUX-IO设置为2.0V时速率最高1866M,1.8V是速率最高1333M,当连接到HR bank时,速率最高1066M。关于“I/O Bank Type”在FPGA芯片中是如何分布的,可以参考ug475 : Die Level Bank Numbering Overview
- PHY to Controller Clock Ratio: DDR3 物理芯片运行时钟和 MIG IP核产生的用户端时钟(ui_clk)之比, 可以理解为(ddr3的工作时钟频率:用户时钟频率) = (4:1),一般有 4:1 和 2:1 两个选项。由于 DDR 芯片的运行时钟是400Mhz,因此 MIG IP 核的用户时钟(ui_clk)就是 100Mhz。一般来说高速传输的场合选择4:1,要求低延时的场合选择 2:1。另外,选择2:1的话,(app_wdf_data、app_rd_data)数据总线位宽是UI界面你选择的(Data Width)物理接口的4倍,Data Width是64的话,app_wdf_data、app_rd_data位宽为256bit, 选择4:1的话,(app_wdf_data、app_rd_data)数据总线位宽是UI界面你选择的(Data Width) 物理接口的8倍,Data Width是64的话,app_wdf_data、app_rd_data位宽为512bit。
- Memory Type: DDR3 储存器类型选择。默认选择 Component。
- Memory Part: DDR3 芯片的具体型号。本次选择 MT41J128M16XX-125,这个型号其实和实际硬件原理图上的型号可以不同的,只要用户的 DDR3 芯片容量和位宽一致即可。以上为例代表这一片ddr的位宽为16,总容量为128Mb x 16bit =256MB。 点击Create Custom Part,会显示DDR3 芯片的Row Address、Column Address、Bank Address(也就是行列地址、块地址)的位宽,这会决定(app_addr)的位宽,app_addr[ADDR_WIDTH – 1:0],ADDR_WIDTH =RANK_WIDTH +BANK_WIDTH + ROW_WIDTH + COL_WIDTH。RANK_WIDTH固定为1.
- Memory Voltage:DDR3 芯片的电压选择,由芯片决定,芯片手册上有。
- Data Width: 数据位宽选择,这里选择 16。
- ECC: ECC 校验使能,数据位宽为 72 位的时候才能使用。
- Data Mask: 数据屏蔽管脚使能。勾选它才会产生屏蔽信号。
- Number of Bank Machines: Bank Machine 的数量是用来对具体的每个或某几个来单独控制的,选择多了控制效率就会高,相应的占用的资源也多。若DDR3 芯片是八个 bank,这里选择 4 个,则平均一个 Bank Machine 控制两个BANK。
- ORDERING: 该信号用来决定 MIG 控制器是否可以对它收到的指令进行重新排序,选择 Normal 则允许,Strict 则禁止。本实验选择 Normal,从而获得更高效率。
7.上面的配置好之后,点击“NEXT”按钮,进入如下界面:
- Input Clock Period: MIG IP 核的系统输入时钟周期,该输入时钟是由 FPGA 内部产生的,即MIG IP 核的工作时钟。
- Read Burst Type and Length: 突发类型选择,突发类型有顺序突发和交叉突发两种,本次选择顺序突发(Sequential),其突发长度固定为 8。
- Output Driver Impdance Control: 输出阻抗控制。本次选择 RZQ/7。
- RTT: 终结电阻,可进行动态控制。本次选择 RZQ/4。
- Controller Chip Select Pin: 片选管脚引出使能。本实验选择 enable,表示把片选信号cs#引出来,由外部控制。
- BANK_ROW_COLUMN: 寻址方式选择。本实验选择第二种,即 BANK-ROW-COLUMN 的形式,这是一种最常规的 DDR3寻址方式,即要指定某个地址,先指定 bank,再指定行,最后指定列,这样就确定了一个具体地址。一般来说这样寻址方式有利于降低功耗,但是读写性能(效率)上不如“ROW_BANK_COLUMN”。
8.上面的配置好之后,点击“NEXT”按钮,进入如下界面:
- System Clock: MIG IP核的输入时钟。用于创建所有MIG设计时钟,用于时钟内部逻辑,相位器的频率参考时钟,以及在多i /O BANK实现中保持PHY控制块同步所需的同步脉冲(看上图)。本次选择“No Buffer”, 是因为IP核的输入系统时钟是单端时钟,是由内部的MMCM产生的,MMCM所产生的时钟默认添加了buffer。当选择No Buffer选项时,IBUF原语不会在RTL代码中实例化,引脚也不会为System Clock分配。但是(sys_clk_i)信号需要连接到内部时钟,也就是上面说的由内部的MMCM产生的时钟,否则设计会失败。
- Reference Clock: MIG IP 核参考时钟。参考时钟驱动设计中的IODELAYCTRL组件,提供200M的参考时钟(看上图)。同样选择“No Buffer”,将由时钟模块生成。当选择No Buffer选项时,IBUF原语不会在RTL代码中实例化,引脚也不会为Reference Clock分配。但是(ref_clk_i)信号需要连接到内部时钟,也就是上面说的由内部的MMCM产生的时钟,否则设计会失败。在Input Clock Period选项中如果选择200M,会出现Use System Clock选项,Reference Clock使用System Clock的时钟,(ref_clk_i)引脚不会出现。
- System Reset Polarity: 复位有效电平选择。本次选择“ACTIVE LOW”低电平有效。
- Debug Signals Control: 该选项用于控制 MIG IP 核是否把一些调试信号引出来,它会自动添加到 ILA,这些信号包括一些 DDR3 芯片的校准状态信息。本实验选择选择“OFF”,不需要让 IP 核生产各种调试信号。
- Sample Data Depth: 采样深度选择。当“Debug Signals Control”选择“OFF”时,所有采样深度是不可选的。
- Internal Vref: 内部参考管脚,表示将某些参考管脚当成普通的输入管脚来用。若 IO资源较为紧张,可以选择“ON”,把参考管脚当做普通的输入管脚来用。
- IO Power Reduction: IO 管脚节省功耗设置。本次选择“ON”,即开启。
- XADC Instantiation: XADC 模块例化。使用 MIG IP 核运行的时候需要进行温度补偿,可以直接选择XADC模块的温度数据引到 MIG IP 核来使用,否则需要额外提供温度数据,所以本实验选择“Enable”。温度监视器通过补偿温度漂移有助于在数据有效窗口保持DQS中心对齐。
9.继续点击“NEXT”按钮,界面如下图所示。
10.以上是高性能 bank 端接匹配阻抗的设置,这里不去改它,默认 50 欧姆即可。接下来点击“NEXT”按钮,界面如下图所示。
这里第一个选项是系统分配它认为的最合适的管脚(如果只是仿真,可以选择这个),第二个选项是由用户自己分配管脚。我这里只看仿真,固选择了第一个。
11.接下来一直点击next即可。
12.点击next即可。
13.点击next即可。
14.先点击accept,再点击next即可。
15.点击next即可。
16.点击generate即可。
17.点击generate生成MIG IP核。
18.等待综合完成后,如下图所示,右键选择Open IP Example Design,即可打开Xilinx官方提供的MIG IP核读写例程。
19.紧接着选择MIG IP核读写例程的存放路径 ,点击OK。

20.下图即为Xilinx官方提供的MIG IP核读写例程 ,点击Run Simulation进行仿真。(仿真就不看了,并不能清晰的反应DDR3的读写时序。)

三、DDR3读写时序
1.命令时序
只有在app接口上的app_rdy端口输出为高时,才能操作命令。当app_rdy为高,app_en拉高后,命令会写入命令FIFO中。读写指令如下:
有些兄弟可能不太明白命令FIFO是怎么回事,看下面这个PHY interface 的图就明白了,在用户和DDR3 SDRAM之间的PHY就是这样的结构。
2. 写时序
之前我们说过,PHY to Controller Clock Ratio 这个参数分4:1和2:1两个mode,两者的写时序不同。
(1)4:1mode写时序,如下图:
有三种写模式,要注意的是第三种方式:数据最晚在命令有效后的两个时钟周期写入。
连续写入就如下图所示:
数据手册上还列举的数据在DRAM接口的采样示例(手册上的图片也不清楚,看文字说明吧):在应用程序界面,如果64位数据驱动为0000_0806_0000_0805 (Hex),则DRAM界面的数据如图1-75所示。这是针对突发长度8 (BL8)事务。
DDR模式,上下沿采样,共用了四个时钟:
(2)2:1mode写数据(与4:1模式对比)
对于2:1模式,应用程序数据宽度为32位。因此,对于BL8事务,应用程序接口上的数据必须在两个时钟周期内提供。第二个数据拉高app_wdf_end信号,如中所示图1 - 76。在本例中,第一个周期提供的应用程序数据是0000_0405(十六进制),,而最后一个周期提供的数据是0000_080A (Hex)。这是针对BL8事务的。如下图:app_wdf_end信号必须用于指示内存写入突发事件的结束。对于2:1模式下的8个内存突发类型,app_wdf_end信号必须在第二个写数据字上拉高。
DRAM接口数据采样,如图:
3.读时序
对于读时序没啥好说的,app_rd_data_valid输出高时,数据有效,如下图:(2:1和4:1没区别,当app_rd_data_valid为高时,接收数据就行了)