目录
一、概述
掌握Xilinx A7 FPGA芯片内已集成的用于控制SDRAM的IP核的调取和使用。
二、DDR3 SDRAM 控制器IP核的调取
1. DDR3的IP核是软核,需要占用FPGA的逻辑。
2. 在建立工程后,在“IPCatalog”里面搜索“memory interface generator”。然后按照里面的提升,一步一步的设置自己需要的IP核。
3.本设计的一些参数有:
(1)DDR3工作频率400MHz;
(2)PHY与用户端的时钟速率设置的4:1模式;
(3)控制器输入时钟200MHz;
4. 导入相应的约束文件(UCF/XDC)。
三、DDR3 SDRAM 控制器IP核的初始化
1. 每次在Controller 初始化之前,首先要进行阻抗设置、IP核自动设置、调整读写时钟相位延迟等操作,目的是为了使DDR3收发数据更加稳定。该操作被称为——自动校准。
在IP核自动校准的时候,勿进行任何操作。
具体初始化思路步骤如下:
(一)顶层源文件的建立
1.在vivado中“sources”栏中添加新的源文件——"top_ctrl",该文件即为顶层源文件;
2.打开"top_ctrl"文件进行编写。
(1)将二中调取的DDR3 SDRAM 控制器的IP 核例化到"top_ctrl"中;在实例化的模板中,以ddr3开头的信号是DDR3 SDRAM芯片引脚的变量,因此在该文件中需要将其设置为端口变量,端口变量模板在ddr_hdmi.srcs\sources_1\ip\DDR3_ctrl\DDR3_ctrl\user_design\rtl 里面的.v文件里便可以找到。
(2)然后在端口列表中再加入系统时钟和复位信号;
(3)由于系统时钟是50MHz输入的,而我们在二中调取IP核的时候选择的输入时钟是200Mhz,所以需要倍频,调取一个“clock wizard”的IP核实现50->200Mhz。再将该IP核例化到"top_ctrl"中;
(4)连接端口信号和例化模块信号;
(二)测试文件建立
1. 在“sources”栏中的“simulation sources”中添加新的仿真源文件——"tb_top";
2.打开"tb_top"文件,在该文件中需要例化顶层文件,并且需要添加DDR3的模型来用于仿真;
3. 模型文件在ddr_hdmi.srcs\sources_1\ip\DDR3_ctrl\DDR3_ctrl\user_design\sim中将.sv和.vh的模型文件复制到和新建的测试文件同一个目录下。然后测试文件需要例化的代码到sim文件夹里的.v文件中找;
4. 在测试文件中产生一个复位和50MHz的系统时钟;
(三)仿真
1. 编译vivado软件和modelsim之间关联的库;
2.启动仿真;观察信号init_calib_complete是否有拉高,如若拉高则DDR3 SDRAM控制器IP核初始化成功。
四、DDR3 SDRAM 控制器IP核的写
1. 调取的ddr3_sdram控制器的ip核给用户预留了接口,我们可以通过这些预留的接口实现对IP核的控制,我们在这个章节中实现写控制。
2.实现的思路步骤如下:
(一)知识铺垫
1.存储器接口的方案核心如图4-1所示。相关信号的作用可自行到xilinx官方下载文档进行查看。

2. 在“二”调取的IP核DDR3的PHY与用户端的时钟速率设置的4:1模式,所以app_wdf_wren和app_wdf_end信号满足如图4-2所示的关系,即app_wdf_wren=app_wdf_end。

3. 写数据与写命令之间的关系我选择数据先到,然后再启动命令。即图4-3中的模式2.

4.我创建A7_wr_ctrl模块来对IP核进行控制,控制模块框图如图4-4所示。

(二)建立新的文件并编写代码
1.在vivado中“sources”栏中添加新的文件“A7_wr_ctrl”;
2. 代码实现,在实现的过程中,要注意的一些问题:
(1)由于我是选择先来数据再给写命令,所以在wr_cmd_start信号拉高一拍以后,先是控制写数据的app_wdf_wren先拉高,然后才是控制写命令的app_en拉高;
(2)输入数据位宽为128bit,DDR3的数据位宽为16bit,burst_length系统默认最大为8,16x8刚好128bit;
(3)app_wdf_rdy和app_wdf_wren同时有效的时候才可以接收数据,同理,app_en和app_rdy同时有效才可以接收写命令进行数据的写入;
(4)为了控制app_wdf_wren和app_en的拉低,要加入data_cnt 和cmd_cnt 信号。
3.代码实现后,将其例化到顶层模块内。
(三)测试文件改写
1.对三中建立的测试文件进行改写,如图4-4中A7_wr_ctrl模块左边的信号,除了从IP核中引出来的输入信号外都要在测试文件中生成;
2.生成这些信号要用到“A7_wr_ctrl” 模块中的时钟信号和复位信号,因为该模块中的时钟信号是由IP核输出给用户端的,与FPGA 提供的时钟不同,所以要用force 语句将“A7_wr_ctrl”模块中的相应信号引入到tb测试文件中,也可以用force 语句将产生的数据、突发长度、开始、地址、掩码、模式信号输入到“A7_wr_ctrl” 模块中。
3.用task-endtask语句产生wr_cmd_start 信号和64 个128bit 的从0到63递增的数据。
(四)仿真
1.在vivado中启动仿真。
2.我在仿真中遇到的问题:
(1)仿真中出现错误:“找不到用force传输的相应的信号”。原因是因为忘记了加“force”了;
(2)发现modelsim中打印的信息中,写到DDR3的数据为“xxx”。经过查找波形图,发现top模块内的mask信号为不定态,到top模块的代码中发现,因为信号命名的问题,掩码没有信号输入。
(3)在data_req为0的时候,数据还是依然递增,但实际在此时数据是不需要的,所以数据不应该递增,而是应该保持;到tb文件中将产生数据的task-endtask语句进行了更改,加入了判断条件;
(4)应注意信号是先赋值再检测时钟上升沿还是相反,将导致波形不一样哦。先检测时钟沿再赋值可能会有延迟哦。
五、DDR3 SDRAM 控制器IP核的读
1. 读的实现与写非常相似,读的控制模块框图如图5-1所示。

从图中不难发现,他与写模块只是在数据相关的信号处理上不一样,其他均类似。
2. 由于P核DDR3的PHY与用户端的时钟速率设置的4:1模式,所以app_rd_data_valid信号与app_rd_data_end信号是一样的。
3. 先有读命令再有读数据。
4. app_en拉低的条件是读命令发完了,所以要有命令计数器,用来判断当IP核控制执行达到设计要求的读数据后,作为判断条件之一将app_en拉低。
5. rd_end的产生需要有数据计数器,数据计数器用来判断读出的数据是否满足设计要求。
6.例化到顶层模块,注意要将写控制的相关代码先注释掉,因为此刻还没有仲裁模块,有些信号是读、写共用的,没有仲裁模块的话就乱套了。就像十字路口没有红绿灯。
7.编写测试文件,仿真调试。
六、DDR3 SDRAM 控制器IP核的仲裁
1.该部分主要控制IP核的读写,决定什么时候进行写操作,什么时候进行读操作,以保证读、写不会冲突。为此,我们设计的仲裁模块,有限状态机如图6-1所示。

2. 需要输入信号rd_req和wr_req(由tb文件产生)、rd_end和wr_end,输出信号rd_cmd_start和wr_cmd_start。
3.文件步骤和前面的读写相同,仲裁代码实现也相对简单,这里介绍一下将仲裁模块例化到top顶层后信号的调整和连接,tb文件的书写:
(1)此时读写共用的信号有:命令、地址、使能、准备信号,在这四个信号中,前三个是DDR3_ctrl的输入信号,最后一个是输出信号。输出信号rdy可以“扇出”,分别给两个读、写两个模、块用,但是输入信号不可以读、写共用。因此,应分别定义读、写的命令、地址、使能信号,然后用按位或的方式输入给IP核。
assign app_en = app_rd_en | app_wr_en;
assign app_addr = app_rd_addr | app_wr_addr;
assign app_cmd = (app_wr_en == 1'b1)?app_wr_cmd:app_rd_cmd;
(2) tb文件之前是产生rd_cmd_start 或 wr_cmd_start 信号来激活相应的读、写模块。此时,我们需要产生rd_req和wr_req信号(我们设计写请求优先),由仲裁模块产生rd_cmd_start 或 wr_cmd_start 信号来激活相应的读、写模块。
注:在写tb文件时候,要先定义信号,然后才可以在initial语句中对该信号进行操作,否则仿真时候会报错相关信号未定义。
(3)可在tb中加入判断读回来的数据是否和写进去的数据相同的信号,并且使用"$display"语句打印不相同数据的个数。该信号在判断时,一定要注意再读数据有效的时候再判断,即要注意ra_data_valid信号的高低。
(4)进行仿真调试。
七、总结
1.要注意IP核DDR3的PHY与用户端的时钟速率设置4:1模式和2:1模式是不一样的,这将会影响写模块的app_wdf_wren和app_wdf_end信号、读模块的app_rd_data_valid 和 app_rd_data_end信号是否一样。
2.注意写入数据的位宽(128bit),ddr3的数据位宽(16bit),突发长度(8)之间的关系,以确定地址的增量。
3.写模块要选择合适的写数据和写命令的先后关系(先数据后命令或者数据命令同时)。
4.这里面的时钟要注意,FPGA的时钟,IP核需要和输出的时钟。
5.注意读、写模块共用的信号可以由IP核输出后进行扇出,但是不能合并输入到IP核。
6.注意信号之间的配合,在开始设计前,应仔细查阅官方文档,理解每个信号及之间的相互配合关系,这个至关重要。要学会看官方文档。