文章目录
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的别的时刻可以进行另外的操作如读写等。