欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > DDR3的使用(二)利用XILINX MIGIP核(native)读写DDR3

DDR3的使用(二)利用XILINX MIGIP核(native)读写DDR3

2025/6/9 1:02:03 来源:https://blog.csdn.net/weixin_42306014/article/details/140691374  浏览:    关键词:DDR3的使用(二)利用XILINX MIGIP核(native)读写DDR3

我们上一节介绍了mig ip核的时钟结构,搞清楚时钟结构后我们尝试着读写下ddr3芯片。我们使用黑金的AX7325平台进行实验。
1.我们建立vivado该工程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.我们建立好工程,然后添加设计文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述3.添加代码

`timescale 1ps/1psmodule top(// Inoutsinout [63:0]                       ddr3_dq,inout [7:0]                        ddr3_dqs_n,inout [7:0]                        ddr3_dqs_p,// Outputsoutput [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 [7:0]                      ddr3_dm,  output [0:0]                      ddr3_odt,  //Differential system clocksinput                              sys_clk_p,input                              sys_clk_n,input                              sys_clk, output                             error,output                             fan_pwm,input                              rst_n);localparam nCK_PER_CLK           = 4;
localparam DQ_WIDTH              = 64;
localparam ADDR_WIDTH            = 29;
localparam DATA_WIDTH            = 64;
localparam PAYLOAD_WIDTH         = 64;localparam APP_DATA_WIDTH        = 2 * nCK_PER_CLK * PAYLOAD_WIDTH;
localparam APP_MASK_WIDTH        = APP_DATA_WIDTH / 8;wire init_calib_complete;
assign fan_pwm                   = 1'b0;// Wire declarationswire sys_clk_200MHz;   IBUFDS sys_clk_ibufgds(.O  (sys_clk_200MHz),.I  (sys_clk_p),.IB (sys_clk_n));//下面接口与ddr核相连  wire [ADDR_WIDTH-1:0]                 app_addr;wire [2:0]                            app_cmd;wire                                  app_en;wire                                  app_rdy;wire [APP_DATA_WIDTH-1:0]             app_rd_data;wire                                  app_rd_data_end;wire                                  app_rd_data_valid;wire [APP_DATA_WIDTH-1:0]             app_wdf_data;wire                                  app_wdf_end;wire [APP_MASK_WIDTH-1:0]             app_wdf_mask;wire                                  app_wdf_rdy;wire                                  app_sr_active;wire                                  app_ref_ack;wire                                  app_zq_ack;wire                                  app_wdf_wren;wire                                  clk;wire                                  rst;ddr3 u_ddr3   //参考 Xilinx 提供的文档“ug586_7Series_MIS.pdf”(// 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                       (sys_clk_200MHz),.sys_rst                        (rst_n));
// End of User Design top instancewire                              wr_burst_data_req;wire                              wr_burst_finish;wire                              rd_burst_finish;wire                              rd_burst_req;wire                              wr_burst_req;wire[9:0]                         rd_burst_len;wire[9:0]                         wr_burst_len;wire[28:0]                        rd_burst_addr;wire[28:0]                        wr_burst_addr;wire                              rd_burst_data_valid;wire[512 - 1 : 0]                  rd_burst_data;wire[512 - 1 : 0]                  wr_burst_data;//对ddr ip核包装,只用对注释的接口进行控制就可实现对ddr的控制
mem_burst
#(.MEM_DATA_BITS(APP_DATA_WIDTH),.ADDR_BITS(ADDR_WIDTH)
)mem_burst_m0
(.rst(rst),                                  /*复位*/.mem_clk(clk),                              /*接口时钟*/.rd_burst_req(rd_burst_req),                /*读请求*/.wr_burst_req(wr_burst_req),                /*写请求*/.rd_burst_len(rd_burst_len),                /*读数据长度*/.wr_burst_len(wr_burst_len),                 /*写数据长度*/.rd_burst_addr(rd_burst_addr),               /*读首地址*/.wr_burst_addr(wr_burst_addr),               /*写首地址*/.rd_burst_data_valid(rd_burst_data_valid),   /*读出数据有效*/.wr_burst_data_req(wr_burst_data_req),       /*写数据信号*/.rd_burst_data(rd_burst_data),               /*读出的数据*/.wr_burst_data(wr_burst_data),               /*写入的数据*/.rd_burst_finish(rd_burst_finish),           /*读完成*/.wr_burst_finish(wr_burst_finish),           /*写完成*/.burst_finish(),                             /*读或写完成*////.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_mask(app_wdf_mask),.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),.ui_clk_sync_rst(),  .init_calib_complete(init_calib_complete)
);
//测试文件,读写数据
mem_test
#(.MEM_DATA_BITS(APP_DATA_WIDTH),.ADDR_BITS(ADDR_WIDTH)
)
mem_test_m0
(.rst(rst),                                 .mem_clk(clk),                               .rd_burst_req(rd_burst_req),                         .wr_burst_req(wr_burst_req),                         .rd_burst_len(rd_burst_len),                     .wr_burst_len(wr_burst_len),                    .rd_burst_addr(rd_burst_addr),        .wr_burst_addr(wr_burst_addr),        .rd_burst_data_valid(rd_burst_data_valid),                 .wr_burst_data_req(wr_burst_data_req),                   .rd_burst_data(rd_burst_data),   .wr_burst_data(wr_burst_data),    .rd_burst_finish(rd_burst_finish),                     .wr_burst_finish(wr_burst_finish),                      .error(error)
);wire probe0;
wire probe1;
wire probe2;
wire probe3;
wire probe4;
wire probe5;
wire probe6;
wire probe7;
wire [511 : 0] probe8;
wire [511 : 0] probe9;
wire [28 : 0] probe10;ila_0 u_ila_0(.clk(clk),.probe0(probe0),.probe1(probe1),.probe2(probe2),.probe3(probe3),.probe4(probe4),.probe5(probe5),.probe6(probe6),.probe7(probe7),.probe8(probe8),.probe9(probe9),.probe10(probe10)						
);
assign probe0 = rd_burst_req;
assign probe1 = wr_burst_req;
assign probe2 = rd_burst_data_valid;
assign probe3 = wr_burst_data_req;
assign probe4 = rd_burst_finish;
assign probe5 = wr_burst_finish;
assign probe6 = error;
assign probe7 = init_calib_complete;
assign probe8 = wr_burst_data[511:0];
assign probe9 = rd_burst_data[511:0];
assign probe10 = app_addr[28:0];
endmodule
module mem_test
#(parameter MEM_DATA_BITS = 64,parameter ADDR_BITS = 24
)
(input rst,                                         /*复位*/input mem_clk,                                     /*接口时钟*/output reg rd_burst_req,                          /*读请求*/output reg wr_burst_req,                          /*写请求*/output reg[9:0] rd_burst_len,                     /*读数据长度*/output reg[9:0] wr_burst_len,                     /*写数据长度*/output reg[ADDR_BITS - 1:0] rd_burst_addr,        /*读首地址*/output reg[ADDR_BITS - 1:0] wr_burst_addr,        /*写首地址*/input rd_burst_data_valid,                         /*读出数据有效*/input wr_burst_data_req,                           /*写数据信号*/input[MEM_DATA_BITS - 1:0] rd_burst_data,          /*读出的数据*/output[MEM_DATA_BITS - 1:0] wr_burst_data,         /*写入的数据*/input rd_burst_finish,                             /*读完成*/input wr_burst_finish,                             /*写完成*/output reg error
);
localparam IDLE = 3'd0;
localparam MEM_READ = 3'd1;
localparam MEM_WRITE  = 3'd2;reg[2:0] state;
reg[7:0] wr_cnt;
reg[MEM_DATA_BITS - 1:0] wr_burst_data_reg;
assign wr_burst_data = wr_burst_data_reg;
reg[7:0] rd_cnt;
always@(posedge mem_clk or posedge rst)
beginif(rst)error <= 1'b0;else if((state == MEM_READ) && rd_burst_data_valid && (rd_burst_data != {(MEM_DATA_BITS/8){rd_cnt}}))error <= 1'b1;elseerror <= error;//写入数据和读出数据不一致
end
always@(posedge mem_clk or posedge rst)
beginif(rst)beginwr_burst_data_reg <= {MEM_DATA_BITS{1'b0}};wr_cnt <= 8'd0;endelse if(state == MEM_WRITE)beginif(wr_burst_data_req)beginwr_burst_data_reg <= {(MEM_DATA_BITS/8){wr_cnt}};//写入数据wr_cnt <= wr_cnt + 8'd1;endelse if(wr_burst_finish)wr_cnt <= 8'd0;end
end
//读数据
always@(posedge mem_clk or posedge rst)
beginif(rst)beginrd_cnt <= 8'd0;endelse if(state == MEM_READ)beginif(rd_burst_data_valid)beginrd_cnt <= rd_cnt + 8'd1;endelse if(rd_burst_finish)rd_cnt <= 8'd0;endelserd_cnt <= 8'd0;
end
//状态机
always@(posedge mem_clk or posedge rst)
beginif(rst)beginstate <= IDLE;wr_burst_req <= 1'b0;rd_burst_req <= 1'b0;rd_burst_len <= 10'd128;//数据长度wr_burst_len <= 10'd128;rd_burst_addr <= 0;wr_burst_addr <= 0;endelsebegincase(state)IDLE:beginstate <= MEM_WRITE;wr_burst_req <= 1'b1;wr_burst_len <= 10'd128;endMEM_WRITE:beginif(wr_burst_finish)beginstate <= MEM_READ;wr_burst_req <= 1'b0;rd_burst_req <= 1'b1;rd_burst_len <= 10'd128;rd_burst_addr <= wr_burst_addr;//地址endendMEM_READ:beginif(rd_burst_finish)beginstate <= MEM_WRITE;wr_burst_req <= 1'b1;wr_burst_len <= 10'd128;rd_burst_req <= 1'b0;wr_burst_addr <= wr_burst_addr + 128;endenddefault:state <= IDLE;endcaseend
endendmodule
/*本模块完成对ddr2 IP的包装,方便后续模块使用,也方便程序的移植,如果更换平台,更新这个文件即可
*/
module mem_burst
#(parameter MEM_DATA_BITS = 64,parameter ADDR_BITS = 24
)
(input rst,                                 /*复位*/input mem_clk,                               /*接口时钟*/input rd_burst_req,                          /*读请求*/input wr_burst_req,                          /*写请求*/input[9:0] rd_burst_len,                     /*读数据长度*/input[9:0] wr_burst_len,                     /*写数据长度*/input[ADDR_BITS - 1:0] rd_burst_addr,        /*读首地址*/input[ADDR_BITS - 1:0] wr_burst_addr,        /*写首地址*/output rd_burst_data_valid,                  /*读出数据有效*/output wr_burst_data_req,                    /*写数据信号*/output[MEM_DATA_BITS - 1:0] rd_burst_data,   /*读出的数据*/input[MEM_DATA_BITS - 1:0] wr_burst_data,    /*写入的数据*/output rd_burst_finish,                      /*读完成*/output wr_burst_finish,                      /*写完成*/output burst_finish,                         /*读或写完成*////与ddrIP核相连的接口output[ADDR_BITS-1:0]                       app_addr,output[2:0]                                 app_cmd,output                                      app_en,output [MEM_DATA_BITS-1:0]                  app_wdf_data,output                                      app_wdf_end,output [MEM_DATA_BITS/8-1:0]                app_wdf_mask,output                                      app_wdf_wren,input [MEM_DATA_BITS-1:0]                   app_rd_data,input                                       app_rd_data_end,input                                       app_rd_data_valid,input                                       app_rdy,input                                       app_wdf_rdy,input                                       ui_clk_sync_rst,  input                                       init_calib_complete
);assign app_wdf_mask = {MEM_DATA_BITS/8{1'b0}};localparam IDLE = 3'd0;
localparam MEM_READ = 3'd1;
localparam MEM_READ_WAIT = 3'd2;
localparam MEM_WRITE  = 3'd3;
localparam MEM_WRITE_WAIT = 3'd4;
localparam READ_END = 3'd5;
localparam WRITE_END = 3'd6;
localparam MEM_WRITE_FIRST_READ = 3'd7;
reg[2:0] state;	
reg[9:0] rd_addr_cnt;
reg[9:0] rd_data_cnt;
reg[9:0] wr_addr_cnt;
reg[9:0] wr_data_cnt;reg[2:0] app_cmd_r;
reg[ADDR_BITS-1:0] app_addr_r;
reg app_en_r;
reg app_wdf_end_r;
reg app_wdf_wren_r;
assign app_cmd = app_cmd_r;
assign app_addr = app_addr_r;
assign app_en = app_en_r;
assign app_wdf_end = app_wdf_end_r;
assign app_wdf_data = wr_burst_data;
assign app_wdf_wren = app_wdf_wren_r & app_wdf_rdy;
assign rd_burst_finish = (state == READ_END);
assign wr_burst_finish = (state == WRITE_END);
assign burst_finish = rd_burst_finish | wr_burst_finish;assign rd_burst_data = app_rd_data;
assign rd_burst_data_valid = app_rd_data_valid;assign wr_burst_data_req = (state == MEM_WRITE) & app_wdf_rdy ;always@(posedge mem_clk or posedge rst)
beginif(rst)beginapp_wdf_wren_r <= 1'b0;endelse if(app_wdf_rdy)app_wdf_wren_r <= wr_burst_data_req;
end
//DDR Burst 写和读,可以参考实验教程“DDR读写测试实验.pdf”
always@(posedge mem_clk or posedge rst)
beginif(rst)beginstate <= IDLE;app_cmd_r <= 3'b000;app_addr_r <= 0;app_en_r <= 1'b0;rd_addr_cnt <= 0;rd_data_cnt <= 0;wr_addr_cnt <= 0;wr_data_cnt <= 0;app_wdf_end_r <= 1'b0;endelse if(init_calib_complete ===  1'b1)begincase(state)IDLE:beginif(rd_burst_req)//读请求beginstate <= MEM_READ;app_cmd_r <= 3'b001;app_addr_r <= {rd_burst_addr,3'd0};//向IP核发送指令app_en_r <= 1'b1;endelse if(wr_burst_req)//写请求beginstate <= MEM_WRITE;app_cmd_r <= 3'b000;app_addr_r <= {wr_burst_addr,3'd0};//向IP核发送指令app_en_r <= 1'b1;wr_addr_cnt <= 0;app_wdf_end_r <= 1'b1;wr_data_cnt <= 0;endendMEM_READ:beginif(app_rdy)beginapp_addr_r <= app_addr_r + 8;if(rd_addr_cnt == rd_burst_len - 1)beginstate <= MEM_READ_WAIT;rd_addr_cnt <= 0;app_en_r <= 1'b0;endelserd_addr_cnt <= rd_addr_cnt + 1;endif(app_rd_data_valid)beginif(rd_data_cnt == rd_burst_len - 1)beginrd_data_cnt <= 0;state <= READ_END;endelsebeginrd_data_cnt <= rd_data_cnt + 1;endendendMEM_READ_WAIT:beginif(app_rd_data_valid)beginif(rd_data_cnt == rd_burst_len - 1)beginrd_data_cnt <= 0;state <= READ_END;endelsebeginrd_data_cnt <= rd_data_cnt + 1;endendendMEM_WRITE_FIRST_READ:beginapp_en_r <= 1'b1;state <= MEM_WRITE;wr_addr_cnt <= 0;endMEM_WRITE:beginif(app_rdy)beginapp_addr_r <= app_addr_r + 'b1000;if(wr_addr_cnt == wr_burst_len - 1)beginapp_wdf_end_r <= 1'b0;app_en_r <= 1'b0;endelsebeginwr_addr_cnt <= wr_addr_cnt + 1;endendif(wr_burst_data_req)beginif(wr_data_cnt == wr_burst_len - 1)beginstate <= MEM_WRITE_WAIT;endelsebeginwr_data_cnt <= wr_data_cnt + 1;endendendREAD_END:state <= IDLE;MEM_WRITE_WAIT:beginif(app_rdy)beginapp_addr_r <= app_addr_r + 'b1000;if(wr_addr_cnt == wr_burst_len - 1)beginapp_wdf_end_r <= 1'b0;app_en_r <= 1'b0;if(app_wdf_rdy) state <= WRITE_END;endelsebeginwr_addr_cnt <= wr_addr_cnt + 1;endendelse if(~app_en_r & app_wdf_rdy)state <= WRITE_END;endWRITE_END:state <= IDLE;default:state <= IDLE;endcaseend
end
endmodule 

4.添加ip核
在这里插入图片描述
这里我们暂时不选择axi接口,使用native
在这里插入图片描述
不需要兼容其他型号
在这里插入图片描述
我们使用的芯片位ddr3
在这里插入图片描述
如下图,1处为给ddr3芯片的时钟,我们使用800M,2处comporment表示是芯片颗粒,下拉菜单里有其他选项,表示内存条。3处是我们使用的芯片型号,我们这里使用MT41J256M16。4处表示总位宽,这里我们看下四片ddr3芯片的连接方式为16*4=64位。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
input clock period表示ip核的输入时钟,我们这里提供200M的时钟。

在这里插入图片描述
下图1处表示输入时钟的形式,有单端,差分和单端no buff,我们这里选择nobuff形式。2处表示参考时钟来源,我们参考时钟使用系统时钟就行。
在这里插入图片描述

在这里插入图片描述
然后进行管脚约束
在这里插入图片描述
添加管脚文件
请添加图片描述
验证通过
请添加图片描述
默认下一步
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
如下图,IP核生成成功。
请添加图片描述
下来我们生成ila的ip核
请添加图片描述
如下设置
请添加图片描述
请添加图片描述
请添加图片描述
两个ip核都能使用了
请添加图片描述
5.我们再添加下约束文件,这里主要约束了时钟周期和一些管脚。
请添加图片描述
接下来进行网表编译
请添加图片描述
网表编译完进行布局布线。
请添加图片描述
布局布线完成后生成下载文件
请添加图片描述
然后连接芯片
请添加图片描述
连接上芯片后就下载程序
请添加图片描述
请添加图片描述
7.下载完我们可以看到波形,我们详细看下:
请添加图片描述
可以看到在1处我们发出了wr_burst_req,当wr_burst_data_valid拉高时我们开始往芯片里面写数据,每次数据累加1,直到7f为止。
请添加图片描述
请添加图片描述
然后我们将写入的数据读出来,我们先发出读请求,当rd_burst_data_valid拉高时,表示读取数据有效。直到读取完毕,我们可以看到写入的数据与读出的数据一致。
请添加图片描述
请添加图片描述
到这里我们就初步完成了读写实验,但是代码逻辑是怎样的,我们后面再分析,进行仿真实验。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词