PL端DDR3读写(1)
1、范围
前面让团队小伙伴仿照米联客教程测试了一下,后面似乎读写有时候有误码,后期小伙伴离职,这个事情就不了了之。最近工作又需要对PL端DDR3进行读写,于是亲自对这一部分进行详细测试论证。该文档用来描述如何读写PL端DDR3、形成统一的接口模块,最后在实际板卡中对DDR3进行功能及性能验证测试。
2、基本概念
2.1、DDR3
目前主流的DDR有DDR3、DDR4和DDR5,DDR属于SDRAM一类的数据存储器,它是一种同步动态存储器,断点数据会丢失。DDR是Double Date Rate的英文缩写,后面数值表示第几代,例如DDR3表示第三代DDR,数值越高表示性能越好。市面上常用的DDR3来自美光的MT41K系列,在贸泽上搜索价格在二十多元。找到美光手册,如下:
可以看到有三个型号,分别为MT41K1G4、MT41K512M8、MT41K256M16,三种型号的容量均为4Gb。4、8和16表示数据线位宽,1G、512M和256M由bank地址、行地址和列地址位宽共同决定,具体如下所示:
同样的数据容量不同的后缀代表不同的速率。
2.2、硬件设计
DDR3供电电压一般为1.5V,如果是在PS端接入DDR3,则固定接在BANK502端,需要将管脚一一对应。例如PYNQ中接入的DDR3连接如下所示:
如果想用两块DDR3扩展出1GB容量,将BANK502高16位的数据线接在另外一块DDR中,DM和DQS接在2、3接口,其他连线两块DDR共接。 当PL端接入DDR3时,需要注意DDR管脚连接关系,应尽量用MIG IP推荐的连接管脚。
3、FPGA设计
本设计实现的功能为基于MIG 完成对DDR3读写操作,最后对读写数据进行校验。DDR3读写有两种工作方式:FIFO模式和RAM模式。在FIFO模式,DDR3可以理解为超大的FIFO,当没有写数据时,禁止读数据。例如当写入10个字节数据,在读取10个数据以后,再读数据时,输出数据内容为0,并将空标志拉高。在RAM模式时,可以允许反复读数据。例如当写入10个数据时,当读取10个数据以后,再读取第11个数据时,将重复读取第1个数据。
3.1、管脚约束
DDR的管脚约束为DDR3.ucf文件,具体将原理图与文件内容进行一一对应就行。
3.2、IP配置
在工程中增加MIG IP,具体步骤如下所示:
a) 选择IP
时钟选择为800MHz,根据板卡硬件选择DDR型号,由于有两片拼接,所以位宽选择为32。
选择系统时钟和参考时钟为no buffer,选中DCI cache
点击Read XDC/UCF,选择前面修改的约束文件,点击Validate,就可以选择Next。
b) 例化IP
mig_7series_0模块对外接口,时钟关系如下图所示,本部分参考其他博客:
如上图,包含了四个时钟:
1)系统时钟,即MIG核工作时钟,通常命名sys_clk;
2)参考时钟,即MIG核参考时钟,通常命名ref_clk,必须是200MHz;
3)DDR芯片工作时钟,由FPGA输出给DDR的差分时钟,可以命名ddr_clk;
4)用户时钟,MIG核输出给用户端的时钟,通常命名ui_clk。
注意1:ddr_clk与ui_clk有比例关系,ddr_clk:ui_clk = 4:1或2:1,当ddr_clk=800MHz时,只能是4:1。
注意2:用户数据位宽如何计算,例如ddr_clk=800MHz时,ui_clk = 200MHz,ddr物理位宽为16bit(2片ddr菊花链连接就是32bit),上下沿采集(2倍),因此用户数据位宽=800*32*2/200=256bit。
注意3:256bit/32bit=8,所以ddr用户地址每次加8。
注意4:app地址位宽:
ADDR_WIDTH = RANK_WIDTH + BANK_WIDTH + ROW_WIDTH + COL_WIDTH
通过UG586可知RANK_WIDTH默认为1,查看DDR手册可以知道BANK_WIDTH为3,ROW_WIDTH为15,COL_WIDTH为10,所以app_addr位宽为29。
序号 | 信号名称 | 位宽 | 方向 | 说明 |
1 | ddr3_dq | 32 | IO | 与DDR连接 |
2 | ddr3_dqs_n | 4 | IO | |
3 | ddr3_dqs_p | 4 | IO | |
4 | ddr3_addr | 15 | O | |
5 | ddr3_ba | 3 | O | |
6 | ddr3_ras_n | 1 | O | |
7 | ddr3_cas_n | 1 | O | |
8 | ddr3_we_n | 1 | O | |
9 | ddr3_reset_n | 1 | O | |
10 | ddr3_ck_p | 1 | O | |
11 | ddr3_ck_n | 1 | O | |
12 | ddr3_cke | 1 | O | |
13 | ddr3_cs_n | 1 | O | |
14 | ddr3_dm | 4 | O | |
15 | ddr3_odt | 1 | O | |
16 | sys_clk_i | 1 | I | 系统时钟,频率为200MHz |
17 | clk_ref_i | 1 | I | 参考时钟,频率为200MHz |
18 | app_addr | 29 | I | 地址输入 |
19 | app_cmd | 3 | I | 读写控制命令0:写 1:读 |
20 | app_en | 1 | I | 命令写入使能,高有效 |
21 | app_wdf_data | 256 | I | 写数据 |
22 | app_wdf_end | 1 | I | 突发写最后一个时钟 |
23 | app_wdf_mask | 32 | I | 写数据掩码 |
24 | app_wdf_rdy | 1 | O | 写DDR准备完成,高有效 |
25 | app_rd_data | 256 | O | 读数据 |
26 | app_rd_data_end | 1 | O | 突发读最后一个时钟 |
27 | app_rd_data_valid | 1 | O | 读数据有效 |
28 | app_rdy | 1 | O | 读写接收准备完成,高有效 |
29 | app_sr_req | 1 | I | 保留位 |
30 | app_ref_req | 1 | I | 刷新请求 |
31 | app_zq_req | 1 | I | ZQ校准请求 |
32 | app_sr_active | 1 | O | 保留位 |
33 | app_ref_ack | 1 | O | 刷新响应 |
34 | app_zq_ack | 1 | O | ZQ校准响应 |
35 | ui_clk | 1 | O | 用户时钟 |
36 | ui_clk_sync_rst | 1 | O | 复位,高电平 |
37 | init_calib_complete | 1 | O | IP初始化完成标志,高电平有效 |
38 | device_temp | 12 | O | |
39 | sys_rst | 1 | I | 低电平复位 |
3.3、时序与流程
a) 命令操作时序
当用户逻辑app_en信号被断言且app_rdy信号从MIG被断言时,MIG接受命令。每当app_rdy被取消断言时,MIG将忽略该命令。用户逻辑需要将app_en与有效命令和地址值沿着保持为高电平,直到app_rdy被断言,如下图所示:
只有当app_rdy 与 app_en同时为高时,命令和地址才会被写入到MIG,如图红色的位置,这类似于AXI里的握手信号。
b) 写数据
首先需要检查app_wdf_rdy,该信号为高表明此时IP核数据接收处于准备状态,可以接收用户发过来的数据,在当前时钟拉高写使能(app_wdf_wren),同时给出写数据这样加上发起的写命令操作就可以成功向IP核写数据,具体时序如下图所示:
如上图所示,写数据有三种情形均可以正确写入:
- 写数据时序和写命令时序发生在同一拍
- 写数据时序比写命令时序提前一拍
- 写数据时序比写命令时序至多延迟两拍
c)读数据
用户发出读命令后,用户只需等待数据有效信号(app_rd_data_valid)拉高,为高表明此时数据总线上的数据是有效的返回数据,有效读数据要晚若干周期才出现在数据总线上。如下图所示:
至此已经完成vivado中DDR的配置和相关基础知识的了解。后续需要自己根据app信号的时序关系,编写对应的控制信号。网络上有很多,但是似乎直接能用的并不多。下一文档详细编写如何编写app控制时序。同时ug586似乎在xilinx官网无法下载,这里将ucf文件和ug586上传到CSDN,可以免费下载:https://download.csdn.net/download/weixin_39813867/91008302