SDRAM初始化操作

FPGA中的SDRAM有缓存容量大的特点,在本篇博客中,将重点介绍SDRAM的初始化操作。
首先看下面初始化的时序图
在这里插入图片描述
可知初始化SDRSAM需要如下操作。
首先在上电和clk使能之后sdram要等待一段时间,根据手册可知最小等待时间位100us。这里我们取200us。此时的COMMAND填充的使NOP命令,下面几条初始化所需要的命令
在这里插入图片描述
之后进行预充电状态,一个时钟周期内完成,而且因为此时是对所有的bank进行充电,则要进行如下设置
在这里插入图片描述
将BA0, BA1设置为2‘b11即可; 当预充电完成之后,需要等待一段时间,预充电的等待时间为tRP。在预充电等待这段时间内,执行的命令依然为NOP。tRP结束后。后面会进入一个周期的自动刷新状态。自动刷新状态之后,也需要尽量自动刷新的等待时间,为tRC。因为SDRAM的自动刷新一般要维持至少两次以上,所以我设置的是8次。设置好之后,接下来进入一周期的配置寄存器模式的状态。具体的配置可以根据自己的要求进行配置。
在这里插入图片描述
最后就是当寄存器配置好之后,就最后等待一个寄存器配置的时间。设置为tMRD。
最后先提出的一点是:SDRAM的工作时钟要仔细看下,比如我这款芯片,时钟频率配置如下
在这里插入图片描述
最后是我的verilog代码设计和仿真波形

`timescale 1ns / 1ps

module sdram_init(
    input   wire        sys_clk     ,
    input   wire        sys_rst_n   ,

    output  reg  [3:0]  init_cmd    ,
    output  reg  [1:0]  init_ba     ,
    output  reg  [12:0] init_addr   ,
    output  wire        init_end    
    );

parameter   INIT_IDLE   =   3'b000,
            INIT_PRE    =   3'b001,
            INIT_TRP    =   3'b011,
            INIT_AR     =   3'b010,
            INIT_TRF    =   3'b110,
            INIT_MRS    =   3'b111,
            INIT_TMRD   =   3'b101,
            INIT_END    =   3'b100;

parameter   WAIT_MAX    =   20000   ;
parameter   TPR         =   3'd2    ,
            TRF         =   3'd7    ,
            TMRD        =   3'd2    ;

parameter   NOP         =   4'b0111,
            P_CHARGE    =   4'b0010,
            AUTO_REF    =   4'b0001,
            M_REG_SET   =   4'b0000;

reg     [2:0]       init_state      ;
reg     [14:0]      cnt_200us       ;
wire                wait_end        ;
reg     [2:0]       cnt_clk         ;
reg                 cnt_clk_rst     ;
wire                trp_end         ;
wire                trfc_end        ;
wire                trmd_end        ;
reg     [3:0]       cnt_aref        ;


always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        init_state <= INIT_IDLE;
    else begin
        case (init_state)
            INIT_IDLE:  init_state <= (wait_end) ? INIT_PRE : INIT_IDLE;
            INIT_PRE :  init_state <= INIT_TRP;
            INIT_TRP :  init_state <= (trp_end) ? INIT_AR : INIT_TRP;
            INIT_AR  :  init_state <= INIT_TRF;
            INIT_TRF :  init_state <= (trfc_end) ? ((cnt_aref == 4'd8) ? INIT_MRS : INIT_AR) : INIT_TRF;
            INIT_MRS :  init_state <= INIT_TMRD;
            INIT_TMRD:  init_state <= (trmd_end) ? INIT_END : INIT_TMRD;
            INIT_END :  init_state <= INIT_END;
            default:    init_state <= INIT_IDLE;
        endcase
    end

/* 200us counter*/
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_200us <= 15'd0;
    else if(cnt_200us == WAIT_MAX)
        cnt_200us <= WAIT_MAX;
    else 
        cnt_200us <= cnt_200us + 1'b1;

/* wait_end*/
assign wait_end = (cnt_200us == WAIT_MAX - 1) ? 1'b1 : 1'b0;

/* cnt_clk*/

always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_clk <= 3'd0;
    else if(cnt_clk_rst)
        cnt_clk <= 3'd0;
    else
        cnt_clk <= cnt_clk + 1'b1;

/* cnt_clk_rst*/

always @(*)
    begin
        case(init_state)
            INIT_IDLE:      cnt_clk_rst <= 1'b1 ;
            INIT_TRP:       cnt_clk_rst <= (trp_end) ? 1'b1 : 1'b0;
            INIT_TRF:       cnt_clk_rst <= (trfc_end) ? 1'b1 : 1'b0;
            INIT_TMRD:      cnt_clk_rst <= (trmd_end) ? 1'b1 : 1'b0;
            INIT_END:       cnt_clk_rst <= 1'b1;
            default:        cnt_clk_rst <= 1'b0;
        endcase
    end

/*end signal */
assign trp_end = ((init_state == INIT_TRP) && cnt_clk == TPR) ? 1'b1 : 1'b0;
assign trfc_end = ((init_state == INIT_TRF) &&cnt_clk == TRF) ? 1'b1 : 1'b0;
assign trmd_end = ((init_state == INIT_TMRD) && cnt_clk == TMRD) ? 1'b1 : 1'b0;

/* cnt_aref */
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        cnt_aref <= 4'd0;
    else if(init_state == INIT_IDLE)
        cnt_aref <= 4'd0;
    else if(init_state == INIT_AR)
        cnt_aref <= cnt_aref + 1'b1;


always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        begin
            init_cmd    <=  NOP;
            init_ba     <=  2'b11;
            init_addr   <=  13'h1fff;
        end
    else begin
        case(init_state)
            INIT_IDLE   : begin
                        init_cmd <= NOP;
                        init_ba <= 2'b11;
                        init_addr <= 13'h1fff;
            end
            INIT_TRP    : begin
                        init_cmd <= NOP;
                        init_ba <= 2'b11;
                        init_addr <= 13'h1fff;
            end
            INIT_TRF    : begin
                        init_cmd <= NOP;
                        init_ba <= 2'b11;
                        init_addr <= 13'h1fff;
            end
            INIT_TMRD   : begin
                        init_cmd <= NOP;
                        init_ba <= 2'b11;
                        init_addr <= 13'h1fff;
            end
            INIT_END    : begin
                        init_cmd <= NOP;
                        init_ba <= 2'b11;
                        init_addr <= 13'h1fff;
            end
            INIT_PRE    :
                    begin
                            init_cmd <= P_CHARGE    ;
                            init_ba  <= 2'b11;
                            init_addr <= 13'h1fff;
                    end
            INIT_AR     :
                    begin
                            init_cmd <= AUTO_REF    ;
                            init_ba  <= 2'b11;
                            init_addr <= 13'h1fff;
                    end
            INIT_MRS    :
                    begin
                            init_cmd <= M_REG_SET    ;
                            init_ba  <= 2'b00;
                            init_addr <= {3'b0, 1'b0, 2'b00, 3'b011, 1'b0, 3'b111};
                    end
            default     :   
                    begin
                            init_cmd    <=  NOP;
                            init_ba     <=  2'b11;
                            init_addr   <=  13'h1fff;
                    end
        endcase
    end


assign init_end = (init_state == INIT_END) ? 1'b1 : 1'b0;


endmodule

testbench 如下

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/27 15:48:44
// Design Name: 
// Module Name: tb_sdram_init
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_sdram_init();

reg                 sys_clk         ;
reg                 sys_rst_n       ;
wire    [3:0]       init_cmd        ;
wire    [1:0]       init_ba         ;
wire    [12:0]      init_addr       ;
wire                init_end        ;


wire        clk_50m         ;
wire        clk_100m        ;
wire        clk_100m_shift  ;
wire        locked          ;
wire        rst_n           ;
initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        $display("yes");
        #30
        sys_rst_n <= 1'b1;
end

always #10 sys_clk = ~sys_clk;

assign  rst_n = (sys_rst_n) & locked;
defparam    sdram_model_plus_inst.addr_bits = 13    ;
defparam    sdram_model_plus_inst.data_bits = 16    ;
defparam    sdram_model_plus_inst.col_bits  = 9     ;
defparam    sdram_model_plus_inst.mem_sizes = 2 * 1024 * 1024;

clk_wiz_0   u_clk_wiz_0
(
    .clk_in1    (sys_clk)       ,
    .reset      (sys_rst_n )    ,
    .clk_50     (clk_50m)       ,
    .clk_100    (clk_100m)      ,
    .clk_100_shift(clk_100m_shift),
    .locked     (locked)
);

sdram_init  u_sdram_init(
    . sys_clk   (sys_clk    )   ,
    . sys_rst_n (sys_rst_n  )   ,

    . init_cmd  (init_cmd   )   ,
    . init_ba   (init_ba    )   ,
    . init_addr (init_addr  )   ,
    . init_end  (init_end   )  
    );

sdram_model_plus sdram_model_plus_inst
(      .Dq      ()    , 
       .Addr    (init_addr)    ,
       .Ba      (init_ba)    , 
       .Clk     (clk_100m_shift)    , 
       .Cke     (1'b1)   , 
       .Cs_n    (init_cmd[3])    , 
       .Ras_n   (init_cmd[2])    , 
       .Cas_n   (init_cmd[1])    , 
       .We_n    (init_cmd[0])    , 
       .Dqm     (2'b00)   ,
       .Debug   (1'b1)
        );
    
endmodule

波形如下 可以知道成功进行了初始化
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值