SDRAM控制器(初始化)

SDRAM控制器(初始化)

初始化模块

SDRAM 在上电之后,执行正常操作之前需要被初始化,实际上就是对上文提到的SDRAM 内部逻辑控制单元进行初始化,初始化成功的 SDRAM 才可进行后续的其他操作。接下来我们将要学习掌握初始化操作时序,设计、实现并仿真验证初始化模块功能。
初始化操作时序
SDRAM 的初始化是芯片上电后必须进行的一项操作,只有进行了初始化操作的SDRAM 芯片才可被正常使用。 SDRAM 的初始化是一套预先定义好的流程,除此之外的其他操作会导致 SDRAM 出现不可预知的后果。 SDRAM 初始化操作时序图,具体见图53-23。在这里插入图片描述
结合 SDRAM 初始化时序图, 列出 SDRAM 初始化参考流程如下:
(1) 对 SDRAM 上电,加载稳定时钟信号, CKE 设置为高电平;
(2) 等待至少 T=100us 的时间,此过程中操作命令保持为空操作命令;
(3) 100us 等待结束后,写入预充电命令, A10 设置为高电平,对所有 L-Bank 进行预充电;
(4) 预充电指令写入后,等待 tRP时间,此过程中操作命令保持为空操作命令;
(5) tRP等待时间结束后,写入自动刷新命令;
(6) 自动刷新命令写入后,等待 tRC时间,此过程中操作命令保持为空操作命令;
(7) tRC等待时间结束后,再次写入自动刷新命令;
(8) 自动刷新命令写入后,等待 tRC时间,此过程中操作命令保持为空操作命令;
(9) tRC 等待时间结束后,写入模式寄存器配置指令,地址总线 A0-A11 参数不同辅助模式寄存器不同模式的设置;
(10) 模式寄存器配置指令写入后,等待 tMRD 时间,此过程中操作命令保持为空操作命令;
(11) tMRD等待时间结束后, SDRAM 初始化完成。
注: 1.对于 tRP、 tRC、 tMRD 等时间参数,不同芯片或速度等级可能存在差异,读者需查阅
芯片对应数据手册进行参数设置;
2.T=100us 为最小等待时间,我们在使用 SDRAM 时,等待时间 T 可适当延长;
3.初始化过程中,至少进行两次自动刷新,也可适当增加刷新次数。

时序逻辑图

在这里插入图片描述
(1)因为对于时间等待参数,我们可以设置成时钟的倍数,所以我们可以用计数器控制 (当然也可以用状态机,因为状态机很适合设计接口) 对于预充电,自刷新,寄存器配置的指令只需要一个cycle即可写入,所以有用的控制命令只保持一个时钟 ,对于trp我们设为3个时钟周期,trp是指写入预充电指令与自动刷新指令之间的时间, 所以在逻辑图里我们只给了trp2个时钟周期,因为还要加上PRE的时钟周期,刚好三个。 类似的不写了。

代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/04/22 17:28:14
// Design Name:   超级无敌大猫猫
// Module Name: SDRAM_INIT
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
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       reg                 init_end
  );  
reg       [14:0]      DELAY_CNT;
reg       [4:0]           command_cnt;
wire                  delay_flag;
always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    DELAY_CNT <= 'b0;
   else if(DELAY_CNT == 15'd20000)
    DELAY_CNT <= DELAY_CNT;
   else
    DELAY_CNT <= DELAY_CNT + 1'b1;
end 
assign delay_flag = (DELAY_CNT == 15'd20000)? 1'b1:1'b0;
always@(posedge sys_clk)	
begin
   if(sys_rst_n == 1'b0)
    command_cnt <= 'b0;
   else if(command_cnt == 5'd31&&delay_flag)
    command_cnt <= command_cnt;
   else if(delay_flag)
    command_cnt <= command_cnt + 1'b1;
end 
always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    init_cmd <= 4'b0111;
   else if(DELAY_CNT == 15'd19999)
    init_cmd <= 4'b0010;
   else if(delay_flag == 1'b1)
   begin
    case(command_cnt)
	 0 : init_cmd <= 4'b0111;
	 2 : init_cmd <= 4'b0001;
	 3 : init_cmd <= 4'b0111;
	 10 :init_cmd <= 4'b0001;
	 11 :init_cmd <= 4'b0111;
	 18 :init_cmd <= 4'b0001;
	 19 :init_cmd <= 4'b0111;
	 26 :init_cmd <= 4'b0000;
	 27 :init_cmd <= 4'b0111;
	 default : init_cmd <= 4'b0111;
	 endcase
	 end
	else 	 
	init_cmd <= 4'b0111;
end 
always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    init_end <= 1'b0;
   else if(command_cnt == 5'd30)
    init_end <= 1'b1;
end 
always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    init_ba <= 2'b11;
   else if(command_cnt == 5'd26)
    init_ba <= 2'b00;
   else
    init_ba <= 2'b11;
end 
always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    init_addr <= 13'h1fff;
   else if(command_cnt == 5'd26)
    init_addr <= {3'b000,1'b0,2'b00,3'b011,1'b0,3'b111};
   else
    init_addr <= 13'h1fff;
end 
endmodule

仿真结果

在这里插入图片描述
记住一定要足够的仿真时间长能出数据,因为我们的上电是200us,所以仿真时间最好设置大于200us才出数据。

猜你喜欢

转载自blog.csdn.net/weixin_44716774/article/details/116044845