SDRAM初始化模块
使用野火的波形图编程 首先明确各个信号之间的依赖关系
- state: 最后来考虑,先把他需要的信号准备好
- cnt_200us: 需要根据数据手册给的参数设定,这里等待200us,因此需要一个200us的计数器,这个计数器只完成一个使命,上电计数,计满200us就不管后面的事
- wait_end: 计满200us后要给出一个计满信号 (依赖 cnt_200us)
- cnt_cmd: 计数器,用来给3个等待时间计数 (依赖 cnt_cmd_reset)
- cnt_cmd_reset:上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end、tmrd_end)
- trp_end、trfc_end、tmrd_end: 自家延时结束的信号(依赖 状态)
- cnt_ref: 自动刷新的次数,至少需要2次自动刷新(依赖状态 INIT_AR)
//SDRAM初始化模块 // 使用野火的波形图编程 // 首先明确各个信号之间的依赖关系 // 1. state: 最后来考虑,先把他需要的信号准备好 // 2. cnt_200us: 需要根据数据手册给的参数设定,这里等待200us // 因此需要一个200us的计数器,这个计数器只完成一个使命,上电计数,计满200us就不管后面的事 // 3. wait_end: 计满200us后要给出一个计满信号 (依赖 cnt_200us) // 4. cnt_cmd: 计数器,用来给3个等待时间计数 (依赖 cnt_cmd_reset) // 5. cnt_cmd_reset:上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end、tmrd_end) // 6. trp_end、trfc_end、tmrd_end: 自家延时结束的信号(依赖 状态) // 7. cnt_ref: 自动刷新的次数,至少需要2次自动刷新(依赖状态 INIT_AR) module sdram_initial( input clk,//100M时钟信号 input rst_n, output reg [3:0] init_cmd,//SDRAM命令,组成{CS#,RAS#,CAS#,WE#} output reg [1:0] init_bank,//BANK地址,共4个BANK output reg [12:0] init_addr,//SDRAM地址总线 output init_end//初始化完成信号,初始化完成后拉高,其他时间保持低电平 ); //命令指令参数 localparam PRECHARGE = 4'b0010 , //预充电指令 AT_REF = 4'b0001 , //自动刷新指令 NOP = 4'b0111 , //空操作指令 MREG_SET = 4'b0000 ; //模式寄存器设置指令 // 状态参数 parameter INIT_IDLE = 8'b0000_0001; parameter INIT_PRE = 8'b0000_0010;//预充电 parameter INIT_TRP = 8'b0000_0100;//等待tRP parameter INIT_AR = 8'b0000_1000;//自动刷新 parameter INIT_TRFC = 8'b0001_0000;//等待tRFC parameter INIT_MRS = 8'b0010_0000;//配置模式寄存器 parameter INIT_TMRD = 8'b0100_0000;//等待tMRD parameter INIT_END = 8'b1000_0000; // 计数器最大参数 parameter CNT_200 = 8'd20_000;//一个周期10ns,200us要用20_000个时钟周期 //最大刷新次数 parameter MAX_REF = 4'd8; //等待时间参数定义 localparam TRP = 3'd2 , //发送预充电指令后进行下一个操作需要等待的时间 TRFC = 3'd7 , //发送自动刷新指令后进行下一个操作需要等待的时间 TMRD = 3'd3 ; //发送设置模式寄存器指令后进行下一个操作需要等待的时间 reg [7:0] state; reg [7:0] next_state; reg [7:0] cnt_200us;//芯片上电后需要等待 至少100us 的时间(在数据手册Figur18左下角) reg [3:0] cnt_cmd; //计数:2、3、7 reg [3:0] cnt_ref; //自动刷新8次 //这些信号要提前准备好,要比状态变化提前一个时钟周期 wire wait_end; wire cnt_cmd_reset; wire trp_end; wire trfc_end; wire tmrd_end; assign wait_end = (cnt_200us == CNT_200 - 1)? 1'd1: 1'd0; assign trp_end = ((state == INIT_TRP) && (cnt_cmd == TRP - 1)) ? 1'd1:1'd0; assign trfc_end = ((state == INIT_TRFC) && (cnt_cmd == TRFC - 1)) ? 1'd1:1'd0; assign tmrd_end = ((state == INIT_TMRD) && (cnt_cmd == TMRD - 1)) ? 1'd1:1'd0; assign cnt_cmd_reset = ((state == INIT_IDLE) || (state == INIT_END) || (trp_end) || (trfc_end) || (tmrd_end))?1'd1:1'd0; assign init_end = (state == INIT_END)? 1'd1 : 1'd0; // 200us计数器 always@(posedge clk or negedge rst_n)begin if(!rst_n )begin
cnt_200us <= 8'd0; end else if(cnt_200us == CNT_200)begin
cnt_200us <= cnt_200us; end else cnt_200us <= cnt_200us + 1; end // 3个延时计数器 always@(posedge clk or negedge rst_n)begin if(!rst_n )begin
cnt_cmd <= 4'd0; end else if(cnt_cmd_reset)begin
cnt_cmd <= 4'd0; end else cnt_cmd <= cnt_cmd + 4'd1; end
always@(posedge clk or negedge rst_n)begin if(!rst_n )begin
cnt_ref <= 4'd0; end else if(state == INIT_AR)begin
cnt_ref <= cnt_ref + 4'd1; end else cnt_ref <= cnt_ref; end // 第一段 always@(posedge clk or negedge rst_n)begin if(!rst_n )begin
state <= INIT_IDLE; end else state <= next_state; end // 第二段 always@(*)begin case(state) INIT_IDLE: if(wait_end) next_state = INIT_PRE; else next_state = INIT_IDLE; INIT_PRE: next_state = INIT_TRP; INIT_TRP: if(trp_end) next_state = INIT_AR; else next_state = INIT_TRP; INIT_AR:next_state = INIT_TRFC; INIT_TRFC: if(trfc_end) if(cnt_ref == MAX_REF) next_state = INIT_MRS; else next_state = INIT_AR; else next_state = INIT_TRFC; INIT_MRS:next_state = INIT_TMRD; INIT_TMRD: if(tmrd_end) next_state = INIT_END; else next_state = INIT_TMRD; INIT_END:next_state = INIT_END; default:next_state = INIT_IDLE; endcase
end // 第三段 always@(posedge clk or negedge rst_n)begin if(!rst_n )begin
init_cmd <= NOP; init_bank <= 2'b11; init_addr <= 13'h1fff; end else case(state) INIT_IDLE:begin
init_cmd <= NOP; init_bank <= 2'b11; init_addr <= 13'h1fff; end
INIT_PRE :begin
init_cmd <= PRECHARGE; init_bank <= 2'b11; init_addr <= 13'h1fff; end
INIT_TRP :begin
init_cmd <= NOP; init_bank <= 2'b11; init_addr <= 13'h1fff; end
INIT_AR :begin
init_cmd <= AT_REF; init_bank <= 2'b11; init_addr <= 13'h1fff; end
INIT_TRFC:begin
init_cmd <= NOP; init_bank <= 2'b11; init_addr <= 13'h1fff; end
INIT_MRS :begin
init_cmd <= MREG_SET;//进入模式寄存器配置 init_bank <= 2'b00; init_addr <= { 3'b000 , //A12-A10:预留 1'b0 , //A9=0:读写方式,0:突发读&突发写,1:突发读&单写 2'b00 , //{A8,A7}=00:标准模式,默认 3'b011 , //{A6,A5,A4}=011:CAS 潜伏期,010:2,011:3,其他:保留 1'b0 , //A3=0:突发传输方式,0:顺序,1:隔行 3'b111 //{A2,A1,A0}=111:突发长度,000:单字节,001:2 字节 }; end
INIT_TMRD:begin
init_cmd <= NOP; init_bank <= 2'b11; init_addr <= 13'h1fff; end
INIT_END :begin
init_cmd <= NOP; init_bank <= 2'b11; init_addr <= 13'h1fff; end default:; endcase
end
endmodule
modlesim命令窗口打印的信息
