目录
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.
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)
由图可知,自动刷新也正常。
如有问题欢迎指正交流。
转载请注明出处:http://www.cnblogs.com/aslmer/p/5860382.html