02-SDRAM:自动刷新

SDRAM自动刷新模块

  1. cnt_7: 自动刷新是周期性的,因此需要时钟去重复计数,计满后就可以发出自动刷新请求信号给仲裁模块(依赖 init_end,计满清零)
  2. auto_ref_req: 传给仲裁模块的自动刷新请求信号,计数器加满拉高,得到内部应答后拉低(依赖计数器 cnt_7、auto_ref_ack)
  3. auto_ref_en:
  4. auto_ref_ack: 当状态跳转到预充电 ATREF_PRE,内部产生应答信号(依赖 ATREF_PRE)
  5. state
  6. cnt_cmd: 计数器,用来给2个等待时间计数 (依赖 cnt_cmd_reset)
  7. cnt_cmd_reset: 上一个计数器的清零信号 (依赖计满信号:trp_end、trfc_end)
  8. trp_end、trfc_end: 自家延时结束的信号(依赖 状态)
  9. cnt_ref: 自动刷新的次数,至少需要2次自动刷新(依赖状态 ATREF_AR 、 ATREF_IDLE)

设计文件

// SDRAM自动刷新模块
// 1. cnt_7:		自动刷新是周期性的,因此需要时钟去重复计数,计满后就可以发出自动刷新请求信号给仲裁模块(依赖 init_end,计满清零)
// 2. auto_ref_req:	传给仲裁模块的自动刷新请求信号,计数器加满拉高,得到内部应答后拉低(依赖计数器 cnt_7、auto_ref_ack)
// 3. auto_ref_en:		
// 4. auto_ref_ack:		当状态跳转到预充电 ATREF_PRE,内部产生应答信号(依赖 ATREF_PRE)
// 5. state
// 6. cnt_cmd:			计数器,用来给2个等待时间计数	 (依赖 cnt_cmd_reset)
// 7. cnt_cmd_reset:	上一个计数器的清零信号			 (依赖计满信号:trp_end、trfc_end)
// 8. trp_end、trfc_end: 自家延时结束的信号(依赖 状态)
// 9. cnt_ref:			 自动刷新的次数,至少需要2次自动刷新(依赖状态 ATREF_AR 、 ATREF_IDLE) 
module sdram_auto_ref(
	input 				    clk,
	input 				    rst_n,
	input 				    init_end,//初始化模块传入
	input 				    auto_ref_en,//仲裁模块传入,仲裁模块用来判断当前SDRAM是否可以自动刷新
	
	output reg    			auto_ref_req,//传给仲裁模块(要得到仲裁模块传来的刷新使能信号auto_ref_en才能开始自动刷新)
	output reg 	[3:0]		auto_ref_cmd,//SDRAM命令,组成{CS#,RAS#,CAS#,WE#}
	output   	[1:0] 		auto_ref_bank,//BANK地址,共4个BANK
	output   	[12:0]		auto_ref_addr,//SDRAM地址总线
	output      			auto_ref_end//初始化完成信号,初始化完成后拉高,其他时间保持低电平
);
//==========================================parameter===========================================================
//状态机
localparam	ATREF_IDLE = 3'b000,			//自动刷新初始状态
			ATREF_PRE  = 3'b001,			//预充电状态
			ATREF_TRP  = 3'b011,			//预充电等待状态
			ATREF_AR   = 3'b010,			//自动刷新状态
			ATREF_TRFC = 3'b110,            //自动刷新等待状态
			ATREF_END  = 3'b111;            //自动刷新结束状态
			
parameter 	MAX_CNT_700  = 12'd700;  //计算出来是 7812ns,但是仲裁模块需要时间去给出auto_ref_en,需要花费时间,因此这里使用7000ns
parameter 	MAX_REF_TIME = 2'd2;

//等待时间参数定义	
localparam	TRP  = 3'd2	,					//发送预充电指令后进行下一个操作需要等待的时间
			TRFC = 3'd7	;					//发送自动刷新指令后进行下一个操作需要等待的时间
			
//命令指令参数				
localparam 	PRECHARGE 	 = 4'b0010 , 		//预充电指令
			AT_REF   	 = 4'b0001 , 		//自动刷新指令
			NOP       	 = 4'b0111 ; 		//空操作指令
//==========================================reg=================================================================			
reg [5:0]   state;
reg [5:0]   next_state;
reg [3:0]   cnt_cmd;
reg [11:0]  cnt_7;//64_000/2^13=7.8125us,于是需要10ns的时钟计数7_00次
reg [1:0]   cnt_ref;
//==========================================wire=================================================================
wire auto_ref_ack;
wire trp_end;
wire trfc_end;
wire cnt_cmd_reset;

//==========================================assign=================================================================
// 内部应答信号
assign auto_ref_ack  = (state ==  ATREF_PRE) ? 1'd1:1'd0;
assign trp_end  	 = ((state == ATREF_TRP)  && (cnt_cmd == TRP-1)) ? 1'd1:1'd0;
assign trfc_end 	 = ((state == ATREF_TRFC) && (cnt_cmd == TRFC-1))? 1'd1:1'd0;
assign cnt_cmd_reset = ((state == ATREF_IDLE) || (state == ATREF_END) || trp_end || trfc_end) ? 1'd1:1'd0;

assign auto_ref_bank = 2'd11;
assign auto_ref_addr = 13'h1fff;
assign auto_ref_end  = (state == ATREF_END)?1'd1:1'd0;

//==========================================always=================================================================
// 自动刷新周期计数器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		cnt_7 <= 12'd0;
	end
	else if(init_end)// 初始化成功后,才开始计数
		if(cnt_7 == MAX_CNT_700)begin
			cnt_7 <= 12'd0;
		end
		else
			cnt_7 <= cnt_7 + 12'd1;
	else
		cnt_7 <= cnt_7;
end

// 请求信号
always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		auto_ref_req <= 1'd0;
	end
	else if(cnt_7 == MAX_CNT_700 - 1)begin
		auto_ref_req <= 1'd1;
	end
	else if(auto_ref_ack)
		auto_ref_req <= 1'd0;
	else
		auto_ref_req <= auto_ref_req;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		cnt_cmd <= 4'd0;
	end
	else if(cnt_cmd_reset)begin
		cnt_cmd <= 4'd0;
	end
	else
		cnt_cmd <= cnt_cmd + 4'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		cnt_ref <= 2'd0;
	end
	else if(state == ATREF_AR)begin
		cnt_ref <= cnt_ref + 2'd1;
	end
	else if(state == ATREF_IDLE)
		cnt_ref <= 2'd0;
	else
		cnt_ref <= cnt_ref ;
end

//==========================================状态机=================================================================

// 第一段
always@(posedge clk or negedge rst_n)begin
	if(!rst_n )begin
		state <= ATREF_IDLE;
	end
	else 
		state <= next_state;
end
//第二段
always@(*)begin
	case(state)
		ATREF_IDLE:
			if(init_end && auto_ref_en)//auto_ref_ack
				next_state = ATREF_PRE;
			else 
				next_state = ATREF_IDLE;
		ATREF_PRE :next_state = ATREF_TRP;
		ATREF_TRP :
			if(trp_end)
				next_state = ATREF_AR;
			else
				next_state = ATREF_TRP;
		ATREF_AR  :next_state = ATREF_TRFC;
	    ATREF_TRFC:
			if(trfc_end)
				if(cnt_ref == MAX_REF_TIME)
					next_state = ATREF_END;
				else
					next_state = ATREF_AR;
			else
				next_state = ATREF_TRFC;
	    ATREF_END :next_state = ATREF_IDLE;
	default:next_state = ATREF_IDLE;
	endcase
end

// 第三段
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n )begin
			auto_ref_cmd	<= NOP;
		end
		else 
			case(state)
				ATREF_IDLE : auto_ref_cmd	<= NOP;	
				ATREF_PRE  : auto_ref_cmd   <= PRECHARGE;
				ATREF_TRP  : auto_ref_cmd   <= NOP;
				ATREF_AR   : auto_ref_cmd   <= AT_REF;
				ATREF_TRFC : auto_ref_cmd   <= NOP;
				ATREF_END  : auto_ref_cmd	<= NOP;
			
			default:auto_ref_cmd	<= NOP;
			endcase
	end
endmodule 


测试文件

`timescale  1ns/1ns

// Author        : EmbedFire
// Create Date   : 2019/08/25
// Module Name   : tb_sdram_init
// Project Name  : uart_sdram
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description   : SDRAM初始化模块仿真
// 
// Revision      : V1.0
// Additional Comments:
// 
// 实验平台: 野火_征途Pro_FPGA开发板
// 公司    : http://www.embedfire.com
// 论坛    : http://www.firebbs.cn
// 淘宝    : https://fire-stm32.taobao.com


module  tb_sdram_auto_ref();

//********************************************************************//
//****************** Internal Signal and Defparam ********************//
//********************************************************************//

//wire define
//clk_gen
wire            clk_50m         ;   //PLL输出50M时钟
wire            clk_100m        ;   //PLL输出100M时钟
wire            clk_100m_shift  ;   //PLL输出100M时钟,相位偏移-30deg
wire            locked          ;   //PLL时钟锁定信号
wire            rst_n           ;   //复位信号,低有效
//sdram_init
wire    [3:0]   init_cmd        ;   //初始化阶段指令
wire    [1:0]   init_ba         ;   //初始化阶段L-Bank地址
wire    [12:0]  init_addr       ;   //初始化阶段地址总线
wire            init_end        ;   //初始化完成信号

wire            auto_ref_req ;
wire   [3:0]    auto_ref_cmd ;
wire   [1:0]    auto_ref_bank;
wire   [12:0]   auto_ref_addr;
wire            auto_ref_end ;
//sdram
wire    [3:0]   sdram_cmd       ;   //SDRAM操作指令
wire    [1:0]   sdram_bank		;   //SDRAM L-Bank地址
wire    [12:0]  sdram_addr      ;   //SDRAM地址总线


//reg define
reg             clk_c1         ;   //系统时钟
reg             sys_rst_n       ;   //复位信号
reg             auto_ref_en;

//defparam
//重定义仿真模型中的相关参数
defparam sdram_model_plus_inst.addr_bits = 13;          //地址位宽
defparam sdram_model_plus_inst.data_bits = 16;          //数据位宽
defparam sdram_model_plus_inst.col_bits  = 9;           //列地址位宽
defparam sdram_model_plus_inst.mem_sizes = 2*1024*1024; //L-Bank容量

//********************************************************************//
//**************************** Clk And Rst ***************************//
//********************************************************************//

//时钟、复位信号
initial
  begin
    clk_c1     =   1'b1  ;
    sys_rst_n   <=  1'b0  ;
    #200
    sys_rst_n   <=  1'b1  ;
  end

always  #10 clk_c1 = ~clk_c1;

//rst_n:复位信号
assign  rst_n = sys_rst_n & locked;



//atref_en:自动刷新使能
always@(posedge clk_100m or negedge rst_n)begin
    if(rst_n == 1'b0)
        auto_ref_en <=  1'b0;
    else if((init_end == 1'b1) && (auto_ref_req == 1'b1))
        auto_ref_en <=  1'b1;
    else if(auto_ref_end == 1'b1)
        auto_ref_en <=  1'b0;
end  

//sdram_cmd,sdram_ba,sdram_addr
assign  sdram_cmd  = (init_end == 1'b1) ? auto_ref_cmd  : init_cmd;
assign  sdram_bank = (init_end == 1'b1) ? auto_ref_bank : init_ba;
assign  sdram_addr = (init_end == 1'b1) ? auto_ref_addr : init_addr;


//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------- clk_gen_inst -------------
clk_gen clk_gen_inst (
    .inclk0     (clk_c1        ),
    .areset     (~sys_rst_n     ),
    .c0         (clk_50m        ),
    .c1         (clk_100m       ),
    .c2         (clk_100m_shift ),

    .locked     (locked         )
);

//------------- sdram_init_inst -------------
sdram_initial  sdram_initial_inst(

    .clk        (clk_100m   ),
    .rst_n      (rst_n      ),

    .init_cmd   (init_cmd   ),
    .init_bank  (init_ba    ),
    .init_addr  (init_addr  ),
    .init_end   (init_end   )

);
sdram_auto_ref  sdram_auto_ref_inst(

    .clk          (clk_100m   ),
    .rst_n        (rst_n      ),
    .init_end     (init_end   ),
    .auto_ref_en  (auto_ref_en),

    .auto_ref_req   (auto_ref_req   ),
    .auto_ref_cmd   (auto_ref_cmd   ),
    .auto_ref_bank  (auto_ref_bank  ),
    .auto_ref_addr  (auto_ref_addr  ),
    .auto_ref_end   (auto_ref_end   )

);

//-------------sdram_model_plus_inst-------------
sdram_model_plus    sdram_model_plus_inst(
    .Dq     (               ),
    .Addr   (sdram_addr      ),
    .Ba     (sdram_bank     ),
    .Clk    (clk_100m_shift ),
    .Cke    (1'b1           ),
    .Cs_n   (sdram_cmd[3]    ),
    .Ras_n  (sdram_cmd[2]    ),
    .Cas_n  (sdram_cmd[1]    ),
    .We_n   (sdram_cmd[0]    ),
    .Dqm    (2'b0           ),
    .Debug  (1'b1           )

);


//------------------------------------------------
//--    状态机名称查看器
//------------------------------------------------
reg [79:0]	name_state_cur;				//每字符8位宽,这里取最多10个字符80位宽
 
always @(*) begin
    case(sdram_auto_ref_inst.state)
        3'b000:		name_state_cur = "ATREF_IDLE";
        3'b001:		name_state_cur = "ATREF_PRE ";
        3'b011:		name_state_cur = "ATREF_TRP ";
        3'b010:		name_state_cur = "ATREF_AR  "; 
		    3'b110:		name_state_cur = "ATREF_TRFC"; 
		    3'b111:		name_state_cur = "ATREF_END "; 
        default:	name_state_cur = "ATREF_IDLE";
    endcase
end

endmodule

窗口打印信息

02-SDRAM:自动刷新_第1张图片

你可能感兴趣的:(#,▶SDRAM,网络,前端,java)