SDRAM控制器操作时序

SDRAM控制器操作时序此为学习http://dengkanwen.com/137.html整理的笔记,侵删!SDRAM工作原理内部的状态跳转图我们所需关注的几个地方:1)粗黑线表示在该状态下会自动跳转到另一个状态,细黑线表示需要给命令才会跳转。2)我们重点关注的几个地方:IDLE状态到WRITE状态:​1)在IDLE状态需要先给ACT命令激活某一行,此时处于Row

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

此为学习http://dengkanwen.com/137.html整理的笔记,侵删!

SDRAM工作原理

内部的状态跳转图

img

我们所需关注的几个地方:

1)粗黑线表示在该状态下会自动跳转到另一个状态,细黑线表示需要给命令才会跳转。

2)我们重点关注的几个地方:

IDLE 状态到WRITE 状态:
​ 1) 在IDLE 状态需要先给ACT 命令激活某一行,此时处于Row Active 状态;
​ 2) 在Row Active 状态之后,给Write 命令则会进入WRITE 状态;
​ 3) 在WRITE 状态后,再给一次Write 命令,就可以继续写入数据。
WRITE 状态到IDLE 状态:
​ 1) 在WRITE 状态给PRE 命令,则SDRAM 将跳出WRITE 状态进入Precharge状态;
​ 2) 在Precharge 状态后,就会自动进入IDLE 状态了。

​ 要从WRITE 状态跳到IDLE 状态的一个原因是,我们需要进行刷新操作,进
入刷新操作,必须从IDLE 状态进入。
​ 另外一点,可能有些朋友看到了WRITE 状态下边还有一个WRITEA 状态,的
确,但是细心的你有没有发现当处于WRITEA 状态时,它会自动的进入Precharge 状态。也就是说WRITEA 比在WRITE 状态的工作效率要低很多,所以在某些对数据交互速度较快的场景中,我们使用WRITE 状态。在本套教程中,我们也只讲WRITE 状态。速度快的都能搞定,那速度慢的操作也是不在话下的。

SDRAM 初始化模块

首先看一下官方数据手册给出的初始化时序图

这里写图片描述

初始化过程

1)首先需要有200us 的一个延时(对应图中左下方的T),

2)在延时满足之后,给一次Precharge 命令,同时需要指定A10及Bank地址;(如果A10为高(All Banks),就意味着是给所有的Bank进行预充电,此时不需要给Bank地址,如果A10为低(SINGLE BANK),就需要指定某一个bank的地址。一般为高)

3)然后再过“tRP”的时间,给“AutoRefresh”命令,然后再过“tRC”的时间,再给“Auto Refresh”命令,(不需要指定bank地址的(大家注意看右下角有说明,灰色部分的数据我们是不需要关心的)。

4)然后再经过“tRP”的时间进行模式寄存器设置。进行模式寄存器设置的时候,需要给的指令会稍微复杂一点,手册上显示A0~A11及BA0,BA1都用到了,下面我们来看下模式寄存器应该怎么进行设置,如图:

这里写图片描述

​ 这里解释一下突发读写:突发长度(A2~A0)设置为4,在我们进行写操作的时候,数据是每4个数据写一次的,就是说我们给一次写指令,就会向SDRAM写进去4个数据,而且四个地址是连续的(如果突发类型设置的是非连续,则地址不会连续,需要我们写一个数据给一次地址,比较耗内存)

初始化时序图中的几个问题

1)tRC、tRP、tMRD的时间是多少,几个时钟周期?

参照官方数据手册ML0006 0012-2中的AC ELECTRICAL CHARACTERISTICS部分给出

tRC:63ns

tRP:20ns

tMRD:2cycle

若fpga内部频率为50MHZ,正好是20ns。(4clk、1clk)

2)时序图中几个command命令的参数怎样设置

这里写图片描述

上述就是整个初始化过程,我们最后以kevin画的时序图作为一个总结

这里写图片描述

具体代码为sdram_init;

SDRAM 刷新模块

我们还是先看一下官方数据手册给出的刷新时序图

img

刷新操作的时序图分析与前面类似。

刷新时序图中的几个问题

1)两次刷新时间间隔有多久呢?

​ SDRAM内部电容保存数据的最长时间是64ms,而我们一个BANK有4096行,64ms/4096~=15us,也就是说为了保证SDRAM内部的数据不被丢失,两次刷新之间的最大时间间隔为15us,所以为了能让SDRAM有更多的时间进行读或者写,我们就设定SDRAM刷新的周期为15us.(若按系统时钟50MHZ,就是计750个数)

​ SDRAM每进行一次刷新,是对每一行进行操作的,并不是单独针对每一个电容进行充电,所以每进行一次刷新,该行中的电容进行充电我们可以理解为是同步发生的

2)在每次自动刷新时,我们需要给一个“Precharge”命令,这个命令有什么作用呢?

大家可以看下开头的那张状态图,如果此时SDRAM正处于“WRITE”或“READ”状态时,这个“Precharge”命令可以使SDRAM跳出“WRITE”或“READ”状态从而入“IDLE”状态。接下来,过“tRP”的时间,给一个“Auto-Refresh”命令可以进入刷新状态。

但此时的Precharge命令我们在写状态模块中给出。在刷新模块中不需要Precharge命令。

SDRAM仲裁模块

在介绍仲裁模块前我们先考虑一个问题:

​ 如果我正在让SDRAM写数据,是不是SDRAM刷新的时间到了,我就必须是让SDRAM马上执行刷新操作吗?这样的话肯定不是现实的,那必然会把还没写的剩下的数据丢失。不能让我们的数据丢失,又要保证SDRAM进行刷新来保证我们整个SDRAM相应BANK中的数据不被丢失,我们应该怎么来写代码呢?

我们可以考虑这样来做:如果刷新的时间到了,先让写操作把正在写的4个数据(突发长度为4)写完,然后再去进行刷新操作。而如果在执行读操作也遇到需要刷新的情况,我们也可以这样来做,先让数据读完,再去执行刷新操作。

为了解决各个模块之间不方便控制的情况,我们引入一个新的机制 ——“仲裁”机制。“仲裁”用来干什么呢?在这里边,“仲裁”相当于我们这个SDRAM控制器的老大,对SDRAM的各个操作统一协调:读、写及自动刷新都由“仲裁”来控制。

仲裁模块状态机示意图:

这里写图片描述

仲裁模块和其他各模块之间的连线:

这里写图片描述

注:一定要搞清楚说的是模块之间连线的关系还是状态机之间跳转的关系哦。

仲裁模块分析

1)初始化操作完成之后便进入到了“ARBIT”仲裁状态,只有处于仲裁状态的时候,“仲裁老大”才能进行下命令。

2)当状态机处于“WRITE”写状态时,如果SDRAM刷新的时间到了,刷新模块同时向写模块和仲裁模块发送刷新请求ref_req信号。

3)当写模块接受到ref_req之后,写模块在写完当前4个数据(突发长度为4)之后,写模块的写结束标志flag_wr_end拉高,然后状态机进入“ARBIT”仲裁状态。

4)处于仲裁状态之后,此时有刷新请求ref_req,然后状态机跳转到“AREF”状态并且仲裁模块发送ref_en刷新使能,刷新模块将刷新请求信号ref_req拉低并给sdram发送刷新的命令。

5)等刷新完毕之后,刷新模块给仲裁模块发送flag_ref_end刷新结束标志,状态机跳转到“ARBIT”仲裁状态。

注意了,当刷新完跳转到“ARBIT”仲裁状态之后,如果之前我们的全部数据仍然没有写完(Kevin指的是全部数据,并不是一个突发长度的4个数据哦),那么此时我们仍然要给仲裁模块写请求“wr_req”,然后仲裁模块经过一系列判断之后,如果符合写操作的时机,那就给写模块一个写使能信号“wr_en”,然后跳转到“WRITE”写状态并且写模块开始工作。

SDRAM写模块

官方数据手册给出的写操作时序图

这里写图片描述

该时序图的分析可以参照前面初始化过程的分析。

现在我们考虑另一个问题:假设我们现在需要往SDRAM 中写入两行数据,那什么时候可以退出仲裁状态机的写状态:
1) 数据已经写完;若我们还想要再写,就需要外部的Wr_trig触发
2) SDRAM 需要进行刷新操作;外部有一个刷新请求信号,并且本次数据已经写完;转到外部仲裁模块去执行刷新操作,如果刷新完毕需要继续写,写模块请求,仲裁模块使能。
3) 数据未写完,需要激活下一行继续写。本行写完标志,重新输入act命令去写下一行

我们将这三个状态化成一个状态机。如图所示:

这里写图片描述

注意上图中的IDLE状态和前面的初始化中的IDLE状态不要搞混。这个IDLE就是写模块中状态机的初始化部分。

S_WR:
        if(wr_data_end == 1'b1)                       
                state   <=      S_PRE;                 
        else if(ref_req == 1'b1 && burst_cnt_t == 'd2 && flag_wr == 1'b1)       
                state   <=      S_PRE;                 
        else if(sd_row_end == 1'b1 && flag_wr == 1'b1)
                state   <=      S_PRE;
S_PRE:
        if(ref_req == 1'b1 && flag_wr == 1'b1)         
                state   <=      S_REQ;
        else if(flag_pre_end == 1'b1 && flag_wr == 1'b1) 
                state   <=      S_ACT;
        else if(flag_wr == 1'b0)                       
                state   <=      S_IDLE;  

我们由以上所述画出写模块时序图:

这里写图片描述

这里写图片描述

分析写模块中五个状态机:

1)IDLE:外部Wr_trig触发写信号,进入S_REQ状态。写模块将Flag_wr拉高直到数据完全写完结束。

2)S_REQ:Flag_wr信号拉高,S_REQ状态向外部仲裁发出请求写信号wr_req,外部仲裁模块判断可以进行写操作了并向写模块发出wr_en 使能信号,告诉写模块可以开始写了。进入S_ACT状态。

3)S_ACT:写模块在S_ACT状态,发出ACT命令(command),并且指定bank的行地址。ACT命令结束发出Flag_act_end结束标志。进入S_WR状态。

4)S_WR:发出写命令开始写数据,此时需要指定列地址

一行数据写完发出Sd_row_end标志信号。刷新请求出现时,该组数据写完发出Flag_wr_end标志信号。所有数据写完返回Wr_data_end信号标志。

5)S_PRE:预充电命令 ,进入预充电状态,充电完毕返回Flag_pre_end标志信号。

SDRAM读模块

SDRAM读模块与写模块一样在此不再详述。

读模块时序图:

这里写图片描述

有一个问题需要注意:

我们再给出读命令后,数据延时了两个周期给出,这个时间段叫潜伏期CAS。

写代码技巧:

1)先写主状态机

2)把时序图中用到的时序信号标志定义出来;

reg                             flag_wr       ;
reg     [ 4:0]                  state         ;
//-----------------------------------------------
reg                             flag_act_end  ;
reg                             flag_pre_end  ;
reg                             sd_row_end    ;
reg     [ 1:0]                  burst_cnt     ; 
reg     [ 1:0]                  burst_cnt_t   ; 
reg                             wr_data_end   ;
//-----------------------------------------------
reg     [ 3:0]                  act_cnt       ;
reg     [ 3:0]                  break_cnt     ;
reg     [ 6:0]                  col_cnt       ;
//-----------------------------------------------
reg     [11:0]                  row_addr      ;
wire    [ 8:0]                  col_addr      ;

3)然后按照这个表写出每个标志信号产生的代码

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160105.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Pycharm中利用Anaconda进行环境配置「建议收藏」

    Pycharm中利用Anaconda进行环境配置「建议收藏」由于不同demo所利用的环境不同,因而大神们开发了Anaconda工具,其中已经安装好了很多包,并且使用conda来对这些进行管理。如此,便可以实现在电脑中存储多个互相不干扰的环境,使用编译器来分别利用这些环境创建不同的项目。

  • APP推送系统工作原理

    APP推送系统工作原理一、传统APP架构下的信息传送APP主动向服务器请求数据,服务器被动的提供数据。步骤如下:然而,如果此时服务器又有了新的新闻,在用户没有主动刷新的情况下,服务器是不会主动推送给用户的。推送解决了这个困境,它让服务器主动连接APP,通知APP有了新的新闻,可以再请求。收到推送的APP(即使已关闭)又去服务器请求最新的新闻,用户就能看到了。二、实现推送的方法实现一个推送系统需要服务器端和…

  • @ResponseBody的作用

    @ResponseBody的作用

  • C#数组

    C#数组数组是一个存储相同类型元素的固定大小的数据集合.数组是引用类型一、定义数组的声明:<数据类型>[]<数组名字>;例:int[]numbers;二、数组的赋值(

  • java 4种 布局方法_JAVA布局模式:GridBagConstraints终极技巧

    java 4种 布局方法_JAVA布局模式:GridBagConstraints终极技巧JAVA布局模式:GridBagConstraints终极技巧(2006-11-1421:07:33)最近正在修改《公交线路查询系统》,做系统的时候都是用NULL布局,由于NULL布局调用windows系统的API,所以生成的程序无法在其他平台上应用,而且如果控件的数量很多,管理起来也比较麻烦,最近我发现一个非常强大的布局模式:GridBagConstraints布局,先发一个实例:gridx…

  • sqlplus中实现上、下键翻动命令

    sqlplus中实现上、下键翻动命令

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号