Xilinx MIG 控制器使用详解(二)

想要自己学习MIG控制器已经很久了,刚开始学习的时候也是在网上到处搜索MIG控制器的资料,深知学习过程的不容易。因此本系列的教程一定会详细的写出关于MIG控制器的相关知识,方便大家一起学习。有问题的朋友可以在下方留言,一起学习和讨论。


关于DDR3的基本知识在这里我就不详细说了,只有在相关的地方会提上一嘴。本教程的目的只是教会大家如何使用MIG控制器,大家一定不要觉得MIG控制器有多难,其实很简单的,跟着我在心里默念“MIG就像BRAM一样简单”。确实哈,当你回过头来看,MIG控制器的使用基本和BRAM的使用方法很像。

话不多说了,那么这第一个系列,我就先交大家来例化一个MIG控制器。

            VIVADO:2016.4

芯片:zynq7035

上一节已经介绍了如何配置一个MIG控制器  Xilinx MIG 控制器使用详解(一)

现在让我们来看看生成的MIG控制器模块。

 mig_7series_0 u_mig_7series_0 (

    
    // Memory interface ports
    // 下面这些都是DDR3的物理管脚,这些已经约束好了,不需要我们自己约束,不用管。
    .ddr3_addr(ddr3_addr),  // output [14:0]		ddr3_addr
    .ddr3_ba(ddr3_ba),  // output [2:0]		ddr3_ba
    .ddr3_cas_n(ddr3_cas_n),  // output			ddr3_cas_n
    .ddr3_ck_n(ddr3_ck_n),  // output [0:0]		ddr3_ck_n
    .ddr3_ck_p(ddr3_ck_p),  // output [0:0]		ddr3_ck_p
    .ddr3_cke(ddr3_cke),  // output [0:0]		ddr3_cke
    .ddr3_ras_n(ddr3_ras_n),  // output			ddr3_ras_n
    .ddr3_reset_n(ddr3_reset_n),  // output			ddr3_reset_n
    .ddr3_we_n(ddr3_we_n),  // output			ddr3_we_n
    .ddr3_dq(ddr3_dq),  // inout [31:0]		ddr3_dq
    .ddr3_dqs_n(ddr3_dqs_n),  // inout [3:0]		ddr3_dqs_n
    .ddr3_dqs_p(ddr3_dqs_p),  // inout [3:0]		ddr3_dqs_p
    
    //初始化完成信号,需要关注
    .init_calib_complete(init_calib_complete),  // outp init_calib_complete
    
    //这也是DDR3的一些物理管脚,我们也不需要管
    .ddr3_cs_n(ddr3_cs_n),  // output [0:0]		ddr3_cs_n
    .ddr3_dm(ddr3_dm),  // output [3:0]		ddr3_dm
    .ddr3_odt(ddr3_odt),  // output [0:0]		ddr3_odt
    
    // Application interface ports
    //下面的app开头的信号才是我们使用MIG控制器需要关注的
    .app_addr(app_addr),  // input [28:0]		app_addr
    .app_cmd(app_cmd),  // input [2:0]		app_cmd
    .app_en(app_en),  // input				app_en
    .app_wdf_data(app_wdf_data),  // input [255:0]		app_wdf_data
    .app_wdf_end(app_wdf_end),  // input				app_wdf_end
    .app_wdf_wren(app_wdf_wren),  // input				app_wdf_wren
    .app_rd_data(app_rd_data),  // output [255:0]		app_rd_data
    .app_rd_data_end(app_rd_data_end),  // output		app_rd_data_end
    .app_rd_data_valid(app_rd_data_valid),  // output		app_rd_data_valid
    .app_rdy(app_rdy),  // output			app_rdy
    .app_wdf_rdy(app_wdf_rdy),  // output			app_wdf_rdy
    
    //下面这三个再例化的时候直接给0就可以
    .app_sr_req(app_sr_req),  // input			app_sr_req
    .app_ref_req(app_ref_req),  // input			app_ref_req
    .app_zq_req(app_zq_req),  // input			app_zq_req
    
    //下面三个是输出,直接输出到三个wire信号即可
    .app_sr_active(app_sr_active),  // output			app_sr_active
    .app_ref_ack(app_ref_ack),  // output			app_ref_ack
    .app_zq_ack(app_zq_ack),  // output			app_zq_ack
   
    //ui_clk就是MIG输出给用户的时钟,在上一节中我们说的是100MHz
    .ui_clk(ui_clk),  // output			ui_clk
    
    //输出的这个复位信号不用管,接到一个wire信号上就可以
    .ui_clk_sync_rst(ui_clk_sync_rst),  // output		ui_clk_sync_rst
    
    //这个是掩码信号,直接赋0,不用管
    .app_wdf_mask(app_wdf_mask),  // input [31:0]		app_wdf_mask
    
    
    // System Clock Ports
    //系统时钟,上一节说的是400MHz
    .sys_clk_i(sys_clk_i),
    // Reference Clock Ports
    //参考时钟
    .clk_ref_i(clk_ref_i),
    //系统复位
    .sys_rst(sys_rst) // input sys_rst
    );

好,到这我们就来看看app打头的这些信号是什么意思。

首先,对DDR3应该有读写两种操作,我们先来看看写操作。

写操作相关信号:

app_cmd :操作命令,确定是读还是写。读: app_cmd = 3'b001; 写:app_cmd = 3'b000;
app_addr:操作地址(往哪写,从哪读)
app_en  :操作地址app_addr的使能,只有它拉高的时候,对应的app_addr才是有效的
app_wdf_data:写入数据的接口(往DDR3里面写什么)
app_wdf_wren:写入的数据接口app_wdf_data的使能,只有它拉高的时候。对应的app_wdf_data才是有效的
app_wdf_end:这里不需要管他。只需要使app_wdf_end = app_wdf_wren。

所以写入数据的时候你只需要处理好这六个信号就可以

app_cmd         
app_addr                                           
app_en                             
app_wdf_data                              
app_wdf_wren           
app_wdf_end

读操作相关信号:

读数据的时候只需要操作以下三个信号,是不是更简单呢?(这里的三个信号和上面是一样的)
app_cmd
app_addr
app_en

看完了相关的信号,我们就该来看看看读写操作是如何操作的了。

写操作:

写操作时序如下:(这个图示从别人的文档里面弄出来的不想去翻手册了)

可以看到写的时候可以有三种情况,分别对应1、2、3种情况。第一种是地址和数据严格对齐的,第二三种是数据和地址不对齐的,推荐曹勇第一种数据和地址对齐的方式。

在这个图里面,我们发现有两个信号之前没有说明。就是

app_rdy:这个信号由DDR3输出,告诉用户在app_rdy拉高的时候拉高app_en。地址app_addr才是有效的。

app_wdf_rdy:这个信号由DDR3输出,告诉用户在app_wdf_rdy拉高的时候拉高app_wdf_wren,写入的数据app_wdf_data才是有效的。

由上图的第一种情况可以看出,在app_rdy和app_wdf_rdy都拉高的时候,把app_en拉高、再给出相应的地址、再写入相应的数据、再给出对应的写使能就可以把相应的数据写入到DDR3中相应的地址。但是,需要注意的是,在app_rdy 或者app_wdf_rdy没有拉高的时候,需要把相应的数据和地址保持不变。

 

读操作:

读操作就更简单了,先把读操作时序贴出来。(这个图也是从别人的文档里面截取的)

 在读的时候,只需要在app_rdy拉高的时候给出地址app_addr和使能app_en即可。然后就等着接数就可以,给几个周期的使能就出几个周期的数据。

 

所以,回到第一节Xilinx MIG 控制器使用详解(一),当时说的MIG的使用就像BRAM一样简单。

你看,我没说错吧。BRAM在写的时候也是给出写地址和写使能,MIG也是,不同的是MIG需要在app_rdy、app_wdf_rdy拉高的时候给出。BRAM在读的时候,也是给出一个地址就可以了,MIG还需拉高app_en。

 

现在让我们来算一下DDR3的带宽吧。

DDR3的物理位宽是32bit的,DDR3跑的时钟频率是400MHz, 又因为是上下沿都采样,所以带宽应该为:400MHz*2*32bit=800MHz * 32bit。那么MIG控制器的读写数据端口的位宽是多少呢?也就是app_wdf_data 和app_rd_data的位宽是多少呢?答案是:256bit。 怎么算出来的呢?800MHz * 32 bit = 100MHz *32*8bit, 所以是32*8=256bit。

下一篇就介绍如何使用MIG控制器进行读写。

猜你喜欢

转载自blog.csdn.net/MaoChuangAn/article/details/85269291