文章目录
功能思路分析
时序接口设计:
- 根据读数据手册步骤分析,看我的博客。
- 对于多时序冲突问题:是否考虑状态机架构
- 看单时序时间参数分析:考虑设计计数器架构;根据单时序一步步执行的命令考虑状态机架构。
- 看命令:command ,查找命令参数表 + 查找不同命令的介绍:如何设置输出端口来实现命令
- 时钟分析:时钟速率;上升沿、下降沿检测(差分时钟设计)
普通设计:
1.根据时间的不同先设计计数器架构,再进行设计其他信号
2.或者考虑先设计状态机架构,选取状态很重要
如何实现SDRAM读写功能
根据数据手册可以进行读写功能,由数据手册得到,只能先进行初始化才能进行后续的写、读、刷新操作。
对于初始化在上个(SDRAM 之初始化博客介绍过了。)那么对于刷新我们该怎么理解呢?
SDRAM自刷新描述
-
为什么要进行刷新?
SDRAM作为一个RAM并没有断电保存的功能,在操作的SDRAM的时候每隔一段时间必须对SDRAM进行自刷新操作,防止SDRAM中的数据丢失。
-
自刷新在SDRAM内部运行状态机如何体现的?PRE命令?
自刷新体现在内部SDRAM里面。
在读结束、或者写结束中遇到了刷新时间到了;或者读写结束后又到了刷新时间,首先给出PRE命令再给2次AUTO FRESH 。后面的 ACTIVE 可以再读写时候给。- 有人疑问读写后面的PRE命令和刷新时序的PRE命令是一样的么是一样的。
- 那么在2个时序都可以写PRE命令么。可以的。因为只要保证SDRAM进行正确跳转就行了。
- 是否可以在写时序不要PRE命令呢?不行,因为要保证写突发结束正确,如果没有PRE,不知道啥时候突发结束了。
- 假设在SDRAM的IDLE状态遇到了PRE咋办,原地踏步就好了
- 这里需要执行ACTIVE么?不需要。在读写执行就好。
- 2次AUTO FRESH 有必要给2次么?没必要只是系统需要执行一次命令长时间就好了
-
选择自刷新还是自动刷新模式?
都可以,自刷新因为路径短更快。自动刷新:操作简单(这里我们选后者)
-
刷新时间间隔多少?
64ms 是电容在未充电的状态下能保持电量的最长时间,也就是 SDRAM 在未刷新的状态下能保存数据的最长时间是 64ms。而SDRAM的刷新操作是一行一行刷新的,该SDRAM一共4096行,所以,每两次刷新的时间间隔大约是 64ms / 4096 = 15.625us。 在本项目中, 我们设置刷新间隔为 15us。
或者理解:刷新4096行总共需要64ms,每行需要 64ms / 4096 = 15.625us。
-
取15us优点?
剩余的0.625us,可以利用来等待写突发、读突发结束。
-
何时才开始刷新?
在读结束、或者写结束中遇到了刷新时间到了;
或者读写结束后又到了刷新时间
-
刷新对于各个模块的影响?
因为写读刷新模块起到冲突,所以要引入仲裁模块来实现不同模块的运转。
由于SDRAM需要同时调控自刷新、读操作、写操作的协调,所以在仲裁控制模块:需要控制三个模块的执行顺序,这三个模块中自刷新命令的优先级最高,但是在执行读写操作时需要等待本次突发结束才可以调到自刷新模块执行,否则就会丢数据。
自动刷新波形
时间参数设计看表
trp含义:上升沿检测到命令1,和检测到命令2之间的时间大于trp,所以不能一直给命令1,
而是给出命令1后,给出空操作,等价于延长第一次SDRAM响应命令的时间,而如果一直给命令1,等价于多次进行相应命令1了。
设置20ns.
TRC:设置80ns.
命令设计看表
从图中我们可以看到COMMAND信号,该信号是由sdram的四个控制信号构成,即sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n,具体每个命令的编码如下:
同时我们可以看到根据命令输出对应的 DQm A0-A12 DQ0-15 BA0 BA1
针对命令输出相应的值:
NOP:不用管
PRE :A10=1就可以表示对所有bank充电 BA0 BA1 A0-A12 DQ0-15 不需要设置
( A10:1 表明对所有bank充电,不需要BA0,BA1设计
A10:0 表明对挑选bank充电,需要对BA0,BA1设计)
AREF:不用管
时钟分析设计:
采用100M设计,便于参数计数。
同时注意:原图上升沿开始检测命令。而我们写代码也是上升沿写命令。考虑采用差分时钟设计。
波形设计
考虑采用计数器架构设计。简单点
由于波形简单就不画了。
代码设计
状态机设计
不采用状态机架构,因为简单,直接采用计数器架构
计数器设计
1.不同时原则,1个计数器可以对不同时间段计数
数据存储设计
main代码
1.case endcase 一起用而且 不要begin end
2.对于输出端口,不能同时赋值,对于多模块都用到这个端口,可以利用暂存器在不同的模块寄存,再输出到顶层模块。
3.信号:0 1 0信号 0 1信号
4.if else 一定要考虑优先级问题
刷新模块代码
//===============================================================================
//******************Cyclone IV E EP4CE15F23C8 ******************************
// 完成自刷新时序操作
//===============================================================================
module sdram_aref (
//system
input wire [0:0] clk ,//系统工作时钟
input wire [0:0] rst_n ,//异步复位
//init
input wire [0:0] init_done ,初始化结束,长1信号
//aref
input wire [0:0] aref_ack ,//自刷新请求
output reg [0:0] aref_req ,//自刷新结束
output reg [0:0] aref_done ,//自刷新完成
//sdram
output reg [3:0] aref_cmd ,//sdram输出端口{sdram_cs,sdram_ras,sdram_cas,sdram_we}
output wire [11:0] aref_addr //sdram地址
);
//===============================================================================
//**************Define Parameter ***************************
//===============================================================================
localparam DELAY_CNT_MAX = 11'd1500 ;//用于15us,电容刷新时间,准确是15.625us
localparam CMD_CNT_MAX = 5 ;//用于命令执行
localparam NOP = 4'b0111 ;//空命令
localparam PRE = 4'b0010 ;//充电命令
localparam AREF = 4'b0001 ;//刷新命令
//===============================================================================
//*********************** Define Intenral Singal ********************************
//===============================================================================
reg [10:0] delay_cnt ;
wire [0:0] add_delay_cnt ;
wire [0:0] end_delay_cnt ;
reg [2:0] cmd_cnt ;
wire [0:0] add_cmd_cnt ;
wire [0:0] end_cmd_cnt ;
reg [0:0] cmd_cnt_flag ;
//===============================================================================
//******************************** Cnt Design **********************************
//===============================================================================
//delay_cnt
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
delay_cnt <= 0;
end
else if(add_delay_cnt)begin
if(end_delay_cnt)
delay_cnt <= 0;
else
delay_cnt <= delay_cnt + 1;
end
end
assign add_delay_cnt =init_done==1 ;
assign end_delay_cnt = add_delay_cnt && delay_cnt==DELAY_CNT_MAX-1;
//cmd_cnt
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cmd_cnt <= 0;
end
else if(add_cmd_cnt)begin
if(end_cmd_cnt)
cmd_cnt <= 0;
else
cmd_cnt <= cmd_cnt + 1;
end
end
assign add_cmd_cnt = cmd_cnt_flag==1;
assign end_cmd_cnt = add_cmd_cnt && cmd_cnt==CMD_CNT_MAX-1;
//cmd_cnt_flag
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cmd_cnt_flag <=1'b0 ; //初始化
end
else if(aref_ack==1)begin
cmd_cnt_flag <= 1'b1;
end
else if(end_cmd_cnt)begin
cmd_cnt_flag <= 1'b0 ;
end
end
//===============================================================================
//*********************** Intenral Singal Design ********************************
//===============================================================================
//===============================================================================
//**************************** Output Singal Design *****************************
//===============================================================================
//aref_cmd
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
aref_cmd <= NOP ; //初始化
end
else begin
case(cmd_cnt)
1: aref_cmd <= PRE ;
4: aref_cmd <= AREF ;
default:aref_cmd <= NOP;
endcase
end
end
//aref_done:一次时序执行完成算刷新结束了。而不是15us
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
aref_done <= 1'b0 ; //初始化
end
else if(end_cmd_cnt == 1'b1)begin
aref_done <= 1'b1 ;
end
else begin
aref_done <= 1'b0 ;
end
end
//aref_req
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
aref_req <= 1'b0 ; //初始化
end
else if(end_delay_cnt == 1'b1)begin
aref_req <= 1'b1 ;
end
else if(aref_ack == 1'b1)begin
aref_req <= 1'b0 ;
end
end
//aref_addr
assign aref_addr=12'b0100_0000_0000;
endmodule
仲裁模块代码
由于SDRAM需要同时调控自刷新、读操作、写操作的协调,所以在顶层需要控制三个模块的执行顺序,这三个模块中自刷新命令的优先级最高,但是在执行读写操作时需要等待本次突发结束才可以调到自刷新模块执行,否则就会丢数据。
以刷新操作为例: 当刷新的时间到了之后,刷新模块向仲裁发起刷新请求,然后仲裁老大根据 SDRAM 当前所处的一个状态来判断是否可以允许 SDRAM 进行刷新,当仲裁老大认为 SDRAM 可以刷新了之后,向刷新模块给出刷新使能信号;当刷新模块对 SDRAM 进行刷新完毕后,再向仲裁老大给出刷新结束标志。模块之间的状态转移图如下:
//===============================================================================
//**************************Cyclone IV E EP4CE15F23C8 ***************************
// 仲裁模块
//===============================================================================
module sdram_ctrl (
//system
input wire [0:0] clk ,//
input wire [0:0] rst_n ,//
//init
input wire [0:0] sdram_en ,//
input wire [0:0] init_done ,//
input wire [11:0] init_addr ,//
input wire [3:0] init_cmd ,//
output reg [0:0] init_en ,//
//aref
input wire [0:0] aref_req ,//
input wire [0:0] aref_done ,//
input wire [11:0] aref_addr ,//
input wire [3:0] aref_cmd ,//
output reg [0:0] aref_ack ,//
//sdram输出端口
output reg [0:0] sdram_cke ,//
output reg [1:0] sdram_bank ,//
output reg [0:0] sdram_cs ,//
output reg [0:0] sdram_ras ,//
output reg [0:0] sdram_cas ,//
output reg [0:0] sdram_we ,//
output reg [1:0] sdram_dqm ,//
output reg [11:0] sdram_addr
);
//===============================================================================
//**************************Define Parameter ******************************
//==============================================================================
parameter IDLE = 6'b000001;//空闲状态
parameter SD_INIT = 6'b000010;//初始化状态
parameter SD_ARBIT = 6'b000100;//仲裁状态
parameter SD_AREF = 6'b001000;//刷新状态
//==========================================================================
//******************************** Define Internal Signals ****************
//==============================================