fpga控制sdram存储器的读写3:sdram自动刷新

一.理论知识

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
六.仿真结果

从网上找到仿真模型
在这里插入图片描述

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值