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

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 具体的上电初始化时序图如图
在这里插入图片描述

具体操作步骤
  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;
always@(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 初始化过程,类似线性序列机
//相应时刻发出对应的命令和操作
always@(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
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值