提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
上一篇,我们生成了一个example,example的测试激励看起来都比较复杂,仿真先不看,实际上,这个example稍加改动就可以直接上板了。这里我们就是查看MIG IP输出的init_calib_complete信号
init_calib_complete是DDR3初始化成功的指示信号,所有的读写操作都必须等待该信号拉高。因此,我们example的内容什么都不改,只改必要的接口时钟,直接上板是否init_calib_complete能够拉高,如果直接上板能够拉高,那么表示DDR3正常工作了,给自己树立极大的信心。
只要改 mig_7series_0模块的两个输入
一个sys_clk_i
一个sys_rst
简单吧,一个系统时钟,需要输入200M,一个复位。
因为板载是100M时钟,这里需要一个PLL把它变成200M,然后把PLL lock信号作为sys_rst不就O了么,很简单呢
example_top文件,注释掉sys_rst,将剩下三个端口绑定管脚,tg_compare_error和init_calib_complete直接连接到两个灯上面
input sys_clk_i,
output tg_compare_error, // LED1
output init_calib_complete // LED2
// input sys_rst
create_clock -period 10.000 -name sys_clk_i -waveform {0.000 5.000} [get_ports sys_clk_i]
set_property PACKAGE_PIN AD12 [get_ports sys_clk_i]
set_property IOSTANDARD SSTL135 [get_ports sys_clk_i]
set_property PACKAGE_PIN AB28 [get_ports tg_compare_error]
set_property IOSTANDARD LVCMOS18 [get_ports tg_compare_error]
set_property PACKAGE_PIN AA27 [get_ports init_calib_complete]
set_property IOSTANDARD LVCMOS18 [get_ports init_calib_complete]
DDR3的管脚不需要在进行约束了,因为在创建MIG的时候就已经约束好了,约束文件在IP核的文件夹里面
然后添加一个PLL
wire sys_rst;
wire clk_200m;
clk_wiz_0 clk_wiz_0
(
// Clock out ports
.clk_out1(clk_200m), // 连接到mig_7series_0.sys_clk_i
// Status and control signals
.locked(sys_rst), // 连接到mig_7series_0.sys_rst
// Clock in ports
.clk_in1(sys_clk_i)); // input clk_in1
就这么简单
但在编译的过程中,会出现一个错误,提示需要加这个约束
CLOCK_DEDICATED_ROUTE = BACKBONE
查阅了资料,也有这么处理,也可以避免错误,sys_clk_i输入先经过一个 BUFG,然后在输入到PLL,PLL中source 需要选Global Buffer。之前选的是pin输入,就会有错误
wire sys_clk_d;
BUFG BUFG_inst (
.O(sys_clk_d), // 1-bit output: Clock output
.I(sys_clk_i) // 1-bit input: Clock input
);
wire sys_rst;
wire clk_200m;
clk_wiz_0 clk_wiz_0
(
// Clock out ports
.clk_out1(clk_200m), // output clk_out1
// Status and control signals
.locked(sys_rst), // output locked
// Clock in ports
.clk_in1(sys_clk_i)); // input clk_in1
修改完成之后,编译可以生成bit文件,下载到FPGA中,init_calib_complete对应的灯点亮了,说明DDR3初始化成功了。说明我们操作无误,尽管我们抢先进行了上板测试,并且证明了DDR3初始化成功。
但里面的测试例程 mig_7series_v4_2_traffic_gen_top比较复杂,作为初学者我也不太像去了解,我直接将其删除
整个工程就剩下如下内容:
`timescale 1ps/1ps
module example_top
(
// Inouts
inout [15:0] ddr3_dq,
inout [1:0] ddr3_dqs_n,
inout [1:0] ddr3_dqs_p,
output [14:0] ddr3_addr,
output [2:0] ddr3_ba,
output ddr3_ras_n,
output ddr3_cas_n,
output ddr3_we_n,
output ddr3_reset_n,
output [0:0] ddr3_ck_p,
output [0:0] ddr3_ck_n,
output [0:0] ddr3_cke,
output [0:0] ddr3_cs_n,
output [1:0] ddr3_dm,
output [0:0] ddr3_odt,
// Single-ended system clock
input sys_clk_i,
output tg_compare_error, // LED1
output init_calib_complete // LED2
);
wire sys_clk_d;
BUFG BUFG_inst (
.O(sys_clk_d), // 1-bit output: Clock output
.I(sys_clk_i) // 1-bit input: Clock input
);
wire sys_rst;
wire clk_200m;
clk_wiz_0 clk_wiz_0
(
// Clock out ports
.clk_out1(clk_200m), // output clk_out1
// Status and control signals
.locked(sys_rst), // output locked
// Clock in ports
.clk_in1(sys_clk_d)); // input clk_in1
reg [28:0] app_addr = 0;
reg [2:0] app_cmd = 0;
reg app_en = 0;
wire app_rdy;
wire [127:0] app_rd_data;
wire app_rd_data_end;
wire app_rd_data_valid;
reg [127:0] app_wdf_data = 128'h0;
reg app_wdf_end = 0;
reg [15:0] app_wdf_mask = 0;
wire app_wdf_rdy;
wire app_sr_active;
wire app_ref_ack;
wire app_zq_ack;
reg app_wdf_wren = 0;
wire [11:0] device_temp;
wire clk;
wire rst;
mig_7series_0 u_mig_7series_0
(
// Memory interface ports
.ddr3_addr (ddr3_addr),
.ddr3_ba (ddr3_ba),
.ddr3_cas_n (ddr3_cas_n),
.ddr3_ck_n (ddr3_ck_n),
.ddr3_ck_p (ddr3_ck_p),
.ddr3_cke (ddr3_cke),
.ddr3_ras_n (ddr3_ras_n),
.ddr3_we_n (ddr3_we_n),
.ddr3_dq (ddr3_dq),
.ddr3_dqs_n (ddr3_dqs_n),
.ddr3_dqs_p (ddr3_dqs_p),
.ddr3_reset_n (ddr3_reset_n),
.init_calib_complete (init_calib_complete),
.ddr3_cs_n (ddr3_cs_n),
.ddr3_dm (ddr3_dm),
.ddr3_odt (ddr3_odt),
// Application interface ports
.app_addr (app_addr),
.app_cmd (app_cmd),
.app_en (app_en),
.app_wdf_data (app_wdf_data),
.app_wdf_end (app_wdf_end),
.app_wdf_wren (app_wdf_wren),
.app_rd_data (app_rd_data),
.app_rd_data_end (app_rd_data_end),
.app_rd_data_valid (app_rd_data_valid),
.app_rdy (app_rdy),
.app_wdf_rdy (app_wdf_rdy),
.app_sr_req (1'b0),
.app_ref_req (1'b0),
.app_zq_req (1'b0),
.app_sr_active (app_sr_active),
.app_ref_ack (app_ref_ack),
.app_zq_ack (app_zq_ack),
.ui_clk (clk),
.ui_clk_sync_rst (rst),
.app_wdf_mask (app_wdf_mask),
// System Clock Ports
.sys_clk_i (clk_200m),
.device_temp (device_temp),
.sys_rst (sys_rst)
);
// End of User Design top instance
endmodule
注意,MIG的输入需要赋值,否则编译的时候会报错
reg [28:0] app_addr = 0;
reg [2:0] app_cmd = 0;
reg app_en = 0;
wire app_rdy;
wire [127:0] app_rd_data;
wire app_rd_data_end;
wire app_rd_data_valid;
reg [127:0] app_wdf_data = 128'h0;
reg app_wdf_end = 0;
reg [15:0] app_wdf_mask = 0;
wire app_wdf_rdy;
wire app_sr_active;
wire app_ref_ack;
wire app_zq_ack;
reg app_wdf_wren = 0;
修改完成之后,重新编译可以生成bit文件,下载到FPGA中,init_calib_complete对应的灯点亮了,说明DDR3功能不受影响。
接下来我就可以基于这个简化的工程添加一些读写功能了。但如果还需要添加更多的功能的话,还是首先需要进行仿真的,接下来,我们就进行DDR3参考例程的仿真工作。