锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

SDRAM 控制器(二)——初始化模块

时间:2023-01-13 12:30:00 电容a3d

一、初始化模块

SDRAM 初始化是芯片上电后必须进行的操作,只进行初始化操作 SDRAM 芯片只能正常使用。SDRAM 除此之外,初始化是一套预定义的过程 他的操作会导致 SDRAM 出现不可预知的后果。

初始化时序图:

CK:工作时钟,具体时钟频率取决于不同的芯片

CKE:在整个初始化过程中,需要提高时钟使能

COMMAND:SDRAM命令由四根线拼接而成CS#(片选信号),RAS#(行选通信号),CAS#(列通信号),WE#(写使能信号),结合这四条命令线SDRAM地址、输入输出数据等SDRAM各种命令操作

DQM/DQML,DQMU:数据掩码可以通过数据掩码掩埋输入或输出数据的某个人,即使某个人失败

A[9:0],A[12:11]:数据地址线也可用于设置模式寄存器

A10:数据地址线也可用于控制自动预充电、预充电等具体操作bank数量

BA[1:0]:bank地址

DQ数据:无数据输出在初始化过程中保持高阻态

初始化过程:

1.上电后保持时钟稳定至少1000us(芯片时间不同)CKE需要拉高;需要同时发送NOP空指令(发送空指令是为了防止SDRAM误操作)

2.对所有BANK预充电操作,A10拉高是所有选择BANK

3.预充操作后需要等待一定的时间,即tRP,在此期间还需要发送NOP空指令(发送空指令是为了防止SDRAM误操作)

4.等待结束后发送自动刷新指令

5.自动刷新后需要等待一定的时间,即tRC,在此期间还需要发送NOP空指令(发送空指令是为了防止SDRAM误操作)

6.重复发送自动刷新指令和等待tRFC,不同的芯片刷新次数不同

7.发送模式寄存器设置指令,地址总线 A0-A11 参数不同 设置不同模式的辅助模式寄存器

8.发送模式寄存器设置指令后需要等待一定的时间、即tMRD,在此期间还需要发送NOP空指令(发送空指令是为了防止SDRAM误操作)

9.tMRD等待时间结束后,SDRAM 初始化完成

补充:

预充电
SDRAM搜索网站是独家的,所以在完成读写操作后,如果你想对同一个Bank寻址的另一行,要有效(ACTIVE)关闭行,重新发送行/列地址。Bank关闭当前工作行,准备打开新行的操作是预充电。 预充电可以由独立的命令控制,也可以在每次发送读写命令时使用A线路控制自动预充电。事实上,预充电是一种重写工作中所有存储阵列的数据,并行地址进行复位,为新行做准备。

除初始化过程中使用预充电指令外,还将在自动刷新和读写操作中使用。

自动刷新
SDRAM 内部存储器是由电容器保持电荷和充放电的特性制成的,电容器中存储的电荷会随着时间的推移而流失,导致存储数据的丢失。 SDRAM 需要中数据的可靠性 SDRAM 进行不断刷新。

刷新操作分为自动刷新和自刷新两种。发送命令后CKE时钟是有效的(低电平),使用自动刷新操作,否则使用自动刷新操作。无论使用什么刷新不需要提供外部地址信息,因为这是内部操作。

对自动刷新,SDRAM内部有一个行地址生成器(也称刷新计数器)依次自动生成行地址,每次收到命令刷新一行。在刷新过程中,一切Bank停止工作,每次刷新占用N个时钟周期。刷新后才能进入正常工作状态,也就是说,在这N个时钟内,所有的工作指令只能等待而不能执行。按行刷新一次又一次。刷新所有行后,第一行将再次刷新。同一行刷新操作的时间间隔已成为SDRAM刷新周期通常为64ms。显然,刷新是对的SDRAM影响性能,但这是SDRAM特征决定,也是SDRAM相对于SRAM取得成本优势的同时所付出的代价。

自刷新主要用于低功耗休眠模式下的数据保存,即即使外部控制器不工作,SDRAM能保证数据正常。发出自我刷新命令后,将CKE将自刷新模式置于无效状态(低电平)。此时,它不再依赖外部时钟,而是基于SDRAM刷新内部时钟。在自我刷新期间,除了CKE除此之外,所有外部信号都无效,只能重新使用CKE退出自刷新模式模式,进入正常运行状态。
因为我们通常控制它SDRAM在正常工作状态下使用,一般是正确的SDRAM自动刷新操作。

模式寄存器配置:

通过对SDRAM模式寄存器的配置可以实现对其各种工作方式、参数的控制,如突发长度BL、读潜伏期CL等。

A12-A10:预留
A9:读写方法0:突然读写&突发写作;1:突发阅读&单写
A8,A7:00:标准模式,默认
A6,A5,A4:CAS1、2、3、保留潜伏期
A3.突发传输方式0:顺序;1:隔行
A2,A1,A0:000:1、2、4、8、全页

等待时间参数:
根据芯片的不同,以下时间参数可能会有所不同:

tRP:PRECHARGE command period,发送预充电指令后需要等待下一次操作的时间

tRFC:AUTO REFRESH period,发送自动刷新指令后需要等待下一次操作的时间

tMRD:LOAD MODE REGISTER command to ACTIVE or REFRESH command,发送设置模式寄存器指令后,需要等待下一次操作的时间

状态机可以实现初始化模块:

INIT_IDLE:上电等待状态,等待时间满足100us要求后,跳转到下一个状态INIT_PRE,在此状态下发送NOP指令
INIT_PRE:发送预充电指令状态,只维持一个时钟周期,下一个时钟跳转到状态INIT_TRP ,在此状态下发送预充电指令
INIT_TRP:预充电指令等待状态,在此状态等待时间满足TRP然后跳到下一个状态INIT_AR,在此状态下发送NOP指令
INIT_AR:发送自动刷新指令状态,只维持一个时钟周期,下一个时钟跳转到状态INIT_TRFC,在此状态下发送自动刷新指令
INIT_TRFC:自动刷新指令等待状态,满足此状态等待时间TRFC判断时,如果自动刷新次数符合要求(2次或其他手册要求),则跳转到下一个状态INIT_MRS,在此状态下发送NOP如果指令不符合自动刷新次数的要求,则继续进行自动刷新操作,跳转到状态INIT_AR
INIT_MRS:发送模式寄存器设置指令状态,只维持一个时钟周期,下一个时钟跳转到状态INITTMRD,在此状态发送模式寄存器设置指令     
INIT_TMRD:模式寄存器设置指令等待状态、在此状态等待时间满足TMRD后就跳转到下一个状态INIT_END,在此状态发送NOP指令    
INIT_END:初始化结束状态,完成初始化后一直停留在这个状态;在此状态发送NOP指令,并将初始化完成信号拉高以通知其他模块开始进行工作

时序图:

 仿真结果:

端口:

信号名称         位宽       属性            描述
init_clk              1           输入      100M时钟信号
init_rst_n          1           输入       复位信号,低电平有效
init_addr         13           输出       SDRAM地址总线
init_cmd           4           输出       SDRAM命令,组成{CS#,RAS#,CAS#,WE#}
init_bank          2           输出       BANK地址,共4个BANK
init_end            1           输出       初始化完成信号,初始化完成后拉高,其他时间保持低电平

代码:

//----------------------------------------------------------------------------------------------------
//--SDRAM初始化模块
//----------------------------------------------------------------------------------------------------
module SDRAM_INIT(
		input              sys_clk				,
		input		       sys_rst_n 			,
		output reg [3:0]   init_cmd    			,
		output reg [1:0]   init_ba				,
		output reg [12:0]  init_addr			,
		output		       init_end		
);

parameter  		INIT_IDLE = 3'b000,
				INIT_PRE  = 3'b001,
				INIT_TRP  = 3'b011,
				INIT_AR   = 3'b010,
				INIT_TRFC = 3'b110,
				INIT_MRS  = 3'b111,
				INIT_TMRD = 3'b101,
				INIT_END  = 3'b100;
			  
parameter 	  WAIT_MAX = 15'd20_000;

parameter     TRP   =  3'd2,
			  TRFC  =  3'd7,
			  TMRD  =  3'd3;

parameter     NOP        = 4'b0111,
			  P_CHARGE = 4'b0010,
			  AUTO_REF   = 4'b0001,
			  M_REG_SET = 4'b0000;


wire				wait_end			;
wire				TRP_end				;
wire				TRFC_end			;
wire				TMRD_end			;


reg 	[2:0]       init_state			;
reg     [14:0]		cnt_200us			;
reg		[2:0]		cnt_clk				;
reg					cnt_clk_rst			;
reg		[3:0]		cnt_aref			;
		
always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		init_state <= INIT_IDLE;
	else  begin
		case(init_state)
			INIT_IDLE  :
				if(wait_end == 1'b1)
					init_state <= INIT_PRE   ;
				else;
			INIT_PRE   :   
				init_state <= INIT_TRP		 ;
            INIT_TRP   :
				if(TRP_end == 1'b1)
					init_state <= INIT_AR    ;
				else;
            INIT_AR    :
				init_state <= INIT_TRFC		 ;
            INIT_TRFC  :
				if(TRFC_end == 1'b1 )
					if(cnt_aref == 4'd8)
						init_state <= INIT_MRS	 ;
					else
						init_state <= INIT_AR	 ;
				else;
            INIT_MRS   :
				init_state <= INIT_TMRD		 ;
            INIT_TMRD  :
				if(TMRD_end == 1'b1)
					init_state <= INIT_END	 ;
				else;
            INIT_END   :
				init_state <= INIT_END		 ;
			default : init_state <= INIT_IDLE;
		endcase
	end
//上电等待200us
always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt_200us <= 15'd0;
	else if(cnt_200us == WAIT_MAX)
		cnt_200us <= WAIT_MAX;
	else
		cnt_200us <= cnt_200us + 1'b1;

//200us标志信号计数器
assign  wait_end = (cnt_200us == WAIT_MAX - 1'b1)? 1'b1 : 1'b0;


always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt_clk <= 3'd0;
	else if(cnt_clk_rst == 1'b1)
		cnt_clk <= 3'd0;
	else
		cnt_clk <= cnt_clk + 1'b1;

always @(*)begin 
	case(init_state)
		INIT_IDLE : cnt_clk_rst <= 1'b1;
		INIT_TRP  : cnt_clk_rst <= (TRP_end == 1'b1)? 1'b1 : 1'b0 ;
	    INIT_TRFC : cnt_clk_rst <= (TRFC_end == 1'b1)? 1'b1 : 1'b0;
		INIT_TMRD : cnt_clk_rst <= (TMRD_end == 1'b1)? 1'b1 : 1'b0;
		INIT_END  : cnt_clk_rst <= 1'b1;
		default : cnt_clk_rst <= 1'b0  ;
	endcase
end
//如何判断先后顺序?不看状态只看cnt_clk计数?应该是在各自的状态下才进行计数?是的,后边修改了
assign  TRP_end  = (init_state == INIT_TRP && cnt_clk == TRP) ? 1'b1 : 1'b0;
assign  TRFC_end = (init_state == INIT_TRFC && cnt_clk == TRFC)? 1'b1 : 1'b0;
assign	TMRD_end = (init_state == INIT_TMRD && cnt_clk == TMRD)? 1'b1 : 1'b0;

//自动刷新次数计数  刷新次数为8    1,2,3,4,5,6,7,8共8次。
always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt_aref <= 4'd0;
	else if(init_state == INIT_IDLE)
		cnt_aref <= 4'd0;
	else if(init_state == INIT_AR)
		cnt_aref <= cnt_aref + 1'b1;
	else
		cnt_aref <= cnt_aref;

always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		begin
			init_cmd    <=  NOP		;
			init_ba     <= 2'b11	;
			init_addr   <= 13'h1fff ;
		end
	else
		case(init_state)
			INIT_IDLE,INIT_TRP,INIT_TRFC,INIT_TMRD,INIT_END : 
				begin 
					init_cmd    <=  NOP		 ;
					init_ba     <=  2'b11	 ;
					init_addr   <=  13'h1fff ;
				end
			INIT_PRE :
				begin 
					init_cmd    <=  P_CHARGE	 ;
					init_ba     <=  2'b11	 ;
					init_addr   <=  13'h1fff ;
				end
			INIT_AR  :
				begin 
					init_cmd    <=  AUTO_REF ;
					init_ba     <=  2'b11	 ;
					init_addr   <=  13'h1fff ;
				end			
			INIT_MRS :
				begin 
					init_cmd    <=  M_REG_SET ;
					init_ba     <=  2'b00	 ;
					init_addr   <=  {3'b000,1'b0,2'b00,3'b011,1'b0,3'b111} ;
				end
			default : 
				begin 
					init_cmd    <=  NOP		 ;
					init_ba     <=  2'b11	 ;
					init_addr   <=  13'h1fff ;
				end				
			endcase
assign  init_end = (init_state == INIT_END) ? 1'b1 : 1'b0;

endmodule

仿真代码:

//----------------------------------------------------------------------------------------------------
//--SDRAM初始化仿真测试
//----------------------------------------------------------------------------------------------------
`timescale 1ns/1ns
module SDRAM_INIT_tb();

wire   	clk50m			;
wire    clk100m			;
wire    clk100m_shift	;
wire    locked			;
wire    rst_n 			;

wire [3:0]  init_cmd	;
wire [1:0]	init_ba		;
wire [12:0] init_addr	;
wire		init_end	;




reg   sys_clk 			;
reg   sys_rst_n			;



initial 
	begin 
		sys_clk  = 1'b1;
		sys_rst_n 	<= 1'b0;
		#30
		sys_rst_n	<= 1'b1;
	end
always #10  sys_clk <= ~sys_clk;	
		 
assign rst_n = sys_rst_n & locked ;	

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;


clk_gen	clk_gen_inst
(
	.areset ( ~sys_rst_n),
	.inclk0 ( sys_clk ),
	.c0 ( clk50m	 ),
	.c1 ( clk100m	 ),
	.c2 ( clk100m_shift ),
	.locked	( locked )
);


SDRAM_INIT SDRAM_INIT_inst(
		.  sys_clk		(clk100m)	,
		.  sys_rst_n 	(rst_n)		,
		.  init_cmd    	(init_cmd)	,
		.  init_ba		(init_ba)	,
		.  init_addr	(init_addr)	,
		.  init_end		(init_end)
);      

sdram_model_plus  sdram_model_plus_inst
(				
				.Dq     ()     		  	  , 
				.Addr	(init_addr)       , 
				.Ba		(init_ba)		  , 
				.Clk	(clk100m_shift)	  , 
				.Cke	(1'b1)		 	  , 
				.Cs_n	(init_cmd[3])     , 
				.Ras_n	(init_cmd[2])	  , 
				.Cas_n	(init_cmd[1])     , 
				.We_n	(init_cmd[0])     , 
				.Dqm	(2'b00)		 	  ,
				.Debug  (1'b1)
);                      


endmodule

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章