在做嵌入式开发过程中“内存”仿佛是无处不在。DDR3颗粒作为当前较为常见的一种储存器,在计算机和嵌入式产品中得到广泛应用,尤其是在涉及到大数据量交互的场合,在FPGA领域比如视频加速处理、AD高速采集、PCIE上位机开发、SFP万兆光口传输等,几乎都能看到DDR3的身影,XILINX也为用户提供了MIG IP核方便实现对DDR3颗粒数据读写的二次开发,但市面上却鲜有不错的教程能快速带领大家入门上手,所以在这一章中笔者选取了两个经典的例程,通过它们就可以很好地去掌握MIG IP核的使用技巧。
DDR3是DDR SDRAM的第三代产品,有着更快地运行速度和更低地存储电压,同早期的SDRAM相比DDR3具有双沿触发的绝对性优势,即在时钟的上升沿和下降沿都能进行数据采集和发送,所以DDR3的读写速度比传统的SDRAM要翻一番。
如图2所示是豌豆开发板Artix7上DDR3内存电路,选用经典的镁光MT41J128M16JT DDR3内存颗粒,该颗粒也是典型的BGA封装,阅读芯片手册如图1所示是MT41J128M16J的地址空间分配说明,其中可以清晰地看到,对应的bank块位宽是3即BA[2:0],row行位宽是14即A[13:0],column列位宽是A[9:0],所以整颗DDR3的地址大小是2^3*2^14*2^10,即2^27=128M,数据线的位宽是16bit,总的容量大小即为128M*16bit,下面笔者首先为朋友们简单地介绍一些DDR3硬件设计上的知识。
图1 MT41J128M16J的地址空间分配说明
市面上存在一些FPGA的付费教程,也会大致地介绍关于FPGA控制DDR3内存读写的方法,但大部分只是就事论事,仅仅告诉大家MIG IP核的读写逻辑,然后附带MIG IP核的配置和一些demo例程。这样做单纯从写FPGA教程的角度来说问题不大,可以帮助读者从完全不懂到简单了解,但笔者个人还是觉得应该把DDR3一些硬件上的知识也搞清楚,这样才有助于建立一个完整的知识体系。
因为从工作角度说,大家在做研发的路上永远都是一个遇到新问题并解决新问题的过程,仅仅看到工作的某一部分,或者说长期把自己局限在产品的某一区域,其实也非常不利于个人的成长,在离开特定的资源平台后,就会发现容易缺乏市场竞争力,所以多了解一些周边的知识比如在清楚了下层PCB选型设计和上层ARM系统进程,这时候再从产品稳定性和易用性的角度看产品中的FPGA设计,便会对整个产品设计有着更深层次的理解,随着工作不断地学习积累,掌握了某一领域或者某一产品的核心技术,不可替代性越来越高,自然而然地社会竞争力也越来越大。
简答地就工作积累为大家谈谈DDR3上的PCB设计,说到DDR3的硬件设计,就不得不说起几个核心的知识点:读写位宽、布局拓扑、同组同层、阻抗匹配、蛇形等长,朋友们在了解过这些背景知识后,再去看MIG IP核的读写逻辑也会有更深刻地理解!
1. 读写位宽,对于很多FPGA工程师,因为本身没有系统性学习PCB设计方面的知识,所以工作后对DDR3内存颗粒芯片选型和工作原理上依然很模糊。在配置MIG IP核的时候,如果实际操作过的朋友应该会记得有选择DDR3读写位宽的选项(在这个例程中笔者也会配图进一步说明),大部分教程会直接告诉读者,选16位的或者选32位的甚至64位的,那为什么要这么选择呢?
如图2和图3所示分别是豌豆Aritx7开发板、黑金Aritx7开发板中对DDR3内存颗粒硬件设计的原理图(可能截图比较小不太方便看清楚),对比可以发现这里都用到了TPS51200经典的德州仪器DDR3供电芯片,也按照DDR3设计规范添加了滤波电容。
其中图2中用了一颗镁光DDR3颗粒,即DDR3_DQ数据线是16根,而图3中用了两颗镁光DDR3颗粒,即DDR3_D数据线是32根,所以在MIG IP核的配置中分别选择了读写位宽16位和32位。另外细心的同学可能会发现图3相对于图2多一排端接电阻,这里主要是为了抑制PCB板上多颗DDR3颗粒之间地址线的信号反射,通过增加端接电阻可有效减少地址线上的信号反射,而单颗DDR3颗粒因为layout布局时不涉及拓扑结构则不需要在地址线上额外添加端接电阻。
图2 豌豆开发板Artix7上DDR3内存颗粒电路
图3 黑金开发板Artix7上DDR3内存颗粒电路
2. 布局拓扑,对于多颗DDR3颗粒的layout布局中,典型地分为有T点和FLY-BY菊花链拓扑,这里不展开具体的细节介绍,因为其本身不是这个例程的重点,但简单地说明一点,也许会对大家以后的PCB设计有所帮助,也是工作中的积累和总结。
硬件上对于T点拓扑来说几乎支持所有CPU类型,但layout时布局布线相对烦琐,且最多支持四颗DDR3颗粒互联;而相反的FLY-BY拓扑,layout时布局布线则比较简单,且可以支持很多颗DDR3颗粒互联,但该拓扑结构不满足CPU不支持读写平衡的情况,所以大家在硬件的设计时需要认真阅读芯片手册,针对具体产品需求评估好SOC芯片选型和所需外扩DDR3内存颗粒的大小和数量。
具体来说对于一个项目的FPGA设计,选型DDR3颗粒时,主要应该考虑两方面因素,即数据位宽和存储深度,前者决定了瞬时读写速度,显然2颗DDR3颗粒32位位宽会比1颗DDR3颗粒16位位宽,在每个时钟下的读写速度快一倍;后者则决定了缓存数据容量,一般没有特殊需求的情况下,直接选用豌豆开发板板载的这颗镁光MT41J128M16JT DDR3内存颗粒,256Mbyte的存储容量即可满足绝大多数设计,这个容量相当于可以存储常见地RGB565格式下1024*768分辨率的图像340幅。
3. 同组同层,对于DDR3的布线,在硬件设计的过程中,对于数据线一定要满足同组同层的设计要求,举例来说如图4-2所示1颗DDR3颗粒,在layout设计的时候,应该注意将DDR3_DQ0-7、DDR3_DQS0_P、DDR3_DQS0_N、DDR3_DM0以及DDR3_DQ8-15、DDR3_DQS1_P、DDR3_DQS1_N、DDR3_DM1每组11根数据线布线在同一层。
4. 阻抗匹配,对于一些低速信号,大家可以认为只要layout时候拉通即可,用8mil线可以,用6mil线也可以,但对于DDR3布局布线的硬件设计,我们需要把阻抗匹配做扎实,才能保证其硬件运行稳定,即单线50ohm,差分100ohm。
5. 蛇形等长,做过硬件设计的朋友们都会知道DDR3的布线设计中需要做等长设计,行业标准是3W原则,所以在layout之前应该留下一些空间余量方便绕线时使用,同时也规划好布局拓扑,笔者经验一般是先把同组同层的数据线先拉到BGA上,接着再拉地址线这样比较方便后期调换过孔、调整走线。
在简明扼要地介绍完DDR3设计上的硬件知识后,我们再来详细阅读XILINX官方所提供的ug586_7Series_MIS手册,不同前面例程中我们直接用verilog代码去驱动IC,感兴趣的同学可以浏览一下镁光MT41J128M16 DDR3颗粒的芯片手册,其实DDR3内部的时序相比于传统的SDRAM来说,整体上变得更加复杂,如果直接手写代码去直接驱动DDR3内存颗粒,那么工作量将是非常巨大的,XILINX官方为此专门提供了MIG IP核去方便用户二次开发DDR3控制器,这就最大限度地减少了用户的开发难度。
使用MIG IP 核,用户可以在不熟悉DDR3底层驱动逻辑的情况下,实现灵活地操作DDR3大批量数据读写的效果,但用户也必需严格遵照MIG IP核所规定的时序来编写代码,这样才保证整个项目中对DDR3读写操作的正确性和实时性。
如图4所示是XILINX 7系列的MIG IP核内部结构框图,其中集成存储器控制模块,实现DDR读写操作的控制流程,大家可以看到MIG IP核对外又划分出了两组接口:左侧是用户接口,即用户侧所编写的代码与MIG IP核交互接口,而右侧为DDR物理芯片接口,负责产生具体的操作时序,并直接操作芯片管脚,以达到硬件上控制DDR3颗粒读写的效果。
如图5所示是MIG IP核的接口说明,图中给出了MIG IP核用户侧的接口信号和细节说明,从表中可以看到MIG IP核用户侧接口数量共20多个,猛地一看感觉很复杂,大家也不用对此心生畏惧,实际上只需要了解常用的一些重要接口即可,而并不用去关心所有的。因为XILINX官方推出IP核需要考虑到很多使用场景,所以为了让IP核更具有普遍应用性就把对外接口做得很复杂,如表1所示,笔者把常用的MIG IP核接口信号整理出来,供大家查阅。
图4 MIG IP核内部结构框图
图5 MIG IP核的接口说明
信号名 |
I/O |
接口说明 |
ui_clk |
O |
用户时钟,由MIG IP核输出 |
ui_clk_sync_rst |
O |
复位高电平有效,由MIG IP核输出 |
init_calib_complete |
O |
初始化完成高电平有效,标志DDR3芯片初始化完成 |
app_addr [ADDR_WIDTH-1:0] |
I |
用户地址输入,这是MIG IP核根据具体DDR3颗粒的型号所给出用户可使用的地址空间,该地址对应芯片的物理地址,其颗粒的物理位宽ADDR_WIDTH = RANK位宽 + BANK位宽 + ROW位宽 + COL位宽 |
app_en |
I |
MIG IP核写入使能,高电平有效,写命令时拉高该信号 |
app_cmd[2:0] |
I |
读写控制命令,其中读:001;写:000 |
app_rdy |
O |
MIG IP核读写地址命令接收的准备完成,高电平有效 |
app_wdf_wren |
I |
MIG IP核数据写使能,高电平有效,向MIG IP核写数据时拉高该信号 |
app_wdf_rdy |
O |
MIG IP核数据接收的准备完成,高电平有效 |
app_wdf_end |
I |
当前时钟是突发写过程的最后一个时钟,高电平有效 |
app_wdf_data [APP_DATA_WIDTH-1:0] |
I |
该信号为用户写数据输入,这里位宽设置是128,因为 DDR3的burst值默认最少是8位即DDR3地址加减操作至少以8位作为最小单位,并且1颗DDR3的数据位宽为16bit,也意味着每次读写长度最少是8*16bit=128bit |
app_rd_data [APP_DATA_WIDTH–1:0] |
O |
该信号用于用户读取IP核发来的数据,位宽设置128 |
app_rd_data_valid |
O |
读数据的有效信号,高电平有效 |
表1 MIG IP核用户接口常用信号的定义
如图6所示是MIG IP核的读写地址时序逻辑示意图,其中DDR3的读写数据操作中都应包括读写地址操作,即指定读写数据操作所对应的DDR3颗粒中物理地址,对于读写地址操作有以下几点需要注意:
1. 写地址操作中app_cmd的值等于0,读地址操作中app_cmd的值等于1;
2. 在读写地址操作时,对于用户端app_rdy为输入,app_addr、app_cmd、app_en均为输出;
3. 在读写地址操作时,用户端则需要去判断app_rdy输入信号,该信号为高则代表此时MIG IP核读写地址命令的接收处于准备就绪状态,在当前时钟拉高app_en写入使能,同时发送读写命令app_cmd和地址app_addr即可。
图6 MIG IP核的读写地址时序逻辑
如图7所示是MIG IP核的非连续性写数据时序逻辑示意图,大家可以看到官方手册上标明了下面几种写入的情况:1. 写数据时序和写命令时序发生在同一拍;2. 写数据时序比写命令时序提前一拍;3. 写数据时序比写命令时序至多延迟晚两拍,所以结合图4-7,可以把MIG IP核的写数据时序总结如下:判断app_wdf_rdy输入信号,该信号为高则代表此时MIG IP核数据接收处于准备完成状态,可以接收用户发过来的数据,在当前时钟去拉高app_wdf_wren写数据使能,同时发送写数据app_wdf_data,配合写地址操作即向MIG IP核的指定地址中写入了数据。
这里有两个信号值得大家去注意:1. app_wdf_mask:该信号是用来屏蔽写入数据的,信号为高则屏蔽相应的字节,一般该信号默认设置成0代表不屏蔽任何字节;2. app_wdf_end:当前时钟是突发写过程的最后一个时钟,该信号从用户端输入到控制器。而当MIG IP核默认突发长度为8时,该信号与写使能信号app_wdf_wren相同。
实际上MIG IP核读写操作都分为连续性读写和非连续性读写,如图4-7和如图4-8所示,分别对应非连续性写入和连续性写入两种,两者的区别仅在于非连续性写入中间存在间隔,而连续性写入中间没有间隔,而对于连续性写入则没有最大延迟的限制,一般情况下,为了充分发挥DDR3内存颗粒突发读写的优势,项目工程中如果要大批量数据的缓存读写,均采用连续性读写的方式,在例程实战中我们也用到连续性读写。
图7 MIG IP核的非连续性写数据时序逻辑
图8 MIG IP核的连续性写数据时序逻辑
相比而言MIG IP核的读数据时序逻辑比较简单,如图9所示分别是MIG IP核的非连续性和连续性读数据时序逻辑,用户只用等待输入app_rd_data_valid数据有效信号被拉高时读取app_rd_data数据即可,该信号为高则代表此时数据总线上数据是有效的,同时需要注意的是在连续性读数据时,读到数据的顺序和请求读地址的顺序是相互对应的。
图9 MIG IP核的读数据时序逻辑
在分析完MIG IP核的读写逻辑后,还需要补充一些FPGA输出输入引脚常用的电平知识,搭配前面介绍的DDR3内存颗粒硬件设计方面知识,帮助朋友们更全面地理解对DDR3的读写操作,同时也建立起更加全面的知识体系。
如图10所示是DDR3内存颗粒连接豌豆开发板Bank15的电路图,大家可以清楚地看到整个DDR3内存颗粒包括地址线、数据线、时钟线、复位线等所有相关引脚都连接到了Artix7芯片的Bank15上。
如图11所示是豌豆开发板对不同Bank供电的电路图,开发板由5V适配器供电,再通过板载的DC/DC芯片分压不同电压如3.3V、1.8V、1.5V、1.0V后供电给相关引脚,对Bank14、Bank15、Bank34、Bank35可以看到不同Bank使用了不同供电电压,比如Bank14、Bank34、Bank35都使用了3.3V供电,而Bank15则使用了1.5V供电,这里需要说明的是对Bank供电电压直接决定了该Bank上引脚输入输出电平的种类,通常情况下会对Bank用3.3V电压供电,因为绝大多数外设都可用标准的LVCMOS33电平去驱动,不过也是具体情况具体分析,比如在做LVDS开发时,需要将对应的Bank用2.5V电压供电,在接DDR3内存颗粒时,则需要将对应的Bank用1.5V电压供电。
图10 DDR3内存颗粒连接豌豆开发板Bank15的电路图
图11 豌豆开发板对不同Bank供电的电路图
感兴趣的朋友们可以在动手实践完整个例程后,打开mig_7series_0.xdc文件,该文件是我们配置完MIG IP核后环境自动生成的,其中记载了DDR3内存颗粒的引脚约束,所以在整个例程的.xdc文件中,我们无需再对DDR3引脚进行重复约束。大家打开mig_7series_0.xdc文件,可以看到MIG IP核对DDR3内存颗粒中的差分信号如:ddr3_ck_p和ddr3_ck_n、ddr3_dqs_p[0]和ddr3_dqs_n[0] 、ddr3_dqs_p[1]和ddr3_dqs_n[1]使用了DIFF_SSTL15电平定义;对复位信号ddr3_reset_n则用了LVCMOS15电平定义;对其他引脚都用了SSTL15电平定义,所以在这里简单地解释下三种电平信号的区别:
1. LVCMOS学名是低压互补金属氧化物半导体,特点是噪声容限大,而速度相比于SSTL较慢;
2. SSTL学名是短截线串联端接逻辑,SSTL速度快,通常要匹配合适的端接电阻,常用于高速内存接口如DDR3;
3. DIFF_SSTL学名是差分短截线串联端接逻辑,则是带有差分功能的SSTL。
下面笔者为大家详细介绍MIG IP核的初始化配置,并截图详细地说明重要选项和界面的含义,从而帮助大家快速上手入门,在此基础上快速实现二次开发。
如图12所示,选择Vivado的IP Catalog选型,并在搜索栏中搜索MIG IP核,即会弹出如图13所示的MIG IP核的芯片类型概况界面,主要是让用户来确认工程信息、芯片信息和编译环境信息等,这里直接Next即可。
如图14所示是MIG IP核顶层配置界面,直接选择“Create Design”,并在“Component Name”一栏设置该IP元件的名称,这里取默认软件的名称即可,选择控制器数量,默认为“1”,最后关于AXI4接口,因为大部分工程中并不使用,所以默认情况下都不勾选。
如图15所示是FPGA芯片管脚兼容设置界面,主要是让用户选择可以兼容的芯片类型,大部分情况下默认不勾选,即不需要兼容其他的FPGA芯片。
如图16所示是MIG IP核存储类型选择界面,其中选择第一个选项“DDR3 SDRAM”即可,因为豌豆开发板本身板载的便是DDR3芯片颗粒。
图12在Vivado的搜索栏中搜索MIG IP核
图13 MIG IP核的芯片类型概况界面
图14 MIG IP核顶层配置界面
图15 FPGA芯片管脚兼容设置界面
图16 MIG IP核存储类型选择界面
如图17 所示是MIG IP核时钟和物理属性配置界面,其中有一些关键性的配置选项需要加以说明,加深大家对DDR3内存颗粒配置细节上的理解:
Clock Period:DDR3芯片运行时钟周期,该参数的范围和FPGA的芯片类型和具体类型的速度等级有关,在这个例程中选择2500ps即对应了400M的时钟频率,这和选取的FPGA芯片速度等级有关,但这个时钟是MIG IP核内部产生输出给DDR3内存颗粒使用,这关系到DDR3芯片具体的运行带宽,比如在豌豆开发板上板载一颗MT41J128M16JT DDR3内存颗粒,数据位宽总共16位,且双沿触发,则带宽达到了800M*16bit=12.8Gb/s。
PHY to Controller Clock Ratio:DDR3内存颗粒运行时钟和MIG IP核的用户端时钟之比,有4:1和2:1两个选项,一般默认均为4:1。比如DDR芯片的运行时钟是400Mhz,MIG IP核的用户时钟ui_clk即为100Mhz。且当DDR3时钟选择350Mhz以上,比例默认只有4:1,只有当选择时钟低于350Mhz才有4:1和2:1两个选项。
Memory Type:DDR3内存颗粒类型选择。其中默认选择Component。
Memory Part:DDR3芯片的具体型号。这里选择MT41J128M16XX-125,即对应豌豆开发板板载的镁光MT41J128M16JT DDR3内存颗粒型号。
Memory Voltage:DDR3内存颗粒的电压选择,默认均为1.5V标准电压。
Data Width:数据位宽选择,这里选择16。
ECC:校验使能,数据位宽为72位的时候才能使用,大部分情况下默认不使用。
Data Mask:数据屏蔽管脚使能。选择后会产生屏蔽信号,默认选择即不生产屏蔽信号。
Number of Bank Machines:Bank Machine的数量是用来对具体的每个或某几个来单独控制的,选择多了控制效率就会高,相应的占用的资源也多,默认选择4个。
ORDERING:该信号用来决定MIG控制器是否可以对它收到的指令重新排序,选择Normal则允许,Strict则禁止,默认选择Normal,从而获得更高效率。
图17 MIG IP核时钟和物理属性配置界面
如图18所示是MIG IP核储存器配置界面,同样的也有一些关键性的参数需要详细地说明下:Input Clock Period:MIG IP核的系统输入时钟周期,该输入时钟是由用户端即FPGA去产生的,这里默认的时钟周期是5000ps即频率是200Mhz。
Read Burst Type and Length:突发类型选择,突发类型有顺序突发和交叉突发两种类型,默认选择Sequential顺序突发,其突发长度固定是8,所以在读写位宽是16 bit的情况下,读写操作最小操作地址是8的整数倍即为128bit,这里也就解释了在后续程序设计中,对于连续性读写操作,为什么每次读写地址都以8为最小单位进行递增。
Output Driver Impdance Control:输出阻抗控制,默认选择RZQ/7。
Controller Chip Select Pin:片选管脚引出使能。这里选择disable,即不把DDR3内存颗粒的片选信号cs#引出来改用外部控制器驱动,这是由硬件原理图设计所决定的,因为在原理图设计中并没有把DDR3内存颗粒的cs#引到FPGA的引脚上。
RTT:终结电阻,可进行动态控制,默认选择RZQ/2。
Memory Address Mapping Selection:寻址方式选择。这里选择第二种,即BANK-ROW-COLUMN的形式,也是一种最常规的DDR3寻址方式,即要指定某个地址,先指定bank,再指定row,最后指定colunm,也就唯一性地确定了一个物理地址。通常这样寻址方式有利于降低功耗,但是读写性能上不如“ROW_BANK_COLUMN”。
图18 MIG IP核储存器配置界面
如图19所示是MIG IP核系统时钟配置界面,一些关键性参数说明如下:
System Clock:MIG IP核输入时钟。一般默认选择“No Buffer”, MIG IP核的输入系统时钟是单端时钟,是由内部的MMCM产生的,而MMCM所产生的时钟默认添加了buffer。
Reference Clock:MIG IP核参考时钟。用户同样可以选择“No Buffer”则参考时钟将由时钟模块生成,也可以选择“ Use System Clock”选项,这时候MIG IP系统时钟同时作为了参考时钟,IP核参考时钟要求是200Mhz,而MIG IP核的系统时钟刚好也使用了200Mhz的系统时钟。
System Reset Polarity:复位有效电平选择,默认选择“ACTIVE LOW”低电平有效。
Debug Signals Control:该选项代表控制MIG IP核是否把一些调试信号引出,它会自动添加到ILA,这些信号包括一些DDR3芯片的校准状态信息。一般默认选择“OFF”,不需要让IP核生产各种调试信号。
Sample Data Depth:采样深度选择,当“Debug Signals Control”选择“OFF”时,所有采样深度是不可选的。
Internal Vref:内部参考管脚,表示将某些参考引脚当成普通的输入引脚来用,选择 “OFF”和“ON”都可以。
IO Power Reduction:IO管脚节省功耗设置。默认选择“ON”开启。
XADC Instantiation:XADC模块例化。使用MIG IP核运行的时候需要进行温度补偿,可以直接选择XADC模块的温度数据引到MIG IP核来使用,默认选择“Enable”。
一路Next到如图22所示的MIG IP核引脚配置界面,这里支持外部导入通过xdc文件导入引脚配置,这里笔者为大家准备好了DDR3与FPGA引脚连接的xdc文件,直接选择“Read XDC/UCF”即可,导入过后选择“Validate”系统则会自动检查是否正确,完成后一路Next完成整个MIG IP核的初始化配置。
图19 MIG IP核系统时钟配置界面
图20 MIG IP核扩展选型界面
图21 MIG IP核“Pin/Bank Selection Mode”选项界面
图22 MIG IP核引脚配置界面
图23 MIG IP核配置信息汇总界面
图24 MIG IP核仿真选项卡界面
图25 MIG IP核Design Notes选项卡界面