码迷,mamicode.com
首页 > 其他好文 > 详细

基于verilog的SDRAM初始化

时间:2016-09-10 23:58:47      阅读:754      评论:0      收藏:0      [点我收藏+]

标签:

目录

1、SDRAM初始化的内容(结合英文数据手册)

2、SDRAM初始化的时序

3、代码的编写

4、modesim的仿真

 


 SDRAM初始化的内容

    SDRAMs must be powered up and initialized in a predefined manner. The 64M SDRAM is initialized after the power is applied to Vdd and Vddq, and the clock is stable with DQM High and CKE High.  A 100μs delay is required prior to issuing any command other than a COMMAND INHIBIT or a NOP.

    The COMMAND INHIBIT or NOP may be applied during the 100μs period and continue should at least through the end of the period.With at least one COMMAND INHIBIT or NOP command having been applied, a PRECHARGE command should be applied once the 100μs delay has been satisfied. All banks must be precharged. This will leave all banks in an idle state, after which at least two AUTO REFRESH cycles must be performed. After the AUTO REFRESH cycles are complete, the SDRAM is then ready for mode register programming.The mode register should be loaded prior to applying any operational command because it will power up in an unknown state. After the Load Mode Register command, at least two NOP commands must be asserted prior to any command.

Sdram 在工作前需要进行初始化
1、sdram 上电,时钟稳定,DQM高,CKE高,开始初始化
2、至少100us的等待时间,在这个等待时间之内不能有除了COMMAND INHIBIT 或 NOP 以外的任何命令,COMMAND INHIBIT 或 NOP命令需持续生效。
3、在100us等待时间结束之后,所有的 bank 需要预充电,(执行 PRECHARGE 需要 tRP 的时间)。
4、至少两个自动刷新命令(每个自动刷新都需要tRC的时间)
5、模式寄存器的配置(需要tMRD的时间)。
6、初始化完成以后处于idle的状态,每隔 64ms/2^12 =64_000_000 ns/4096=15625ns,因为工作时钟为100Mhz,所以需要每隔1562个时钟需要发一个自动刷新指令(这个64ms将所有行刷新一次是由SDRAM的内部结构决定的)
 注意:所需要的时间需要从数据手册中得到(datasheet一定要看英文原版)
技术分享

技术分享 

状态机
技术分享
 

SDRAM初始化的时序 

技术分享

这个时序图可以结合状态机的图理解,非常重要,因为每个状态需要的时间都不一样,所以需要设计计数器。

1、CKE 一直为高电平

2、command 由 cs,ras,cas,we 四个控制信号实现,具体如下图

例如 NOP命令 cs=0,ras=1,cas=1,we=1

技术分享

3、DQM在初始化的时候始终为1

4、A10为高,则忽略BA0,BA1,对所有bank 进行预刷新。

5、在配置模式寄存器时,根据自己的需求设置参数

例如当 mode_value=000_00_011_0_111 即全页模式,顺序,CL=3,突发读,突发写。

技术分享

 


代码的编写

初始化代码

/*1、工作时钟定为100Mhz
  2、 Sdram 初始化
  3、Sdram 的自动刷新功能:每隔 64ms/2^12=15625 个时钟周期,给出刷新命令。*/
//------------------------------------------------------------------------------------  

module Sdram_initial(
                      clk   ,
                      rst_n ,
                      cke   ,
                      cs    ,
                      ras   ,
                      cas   , 
                      we    ,
                      dqm   ,  
                      addr  ,
                      bank  ,
                      dq   
                    );

 input         clk   ;  //100Mhz
 input         rst_n ;  
output         cke   ;  //clk enable
output         cs    ;  //片选信号
output         ras   ;  //
output         cas   ;  //
output         we    ;  //读写控制端
output [11:0]  dqm   ;  //byte controlled by LDQM and UDQM
output [11:0]  addr  ;  //12个位地址
output [ 1:0]  bank  ;  //sdram有4个逻辑bank
inout  [15:0]  dq    ;  //是三态门


wire         cs    ;
wire         ras   ;
wire         cas   ;
wire         we    ;
wire  [15:0]  dq    ;

reg  [11:0]  dqm   ;
reg  [11:0]  addr  ;
reg [ 1:0]  bank  ;

reg [3:0] command  ;
reg [2:0] c_state  ;
reg [2:0] n_state  ;
reg [13:0] cnt_0   ;
wire get_100us  ;
wire get_trp    ;
wire get_trc1   ;
wire get_trc2   ;
wire get_tmrd   ;
wire get_1562   ;
wire get_trc3   ;

//----------------------------------------------------------------------
parameter  NOP        = 3b000;
parameter  PRECHARG   = 3b001;
parameter  AUTO_REF1  = 3b010;
parameter  AUTO_REF2  = 3b011;
parameter  MODE_REG   = 3b100;
parameter  IDLE       = 3b101;
parameter  AUTO_REF   = 3b110;

parameter   TIME_100US = 10_000 ;
parameter   TRP        = 3          ; //这些数据由数据手册可以获得
parameter   TRC        = 7          ;
parameter   TMRD       = 2          ;
parameter   TIME_1562  = 1562       ;
parameter   MODE_VALUE = 12b000_00_011_0_111;  //即全页模式,顺序,CL=3,突发读,突发写。

parameter  NOP_CD       = 4b0111;
parameter  PRECHARGE_CD = 4b0010;
parameter  AUTO_REF_CD  = 4b0001;
parameter  MODE_REG_CD  = 4b0000;
 

//----------------------------------------------------------------------状态机的设计

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
        c_state<=NOP;
    end
    else begin
        c_state<=n_state;
    end
end

always  @(*)begin
    case(c_state)
        NOP       :begin
                      if(get_100us)    //等待100us后跳转
                         n_state = PRECHARG;
                      else
                         n_state = c_state;
                   end
        PRECHARG  :begin
                      if(get_trp)    //trp时间后
                         n_state = AUTO_REF1;
                      else
                         n_state = c_state;
                   end
        AUTO_REF1 :begin 
                      if(get_trc1) //trc
                         n_state = AUTO_REF2;
                      else
                         n_state = c_state; 
                   end 
        AUTO_REF2 :begin
                      if(get_trc2) //trc
                         n_state = MODE_REG;
                      else
                         n_state = c_state;
                   end
        MODE_REG  :begin
                      if(get_tmrd) //tmrd
                         n_state = IDLE;
                      else
                         n_state = c_state;
                   end
        IDLE      :begin
                       if(get_1562) //等待1562个始终周期
                         n_state = AUTO_REF;
                      else
                         n_state = c_state;
                   end
        AUTO_REF  :begin if(get_trc3) //trc
                         n_state = IDLE;
                      else
                         n_state = c_state;
                   end

          default  :     n_state = NOP;  //其他状态转移到NOP

    endcase
end

assign get_100us = (c_state == NOP      && cnt_0 == 0)? 1b1 : 1b0;  //cnt_0是一个递减计数器
assign get_trp   = (c_state == PRECHARG && cnt_0 == 0)? 1b1 : 1b0;
assign get_trc1  = (c_state == AUTO_REF1&& cnt_0 == 0)? 1b1 : 1b0 ;
assign get_trc2  = (c_state == AUTO_REF2&& cnt_0 == 0)? 1b1 : 1b0 ;
assign get_tmrd  = (c_state == MODE_REG && cnt_0 == 0)? 1b1 : 1b0 ;
assign get_1562  = (c_state == IDLE     && cnt_0 == 0)? 1b1 : 1b0 ;
assign get_trc3  = (c_state == AUTO_REF && cnt_0 == 0)? 1b1 : 1b0 ;

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
        cnt_0 <= TIME_100US-1;
    end
    else if(get_100us) begin
        cnt_0 <= TRP-1;
    end
    else if(get_trc1 || get_1562||get_trp) begin
        cnt_0 <= TRC-1;
    end
    else if(get_trc2)begin
        cnt_0 <= TMRD-1;
    end
    else if(get_tmrd||get_trc3)
        cnt_0 <= TIME_1562-1;
    else if(cnt_0 != 0)
        cnt_0 <= cnt_0 -1;
end


//----------------------------------------------------------------------


assign cke=1;   //cke始终为1
always  @(posedge clk or negedge rst_n)begin //dqm在初始化状态始终为1
    if(rst_n==1b0)begin
        dqm<=2b11;
    end
    else if( c_state == NOP || c_state == PRECHARG || c_state == AUTO_REF1 ||
        c_state == AUTO_REF2 || c_state ==AUTO_REF2 || c_state == MODE_REG )  begin 
       dqm<=2b11;            
    end
    else
        dqm<=2b00;
end


assign dq = 16hzzzz;  //dq为高阻态

assign {cs,ras,cas,we} = command; //cs,ras,cas,we的设计
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
        command <= NOP_CD ;
    end
    else if(get_100us) begin
        command <= PRECHARGE_CD ;
    end
    else if(get_trp || get_trc1 || get_1562 )
        command <= AUTO_REF_CD  ;
    else if(get_trc2)
        command <= MODE_REG_CD  ;
    else
        command <= NOP_CD       ;

end

always  @(posedge clk or negedge rst_n)begin 
    if(rst_n==1b0)begin
        addr <= 0;
    end
    else if(get_trc2) begin
        addr <= MODE_VALUE;
    end
    else if(get_100us)
        addr <= (12b1 << 10 );  //A10=1
    else
        addr <= 0;
end

always  @(posedge clk or negedge rst_n)begin  //bank初始化用不到,取0;
    if(rst_n==1b0)begin
        bank <= 2b00;
    end
    else begin
        bank <= 2b00;
    end
end
endmodule

testbench

`timescale 1 ns/1 ns

module Sdram_test();

//时钟和复位
reg clk  ;
reg rst_n;

//uut的输入信号
wire         cke   ;
wire         cs    ;  //片选信号
wire         ras   ;  //
wire         cas   ;  //
wire         we    ;  //读写控制端
wire [11:0]  dqm   ;  //byte controlled by LDQM and UDQM
wire [11:0]  addr  ;  //12个位地址
wire [ 1:0]  bank  ;  //sdram有4个逻辑bank
wire [15:0]  dq    ;  //是三态门
   

        //时钟周期,单位为ns,可在此修改时钟周期。
        parameter CYCLE    = 10;

        //复位时间,此时表示复位3个时钟周期的时间。
        parameter RST_TIME = 3 ;

        //待测试的模块例化
      Sdram_initial  uu1(
                    .clk  (clk ),
                    .rst_n(rst_n),
                    .cke  (cke ),
                    .cs   (cs  ),
                    .ras  (ras ),
                    .cas  (cas ), 
                    .we   (we  ),
                    .dqm  (dqm ),  
                    .addr (addr),
                    .bank (bank),
                    .dq   (dq  )
                    ); 


            //生成本地时钟50M
            initial begin
                clk = 0;
                forever
                #(CYCLE/2)
                clk=~clk;
            end

            //产生复位信号
            initial begin
                rst_n = 1;
                #2;
                rst_n = 0;
                #(CYCLE*RST_TIME);
                rst_n = 1;
            end
            endmodule

 


 modesim的仿真

技术分享

1、2、3、4、5就是初始化的5个状态,用红框框起来的数字就是各种时间的初始值 Trp=3 , Trc=7, Tmrd=2(倒数到0,因此需要减1)

技术分享

由图可知,自动刷新也正常。

如有问题欢迎指正交流。

 转载请注明出处:http://www.cnblogs.com/aslmer/p/5860382.html

基于verilog的SDRAM初始化

标签:

原文地址:http://www.cnblogs.com/aslmer/p/5860382.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!