一.理论知识
1.SDRAM内部存储体是利用电容能够保持电荷以及可充放电的特性制成,而电容所存储的电荷会随时间不断流失,会造成存储数据的丢失。为保证SDRAM 中数据的可靠性,需要对 SDRAM 进行不断刷新。SDRAM的刷新方式分为自刷新和自动刷新两种。
2.自动刷新模式:作用是在 SDRAM 的正常操作过程中,保证数据不丢失,自动刷新过程需要外部时钟的参与,但刷新行地址由内部刷新计数器控制,无需外部写入。
3.自刷新模式则主要用于休眠模式低功耗状态下的数据保存, 自刷新过程无需外部时钟参与,与自动刷新相同的是,刷新行地址由内部刷新计算器控制,无需外部写入。
4.两者的操作命令相同{CS_N,RAS_N,CAS_N,WE_N} = 4’b0001,当 CKE 信号保持高电平时,写入刷新指令,进入自动刷新模式;当 CKE 信号为低电平时,写入刷新指令,进入自刷新模式。
5.自刷新模式下,除 CKE 之外的其他外部信号均无效,当 CKE 再次拉高时,退出自刷新模式,进入正常操作状态。
6.目前国际公认的标准是,存储体中电容的数据有效保存期上限是 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。
二.芯片时序分析
1.自动刷新操作时序
2.延迟时间
三.设计verilog时序图
四.verilog代码
module sdram_aref
(
input wire sys_clk,
input wire sys_rst_n,
input wire init_end,
input wire aref_en,
output reg aref_req,
output reg [3:0] aref_cmd,
output wire [1:0] aref_ba,
output wire [12:0] aref_addr,
output reg aref_end
);
// 每次自动刷新的间隔计数器
parameter CNT_AREF_WAIT = 750;
// 状态
parameter ST_IDLE = 0,
ST_PRE = 1,
ST_PRE_WAIT = 2,
ST_AUTO = 3,
ST_AUTO_WAIT = 4,
ST_AREF_END = 5;
// 延迟计数器的值
parameter CNT_PRE_WAIT = 2,
CNT_AUTO_WAIT = 7;
// 命令
parameter CMD_NOP = 4'b0111, // 无操作命令也叫空命令,控制指令为{CS_N,RAS_N,CAS_N,WE_N} = 4'b0111
CMD_PRE = 4'b0010, // 预充电命令,分为全部预充电和指定L-Bank预充电两种,控制指令均为{CS_N,RAS_N,CAS_N,WE_N} = 4'b0010
CMD_AUTO = 4'b0001; // 自动刷新命令,分为自动刷新命令和自刷新,控制指令均为{CS_N,RAS_N,CAS_N,WE_N} = 4'b0001
reg [9:0] cnt_wait;
reg cnt_wait_rst;
reg [2:0] state;
reg auto_flag;
reg end_flag;
reg [1:0] cnt_auto;
// cnt_wait信号
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_wait <= 0;
else if(cnt_wait_rst == 1)
cnt_wait <= 0;
else if(cnt_wait_rst == 0)
cnt_wait <= cnt_wait + 1;
end
// cnt_wait_rst信号
always@(*) begin
if(!sys_rst_n)
cnt_wait_rst <= 1;
else if(state == ST_IDLE && cnt_wait == CNT_AREF_WAIT)
cnt_wait_rst <= 1;
else if(aref_req == 1)
cnt_wait_rst <= 1;
else if(auto_flag == 1 || end_flag == 1)
cnt_wait_rst <= 1;
else if(init_end == 1)
cnt_wait_rst <= 0;
end
// aref_req信号
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
aref_req <= 0;
else if(state == ST_IDLE && cnt_wait == CNT_AREF_WAIT)
aref_req <= 1;
else if(aref_en == 1)
aref_req <= 0;
end
// state信号
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
state <= ST_IDLE;
else
case(state)
ST_IDLE :
if(aref_en == 1)
state <= ST_PRE;
else
state <= ST_IDLE;
ST_PRE :
state <= ST_PRE_WAIT;
ST_PRE_WAIT :
if(auto_flag == 1)
state <= ST_AUTO;
else
state <= ST_PRE_WAIT;
ST_AUTO :
state <= ST_AUTO_WAIT;
ST_AUTO_WAIT:
if(cnt_wait == CNT_AUTO_WAIT && cnt_auto == 2)
state <= ST_AREF_END;
else if(cnt_wait == CNT_AUTO_WAIT)
state <= ST_AUTO;
else
state <= ST_AUTO_WAIT;
ST_AREF_END :
state <= ST_IDLE;
default:
state <= ST_IDLE;
endcase
end
// auto_flag信号
always@(*) begin
if(!sys_rst_n)
auto_flag <= 0;
else if(state == ST_PRE_WAIT && cnt_wait == CNT_PRE_WAIT)
auto_flag <= 1;
else if(state == ST_AUTO_WAIT && cnt_wait == CNT_AUTO_WAIT && cnt_auto == 1)
auto_flag <= 1;
else
auto_flag <= 0;
end
// cnt_auto信号
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_auto <= 0;
else if(state == ST_IDLE)
cnt_auto <= 0;
else if(state == ST_AUTO)
cnt_auto <= cnt_auto + 1;
else
cnt_auto <= cnt_auto;
end
// end_flag信号
always@(*) begin
if(!sys_rst_n)
end_flag <= 0;
else if(state == ST_AUTO_WAIT && cnt_wait == CNT_AUTO_WAIT && cnt_auto == 2)
end_flag <= 1;
else
end_flag <= 0;
end
// aref_end信号
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
aref_end <= 0;
else
aref_end <= end_flag;
end
// aref_cmd信号
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
aref_cmd <= CMD_NOP;
else if(state == ST_PRE)
aref_cmd <= CMD_PRE;
else if(state == ST_AUTO)
aref_cmd <= CMD_AUTO;
else
aref_cmd <= CMD_NOP;
end
// aref_ba信号
assign aref_ba = 2'b11;
// aref_addr信号
assign aref_addr = 13'h1fff;
endmodule
五.仿真代码
`timescale 1ns/1ns
module tb_sdram_aref();
reg sys_clk;
reg sys_rst_n;
reg aref_en;
wire [3:0] init_cmd;
wire [1:0] init_ba;
wire [12:0] init_addr;
wire init_end;
wire aref_req;
wire [3:0] aref_cmd;
wire [1:0] aref_ba;
wire [12:0] aref_addr;
wire aref_end;
wire clk_100m;
wire clk_100m_shift;
wire clk_locked;
wire rst_n;
wire [3:0] sdram_cmd;
wire [1:0] sdram_ba;
wire [12:0] sdram_addr;
initial begin
sys_clk = 0;
sys_rst_n <= 0;
#100
sys_rst_n <= 1;
end
always #10 sys_clk = ~sys_clk;
clk_100m clk_100m_inst
(
.areset (~sys_rst_n ),
.inclk0 (sys_clk ),
.c0 (clk_100m ),
.c1 (clk_100m_shift ),
.locked (clk_locked)
);
assign rst_n = sys_rst_n & clk_locked;
sdram_init sdram_init_inst
(
.sys_clk (clk_100m ),
.sys_rst_n (rst_n ),
.init_cmd (init_cmd ),
.init_ba (init_ba ),
.init_addr (init_addr ),
.init_end (init_end )
);
// aref_en信号
always@(posedge clk_100m or negedge rst_n) begin
if(!rst_n)
aref_en <= 0;
else if(init_end == 1 && aref_req == 1)
aref_en <= 1;
else if(aref_end == 1)
aref_en <= 0;
end
sdram_aref sdram_aref_inst
(
.sys_clk (clk_100m ),
.sys_rst_n (rst_n ),
.init_end (init_end ),
.aref_en (aref_en ),
.aref_req (aref_req ),
.aref_cmd (aref_cmd ),
.aref_ba (aref_ba ),
.aref_addr (aref_addr ),
.aref_end (aref_end )
);
assign sdram_cmd = (init_end == 1) ? aref_cmd : init_cmd;
assign sdram_ba = (init_end == 1) ? aref_ba : init_ba;
assign sdram_addr = (init_end == 1) ? aref_addr : init_addr;
defparam sdram_model_plus_inst.addr_bits = 13; // 行地址13位
defparam sdram_model_plus_inst.data_bits = 16; // 一次读写数据16位
defparam sdram_model_plus_inst.col_bits = 9; // 列地址9位
defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024; // L-Bank容量
sdram_model_plus sdram_model_plus_inst
(
.Dq ( ), // 数据输入输出端口
.Addr (sdram_addr ), // 地址端口
.Ba (sdram_ba ), // Bank地址
.Clk (clk_100m_shift ), // 带有偏移的时钟信号
.Cke (1 ), // 时钟使能信号
.Cs_n (sdram_cmd[3]), // 命令第4位
.Ras_n (sdram_cmd[2]), // 命令第3位
.Cas_n (sdram_cmd[1]), // 命令第2位
.We_n (sdram_cmd[0]), // 命令第1位
.Dqm (2'b00 ), // 数据掩码
.Debug (1 ) // 开启Debug模式
);
endmodule
六.仿真结果
从网上找到仿真模型