引言:本文我们介绍下Xilinx DDR3 IP核的重要架构、IP核信号管脚定义、读写操作时序、IP核详细配置以及简单的读写测试。
7系列FPGA DDR接口解决方案如图1所示。
图1、7系列FPGA DDR3解决方案
1.1 用户FPGA逻辑(User FPGA Logic)
如图1中①所示,用户FPGA逻辑块是任何需要连接到外部DDR2或DDR3 SDRAM的FPGA设计。用户FPGA逻辑通过用户接口连接到内存控制器。
1.2 用户接口(User Interface,UI)
如图1中②和③所示,用于连接用户FPGA逻辑资源和用户接口块,它提供了一个简单的本地接口,用于实现缓冲读写数据,这也是DDR3 IP核对外接口,是编写FPGA读写逻辑需要操作的接口。
1.3 内存控制器和本地接口
如图1中④和⑤所示,内存控制器(MC)的前端向UI块显示本机接口。本机接口允许用户设计提交内存读写请求,并提供将数据从用户设计移动到外部内存设备的机制,反之亦然。内存控制器的后端连接到物理接口,并处理该模块的所有接口要求。内存控制器还提供了一个重新排序选项,可以重新排序接收到的请求,以优化数据吞吐量和延迟。
1.4 物理层和物理接口
如图1中⑥所示,PHY的前端连接到内存控制器。PHY的后端连接到外部存储设备。PHY处理存储器件信号所有的排序和时序。
DDR3 PHY设计要求使用PLL模块生成各种时钟,并使用全局和本地时钟网络在整个设计中分配时钟。PHY还需要在PLL所在的同一组中例化一个MMCM。该MMCM补偿BUFG到PHY的插入延迟。
图2、DDR3时钟架构
PHY内的时钟生成和分配电路及网络驱动块大致用于四个独立的通用功能:
内部(FPGA)逻辑
写入路径(输出)I/O逻辑
读取路径(输入)和延迟I/O逻辑
IDELAY参考时钟
对于DDR3设计,IDELAY参考时钟生成需要一个MMCM。如果设计频率>667 MHz,则IDELAY参考时钟为300 MHz或400 MHz(取决于FPGA速度等级)。MIG IP核为300 MHz和400 MHz时钟生成实例化了一个MMCM。
PHY需要一个MMCM和一个PLL。PLL用于生成大多数内部逻辑的时钟、相位器的频率参考时钟,以及在多I/O Bank实现中保持PHY控制块同步所需的同步脉冲。
2.1 内部(FPGA)逻辑时钟
内部FPGA逻辑由全局时钟资源以DDR2或DDR3 SDRAM时钟频率的一半或四分之一的频率工作,这取决于MIG工具中选择的4:1或2:1模式。该PLL还输出高速DDR2或DDR3内存时钟。
2.2 写路径(输出)I/O逻辑时钟
图3、控制/地址路径时钟路径框图
由数据和控制组成的输出路径由PHASER_OUT时钟触发。PHASER_OUT为OUT_FIFO和OSERDES/ODDR的每个字节组提供同步时钟。PHASER_OUT为其相关字节组生成字节时钟(OCLK)、分字节时钟(OCLKDIV)和延迟字节时钟(OCLK_DELAYED)。这些时钟直接从频率基准时钟生成,并且彼此同相。字节时钟的频率与频率参考时钟的频率相同,分字节时钟的频率为频率参考时钟频率的一半。OCLK_DELAYED用于对DQS ODDR进行时钟设置,以实现写入DQS及其相关DQ位之间所需的90°相位偏移。PHASER_OUT还驱动写入期间生成DQ所需的信号、与数据字节组相关的DQ和DQ 三态,以及字节组OUT_FIFO的读取使能。图3和图4显示了地址/控制的时钟细节以及使用PHASER_OUT的写入路径。
2.3 读路径(输入)I/O逻辑时钟
图4、读写数据时钟路径框图
输入读取数据路径由PHASER_IN块触发。PHASER_IN块为IN_FIFO和IDDR/ISERDES的每个字节组提供同步时钟。PHASER_IN块接收相关字节组的DQS信号,并为DDR2或DDR3 SDRAM数据捕获生成两个延迟时钟:读取字节时钟(ICLK)和读取分字节时钟(ICLKDIV)。ICLK是频率基准时钟的延迟版本,其相位与其相关的DQ对齐。ICLKDIV用于将数据捕获到ISERDES中的第一级触发器中。ICLKDIV与ICLK对齐,是ISERDES中最后一列触发器的并行传输时钟。ICLKDIV还用作与字节组关联的IN_FIFO的写入时钟。移相器输入块还驱动字节组输入FIFO的写入启用(可写入)。图4显示了使用PHASER_IN读取路径的时钟细节。
2.4 延迟参考时钟
您需要始终提供200 MHz参考时钟,然后MIG使用额外的MMCM创建适当的IDELAYCTRL频率。IDELAYCTRL模块持续校准I/O区域中的IDELAY组件,以适应不同的环境条件。IP核需要外部时钟信号驱动IDELAYCTRL模块。如果PLL时钟驱动IDELAYCTRL输入时钟,则PLL锁定信号需要包含在IODELAY_CTRL.v内的rst_tmp_idelay信号,这确保了时钟在使用前是稳定的。
03、DDR3 IP核用户接口
用户接口定义如表1所示,允许通过DDR3控制器访问外部DDR3芯片。
表1、DDR3用户接口定义
4.1命令地址时序
图5、用户接口命令时序
当用户逻辑app_en信号被插入时,且app_rdy信号从用户接口(UI)被插入时,用户接口接受命令并将其写入IP核内部写FIFO。任何时候当app_rdy无效时,用户接口就会忽略该命令。用户逻辑需要将app_en与有效的命令和app_addr地址保持插入,直到如图1-74所示app_rdy有效插入。
4.2用户接口写时序
图6、4:1模式用户接口写时序(存储器突发类型=BL8)
可以发出非背靠背写入命令,如图6所示。该图描述了app_wdf_data、app_wdf_wren和app_wdf_end信号的三种情况,如下所示:
①写入数据与相应的写入命令一起插入,推荐的写入时序(BL8的后半部分)。
②写入数据在相应写入命令之前插入。
③写入数据在相应的写入命令后插入,但不应超过两个时钟周期的限制。
4.3用户接口读时序
图7、4:1模式用户接口读时序(存储器突发类型=BL8)
读取的数据由UI按请求的顺序返回,并且在以下情况下有效:app_rd_data_valid被插入(图7和图1-82)。app_rd_data_end信号表示每个读取命令突发的结束,在用户逻辑中不需要。
硬件平台:XC7Z035FFG676-2
Vivado软件:2017.4
建立DDR3测试工程,进入DDR3 MIG IP配置界面。
2.点击Next,进入下一步。
3. 创建MIG IP设计。
① Create Design 创建新设计
② Component Name,编辑MIG IP核名称,自定义
③ Number of Controller,控制器数据量,此处选择1个
③ AXI4 Interface,AXI4接口,测试工程选择Native Interface接口,不选择AXI4接口。
4. Pin Compatible FPGAs,选择IP核兼容器件,方便DDR3 IP核工程移植。此处不选择。
5.存储器选择,由于电路板板载DDR3内存,故此处选择DDR3 SDRAM。
6.Controller Options,DDR3 SDRAM配置。
① Clock Period,这个时钟为DDR3 IO接口时钟,即CK/CK#管脚时钟,图中配置为400MHz;
② PHY to Controller Clock Ratio:DDR3 IO接口时钟和DDR3 MIG IP核用户接口时钟ui_clk比例,如① Clock Period=400MHz,此处设置4:1,则,ui_clk = 400MHz/4 = 100MHz。
③ 该部分设置DDR3芯片的特性。
Memory Part,IP核给出了很多定制好的镁光系列芯片,用户可以根据自己板载DDR3直接选择,如果器件参数不能满足需要,也可以自己输出DDR3芯片相关参数,即点击Create Custom Part即可进入参数编辑页面。此处选择MT41K256M16XX-107;
Memory Voltage,设置存储器电压,板载为1.5V芯片,故此处选择1.5V;
Data Width,选择DDR3数据位宽,板载为2片16bit DDR3,共用控制和地址,组成32bit位宽数据总线,故此处选择32;
ECC,ECC校验只支持72bit位宽,故不能选择;
Data Mask,数据屏蔽位,使能后,IP核会例化相应data mask接口,此处选择使能。
④Nuber of Bank Machines,选择默认4;
ORDERING,选择默认Normal
7.Memory Options,DDR3 MIG IP配置。
①Input Clock Period,输入时钟设置,该时钟为DDR3 MIG IP核输入时钟,及IP核内部PLL源时钟,此处选择5000ps(200MHz);
②Read Burst Type and Length,读突发长度和类型,DDR3只支持突发长度BL = 8,此处选择突发类型为Sequential;
③Output Driver Impedance Control,编程输出buffer阻抗,此处选择RZQ/7;
④Controller Chip Select Pin,控制器片选信号选择,此处选择Enabel;
⑤On Die Termination(ODT),片上端接大小,此处选择RZQ/4;
⑥Memory Address Mapping Selection,存储器地址映射,此处选择{Bank,ROW,COLUMN}寻址方式。
8. DDR3 MIG IP时钟、复位、参考电压等配置。
①System Clock,系统时钟输入方式,可选选择单端、差分或者No Buffer,此处选择No Buffer;
②Reference Clock,参考时钟,可选选择单端、差分或者No Buffer或则Use System Clock,此处选择Use System Clock,即200MHz时钟;
③System Reset Polarity,IP核复位信号极性,此处选择ACTIVE LOW,即低电平复位;
④Debug Signals for Memory Controller,是否选择存储器调试接口,此处选择No;
⑤Internal Verf,是否使用内部参考电压,IP核支持DDR3参考电压输出,此处不勾选,即使用板载参考电压;
⑥IO Power Reduciton,选择IO功耗降低,此处选ON,即打开功耗降低功能;
⑦XDAC Instantiation,是否例化XDAC,此处选择Enable。
9. FPGA内部端接及DCI级联配置。
① Internal Termination Impedence,内部端接阻抗,此处选择50ohms;
②DCI Cascade,DCI级联选择,此处不勾选;
关于DCI级联参考:Xilinx FPGA时钟及I/O接口规划(二)
10.选择 Fixed Pin Out。
11.配置DDR3 SDRAM IO管脚分配。
根据原理图DDR3 SDRAM和FPGA管脚连接关系分配对应管脚。如果已有管脚.ucf文件,则可以点击“Read XDC/UCF”,选择.ucf文件,读入IO约束文件;
配置完成后,需要点击Validate,进行管脚分配验证,验证通过后,方可进行NEXT。
12.选择状态信号,此处均选择No connect,即不连接。
13. 该页给出了前面DDR3 MIG IP配置总结页,可快速浏览前面配置的参数内容。
14.选择Accept,点击NEXT。
15.点击Generate,生产IP核。
至此,DDR3 MIG IP核参数配置完毕。
根据上一小结,生成DDR3 IP核后,编写VerilogHDL代码,进行DDR3读写测试。
①控制信号及命令:读写DDR3,主要是按照4.1~4.3小结中的DDR3 IP核读写时序编写逻辑代码。
app_cmd,控制命令:3'b000为写命令,3'b001为读命令;
app_addr,读写地址,由于DDR3突发长度固定为8,故地址递增为8;
app_en,使能信号,高有效;
app_rdy,准备ok信号,表示UI接口可以接收命令数据;
app_wdf_rdy,写数据FIFO准备ok,可以写数据到DDR3;
app_wdf_wren,写数据有效信号,高有效;
app_wdf_end,表示当前写为最后一个数据,根据DDR3写时序,该信号和app_wdf_wren时序相同即可;
app_wdf_data,写DDR3数据,需要注意该接口数据位宽的计算;
app_rd_data,读出DDR3数据,该接口位宽和app_wdf_data相同;
app_rd_data_valid,读出DDR3数据有效信号,高有效。
//地址、命令及使能
assign app_cmd = (state==WRITE) ? CMD_WRITE : CMD_READ;
assign app_addr = app_addr_begin;
assign app_en = (state==WRITE) ? (app_rdy&&app_wdf_rdy) : ((state==READ)&&app_rdy);//IP核使能
//写控制及写入数据
assign app_wdf_end = app_wdf_wren;
assign app_wdf_wren = (state==WRITE) ? (app_rdy&&app_wdf_rdy) : 1'b0; //写使能
assign app_wdf_data = {
Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],
Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],
Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],
Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0],Count_64[7:0]
};//写入的数据是计数器
②DDR3读写状态机:先写入一定长度数据,然后读出对应长度数据,读完后再返回写状态。读写状态机比较简单,主要是读写地址主要增量为突发长度8。
always@(posedge ui_clk)
if(ui_clk_sync_rst&!init_calib_complete)//
begin
state <=IDLE;
app_addr_begin <=29'd0;
Count_64 <=24'd0;
end
else case(state)
IDLE: begin
state <=WRITE;
if(app_addr_begin > TEST_DATA_RANGE)
app_addr_begin <=29'd0;
Count_64 <=24'd0;
end
WRITE: begin//写DDR3
state <=(Count_64==TEST_DATA_RANGE)&&app_rdy&&app_wdf_rdy ? WAIT:state; //最后一个地址写完之后跳出写状态
Count_64 <=app_rdy&&app_wdf_rdy?(Count_64+24'd1):Count_64; // 计数写入的数据个数
app_addr_begin <=app_rdy&&app_wdf_rdy?(app_addr_begin+29'd8):app_addr_begin; //地址突发BL=8,跳到下一个(8*32=256)bit数据地址
end
WAIT: begin
state <=READ;
Count_64 <=24'd0;
app_addr_begin <=29'd0;
end
READ: begin//读DDR3
state <=(Count_64==TEST_DATA_RANGE)&&app_rdy? IDLE:state; //读完写入数据长度,切换至初始状态
Count_64 <=app_rdy?(Count_64+24'd1):Count_64; //读出数据个数
app_addr_begin <=app_rdy?(app_addr_begin+29'd8):app_addr_begin; //读地址突发BL=8
end
default:begin
state <=IDLE;
app_addr_begin <=29'd0;
Count_64 <=24'd0;
end
endcase
③DDR3管脚约束。在工程文件中,不需要手动编写约束文件,如本工程,只进行了如下管脚约束。
set_property IOSTANDARD SSTL15 [get_ports clk_100M]
set_property PACKAGE_PIN C8 [get_ports clk_100M]
这是因为在创建DDR3 MIG IP核时,已经对DDR3 SDRAM管脚进行了分配,IP核自动生成对应的约束文件,包含在IP文件目录下,工程编译综合时,会自动编译该IP的约束文件。
DDR3 IP核约束文件
④测试结果。
DDR3 写入时序及数据
DDR3 读出时序及数据