继续死磕SDRAM控制器
SDRAM控制器
博主上一篇介绍了一些SDRAM的基本原理是否有必要学习使用纯Verilog写一个SDRAM控制器,接下来记录SDRAM控制器的工作原理。首先是上电初始化。
上电初始化

时序图中,tRP、tRC、这些时间参数可以从手册中找到,这里的系统时钟采用50Mhz。
从初始化的时序图可以看出,首先在进行预充电(Precharge)命令之前要等待100us(手册要求是至少100us,我们设定延时200us),等待系统上电稳定和时钟稳定,然后对所有bank进行预充电(Precharge),经历一个trp(20ns,一个时钟周期,手册可以查询)时间,然后进行至少两次自刷新(Auto refresh)(我这里设置进行8次自刷新,),每次自刷新至少需要trc(63ns,四个时钟周期,手册查询)时间,最后进行模式寄存器(MODE register)的配置,需要tmrd(两个时钟周期)时间,初始化完成。
预充电时当A10为高电平对所有的bank进行操作,当A10为低电平时对单个bank进行操作,BA0,BA1选择bank。我们这里预充电时对所有的bank操作,把A10置高即可。


SDRAM初始化流程
- 上电后延时200us
- 对所有的bank进行预充电(Precharge)
- 8个自刷新操作,每次自刷新使用四个时钟周期
- 进行模式寄存器的配置 ,配置完后输出初始化完成标志。
这里先设置SDRAM的突发长度为4 Addr = 12’b0000_0110_0010
SDRAM初始化仿真
这里仿真需要用到SDRAM的仿真模型,通过仿真模型可以把当前SDRAM进行的操作打印出来,如果有错误也会提示错误,这时候再去查看波形时序。这里需要注意的是仿真的时候sdram_dqm信号必须和仿真模型连接,否则数据是写不进去的,设置sdram_dqm = 0就可以了。
将SDRAM仿真模型添加进去后,要对放着模型的参数进行重定义

对于各个参数的值,不同的SDRAM芯片的参数是不同的,具体根据手册而定,mem_sizes设置的是1个bank的容量。Verilog语法笔记:这种方式可以对例化模块里面已有的宏定义进行重定义,写法是defparam + 例化之后的模块名+ . +需要重定义名。

然后在transcript中输入run 200us,先跑200us等待系统上电稳定,在输入run 50us,如上图所示CAS Latency(列选通潜伏期)为3,burst length(突发长度)为4,burst type(突发类型)顺序(Sequrntial)执行,模式寄存器配置都按照我们设置的进行。
SDRAM工作原理
初始化模块设计完成后,对SDRAM已经有了一些简单的了解,下面先来看看SDRAM的工作原理。

粗线——自动跳转,细线——受到命令后才能跳转(看不清楚图片点击阅读原文)
从一个官方给的SDRAM手册的参考状态转移图看,我们可以简单写一下SDRAM的工作流程。这部分用状态机来实现最好不过了。
上电后,给一个Precharge命令,进入Precharge状态,然后自动进入IDLE(初始化)状态,然后给自刷新命令,进入自刷新状态,自刷新完后回到IDLE状态,IDLE状态给一个配置模式寄存器命令,进入模式寄存器的配置,配置完后才能自动回到IDLE状态,然后进行读写状态的操作。
以写操作为例,需要给一个行激发命令,进入行激发状态,给出写命令才能进入写状态,写完后自动返回行激发状态,给一次写命令,会写入一个突发长度的数据,在一行没有写完不需要跳回行激发状态,只需要继续给写命令,只有当一行写完或刷新请求来临或数据写完才会跳出写状态,这里后面设计写模块再讲。数据写完或刷新请求来临或数据写完,需要先进入预充电状态,给一次预充电命令,然后自动跳转到初始状态进行重新等待命令。至于读模块的操作和写模块是完全一样的,读者自行读图。
这里要提的是图中有两个状态WRITEA和READA,这里我们不需要用到,如图也可以看到,这两个状态在进行一次读或写后会自动跳入预充电状态,从而回到初始化状态,这样和WRITE和READ这两个状态相比,读写速度肯定是会慢的,WRITE和READ可以连续给读写命令进行读写,所以直接忽略掉这两个状态不管。
仲裁机制
这里要引出一个设计技巧,初始化完成后,进行自刷新和读写操作状态都是相互独立的,所以我们需要写一个状态机去完后这些状态之间的跳转,大概意思就如下图所示,写一个仲裁状态机,当SDRAM控制器要进行自刷新时,自刷新模块需要给一个刷新请求,仲裁状态收到后,就结束当前进行的状态,给一个刷新使能,刷新模块才会进行刷新操作。同样的,当SDRAM控制器要进行写数据时,写数据模块需要给一个写请求,仲裁状态收到后,就结束当前进行的状态,给一个写使能,写数据模块才会进行写操作。后面的模块相应的也是这样的设计。

刷新模块
手册规定SDRAM自刷新需在64ms内刷新4096次(不同型号的芯片对应的不同),必须64ms是因为SDRAM内部使用电容存储数据的,它保证不断电的时间就是64ms。4096次的意思是,我所使用的这款SDRAM芯片它的行地址为A0~A11,一共是12位,2的12次方一共是4096行,我们每给一次刷新命令实际上是刷新一行,且是四个bank同时刷新,所以说一共要刷新4096次。两次刷新间隔15us。刷新是在SDRAM初始化完成后就要开始进行刷新。

从时序图可以看出,先给一个precharge命令(一般都是对all bank进行操作),经过trp(20ns,一个周期)时间进行一次自刷新命令,再过trc时间,进行再一次自刷新命令,然后trc(63ns, 四个周期)时间后激发读或写命令。
在时序图中我们看到了两次自刷新命令,但是实际上只要给一次自刷新命令即可,所以不要被时序图忽悠了,当然给两次也是没有什么关系的。这里的意思是,每次进行自刷新操作都需要给一次预充电即可。
刷新模块仿真

仿真的时候发现我犯了一个错误,就是每15us的刷新操作是不用每次都给预充电(Percharge)命令,但是从另一个状态跳转到自刷新状态是需要给一个预充电(Percharge)命令。之后便不需要再给了,这上面这里的原因是因为在刷新模块里有预充电(Percharge)命令,所以每次状态跳转到执行刷新模块,都会给一个预充电(Percharge)命令。这个问题已经得到解决。如图每15us进行一个自刷新。

关于SDRAM的读模块和写模块操作,下一篇再写。博主最近基于上次50Mhz下的简易SDRAM控制器的基础上修改成100Mhz的SDRAM控制器,实现用上位机串口发送一副彩色图片到SDRAM存储,再用VGA显示,下一步的目标是实现摄像头实时采集视频流数据显示。目前把最近写的这两个项目工程放到了Github上分享出来,希望能一起讨论,多多指点,这个东西我个人感觉不懂内部的操作时序,想要移植也是很麻烦的,所以干脆直接分享出来,后面博主会继续优化,尽量做成一个像IP Core一样的直接修改参数就可以调用的一个SDRAM控制器。
https://github.com/NingHeChuan/Open-FPGA.git


转载请注明出处:NingHeChuan(宁河川)
个人微信订阅号:开源FPGA
如果你想及时收到个人撰写的博文推送,可以扫描左边二维码(或者长按识别二维码)关注个人微信订阅号
知乎ID:NingHeChuan
微博ID:NingHeChuan
原文地址:http://www.cnblogs.com/ninghechuan/p/8992683.html
继续死磕SDRAM控制器的更多相关文章
- 是否有必要学习使用纯Verilog写一个SDRAM控制器
在做这个SDRAM控制器之前,博主有一个疑问,对于学生来说,是否有必要学习用纯Verilog写一个SDRAM控制器?因为目前X家和A家都有了DDR IP Core,对于要实现一个应用可以直接调用IP ...
- 死磕安卓前序:MVP架构探究之旅—基础篇
前言 了解相关更多技术,可参考<我就死磕安卓了,怎么了?>,接下来谈一谈我们来学习一下MVP的基本认识. 大家对MVC的架构模式再熟悉不过.今天我们就学习一下MVP架构模式. MVC和MV ...
- 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?
通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...
- mysql每秒最多能插入多少条数据 ? 死磕性能压测
前段时间搞优化,最后瓶颈发现都在数据库单点上. 问DBA,给我的写入答案是在1W(机械硬盘)左右. 联想起前几天infoQ上一篇文章说他们最好的硬件写入速度在2W后也无法提高(SSD硬盘) 但这东西感 ...
- 【死磕Java并发】-----Java内存模型之happend-before
在上篇博客([死磕Java并发]-–深入分析volatile的实现原理)LZ提到过由于存在线程本地内存和主内存的原因,再加上重排序,会导致多线程环境下存在可见性的问题.那么我们正确使用同步.锁的情况下 ...
- 死磕 java集合之DelayQueue源码分析
问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...
- 死磕 java集合之PriorityBlockingQueue源码分析
问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...
- 死磕 java集合之PriorityQueue源码分析
问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...
- 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程
原文出自:http://cmsblogs.com import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程. 在方法 parseDefaultElement ...
随机推荐
- Linux内存映射--mmap函数
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明: 头文件: < ...
- ios zxing扫码问题
在ios 中 扫瞄二维码,条形码基本有 2中第三方的库,一个是zbar 一个是zxing,zxing 在android中表现的比较出色,但是在ios 中不是很好用,扫瞄效率低,我们一般都用zbar,但 ...
- 最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)
===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...
- sed在行首或者行尾添加内容
原文地址:http://www.cnblogs.com/ITEagle/archive/2013/06/20/3145546.html 用sed命令在行首或行尾添加字符的命令有以下几种: 假设处理的文 ...
- 【翻译】如何创建Ext JS暗黑主题之二
原文:How to Create a Dark Ext JS Theme– Part 2 我已经展示了如何去开发一个精致的暗黑主题,看起来就像Spotify.在本文的第一部分,了解了Fashion.S ...
- VC和GCC静态变量析构顺序不同
VC和GCC静态变量析构顺序不同(金庆的专栏)静态变量析构顺序正常情况下是构造的反序.但是VC对DLL中的静态变量好像是需等待DLL卸载时再析构,表现为主程序中的静态变量先析构,DLL中的静态变量后析 ...
- How Many Processes Should Be Set For The Receiving Transaction Manager (RTM)
In this Document Goal Solution References APPLIES TO: Oracle Inventory Management - Version 10 ...
- C语言中 sscanf 的用法
名称: sscanf() - 从一个字符串中读进与指定格式相符的数据. 函数原型: Int sscanf( string str, string fmt, mixed var1, mixed var2 ...
- 修改量更新API
/* Update a Modifier header of type 'PRO' (Promotion) */ l_MODIFIER_LIST_rec.active_flag := 'N'; l_M ...
- 文档流 css中的float clear与布局
文档流 先说说什么是文档流 流是什么 就是一串连续的东西 <div style="background-color:pink;width:40px;height:80px;" ...