SDRAM之刷新(原理分析、波形设计、代码编写、仿真测试)

功能思路分析

时序接口设计:

  1. 根据读数据手册步骤分析,看我的博客。
  2. 对于多时序冲突问题:是否考虑状态机架构
  3. 看单时序时间参数分析:考虑设计计数器架构;根据单时序一步步执行的命令考虑状态机架构。
  4. 看命令:command ,查找命令参数表 + 查找不同命令的介绍:如何设置输出端口来实现命令
  5. 时钟分析:时钟速率;上升沿、下降沿检测(差分时钟设计)

普通设计:

1.根据时间的不同先设计计数器架构,再进行设计其他信号

2.或者考虑先设计状态机架构,选取状态很重要

如何实现SDRAM读写功能

根据数据手册可以进行读写功能,由数据手册得到,只能先进行初始化才能进行后续的写、读、刷新操作。
对于初始化在上个(SDRAM 之初始化博客介绍过了。)那么对于刷新我们该怎么理解呢?

SDRAM自刷新描述

  1. 为什么要进行刷新?

    SDRAM作为一个RAM并没有断电保存的功能,在操作的SDRAM的时候每隔一段时间必须对SDRAM进行自刷新操作,防止SDRAM中的数据丢失。

  2. 自刷新在SDRAM内部运行状态机如何体现的?PRE命令?

    自刷新体现在内部SDRAM里面。
    在这里插入图片描述
    在这里插入图片描述
    在读结束、或者写结束中遇到了刷新时间到了;或者读写结束后又到了刷新时间,首先给出PRE命令再给2次AUTO FRESH 。后面的 ACTIVE 可以再读写时候给。

    1. 有人疑问读写后面的PRE命令和刷新时序的PRE命令是一样的么是一样的。
    2. 那么在2个时序都可以写PRE命令么。可以的。因为只要保证SDRAM进行正确跳转就行了。
    3. 是否可以在写时序不要PRE命令呢?不行,因为要保证写突发结束正确,如果没有PRE,不知道啥时候突发结束了。
    4. 假设在SDRAM的IDLE状态遇到了PRE咋办,原地踏步就好了
    5. 这里需要执行ACTIVE么?不需要。在读写执行就好。
    6. 2次AUTO FRESH 有必要给2次么?没必要只是系统需要执行一次命令长时间就好了
  3. 选择自刷新还是自动刷新模式?

    都可以,自刷新因为路径短更快。自动刷新:操作简单(这里我们选后者)

  4. 刷新时间间隔多少?

    64ms 是电容在未充电的状态下能保持电量的最长时间,也就是 SDRAM 在未刷新的状态下能保存数据的最长时间是 64ms。而SDRAM的刷新操作是一行一行刷新的,该SDRAM一共4096行,所以,每两次刷新的时间间隔大约是 64ms / 4096 = 15.625us。 在本项目中, 我们设置刷新间隔为 15us。

    或者理解:刷新4096行总共需要64ms,每行需要 64ms / 4096 = 15.625us。在这里插入图片描述

  5. 取15us优点?

    剩余的0.625us,可以利用来等待写突发、读突发结束。

  6. 何时才开始刷新?

    在读结束、或者写结束中遇到了刷新时间到了;

    或者读写结束后又到了刷新时间

  7. 刷新对于各个模块的影响?

    因为写读刷新模块起到冲突,所以要引入仲裁模块来实现不同模块的运转。

    由于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设计,便于参数计数。

同时注意:原图上升沿开始检测命令。而我们写代码也是上升沿写命令。考虑采用差分时钟设计。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dS7ob6oA-1587353889115)(F:\FPGA\MDY_FPGA\image_sobel_system\01uart_sdram\doc\07SDRAM模块之初始化模块\1586149059205.png)]

波形设计

考虑采用计数器架构设计。简单点

由于波形简单就不画了。

代码设计

状态机设计

不采用状态机架构,因为简单,直接采用计数器架构

计数器设计

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 ****************
//==============================================
  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值