欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SDRAM控制器设计(3)初始化操作

程序员文章站 2022-04-01 23:01:48
...

1.初始化操作

参考博客https://blog.csdn.net/fxltsbl007/article/details/79114640

在对 SDRAM 进行正常的操作之前, SDRAM 必须被初始化。

初始化流程

a、给SDRAM上电,并提供稳定的时钟,至少100us

b、发送“空操作”(NOP)命令

c、发送“预充电”命令,控制所有BANK进行预充电,并等待tRP的时间

 tRP表示预充电和其他命令之间的延时

d、发送至少2个“自送刷新”命令,每个命令后需等待

tRC时tRC表示自送刷新时间

e、发送“加载模式寄存器”命令,配置SDRAM的工作参数,等待tMDR时间

tMDR表示加载模式寄存器命令与行有效或刷新命令之间的延时

f、初始化流程完毕,可以开始读写操作

SDRAM 具体的上电初始化时序图如图
SDRAM控制器设计(3)初始化操作

具体操作步骤
  1. 加载电源( VDD 和 VDDQ);
  2. CKE 设置为低低电平( LVTTL 逻辑低电平);
  3. 加载稳定的时钟信号;
  4. 等待至少 100us 的时间,此过程中的命令保持为禁止命令或空操作命令;
  5. 在步骤 4 的 100us 中的某个时刻,将 CKE 设置为高;
  6. 步骤 4 的 100us 等待时间结束后,随即可发出一个全部 BANK 的预充电命令;
  7. 等待时间 tRP,此过程中命令保持为禁止命令或空操作命令;
  8. 步骤 7 钟的等待时间 tRP 结束时,发出一个自动刷新命令;
  9. 等待时间 tRFC( Auto refresh period),此过程中命令仅允许是禁止命令或空操作命令;
  10. 步骤 9 中的等待时间 tRFC 结束时,再发出一个自动刷新命令;
  11. 再等待时间 tRFC,此过程中命令仅允许是禁止命令或空操作命令;
  12. 步骤 11 中的等待时间 tRFC 结束时,发出装载模式寄存器命令设置模式寄存器,具体模式寄存器的值由 A0~A11 传输;
  13. 等待时间 tMRD( LOAD MODE REGISTER command to ACTIVE orREFRESH command),此过程中命令仅允许是禁止命令或空操作命令。

为什么要预充电呢?下面来看一下专业的解释:

SDRAM的寻址具有独占性,所以在进行完读写操作后,如果要对同一个Bank的另一行进行寻址,就要将原来有效(ACTIVE)的行关闭,重新发送行/列地址。Bank关闭当前工作行,准备打开新行的操作就是预充电。
预充电可以通过独立的命令控制,也可以在每次发送读写命令的同时使用“A10”线控制自动进行预充电。实际上,预充电是一种对工作中所有存储阵列进行数据重写,并对行地址进行复位,以准备新行的工作。

查阅手册,设置时间参数,假如本实验时钟为100Mhz,则单位均为一周期10ns。

parameter INIT_PRE = 20000; //初始化等待时间,不小于 100us,这里取 200us
parameter REF_PRE = 3; //等待时间 tRP,不小于 20ns,这里取 30ns
parameter REF_REF = 10; //等待时间 tRFC,不小于 66ns,这里取 100ns
localparam   init_PRE_TIME = INIT_PRE, //预充电时刻
					init_AREF1_TIME = INIT_PRE+REF_PRE, //自动刷新时刻
					init_AREF2_TIME = INIT_PRE+REF_PRE+REF_REF, //自动刷新时刻
					init_LMR_TIME = INIT_PRE+REF_PRE+REF_REF*2,//加载模式寄存器
					init_END_TIME = INIT_PRE+REF_PRE+REF_REF*2+LMR_ACT;  //结束时刻

其他参数设置

// 地址和数据位宽
`define ASIZE 13 //SDRAM 地址位宽
`define DSIZE 16 //SDRAM 数据位宽
`define BSIZE 2 //SDRAM 的 bank 地址位宽

//操作命令{CS_N,RAS_N,CAS_N,WE}
parameter C_NOP = 4'b0111, //空操作命令
C_PRE = 4'b0010, //预充电命令
C_AREF = 4'b0001, //自动刷新命令
C_MSET = 4'b0000, //加载模式寄存器命令
C_ACT = 4'b0011, //**命令
C_RD = 4'b0101, //读命令
C_WR = 4'b0100; //写命令

////////////100 MHz ///////////////
parameter INIT_PRE = 20000; //初始化等待时间>100us,取 200us
parameter REF_PRE = 3; //tRP >=18ns,取 30ns
parameter REF_REF = 10; //tRFC >=60ns,取 100ns
parameter AUTO_REF = 750; //自动刷新周期<64ms/8192=7812.5ns
parameter LMR_ACT = 2; //装在模式寄存器到可**延时
parameter WR_PRE = 2; //写操作写数据完成到预充电时间间隔
parameter SC_RCD = 3; //**到读命令或写命令延时 tRCD>18ns

// SDRAM 模式寄存器参数化表示
parameter SC_CL = 2; //列选通潜伏期
parameter SC_BL = 8; //突发长度设置, 1,2,4,8 可选
parameter OP_CODE = 1'b0; //写突发模式设置
parameter 
  SDR_BL = (SC_BL == 1)? 3'b000:(SC_BL == 2)? 3'b001:(SC_BL == 4)? 3'b010:(SC_BL == 8)? 3'b011:3'b111;
//用parameter达成了优先级式选通的功能  
parameter SDR_BT = 1'b0; //突发类型设置
parameter SDR_CL = (SC_CL == 2)? 3'b10: 3'b11;

在其他模块文件中如果需要使用这些参数,只需在其模块内部包含文件夹中的这个文件即可,文件的路径读者根据自己的实际情况进行更改,具体表示如下:

`include "../src/Sdram_Params.h"

接下来就通过线性序列机的方法进行初始化过程的设计,首先,对初始化过程的时间进行计数


//SDRAM 初始化过程时间计数器
reg [15:0]init_cnt;
aaa@qq.com(posedge Clk or negedge Rst_n)
	begin
		if(!Rst_n)
			init_cnt <= 16'd0;
		else if(init_cnt < init_END_TIME)
			init_cnt <= init_cnt + 16'd1;
		else
			init_cnt <= 16'd0;
	end	

//SDRAM 初始化过程,类似线性序列机
//相应时刻发出对应的命令和操作
aaa@qq.com(posedge Clk or negedge Rst_n)
begin
	if(!Rst_n)
		begin
			Command <= C_NOP;
			Saddr <= 0;
		end
	else 
		begin
		case(init_cnt)
			init_PRE_TIME:
			begin
			Command <= C_PRE;
			Saddr[10] <= 1'b1;
			end
		
			init_AREF1_TIME:
			begin
			Command <= C_AREF;
			end
			
			init_AREF2_TIME:
			begin
			Command <= C_AREF;
			end
			
			init_LMR_TIME:
			begin
			Command <= C_MSET;
			Saddr <= {OP_CODE,2'b00,SDR_CL,SDR_BT,SDR_BL};
			end
			
			default:
			begin
			Command <= C_NOP;
			Saddr <= 0;
			end
			
		endcase
		end
end


//SDRAM 初始化完成结束标志位
assign Init_done = (init_cnt == init_END_TIME);


仿真

选用了镁光官网下载的 SDRAM 模型sdr,是包含多个文件的压缩包,仿真需要用到是压缩包里的sdr.v 和 sdr_parameters.vh 两个文件,具体改动详见小梅哥教程P636

`timescale 1ns/1ns
`define CLK100_PERIOD 10
module sdram_init_tb;
`include "../src/Sdram_Params.h"
reg Clk;
reg Rst_n;
wire [3:0] Command;
wire [`ASIZE-1:0]Saddr;
wire Init_done;
wire sd_clk;
wire Cs_n;
wire Ras_n;
wire Cas_n;
wire We_n;

//SDRAM 初始化模块例化
sdram_init sdram_init(
.Clk(Clk),
.Rst_n(Rst_n),
.Command(Command),
.Saddr(Saddr),
.Init_done(Init_done)
);
assign {Cs_n,Ras_n,Cas_n,We_n} = Command;
assign sd_clk = ~Clk;

//SDRAM 模型例化
sdr sdram_model(
.Dq(),
.Addr(Saddr),
.Ba(),
.Clk(sd_clk),
.Cke(Rst_n),
.Cs_n(Cs_n),
.Ras_n(Ras_n),
.Cas_n(Cas_n),
.We_n(We_n),
.Dqm()
);

//系统时钟产生
initial Clk = 1'b1;
always #(`CLK100_PERIOD/2) Clk = ~Clk;
initial
begin
Rst_n = 1'b0;
#(`CLK100_PERIOD*200+1);
Rst_n = 1'b1;
@(posedge Init_done)
#2000;
$stop;
end
endmodule
相关标签: FPGA sdram fpga