SDRAM控制器(自动刷新模块)

SDRAM自动刷新

刷新命令(Refresh)

SDRAM 只有通过刷新操作才能保证数据的可靠性,当然不能一直进行刷新,那将变得毫无意义, SDRAM 的刷新操作是周期性的,在两次刷新的间隔可以进行数据的相关操作,那我们不禁要问,刷新周期是多少呢?
目前国际公认的标准是,存储体中电容的数据有效保存期上限是 64ms, 也就是说每一行刷新的循环周期最大为 64ms,那么刷新速度就是:行数/64ms。我们在 SDRAM 的数据手册中经常会看到 4096 Refresh Cycles/64ms 或 8192 Refresh Cycles/64ms 的相关介绍, 这里的 4096 与 8192 就代表SDRAM 芯片中单个 L-Bank 的行数。刷新命令一次对一行有效,发送间隔也是随总行数而变化, 当单个 L-Bank 为 4096 行时,刷新间隔最大为 15.625μs,单个 L-Bank 为 8192 行时,刷新间隔最大为 7.8125μs。(但是通常不会在边缘刷新,所以我们采用7.5us刷新一次
关于具体的内容可以查看野火的教程

《征途Pro FPGA Verilog开发实战指南–基于Altera EP4CE10 》(下)

自动刷新模块

我们提到, SDRAM 内部存储体是利用电容能够保持电荷以及可充放电的特性制成,而电容所存储的电荷会随时间不断流失,会造成存储数据的丢失。为保证SDRAM 中数据的可靠性,需要对 SDRAM 进行不断刷新。

自动刷新时序

在进行自动刷新模块设计之前,我们先来了解一下 SDRAM 刷新操作的两种方式。SDRAM 的刷新方式分为自刷新和自动刷新两种,这两种刷新方式,在实现和作用上存在差异。

自动刷新模式:作用是在 SDRAM 的正常操作过程中,保证数据不丢失,自动刷新过程需要外部时钟的参与,但刷新行地址由内部刷新计数器控制,无需外部写入。

自刷新模式则主要用于休眠模式低功耗状态下的数据保存, 自刷新过程无需外部时钟参与,与自动刷新相同的是,刷新行地址由内部刷新计算器控制,无需外部写入。两者的操作命令相同,当 CKE 信号保持高电平时,写入刷新指令,进入自动刷新模式;当 CKE 信号为低电平时,写入刷新指令,进入自刷新模式。自刷新模式下,除 CKE 之外的其他外部信号均无效,当 CKE 再次拉高时,退出自刷新模式,进入正常操作状态。两种刷新方式时序图,具体见图 53-35、 图 53-36。
在这里插入图片描述
在本章节实验中,我们是在 SDRAM 正常模式下进行刷新操作,要使用自动刷新方式。在此我们只对 SDRAM 的自动刷新操作的时序图和参考流程进行讲解。若读者对自刷新操作的相关知识感兴趣,可自行查阅芯片数据手册或相关资料。
由 SDRAM 自动刷新时序图可知, SDRAM 的自动刷新类似于简化版的初始化操作,只是缺少了上电后的等待时间和模式寄存器配置部分,只包含一次预充电操作和两次自动刷新操作,自动刷新操作参考流程如下。
(1) 写入预充电命令, A10 设置为高电平,对所有 L-Bank 进行预充电;
(2) 预充电指令写入后,等待 tRP时间,此过程中操作命令保持为空操作命令;
(3) tRP等待时间结束后,写入自动刷新命令;
(4) 自动刷新命令写入后,等待 tRC时间,此过程中操作命令保持为空操作命令;
(5) tRC等待时间结束后,再次写入自动刷新命令;
(6) 自动刷新命令写入后,等待 tRC时间,此过程中操作命令保持为空操作命令;
(7) tRC等待时间结束后,自动刷新操作完成。
注:对于 tRP、 tRC 等时间参数,不同芯片可能存在差异,读者需查阅芯片对应数据
手册。

在学习了 SDRAM 自动刷新时序和参考流程之后,我们来设计一下自动刷新模块的整体框架。自动刷新模块整体框图和输入输出信号的功能描述,具体见图 53-37、 表格53-6。
在这里插入图片描述
输入信号: init_end 为初始化模块传入的初始化完成标志信号,表示初始化完成,SDRAM 进入正常模式,可进行其他操作; aref_en 为自动刷新使能信号,表示仲裁模块响应自动刷新请求,自动刷新模块可以开始自动刷新操作。
输出信号: aref_cmd、 aref_ba、 aref_addr 分别为自动刷新阶段的指令信号、逻辑 Bank地址和地址总线; aref_req 为自动刷新请求信号,向仲裁模块请求执行自动刷新操作;aref_end 为自动刷新结束标志信号,告知仲裁模块自动刷新操作完成, SDRAM 可进行其他操作。

自动刷新模块波形图
在这里插入图片描述

附上代码:(感觉野火把代码复杂化了)

`timescale 1ns / 1ps
//
// Company: 喵喵
// Engineer: 喵
// 
// Create Date: 2021/04/25 16:59:00
// Design Name: 喵喵喵超级无敌大猫猫
// Module Name: SDRAM_AREF
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module SDRAM_AREF
(
      input             wire               sys_clk,
	  input             wire               sys_rst_n,
	  input             wire               sd_init_end,
	  input             wire               aref_en,
	  output            reg     [3:0]      aref_cmd,
	  output            reg     [1:0]      aref_ba,
	  output            reg                aref_re,
	  output            reg     [12:0]     aref_add,
	  output            reg                aref_end
);

parameter      NOP = 4'b0111,
               PRE = 4'b0010,
			   REF = 4'b0001;
parameter      aref_cnt_max = 10'd749;
reg     [9:0]  aref_cnt;

reg     [4:0]  aref_cmd_cnt;
reg            aref_cmd_en;

always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    aref_cnt <= 'b0;
   else if(aref_cnt == aref_cnt_max&&sd_init_end == 1'b1)
    aref_cnt <= 'b0;
   else if(sd_init_end == 1'b1)
    aref_cnt <= aref_cnt + 1'b1;
end

always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    aref_cmd_en <= 1'b0;
   else if(aref_en == 1'b1)
    aref_cmd_en <= 1'b1;
   else if(aref_cmd_cnt == 5'd19)
    aref_cmd_en <= 1'b0;
end 

always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    aref_cmd_cnt <= 'b0;
   else if(aref_cmd_en)
    aref_cmd_cnt <= aref_cmd_cnt + 1'd1;
   else 
    aref_cmd_cnt <= 'd0;
end 

always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    aref_cmd <= NOP;
   else if(aref_cmd_en == 1'b1)
    case(aref_cmd_cnt)
	0:aref_cmd <= PRE;
	3:aref_cmd <= REF;
	11:aref_cmd <= REF;
	default:aref_cmd <= NOP;
    endcase
   else
    aref_cmd <= NOP;
end 

always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    aref_re <= 1'b0;
   else if(aref_cnt == aref_cnt_max)
    aref_re <= 1'b1;
   else if(aref_en)
    aref_re <= 1'b0;
end 

always@(posedge sys_clk)
  aref_ba <= 2'b11;
always@(posedge sys_clk)
  aref_add <= 13'h1fff;
always@(posedge sys_clk)
begin
   if(sys_rst_n == 1'b0)
    aref_end <= 1'b0;
   else if(aref_cmd == 5'd19)
    aref_end <= 1'b1;
   else
    aref_end <= 1'b0;
end 


endmodule

仿真
在这里插入图片描述
可以得知每个7.5us刷新一次。

总结

其实自动刷新就是不要上电和寄存器配置的初始化,不过记得刷新是周期性的,每隔7.5us执行刷新一次,在7.5us的别的时刻可以进行另外的操作如读写等。

猜你喜欢

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