最近针对黑金的光纤开发板上的DDR3进行了代码学习及板级调试。该模块功能流程已经搞清楚,以后针对DDR3的控制模块可以直接修改调用了,哦也!
有几个需要注意的细节列举如下:
(1)整个DDR3控制模块的架构要清楚,方便以后使用(数据的产生源和消耗源);
首先说明整个DDR3的工程模块是个啥。
DDR3的模块代码层次结构如上图所示,ddr2fifo_top是DDR3模块的顶层,下分3个子模块,分别是ddr_ctrl.v、dcfifo_ctrl.v、bank_switch.v。接着说这3个子模块。
ddr_ctrl.v:包含mem_burst.v模块,该模块具体实现DDR用户接口层的操作,用户接口信号如下图所示。另外还有个MIG 的IP核调用模块,它是最底层操作DDR时序的模块,有对应的用户接口(app_xxx)留出给用户使用,该模块需要在IP catlog里生成,注意生成的设置项选择。
dcfifo_ctrl.v:封住两个FIFO,分别是wrfifo和rdfifo。其中wrfifo是数据源产生模块对接DDR的数据写入缓存,rdfifo是DDR的数据读出对接数据消耗模块的缓存。两个异步FIFO的读写位宽均设置为256bit,深度均设置为512。
bank_switch.v是DDR3的BANK切换,该代码在MIG生成时,地址方式选择的是Bank+Row+Column方式,因此在实现乒乓操作时,通过切换Bank即可。DDR3的Bank地址有3bit,即有8个bank,代码只使用了其中的4个bank,代码里是将一帧图像写在一个Bank里,一帧图像的字节总数=1280x720x2(RGB565模式),写完一帧图像后通过bank_switch来切换BANK。
下面说明数据源的产生及数据消耗模块是个啥。
数据源的产生来自OV5640的相机数据,该相机采用的是RGB565的输出模式,即一个像素点是2个字节,每次在数据产生模块(相机模块里),都是凑到32个字节,发起wrfifo的写入操作,当分辨率设置的是1280x720,因此一个Bank内的最大写入地址wr_max_addr=1280x720x2x8bit/256bit=57600。放在低位上,高位是Bank地址,如下图所示。
(2)地址递增的原因要搞清楚,若改变读写FIFO的位宽或硬线位宽,会影响递增值;
具体是在mem_burst.v模块里地址的app_addr的每次递增是8,另外在该模块的状态机初始态Idle下,每次reload 起始地址时,起始地址都做了左移3bit,即x8。这个原因要搞清楚,方便以后复用。
原因先写下,以免年纪大了又忘了。原因是因为每次突发写的长度为128,而每次从FIFO读出的数据位宽是256bit(即app_wr_data的位宽是256bit),而板上的DDR3的数据线硬线位宽是32位(2片DDR3控制线复用,数据线并用,扩展了数据线位宽),因此在一次突发写的过程中,每次app_addr需要加8(256bit/32bit=8),而当突发完一次128 length后,下一个起始地址都要加上128x8。
然而在代码里的起始地址ddr_wraddr是在dcfifo_ctrl.v模块里产生的,该地址在每次ddr_wr_finish(对应mem_burst.v模块里的wr_burst_finish信号)拉高时,地址加上128。因此到了mem_burst.v模块里需要将起始地址左移3bit,即x8。同理,读操作的地址变化也是这么个过程。
(3)为啥读写的突发长度的设置是128(1280x720的分辨率)
(4)读写FIFO的位宽是256bit,即32个字节,这个可以更改,当然更改了会影响后面的地址递增,还有硬线位宽也影响地址的递增变化;256/32bit,这个公式会变化
(5)读写地址的产生方式,这个在dcfifo_ctrl.v模块里,注意一些信号的使用技巧,可借鉴。如下图所示:
代码里的wr_flag,用来执行每次256bit数据块的写操作完成标记。写完以后拉低,重新判断wrf_use是否大于一个128长度。
(6)MIG核输出了一个时钟,phy_clk的频率是200M,根据MIG两端的带宽是匹配的,来推断出phy_clk的频率是200M。
(200Mx256bit SDR )---> MIG ---> (800Mx32bitx2 DDR)
(7)读写FIFO的计数判断,wr_fifo用的rd_cnt,rd_fifo用的wr_cnt。