一、知识点
- 存储单元主要由列选通三极管、存储电容、刷新放大器组成。
- SRAM(异步静态随机存储器)要正确存储一位数据,需要最少6个晶体管,因此,从芯片面积上来说,单片SRAM芯片的容量不可能做到很高。
- 工作电压:SDRAM的工作电压是3.3V,DDR的工作电压是2.5V,DDR2的工作电压是1.8V
- HY57V281620 芯片,容量128Mbit,数据位宽16bit,具有4个BANK,每个BANK存储32MBit的数据。每个BANK由4096*512个存储单元组成,每个存储单元存储16bit数据。
- 控制总线:由4条控制总线来控制SDRAM:
片选信号CS_N,行选通信号RAS_N,列选通信号CAS_N,写使能信号WE_N。
13位地址总线,2位BANK地址线,2位掩码DQM
- 为了保证SDRAM器件读写的稳定性,控制器的时钟和器件工作时钟均为100MHz,但是器件工作时钟理论向后偏移180°,考虑到布局布线延迟,实际不偏移。
- 为了保证存储的数据不丢失,每一行每64ms刷新一次
二、具体工作时序
- 上电初始化
module sdr_initial(
input clk,
input sdr_rst_n,
input sdr_initial_en,
output [19:0]init_bus,
output reg initial_done
);
parameter clk_period = 10;//时钟周期10ns
parameter t100us = 100000/clk_period;
parameter tRp = 30/clk_period;//延迟30ns
parameter tRfc =100/clk_period;//延迟100ns
parameter tMrd = 20/clk_period;//延迟2个时钟周期
parameter IDEL=7'b000_0001,//空闲态
s0 =7'b000_0010,//初始化状态,延迟100ns
s1 =7'b000_0100,//NOP过渡状态
s2 =7'b000_1000,//预充电
s3 =7'b001_0000,//自动刷新
s4 =7'b010_0000,//自动刷新
s5 =7'b100_0000;//加载模式寄存器
parameter NOP = 4'b0111,//空操作命令
PRE = 4'b0010,//预充电命令
AREF= 4'b0001,//自动刷新命令
MEST= 4'b0000,//加载模式寄存器命令
ACT = 4'b0011;//激活命令
parameter ZEROS = 3'b000,//默认3个0
OP_CODE = 1'b0,//写突发模式设置
OP_MODE = 2'b00,//标准模式
CLs = 2,//列选通潜伏期:2
BT = 1'b0,//突发类型:顺序
BLs = 2;//突发长度:2
parameter BL=(BLs==1)?3'b000:
(BLs==2)?3'b001:
(BLs==4)?3'b010:
(BLs==8)?3'b011:3'b111;//突发长度为1 2 4 8 或者FULL PAGE(111)
parameter CL=(CLs==2)?3'b010:3'b011;//列选通潜伏期为2或者3
reg [6:0]state;
reg [15:0]cnt;
reg [1:0]init_ba;
reg [12:0]init_addr;
reg [3:0]init_cmd;
reg init_cke;
assign init_bus = {init_ba,init_addr,init_cmd,init_cke};
always@(posedge clk or negedge sdr_rst_n)
if(!sdr_rst_n)begin
cnt <= 16'd0;
init_cke <= 1'd0;
init_addr <= 13'd0;
init_cmd <= NOP;
initial_done <= 1'd0;
state <= IDEL;
init_ba <= 2'd0;
end
else begin
case(state)
IDEL:
begin
if(sdr_initial_en)
begin
state <= s0;
end
else begin
state <= IDEL;
cnt <= 16'd0;
init_cke <= 1'd0;
init_addr <= 13'd0;
init_cmd <= NOP;
initial_done <= 1'd0;
init_ba <= 2'd0;
end
end
s0:
begin
if(cnt >= 9999)
begin
init_cke <= 1'd1;
cnt <= 16'd0;
state <= s1;
end
else
cnt <= cnt+1'b1;
end
s1:
begin
init_addr[10] <= 1'b1;
init_cmd <= PRE;
state <= s2;
end
s2:
begin
if(cnt >=2)
begin
cnt <= 16'd0;
init_cmd <= AREF;
state <= s3;
end
else begin
cnt <= cnt+1'b1;
init_cmd <= NOP;
end
end
s3:
begin
if(cnt >=9)
begin
cnt <= 16'd0;
init_cmd <= AREF;
state <= s4;
end
else begin
cnt <= cnt+1'b1;
init_cmd <= NOP;
end
end
s4:
begin
if(cnt >=9)
begin
cnt <= 16'd0;
init_cmd <= MEST;
init_addr <= {ZEROS,OP_CODE,OP_MODE,CL,BT,BL};//模式寄存器设置
state <= s5;
end
else begin
cnt <= cnt+1'b1;
init_cmd <= NOP;
end
end
s5:
begin
if(cnt >= 1)
begin
initial_done <= 1'b1;
cnt <= 16'd0;
state <=IDEL;
end
else begin
init_cmd <= NOP;
cnt <= cnt+1'b1;
end
end
default:begin
cnt <= 16'd0;
init_cke <= 1'd1;
init_addr <= 13'd0;
init_cmd <= NOP;
initial_done <= 1'd0;
state <= IDEL;
end
endcase
end
// reg [6:0]current_state;
// reg [6:0]next_state;
// reg [15:0]cnt;
//
// always@(posedge clk or negedge sdr_rst_n)
// if(!sdr_rst_n)
// current_state <= IDEL;
// else
// current_state <= next_state;
//
// always@(*)
// begin
// case(current_state)
// IDEL:
// begin
// if(sdr_initial_en)
// next_state = s0;
// else
// next_state = IDEL;
// end
// s0:
// begin
// if(cnt>=t100us-1)
// next_state=s1;
// else
// next_state = current_state;
// end
// s1:
// begin
// next_state = s2;
// end
// s2:
// begin
// if(cnt>=tRp-1)
// next_state = s3;
// else
// next_state = current_state;
// end
// s3:
// begin
// if(cnt>=tRfc-1)
// next_state = s4;
// else
// next_state = current_state;
// end
// s4:
// begin
// if(cnt>=tRfc-1)
// next_state = s5;
// else
// next_state = current_state;
// end
// s5:
// begin
// if(cnt>=tMrd-1)
// next_state = IDEL;
// else
// next_state = current_state;
// end
// default:next_state=IDEL;
// endcase
// end
//
// always@(posedge clk or negedge sdr_rst_n)
// if(!sdr_rst_n)begin
// cnt <= 16'd0;
// init_cke <= 1'd0;
// init_addr <= 13'd0;
// init_cmd <= NOP;
// initial_done <= 1'd0;
// end
// else begin
// case(next_state)
// IDEL:
// begin
// cnt <= 16'd0;
// init_cke <= 1'd0;
// init_addr <= 13'd0;
// init_cmd <= NOP;
// end
// s0:
// begin
// if(cnt >= t100us-1)
// begin
// init_cke <= 1'd1;
// cnt <= 16'd0;
// end
// else
// cnt<=cnt+1'b1;
// end
// s1:
// begin