FPGA中DDR3 MIG ip核使用说明

19 篇文章 7 订阅

        此篇是我在学习中做的归纳与总结,其中如果存在版权或知识错误请直接联系我,欢迎留言。
PS:本着知识共享的原则,此篇博客可以随意转载,但请标明出处!

目录

1、DDR3工作原理

简介:

DDR基础操作步骤:

DDR读操作:

DDR写操作:

预充电:

2、DDR3 MIG ip核配置与调用

MIG ip核配置:

关键代码:


1、DDR3工作原理

简介:

DDR3(全称:double-data-rate 3 synchronous dynamic RAM),即第三代双倍速率同步动态随机存储器。

        1、同步是指DDR3数据的读取写入是按时钟同步的;

        2、动态是指DDR3中的数据掉电无法保存,且需要周期性的刷新,才能保持数据;

        3、随机存取即可以随机操作任一地址的数据;

        4、double-data-rate,即时钟的上升沿和下降沿都发生数据传输。

micron的MT41K128M16TW;MT41K为型号,128M16表示DDR3容量大小为128M*16 = 2Gb;

        该DDR3是8Bank配置,即BA[2:0];数据位宽配置为16bit;行地址A[13:0],列地址BA[2:0],那么算下来正好2Gb。

        1、控制器单元:包括输入命令解析,模式配置&控制部分;

        2、行地址选通单元:行激活通过此处操作;

        3、Bank控制逻辑:行/列地址解码用到bank选通

        4、列地址选择单元,读写操作同时在打开列地址的时候送到1;

        5、锁存与控制逻辑:刷新与预充电用到该模块;

        6、内部存储阵列,此处分8个bank,每个bank分16384行,128列;

        7、读写数据缓存及接口驱动; dq数据在此变换位宽后内外交互;

DDR基础操作步骤:

启动:上电->解复位->初始化->ZQCL->LEVELING->IDLE(READY)

读:IDLE—>行激活—>读数据(1次或多次突发)—>预充电—>IDLE

写:IDLE—>行激活—>写数据(1次或多次突发)—>预充电—>IDLE

刷新:IDLE->REF->IDLE

自刷新的进入与退出:IDLE->SFR->IDLE

定期校正:IDLE—>ZQCS—>IDLE,一般外部温度或电压改变时操作

动态更改配置:IDLE->MRS/MPR->IDLE

DDR读操作:

 ddr发起一次读的过程包含有:

        1、Active命令—含带地址位,以选择Bank和Row地址(BAO-BA2选择BANK、AO-A13选择Row)。用于打开一个工作行。

        2、Read命令—含带突发操作的起始Column地址和bank号,打开对应gating的列;

        3、数据经过特定的延时(CL+AL);将数据传出IO;

        4、完成数据传出后,需将当前cache的数据刷回存储整列并关闭当前工作行(携带命令和BA信息);[是否发布自动预充电命令(通过A10)]

DDR写操作:

        (第三步与读操作不同,其他与读操作一致)

        1、Active命令—含带地址位,以选择Bank和Row地址(BAO-BA2选择BANK、AO-A13选择Row)。用于打开一个工作行。

        2、Write命令—含带突发操作的起始Column地址和bank号,打开对应gating的列;

        3、数据经过特定的延时(CL+AL);将数据传入IO;

        4、完成数据传出后,需将当前cache的数据刷回存储整列并关闭当前工作行(携带命令和BA信息);[是否发布自动预充电命令(通过A10)]

预充电:

        由于SDRAM的寻址具体独占性,所以在进行完读写操作后,如果要对同—L-Bank的另一行进行寻址,就要将原来有效(工作)的L行关闭,重新发送行/列地址。

        L-Bank关闭现有工作行,准备打开新行的操作就是预充电(Precharge)。

        预充电可以通过单独的命令控制,也可以通过辅助设定让芯片在每次读写操作之后自动进行预充电。(A10)

        预充电的本质是一种对工作行中所有存储体进行数据重写,并对行地址进行复位,同时释放S-AMP。

2、DDR3 MIG ip核配置与调用

        上海勤谋电子科技有限公司推出的QM_XC7A35T开发板,采用Xilinx最新推出的7系列的XC7A35T-1FTG256C作为主控FPGA。

MIG ip核配置:

        选择DDR3控制器的类型为“DDR3 SDRAM

 

        选择DDR3颗粒的工作频率为400MHz,1系列的最高支持频率为400MHz,所以测试时不要采用更高的测试工作频率,内存型号为:MT41J128M16HA-15E,实际上的DDR3数据率是时钟频率的2倍,单击Next:

        配置“Controller Chip Select Pin”为“Disable”,这是为了在硬件设计时节省了一个FPGA的IO引脚资源,直接将DDR3 SDRAM的Chip Select引脚拉低保持片选信号一直有效

        System Clock和Reference Clock时钟输入,Internal Vref等配置如下图所示

        选择“Fixed Pin Out”

 

 单击“Read XDC/UCF”按钮,然后跳出 “Load your UCF” 对话框,选择资料包里提供或者网上的“DDR3.ucf”文件。

 DDR3.ucf 文件:

NET "ddr3_dq[0]"                             LOC = "F15"          ;       
NET "ddr3_dq[1]"                             LOC = "F13"          ;       
NET "ddr3_dq[2]"                             LOC = "E16"          ;       
NET "ddr3_dq[3]"                             LOC = "D11"          ;       
NET "ddr3_dq[4]"                             LOC = "E12"          ;       
NET "ddr3_dq[5]"                             LOC = "E13"          ;       
NET "ddr3_dq[6]"                             LOC = "D16"          ;       
NET "ddr3_dq[7]"                             LOC = "E11"          ;       
NET "ddr3_dq[8]"                             LOC = "G12"          ;       
NET "ddr3_dq[9]"                             LOC = "J16"          ;       
NET "ddr3_dq[10]"                            LOC = "G16"          ;       
NET "ddr3_dq[11]"                            LOC = "J15"          ;       
NET "ddr3_dq[12]"                            LOC = "H14"          ;       
NET "ddr3_dq[13]"                            LOC = "H12"          ;       
NET "ddr3_dq[14]"                            LOC = "H16"          ;       
NET "ddr3_dq[15]"                            LOC = "H13"          ;       
NET "ddr3_dm[0]"                             LOC = "F12"          ;       
NET "ddr3_dm[1]"                             LOC = "H11"          ;       
NET "ddr3_dqs_p[0]"                          LOC = "D14"          ;       
NET "ddr3_dqs_n[0]"                          LOC = "D15"          ;       
NET "ddr3_dqs_p[1]"                          LOC = "G14"          ;       
NET "ddr3_dqs_n[1]"                          LOC = "F14"          ;       
NET "ddr3_addr[13]"                          LOC = "B11"          ;       
NET "ddr3_addr[12]"                          LOC = "A8"           ;       
NET "ddr3_addr[11]"                          LOC = "A9"           ;       
NET "ddr3_addr[10]"                          LOC = "B12"          ;       
NET "ddr3_addr[9]"                           LOC = "A13"          ;       
NET "ddr3_addr[8]"                           LOC = "D8"           ;       
NET "ddr3_addr[7]"                           LOC = "A12"          ;       
NET "ddr3_addr[6]"                           LOC = "D9"           ;       
NET "ddr3_addr[5]"                           LOC = "B10"          ;       
NET "ddr3_addr[4]"                           LOC = "C9"           ;       
NET "ddr3_addr[3]"                           LOC = "C14"          ;       
NET "ddr3_addr[2]"                           LOC = "A14"          ;       
NET "ddr3_addr[1]"                           LOC = "C8"           ;       
NET "ddr3_addr[0]"                           LOC = "B14"          ;       
NET "ddr3_ba[2]"                             LOC = "B15"          ;       
NET "ddr3_ba[1]"                             LOC = "A15"          ;       
NET "ddr3_ba[0]"                             LOC = "C16"          ;       
NET "ddr3_ck_p[0]"                           LOC = "B9"           ;       
NET "ddr3_ck_n[0]"                           LOC = "A10"          ;       
NET "ddr3_ras_n"                             LOC = "B16"          ;       
NET "ddr3_cas_n"                             LOC = "C11"          ;       
NET "ddr3_we_n"                              LOC = "C12"          ;       
NET "ddr3_reset_n"                           LOC = "E15"          ;       
NET "ddr3_cke[0]"                            LOC = "D13"          ;       
NET "ddr3_odt[0]"                            LOC = "C13"          ;       

然后完成IP核配置,MIG IP核例化如下所示:

assign  app_wdf_wren  =     app_en & app_wdf_rdy & app_rdy & (app_cmd == 3'd0);
assign  app_wdf_end   =     app_wdf_wren;
assign  app_addr      =     ( app_cmd == 3'd1 ) ?  read_addr : write_addr ;

mig_7series_0 u_mig_7series_0 (
    // Memory interface ports
    .ddr3_addr                      (ddr3_addr),  // output [13: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 [15:0]     ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n),  // inout [1:0]       ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p),  // inout [1:0]       ddr3_dqs_p
    .init_calib_complete            (init_calib_complete),  // output           init_calib_complete
    .ddr3_dm                        (ddr3_dm),  // output [1:0]     ddr3_dm
    .ddr3_odt                       (ddr3_odt),  // output [0:0]        ddr3_odt
    // Application interface ports
    .app_addr                       (app_addr),  // input [27: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 [127: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 [127: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
    .app_sr_req                     (1'b0),  // input         app_sr_req
    .app_ref_req                    (1'b0),  // input            app_ref_req
    .app_zq_req                     (1'b0),  // input         app_zq_req
    .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                         (ui_clk),  // output            ui_clk
    .ui_clk_sync_rst                (ui_clk_sync_rst),  // output           ui_clk_sync_rst
    .app_wdf_mask                   ( 16'd0 ),  // input [15:0]        app_wdf_mask
    // System Clock Ports
    .sys_clk_i                      (ddrclk_200Mhz),
    .sys_rst                        (~ ddr_rst_n) // input sys_rst
    );

        本文阐述的DDR3应用场景为,首先读取SPI-Flash中数据,然后存储至DDR3中,最后读取DDR3中数据输出。

        Verilog SPI-Flash读写总线控制模块程序:https://blog.csdn.net/m0_37779673/article/details/118033580

关键代码:

always @(posedge ui_clk ) begin  //DDR_output_clk is 200MHz
    if (!sys_rst_n) begin 
        ///   DDR3
        app_en          <= 1'b0         ;
        app_cmd         <= 3'd0         ;
        write_addr      <= 28'd0        ;
        read_addr       <= 28'd0        ;
        app_wdf_data    <= 128'd0       ;
    end else begin
        case(top_state)
            4'd0: begin // begin state 
                if ( app_wdf_rdy & app_rdy ) begin  // DDR3 is ready
                    led_0       <= 0      ;
                    flash_state <= 4'd0   ;  //read flash ID
                end  else  
                    led_0 <=  1;

                if ( flash_flag > 4'd0 ) //已读出一批数据
                    top_state       <= 4'd1  ;
            end 
            4'd1: begin // read Flash_data
                if ( rd_flash_data_cnt < 23'd8000000 ) begin //判断读取flash中数据数量
                    cnt_rd_flash_data   <= 3'd1 ;
                    rd_flash_data_cnt   <= rd_flash_data_cnt  + 23'd4 ;
                    flash_state         <= 4'd1         ;  //read flash 4bytes data
                    flash_addr          <= flash_addr  + 24'd32       ;
                    top_state           <= 4'd2         ;
                end else begin
                    rd_flash_data_cnt   <= 0            ;
                    flash_addr          <= 0            ;
                    top_state           <= 4'd4         ;
                end
            end 
            4'd2: begin // build up DDR3 128bit save data
                flag_read_byte0    <= flag_read_byte  ;
                l2h_flag_read_byte <= ( ~ flag_read_byte0 ) & flag_read_byte ;
                if ( l2h_flag_read_byte && (cnt_rd_flash_data == 1) ) begin
                    cnt_rd_flash_data  <= cnt_rd_flash_data + 3'd1 ;
                    if ( flash_flag[0] == 1 ) begin
                        app_wdf_data [ 7 : 0 ] <= read_flash_data0 ;
                    end else begin
                        app_wdf_data [ 7 : 0 ] <= 8'b0 ;
                    end

                    if ( flash_flag[1] == 1 ) begin
                        app_wdf_data [ 15 : 8 ] <= read_flash_data1 ;
                    end else begin
                        app_wdf_data [ 15 : 8 ] <= 8'b0 ;
                    end

                    if ( flash_flag[2] == 1 ) begin
                        app_wdf_data [ 23 : 16 ] <= read_flash_data2 ;
                    end else begin
                        app_wdf_data [ 23 : 16 ] <= 8'b0 ;
                    end

                    if ( flash_flag[3] == 1 ) begin
                        app_wdf_data [ 31 : 24 ] <= read_flash_data3 ;
                    end else begin
                        app_wdf_data [ 31 : 24 ] <= 8'b0 ;
                    end
                end
                if ( l2h_flag_read_byte && (cnt_rd_flash_data == 2) ) begin
                    cnt_rd_flash_data  <= cnt_rd_flash_data + 3'd1 ;
                    if ( flash_flag[0] == 1 ) begin
                        app_wdf_data [ 39 : 32 ] <= read_flash_data0 ;
                    end else begin
                        app_wdf_data [ 39 : 32 ] <= 8'b0 ;
                    end

                    if ( flash_flag[1] == 1 ) begin
                        app_wdf_data [ 47 : 40 ] <= read_flash_data1 ;
                    end else begin
                        app_wdf_data [ 47 : 40 ] <= 8'b0 ;
                    end

                    if ( flash_flag[2] == 1 ) begin
                        app_wdf_data [ 55 : 48 ] <= read_flash_data2 ;
                    end else begin
                        app_wdf_data [ 55 : 48 ] <= 8'b0 ;
                    end

                    if ( flash_flag[3] == 1 ) begin
                        app_wdf_data [ 63 : 56 ] <= read_flash_data3 ;
                    end else begin
                        app_wdf_data [ 63 : 56 ] <= 8'b0 ;
                    end
                end
                if ( l2h_flag_read_byte && (cnt_rd_flash_data == 3) ) begin
                    cnt_rd_flash_data  <= cnt_rd_flash_data + 3'd1 ;
                    if ( flash_flag[0] == 1 ) begin
                        app_wdf_data [ 71 : 64 ] <= read_flash_data0 ;
                    end else begin
                        app_wdf_data [ 71 : 64 ] <= 8'b0 ;
                    end

                    if ( flash_flag[1] == 1 ) begin
                        app_wdf_data [ 79 : 72 ] <= read_flash_data1 ;
                    end else begin
                        app_wdf_data [ 79 : 72 ] <= 8'b0 ;
                    end

                    if ( flash_flag[2] == 1 ) begin
                        app_wdf_data [ 87 : 80 ] <= read_flash_data2 ;
                    end else begin
                        app_wdf_data [ 87 : 80 ] <= 8'b0 ;
                    end

                    if ( flash_flag[3] == 1 ) begin
                        app_wdf_data [ 95 : 88 ] <= read_flash_data3 ;
                    end else begin
                        app_wdf_data [ 95 : 88 ] <= 8'b0 ;
                    end
                end
                if ( l2h_flag_read_byte && (cnt_rd_flash_data == 4) ) begin
                    if ( flash_flag[0] == 1 ) begin
                        app_wdf_data [ 103 : 96 ] <= read_flash_data0 ;
                    end else begin
                        app_wdf_data [ 103 : 96 ] <= 8'b0 ;
                    end

                    if ( flash_flag[1] == 1 ) begin
                        app_wdf_data [ 111 : 104 ] <= read_flash_data1 ;
                    end else begin
                        app_wdf_data [ 111 : 104 ] <= 8'b0 ;
                    end

                    if ( flash_flag[2] == 1 ) begin
                        app_wdf_data [ 119 : 112 ] <= read_flash_data2 ;
                    end else begin
                        app_wdf_data [ 119 : 112 ] <= 8'b0 ;
                    end

                    if ( flash_flag[3] == 1 ) begin
                        app_wdf_data [ 127 : 120 ] <= read_flash_data3 ;
                    end else begin
                        app_wdf_data [ 127 : 120 ] <= 8'b0 ;
                    end
                end
                if ( (l2h_flag_read_byte == 0 ) && ( cnt_rd_flash_data == 3'd4 )) begin
                    top_state           <= 4'd3         ;
                    flash_state         <= 4'd2         ;
                    once_data_flag      <= 1            ;
                end
            end 
            4'd3: begin // read 4bytes Flash data end --> DDR3 trans_end
                if ( init_calib_complete ) begin  //DD3 loading finished
                    if( app_rdy & app_wdf_rdy ) begin//等待这两个信号拉高就使命令有效
                        if ( once_data_flag ) begin
                            once_data_flag  <= 0    ;  
                            app_cmd         <= 3'd0 ;  // write commend 
                            app_en          <= 1'b1 ;
                            write_addr      <= write_addr + 28'd8;
                        end else begin
                            top_state       <= 4'd1 ;
                            app_en          <= 1'b0 ;
                        end
                    end
                end
            end 
            4'd4: begin // DDR3 --> 输出数据

            end 
            default :     ;
        endcase
    end
end

参考文献:

1、ug586_7Series_MIS.pdf

2、MT41J128M16JT-125K.pdf

3、ug470_7Series_Config.pdf

  • 9
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虚怀若水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值