SDRAM是基于电容存储的,因此需要不断刷新来保证数据不会丢失。 此文总结SDRAM的刷新模块。
数据手册分析(及时序分析)
这是刷新模块的时序图。
这里据视频邓堪文老师讲解,AutoRefresh 只需要进行一次即可。
时间间隔
描述
在SDRAM内部有刷新计数器,刷新完一次后,计数器会自动加一 。
SDRAM模块工作有三种,1,刷新2,写,3,读,所以需要引入仲裁机制,自身的工作状态进行决定,后文填坑,仲裁以及读写
这里的刷新请求就是给仲裁模块的信号。具体实现思路和上篇很像。
代码实现
module sdram_aref(
//system singles
clk,rst_n,
//communicate with abfer singles
ref_en,ref_req,flag_ref_end,
//others singles
aref_cmd,sdram_addr,flag_init_end
);
//////////////////////////////////////////////////////////////////////////////////
input clk ;
input rst_n ;
input ref_en ;
input flag_init_end ;
output ref_req ;
output flag_ref_end ;
output reg [3:0 ] aref_cmd ;
output [11:0] sdram_addr ;
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//*************************************************\
//define parameter and intennal singles
//*************************************************/
localparam DELAY_15US = 749 ;
localparam CMD_AREF = 4'b0001 ;
localparam CMD_NOP = 4'b0111 ;
localparam CMD_PRE = 4'b0010 ;
reg [3:0] cmd_cnt ;
reg [9:0] ref_cnt ;
reg flag_ref;
//*************************************************\
//main code
//*************************************************/
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
ref_cnt <= 'd0;
else
if(ref_cnt >= DELAY_15US)
ref_cnt <= 'd0;
else
if(flag_init_end == 1'b1) //初始化结束后,直接进行刷新计数
ref_cnt <= ref_cnt + 1'b1;
end
assign ref_req = (ref_cnt >= DELAY_15US) ? 1'b1 : 1'b0 ; //刷新请求信号在15us计数结束后产生
always @ (posedge clk or negedge rst_n)//当flag_ref为高电平时,该模块才进行工作
begin
if(!rst_n)
flag_ref <= 1'b0;
else
if(flag_ref_end)
flag_ref <= 1'b0;
else
if(ref_en)
flag_ref <= 1'b1;
else
flag_ref <= flag_ref;
end
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
cmd_cnt <= 'b0;
else
if(flag_ref) //只有在刷新模块工作的时候,命令计数器开始计数
cmd_cnt <= cmd_cnt + 1'b1;
else
cmd_cnt <= 'd0;
end
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
aref_cmd <= CMD_NOP;
else
case(cmd_cnt)
1: aref_cmd <= CMD_PRE;
2: aref_cmd <= CMD_AREF;
default:aref_cmd <= CMD_NOP;
endcase
end
assign flag_ref_end = (cmd_cnt == 'd4) ? 1 : 0 ;//20 + 63 就是不到80ns
assign sdram_addr = 12'b0100_0000_0000 ;
endmodule