一、SDRAM概念
SDRAM 的全称即同步动态随机存储器(Synchronous Dynamic Random Access Memory),同步是指其时钟频率与对应控制器(CPU/FPGA)的系统时钟频率相同,并且内部命令的发送与数据传输都是以该时钟为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失;随机指数据的读取和写入可以随机指定地址,而不是必须按照严格的线性次序变化。
二、SDRAM存取原理
存储单元主要由行列选通三极管,存储电容,刷新放大器组成。对于这一位的数据,首先需要打开行地址,然后打开列地址,则电容的电平状态就能呈现在数据线(data_bit)上,即实现了读取。数据线上的电平值被送到电容上,从而实现写入数据。注意此处行列打开后,数据不会立刻被处理,有延时,称作行列选通潜伏期,不同速度延时tRP不同。
三、SDRAM引脚
四、SDRAM操作命令
{CS_N,RAS_N,CAS_N,WE} | 命令 | 说明 |
---|---|---|
0011 | 激活命令 | BA0 和 BA1 用来选择需要操作的 BANK,地址线A0–A12 选择指定的行。该行会一直保持激活状态并可以进行读写,只有执行一个预充电命令后,才能关闭,并对其他行进行操作 |
0101 | 已经激活行的突发读取操作 | 位 A0–A9, A11(x4),A0–A9(x8),A0–A8(x16))指定需要读取的数据起始列地址,A10读取完成之后立即执行预充电,即关闭当前行操作 |
0100 | 写命令 | 位 A0–A9, A11(x4),A0–A9(x8),A0–A8(x16))指定需要写的数据起始列地址,A10写完成之后立即执行预充电,即关闭当前行操作 |
0010 | 预充电 | 关闭指定或全部BANK(由A10状态选择)中已经打开的行,等待 tRP 的时间后对应的 BANK 将可以重新被操作 |
xxxx | 自动预充电 | 不额外增加执行指令的使用预充电指令,A10指明是否在突发读写完成后立即自动执行预充电操作 |
0110 | 突发中断 | 离该命令最近的一次被 SDRAM 寄存的读或者写命令被截断,截断后仍处于激活状态 |
0001 | 自动刷新 | 用来保持SDRAM中的数据,该命令是非持续性的,自动刷新命令之前,所有的BANK必须被预充电(关闭) |
五、SDRAM操作时序 | ||
上电初始化步骤: | ||
加载电源—— CKE设置为低电平——时钟信号——等待100毫秒,禁止命令操作,其中一时刻cke拉高——全部 BANK 的预充电命令——预充电后等待tRP后才能进行命令——自动刷新命令,然后等待tRFc——重复自动刷新命令,然后等待tRFc——发出装载模式寄存器命令设置模式寄存器——等待时间 tMRD——初始化完成 |
//定义操作操作命令{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; //写命令
//线性序列机
parameter INIT_PRE = 20000;//初始化等待时间>100us,取200us
REF_PRE = 3; //tRP >=20ns,取30ns
REF_REF = 10; //tRRC >=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; //结束时刻
//相应时刻发出对应的命令和操作
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 //预充电时刻,预充电命令,A10拉高,对所有BANK行进行预充电(若A10为低电平,则只对BA0和BA1定的BANK中的行进行预充电)
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 //加载模式寄存器,加载模式寄存器命令,A0-A10为{写突发模式设置,00,列选通潜伏期设置,突发类型设置,突发长度设置}此处各位对应功能查表
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 仿真模型
`timescale 1ns/1ns
`define clock_period 10 //100M
module sdram_int_tb;
`include "../rtl/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 #(`clock_period/2) clk = ~clk;
initial
begin
rst_n = 1'b0;
#(`clock_period*200 + 1);
rst_n = 1'b1;
@(posedge init_done)
#2000;
$stop;
end
endmodule
仿真图像
镁光自动打印信息
至此SDRAM初始化完成。