四、内存颗粒缓存,进阶之路
10.遍历DDR3内存颗粒读写循环校验
打样焊接完一批次的FPGA板后,如果板载一颗或者多颗DDR3内存颗粒,在进行FPGA逻辑开发之前,其实大家都会希望能有一个系统性的验证,可以去判断硬件上有没有问题和隐患等,看一看板子稳不稳定,靠不靠谱,在软件开发完成后,硬件能不能支持大规模批量生产。一般性地在做一些复杂的FPGA开发时,产品上板载两颗、四颗甚至更多颗DDR3内存颗粒已经是常态了,当然不同的需求和设计又会对应不同的硬件开销,在这个例程中我们去实现FPGA遍历读写DDR3内存颗粒循环校验。该例程本身也具有很好地应用价值,朋友们一方面通过这个例程的学习实践可以加深对DDR3内存颗粒读写时序的理解,另一方面也可以简单地改写代码用来确定硬件上DDR3与FPGA之间的链路是否稳定。
例程的整体功能如下:按下豌豆开发板的按键,触发开发板一次性遍历读写DDR3内存颗粒循环校验,开发板板载的DDR3芯片型号是镁光MT41J128M16JT,在上一个例程中我们也详细地阅读了其芯片手册,所对应的bank块位宽是3即BA[2:0],row行位宽是14即A[13:0],column列位宽是A[9:0],整颗DDR3的地址大小是2^3*2^14*2^10,即2^27=128M,我们需要把整个内存颗粒的所有地址都遍历读写测试一遍,进而确认硬件物料和链路整体上的可靠性。
具体校验方法是:程序中设置一次性读写DDR3内存颗粒32个突发长度的地址,先对这段地址依次写入0-31,再从写入地址中依次读取判断是否是0-31,为了更加直观地观察实验现象,在程序中我们设置了错误统计计数器。一次性读写32个突发长度的地址,先写入后读取,循环去遍历读写整个DDR3内存颗粒,如果在读操作时判断到读取的数据和写入的数据不一致,则错误统计计数器加一,最后遍历读写完成后,再把错误统计计数器的值送串口调试助手上显示。
那么如果打印的值是32'b0,则能够确认硬件物料和链路整体上是可靠的,同时开发板LED指示灯熄灭;如果打印的值不是32'b0,则这个值说明了在读写校验中具体有多少个突发长度的地址是校验错误的,同时开发板LED指示灯点亮。如图1所示是遍历DDR3内存颗粒读写循环校验设计流程图,流程图可能比文字性地描述看得更加直观具体,大家如果还有不清楚地地方对照下图查看即可。
图1 遍历DDR3内存颗粒读写循环校验设计流程图
如表1所示是ddr3_driver模块信号列表,这里和上个例程的设计大同小异,如图2所示是DDR3驱动模块的代码设计,只是有几个地方需要注意:
1. 一次性读写突发长度的地址数量由16改为32,实际上现实工程中大多数都习惯性把这个值设置成32、64、128以方便进行MIG IP核读写操作的切换,这个值太小或者太大都不合适,值太大读写切换迟钝,读写的实时性相对差些;值太小读写切换频繁,很难发挥DDR3突发性读写的优势,当然值具体取多少还是具体问题具体分析;
2. 先在32个连续突发长度的地址中写入0-31,后去读取这段地址,再判断当前突发地址内读取的数据和写入的数据是否一致,如果不一致那么错误统计计数器加一;
3. 程序中用burst_timer计数已经完成的一次性突发读写次数,即一次性突发读写计数器,所以能够用该计数器值和32次读写突发长度地址的计数器值拼接组成读写DDR3内存颗粒的读物理地址和写物理地址,具体设计请大家参考代码;
4. 当读写校验完整个DDR3内存颗粒后,即拉高一个时钟周期的ddr3_err_dout_vld指示信号,同时把ddr3_err_dout错误统计计数器的值送到下游的串口发送模块,这里直接把32位的数据送到串口发送模块,为了简单起见不经过FIFO缓存,直接由串口发送模块进行数据拆分直接把32位的数据按照4个字节,一个个字节发送出去即可。
表1 ddr3_driver模块信号列表
图2 DDR3驱动模块的代码设计
如图3所示是遍历DDR3内存颗粒读写循环校验顶层文件的例化,这里只需要把按键模块,串口发送模块以及DDR3驱动模块的相关信号例化到一起即可。
图3 遍历DDR3内存颗粒读写循环校验顶层文件的例化
如图4所示,当按下豌豆开发板按键后,即可触发FPGA进行一次DDR内存颗粒读写循环校验,短暂地间隔1-2秒钟遍历校验完成后,串口助手打印即可打印出错误统计计数器的值,朋友们可以看到遍历校验完成后,DDR3颗粒每个突发地址都读写正常。
图4 串口助手打印DDR内存颗粒读写循环校验后错误统计计数器的值