SDRAM(Synchoronous Dynamic Ramdom Access Memory),即同步动态随机存储器。
DRAM,动态存储器,是异步的
SDRAM特点:1.动态:即他是采用电容来存储数据的,电容会放电,为了保证数据的可靠性,需要不停的给电容冲电,即不断刷新。
2.随机性,即有地址的,行地址和列地址共用一个端口,地址线要使用分时复用。
SDRAM数据存取原理:
![](https://img-blog.csdnimg.cn/img_convert/0877f62799510be7643c99a9322a7c72.png)
N个存储单元构成一个存储阵列(N=行*列),存储阵列又称为逻辑BANK,4个逻辑BANK又构成了整个SDRAM的存储空间。
所以再SDRAM数据存取的时候,首先要确定逻辑BANK地址,然后确定行地址,然后才是确定列地址,才能进行数据的读取。
下面根据镁光数据手册来了解一些重要参数
SDRAM的容量计算表示容量有256Mb,即存储256Mbit的信息,有4位宽,8位宽,16位宽
![](https://img-blog.csdnimg.cn/img_convert/9aeb1d16ca339e79afa1de28ada87028.png)
任务要求:使用串口向SDRAM写入10个字节的数据,再利用串口将这10个字节的数据发送到电脑上。
绘制框图
确定好整个设计需要哪几个模块,本次设计中用到的有写模块,读模块,初始化模块,刷新模块(给电容充电),仲裁模块(当几个模块发生冲突时,决定哪个优先。)
![](https://img-blog.csdnimg.cn/img_convert/033f0141c9b95471a7819db245d85b3c.png)
下面进行各个模块的设计
初始化模块的设计
给出初始化模块的时序图
![](https://img-blog.csdnimg.cn/img_convert/3bdd45fdcf2a0d86630ab8f693f1d183.png)
由时序图可以知道,上电后先要等待100us的时间,在等待期间必须使用NOP指令,随后执行预充电指令,预充电指令后需要等待TRP的时间,随后进行自刷新指令,自刷新指令后需要等待TRFC时间,(自刷新指令以及之后的等待时间进行2次)随后进行加载寄存器指令,等待tMRD时间,初始化结束。上述等待时间都要进行NOP指令。
给出初始化模块的输入输出:
![](https://img-blog.csdnimg.cn/img_convert/ebc82dfc0c4401e2436385ce18116022.png)
该模块儿设计采用状态机设计。
初始化模块写完之后要对顶层模块进行编写以供仿真.
自动刷新模块
自动刷新模块接口图如图所示,这一模块的设计需要引入仲裁模块,即像仲裁模块发出自动刷新请求,仲裁模块返回刷新使能信号后才能进行刷新操作:本次设计中在顶层文件中处理自动刷新请求,并发出刷新使能信号。
![](https://img-blog.csdnimg.cn/img_convert/2ed74e885da703643c1c1c94ab2d1e18.png)
自动刷新的时序图:
![](https://img-blog.csdnimg.cn/img_convert/ca75456fec21c52b0d16fd65049d7a8f.png)
部分时序图和注意事项
![](https://img-blog.csdnimg.cn/img_convert/bd87e4e0890fbfbc8f7a035088e53050.png)
刷新模块代码:
`timescale 1ns / 100ps
//自动刷新模块
module Sdram_auto_refresh (
input sys_clk ,
input sys_rst_n ,
input auto_refresh_en , //仲裁模块返回来的刷新使能信号
input init_end , //初始化模块
output reg auto_refresh_req , //向仲裁模块发出刷新请求信号
output reg [3:0] auto_refresh_cmd ,
output reg [12:0] auto_refresh_addr ,
output wire auto_refresh_end
);
//定义自刷新模块的几个状态
reg [2:0] auto_refresh_state;
parameter AREF_IDLE = 3'b000; //初始化状态,注意向仲裁模块发送请求信号以及接收到使能信号要在初始化模块完成
parameter AREF_PRE = 3'b001; //预充电状态
parameter AREF_tRP = 3'b011; //等待tRP时间状态
parameter AREF_AUT0_REFRESH = 3'b010; //自刷新状态
parameter AREF_tRFC = 3'b110; //等待tRFC时长状态
parameter AREF_end = 3'b111; //自刷新结束状态
//定义几个命令
parameter NOP = 4'b0111;
parameter PRECHARGE = 4'b0010;
parameter AUTO_REFRESH = 4'b0001;
parameter LOAD_MODE_REGISTER = 4'b0000;
//各个计数器定义
reg cnt_tRP ; //tRP维持两个时钟周期
reg [2:0] cnt_tRFC ; //tRFC维持7个时钟周期
reg [1:0] tRFC_time ; //自动刷新次数
reg [9:0] cnt_Refresh_interval; //每7.5us进行一次刷新,刷新间隔时间计数
//参数定义
parameter cnt_Refresh_interval_MAX = 10'd749;
//刷新请求
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) cnt_Refresh_interval <= 0;
else if( cnt_Refresh_interval == cnt_Refresh_interval_MAX) cnt_Refresh_interval <= 0;
else cnt_Refresh_interval <= cnt_Refresh_interval + 1'd1;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) auto_refresh_req <= 0;
else if( cnt_Refresh_interval == cnt_Refresh_interval_MAX && init_end == 1'd1 ) auto_refresh_req <= 1;
else auto_refresh_req <= 0;
//几个状态的跳转
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) begin
auto_refresh_addr <= 13'd0;
auto_refresh_state <= AREF_IDLE;
end
else case(auto_refresh_state)
AREF_IDLE: begin
if(init_end == 1'd1 && auto_refresh_en == 1)begin
auto_refresh_addr[10] <= 1;
auto_refresh_state <= AREF_PRE;
auto_refresh_cmd <= PRECHARGE;
end
end
AREF_PRE: begin
auto_refresh_state <= AREF_tRP;
auto_refresh_cmd <= NOP;
end
AREF_tRP:begin
if(cnt_tRP == 1) begin
auto_refresh_state <= AREF_AUT0_REFRESH;
auto_refresh_cmd <= AUTO_REFRESH;
end
else begin
auto_refresh_state <= auto_refresh_state;
auto_refresh_cmd <= NOP;
end
end
AREF_AUT0_REFRESH:begin
auto_refresh_state <= AREF_tRFC;
auto_refresh_cmd <= NOP;
end
AREF_tRFC:begin
if(cnt_tRFC == 3'd6 && tRFC_time == 2'd2) auto_refresh_state <= AREF_end;
else if(cnt_tRFC == 3'd6)begin
auto_refresh_state <= AREF_AUT0_REFRESH;
auto_refresh_cmd <= AUTO_REFRESH;
end
else begin
auto_refresh_state <= auto_refresh_state;
auto_refresh_cmd <= NOP;
end
end
AREF_end: auto_refresh_state <= AREF_IDLE;
default : auto_refresh_state <= AREF_IDLE;
endcase
//cnt_tRP
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) cnt_tRP <= 0;
else if(cnt_tRP == 1 && auto_refresh_state == AREF_tRP ) cnt_tRP <= 0;
else if( auto_refresh_state == AREF_tRP ) cnt_tRP <= cnt_tRP+1;
else cnt_tRP <= cnt_tRP;
//cnt_tRFC
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) cnt_tRFC <= 0;
else if(cnt_tRFC == 3'd6 && auto_refresh_state == AREF_tRFC ) cnt_tRFC <= 0;
else if( auto_refresh_state == AREF_tRFC ) cnt_tRFC <= cnt_tRFC+1;
else cnt_tRFC<= cnt_tRFC;
//tRFC_time,进行2次自动刷新
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) tRFC_time <= 0;
else if(tRFC_time == 2'd2 && cnt_tRFC == 3'd6) tRFC_time <= 0;
else if(auto_refresh_state == AREF_AUT0_REFRESH) tRFC_time <= tRFC_time + 1;
else tRFC_time <= tRFC_time;
//赋值auto_refresh_end
assign auto_refresh_end = (auto_refresh_state == AREF_end ? 1 : 0 );
endmodule
顶层模块:
`timescale 1ns / 100ps
module SDRAM(
input clk,
input rst,
output sys_clk,
output sys_rst_n,
output CKE,
output CS,
output WE,
output CAS,
output RAS,
output [1:0] DQM,
output [1:0] BA,
output [12:0] A,
inout [15:0] DQ
); //每个端口的意义参见数据手册
//定义SDRAM的工作状态
reg [3:0] SDRAM_STATE;
parameter SDRAM_IDLE = 3'b000 ;
parameter SDRAM_HANDLE = 3'b001 ; //仲裁模块
parameter SDRAM_AUTO_REFRESH = 3'b011 ;
assign sys_rst_n = rst;
sdram_clk sdram_clk_Inst(
.areset(!rst),
.inclk0(clk),
.c0(sys_clk)
);
wire [3:0] init_cmd;
wire init_end;
wire [12:0] init_addr;
//例化初始化模块
Sdram_Init Sdram_Init_Inst(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.init_cmd(init_cmd),
.init_addr(init_addr),
.init_end(init_end)
);
//例化自刷新模块
wire [3:0] auto_refresh_cmd;
wire [12:0] auto_refresh_addr;
wire auto_refresh_req;
wire auto_refresh_end;
reg auto_refresh_en;
Sdram_auto_refresh Sdram_auto_refresh_Inst(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.auto_refresh_en (auto_refresh_en),
.init_end (init_end),
.auto_refresh_req (auto_refresh_req),
.auto_refresh_cmd (auto_refresh_cmd),
.auto_refresh_addr(auto_refresh_addr),
.auto_refresh_end (auto_refresh_end)
);
//SDRAM的几个工作状态
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) SDRAM_STATE <= SDRAM_IDLE;
else case(SDRAM_STATE)
SDRAM_IDLE:begin
if(init_end) SDRAM_STATE <= SDRAM_HANDLE;
else SDRAM_STATE <= SDRAM_STATE;
end
SDRAM_HANDLE:begin
if(auto_refresh_en) SDRAM_STATE <= SDRAM_AUTO_REFRESH;
else SDRAM_STATE <= SDRAM_STATE;
end
SDRAM_AUTO_REFRESH: begin
if(auto_refresh_end) SDRAM_STATE <= SDRAM_HANDLE;
else SDRAM_STATE <= SDRAM_STATE;
end
default:SDRAM_STATE <= SDRAM_IDLE;
endcase
//刷新使能
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n) auto_refresh_en <= 0;
else if(auto_refresh_req)
auto_refresh_en <= 1;
else if(auto_refresh_end)
auto_refresh_en <= 0;
else auto_refresh_en <= auto_refresh_en;
//赋值地址和命令
assign A = (SDRAM_STATE == SDRAM_IDLE ? init_addr : auto_refresh_addr);
assign {CS,RAS,CAS,WE} = (SDRAM_STATE == SDRAM_IDLE ? init_cmd : auto_refresh_cmd);
endmodule