目錄
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、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 = 3'b000; parameter PRECHARG = 3'b001; parameter AUTO_REF1 = 3'b010; parameter AUTO_REF2 = 3'b011; parameter MODE_REG = 3'b100; parameter IDLE = 3'b101; parameter AUTO_REF = 3'b110; parameter TIME_100US = 10_000 ; parameter TRP = 3 ; //這些數據由數據手冊可以獲得 parameter TRC = 7 ; parameter TMRD = 2 ; parameter TIME_1562 = 1562 ; parameter MODE_VALUE = 12'b000_00_011_0_111; //即全頁模式,順序,CL=3,突發讀,突發寫。 parameter NOP_CD = 4'b0111; parameter PRECHARGE_CD = 4'b0010; parameter AUTO_REF_CD = 4'b0001; parameter MODE_REG_CD = 4'b0000; //----------------------------------------------------------------------狀態機的設計 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)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)? 1'b1 : 1'b0; //cnt_0是一個遞減計數器 assign get_trp = (c_state == PRECHARG && cnt_0 == 0)? 1'b1 : 1'b0; assign get_trc1 = (c_state == AUTO_REF1&& cnt_0 == 0)? 1'b1 : 1'b0 ; assign get_trc2 = (c_state == AUTO_REF2&& cnt_0 == 0)? 1'b1 : 1'b0 ; assign get_tmrd = (c_state == MODE_REG && cnt_0 == 0)? 1'b1 : 1'b0 ; assign get_1562 = (c_state == IDLE && cnt_0 == 0)? 1'b1 : 1'b0 ; assign get_trc3 = (c_state == AUTO_REF && cnt_0 == 0)? 1'b1 : 1'b0 ; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)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==1'b0)begin dqm<=2'b11; 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<=2'b11; end else dqm<=2'b00; end assign dq = 16'hzzzz; //dq為高阻態 assign {cs,ras,cas,we} = command; //cs,ras,cas,we的設計 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)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==1'b0)begin addr <= 0; end else if(get_trc2) begin addr <= MODE_VALUE; end else if(get_100us) addr <= (12'b1 << 10 ); //A10=1 else addr <= 0; end always @(posedge clk or negedge rst_n)begin //bank初始化用不到,取0; if(rst_n==1'b0)begin bank <= 2'b00; end else begin bank <= 2'b00; 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)

由圖可知,自動刷新也正常。
如有問題歡迎指正交流。
