软件环境:vivado 2017.4 硬件平台:XC7Z035
工程建立好以后,IP catalog里搜索mig,借用mig即Memory Interface Generator来操作PL端的DDR3。打开后如图。
component name改为ddr3。
next以后什么也不做,保持默认。
next以后,让选控制器类型,不用说,自然是DDR3 SDRAM。
next后,主要改动地方有三个,时钟、DDR型号、数据位宽都在下图用红框标出来了,这里一定要设置对,其他默认即可。
next以后,选择PLL输入时钟,我这里是200MHz。
next以后,系统时钟选择no buffer,参考时钟选择系统时钟,低电平复位有效。
next以后,DCI勾选,可以精确的匹配传输线上的特征阻抗。
next后,选择固定的引脚配置。
然后根据原理图,把对应的管脚关系添加进来。
next以后,让选择状态信号,这里保持默认。
next以后看到刚才整个过程的配置信息。
next以后,勾选accept同意条款。
next以后,点击generat,控制器就自动生成了。
然后继续添加时钟模块。输入时钟50MHz。
输出时钟200MHz。这里需要注意一下复位电平的高低,默认低电平复位,但是这模块默认的却是高,记得改一下。
还有一些测试代码,等一会儿再添加,整体的一个大致连接关系如下图所示。
左侧是用户操作的接口,中间相当于是MIG控制器,右边就是DDR了。 管脚的定义如下表,这里只关心用户接口部分。
引脚名称 |
引脚方向 |
备注 |
app_addr |
input |
要操作地址每次step为8 |
app_cmd |
Input |
写000/读001 |
app_en |
Input |
使能信号 |
app_wdf_data |
input |
写入的数据[255:0] |
app_wdf_end |
input |
last |
app_wdf_wren |
input |
写使能 |
app_rd_data |
output |
读出的数据[255:0] |
app_rd_data_end |
output |
最后一行一个上升沿last |
app_rd_data_valid |
output |
读有效 |
app_rdy |
output |
|
app_wdf_rdy |
output |
|
app_sr_req |
input |
0 |
app_ref_req |
input |
0 |
app_zq_req |
input |
0 |
app_sr_active |
Output |
|
app_ref_ack |
Output |
|
app_zq_ack |
Output |
|
ui_clk |
output |
Usr的always时钟 |
ui_clk_sync_rst |
output |
Usr的复位信号 |
app_wdf_mask |
input |
Keep信号 |
|
|
|
sys_clk_i |
input |
直连板子时钟 |
clk_ref_i |
input |
直连板子时钟 |
sys_rst |
input |
直连板子系统复位 |
操作DDR,要么写,要么读,当处于写状态时。
在app_rdy(DDR3控制)与app_en(用户控制)同时拉高时,写地址app_addr有效。同理,app_wdf_rdy(DDR3控制)与app_wdf_wren(用户控制)同时拉高时,写数据app_wdf_data有效。值得注意的是:DDR允许写使能信号提前cmd一个,或者落后cmd两个时钟后期之内。但是还是建议写的数据和地址都在一个周期之内。
当处于读状态时。
相对于写来说,读就简单的多了, 下几个周期的app_cmd读指令,发几个app_addr读地址,保持几个app_en使能,就会有多少个数据传回来。
最后还有一点需要注意,在最开始设置用户时钟和DDR输入时钟的时候,选的1:4,所以用户每个时钟动作时候,DDR动作四次了,而DDR是在时钟的上升沿和下降沿都可以进行数据操作,当数据宽度32 bits的时候,用户单次突发传输理论的位宽=4*2*32 bits = 256 bits,这也是很多verilog里都有2 * nCK_PER_CLK * PAYLOAD_WIDTH的原因,至少我是这么理解的。
添加DDR3时序控制文件、DDR3用户接口文件和顶层文件之后,在线跑即可看到下面时序图。
展开可以看到,突发传输128,数据每次增加1。单次传输256bits。跟测试文件中参数设置的是一样的。
代码就不直接贴了吧,琢磨琢磨是扔github上,还是扔优快云上,方便管理一点,要么每篇博客都贴代码,太零碎了。