目录
前言
工作中使用过SDRAM芯片,型号:IS42/45R86400D/16320D/32160D
对SDRAM使用中需要注意的一些事项进行整理。
在SDRAM设计中,需要注意三点:(1)若状态机使用clk时钟,则采用多少相位的时钟给SDRAM芯片管脚/采用多少相位的时钟采样SDRAM芯片返回的回读数据?(2)关于刷新的处理方式。(3)状态转移的设计,如何响应读写和刷新请求,冲裁机制是怎样的?
若仔细思考过上面三个问题,剩下的就按SDRAM芯片手册时序图写代码即可实现该控制器。
再进一步提高,就是思考如何对代码、对时序优化、提高速度的问题。
1、关于刷新
关于SDR SDRAM的刷新机制,有一点值得说明一下:64ms刷新8K次;或类似的刷新要求吧
这一点,是指64ms内,需要进行8K次自刷新,但是它并没有要求这8K次平均分布在64ms的时间区域内。
也就是说,你可以在64ms里的第一个ms内,直接做完8K次刷新;在省下的63ms内,你可以不进行刷新操作。
读者会疑问,这样的刷新操作 与 8K次刷新均匀分布在64ms区间的差别在哪????
若你第1ms就执行完8K次刷新,则你省下的63ms就可以上SDRAM去做读写操作!
换个意思就是说,在不需要进行SDRAM读写访问的时候,就让它多做一些刷新;这样就能为读写操作提供大量完整的时间,而不被刷新操作打断!
2、关于数据中心对齐
需要注意信号的跨时钟域处理,信号从一个时钟域出来,如何在另一个时钟域进行准确的采样接收。
若sys_clk用于状态机发送命令cmd[3:0]、地址address[12:0],可以采用sys_clk_180相移180度的时钟来驱动SDRAM芯片的时钟管脚。
在数据写入SDRAM时,SDRAM芯片用sys_clk_180时钟来对cmd、address、DQ进行数据采样;
在读访问SDRAM数据时,状态机在sys_clk时钟驱动下发送读命令cmd[3:0]、读地址address[12:0],然后使用sys_clk_180时钟采样SDRAM返回的读数据。
上述红色字体格外需要注意,因为若采用sys_clk时钟采样SDRAM返回的读数据的话,可能就采样不到数据,modelsim仿真也会显示无法采样三态门IO端口回读到的数据。比如,下图仿真遇到的问题。
I端口向IO端口写数据:在EN_SEL_N_DLY=0时,三态门将I端口数据送到IO端口。
EN_SEL_N_DLY=1时,O端口从IO端口回读数据:但O端口的数值在仿真中显示无法赋值给寄存器r_APP_RD_DATA??
实际调试中,可能会遇到的问题:
举个栗子,提个问题:如果SDRAM在上电初始化的时候,没有进行load MODE register,请问其CAS潜伏期会是多少?
举个栗子,提个问题:如何保证送到SDRAM芯片管脚的CMD、addr、DQ与采样时钟是中心对齐的?如何采样SDRAM送出的DQ数据,保证采样的准确性?如何提高SDRAM控制器的工作频率?
3、SDRAM芯片手册介绍
SDR SDRAM芯片型号:IS42/45R86400D/16320D/32160D
3.1SDRAM芯片的管脚
3.2 SDRAM指令集
3.3 模式寄存器
通过配置模式寄存器,可以配置SDRAM芯片工作的状态。
通过配置模式寄存器,来配置SDRAM的:突发长度(burst length,BL)、突发类型、潜伏期(CAS Latency, CL)、操作模式、写突发模式。
3.4 关于SDRAM上电初始化和装载模式寄存器
按照芯片手册里的时序图配置即可,如下图所示。
需要注意的是,在SDRAM上电开始时刻,需要等待至少100us的时间,之后才开始给SDRAM配置下面的控制时序。
等待100us的时间,是为了等待PLL输出的时钟稳定;待PLL时钟稳定后,才开始初始化SDRAM、以及配置模式寄存器。
下图是手绘的上电和加载模式寄存器时序图。
初始化流程如下:
- 在复位结束、有时钟clk信号开始后,计时T1、即经历100us后,发送nop命令码;
- 所有bank预充电。在T1的下一个clk上升沿来临时、即在T2时刻,发送Precharge命令码,Sdr_a[10]=1拉高。。
- 第一次自动预充电。在T2之后,计时TRP的时间长度。在T3=T2+TRP到来时,发送REF命令码,执行第一次自动预充电。TRP最小是15ns,如果是100M时钟的话,TRP取两个clk周期即可。
- 第二次自动预充电。在T3之后,计时TRC,也即TRFC的时间长度。在T4=T3+TRFC到来时,发送REF命令码,执行第二次自动预充电。TRFC取个最大的下限是66ns,如果是100M时钟的话,TRFC取7个clk周期即可。
- 模式寄存器装入命令。在T5=T4+TRFC到来时,发送LMR命令码,即load mode register指令码,同时发送Sdr_a[12:0]=13'b0_0010_0010_0000(突发长度为1,潜伏期为2)和Sdr_ba=0,即选择bank0。TRFC取个最大的下限是66ns,如果是100M时钟的话,TRFC取7个clk周期即可。
- 输出初始化完成标志。 在T5之后,计时TRMD的时间长度。在T6=T5+TRMD到来时,发送初始化完成标志init_done。TRMD取个最大的下限是14ns,如果是100M时钟的话,TRMD取2个clk周期即可。
3.5 SDRAM刷新时序
下图中第一个指令Precharge,其作用是关闭当前行/所有行,即是在当前行/所有行关闭的情况下,才能执行刷新AutoRefresh操作。
如果在当前行/所有行没有关闭的情况下,进行刷新操作,会导致SDRAM中存储的数据丢失、或数据错误。
若每次读写结束就执行Precharge操作,则在进行刷新AutoRefresh操作时,是不需要在开始的时候发Precharge指令。
下图是执行了两次连续刷新操作,只进行一次刷新也是可以的。
3.6 关于写访问
在BL突发模式设置为1的情况下,可以按下面的时序,实现连续的写访问(必须是在SDRAM的同一行(同一页)访问)。
读访问,在BL=1的情况下,也可以实现类似的灵活访问。
3.7 关于突发访问
突发(Burst)是指在同一行中相邻的存储单元连续进行数据传输的方式,不能在一次突发访问中、出现SDRAM跨行的情况。举例,如BL=8,若起始地址=1023,当发下写命令后,SDRAM实际是对地址空间1023/0/1/2/3/4/5/6进行burst 写访问,而不是对地址空间1023/1024/1025..../1030进行burst写访问。
连续传输的周期数就是突发长度(Burst Lengths,简称BL)。
SDRAM芯片支持突发长度为1/2/4/8/全页。需要注意,突发访问,不能跨行(又称为跨页)访问。
当BL=2,一次写突发访问控制时序示例如下:
4、FPGA工程设计
(1)设计SDDRAM_CTRL控制器的输入输出端口,并绘制模块框图。
(2)确定SDDRAM_CTRL控制器的潜伏期CL、突发长度BL、模式寄存器配置。
(3)分析设计SDDRAM_CTRL控制器的时钟域,并绘制数据流图,注意数据的跨时钟域处理。
这点格外重要!比如,状态机的驱动时钟是clk,则SDRAM芯片管脚的驱动时钟相位是多少?用多少相位的时钟采样SDRAM信号范围的读数据?
(4)设计SDRAM_CTRL控制器的状态转移图。
(5)设计SDRAM_CTRL控制器的测试文件。
(6)按照设计好的文档进行Verilog代码编写。
(7)对SDRAM_CTRL控制器进行时序仿真。
(8)下板测试。
(9)多块板卡测试。
4.1状态机设计
由上图可知,关键状态有:
- INIT状态 :系统上电后、等待CLK稳定后(100us),在该状态配置模式寄存器等相关信息。该状态仅在系统上电且CLK稳定后执行一次。以后状态机复位也仅进入IDLE状态,不再进入INIT状态。
- IDLE状态 :即空闲状态,在该状态对读请求/写请求/刷新请求进行仲裁判断。
- ACT_ROW状态 :激活行,之后跳转下一状态(WR_RD)。
- WR_RD状态 :在该状态,根据读写请求标志,发读写命令、读写地址、写数据等相关信息。
- CLOS_ROW状态:在该状态,关闭行。之后,跳转对应状态。
上述几个状态的灵活应用,即可实现SDRAM的灵活访问。
5、仿真测试
5.1仿真模型
下面是仿真过程中遇到的仿真模型报告的问题,提升一个时间违规。
补充概念:
下文来自文献1:SDRAM 控制器的解析
1.Precharge与Refresh的区别?
两者都是对存储单元的电容进行充电、回写。但差异在于:
Precharge是对(一个或所有Bank)的所有工作行(active row)操作,并且是随机的,被操作工作行的地址在各Bank中不一相同。
Refresh是对所有行依次操作,且是有固定周期的,被操作行在各Bank中均相同。
2.AutoRefresh与SelfRefresh的区别?
AutoRefresh是user依照指定周期发给芯片的刷新命令
SelfRefresh是芯片内部逻辑发给自己的刷新命令
无论何种Refresh均不需要提供地址,它是芯片内部的自动操作。
3.R/W带与不带Auto Precharge的区别?
带AutoPrecharge时:在R时,芯片自动在(最后一个有效输出数据)前(CL-1)个时钟时产生Precharge命令。在W时,芯片自动在(最后一个有效输出数据)后(Twr)时间产生Precharge命令。
不带AutoPrecharge时,需要user在上述时刻自己产生Precharge命令。
4.CL参数只有效于Read操作。
5. 每个Bank中只能有一个Row处于active状态,且可以进行R/W。
如果想操作同Bank中的另外一个Row,必须使用Precharge关闭当前工作Row,然后再active目的Row,这样才能R/W
6. 每个Bank均active一个Row,依次在各个Bank间操作Row,这样避免R/W时消耗的多余时钟周期,可以提高数据传输带宽
7.正常Read时的Precharge
Auto_Precharge和手动Precharge都在最后一个有效数据(LVD)前CL-1个时钟上升沿发出
8. 手动Precharge终结Read
手动Precharge在最后一个有效数据(LVD)前CL-1个时钟上升沿发出
9.手动Burst Terminate终结Read
Burst Terminate在最后一个有效数据(LVD)前CL-1个时钟上升沿发出
10.正常Write时的Precharge
Auto_Precharge和手动Precharge都在最后一个有效数据(LVD)后tWR/tDPL时间的时钟上升沿发出
11. 手动Precharge终结Write
手动Precharge在最后一个有效数据(LVD)后tWR/tDP时间的时钟上升沿发出,或者在Precharge同时使能DQM屏蔽掉同时刻写入的数据。
12.手动Burst Terminate终结Write
Burst Terminate在最后一个有效数据(LVD)后1个时钟上升沿发出
13.Burst Terminate与手动Precharge在终结Read/Write中的区别?
带AutoPrecharge的R/W过程中,禁止使用BT和手动Precharge命令。
Burst Terminate适用于 全页R/W、不带AutoPrecharge的突发R/W
参考
作者 | 博文 |
1、 清霜一梦 | SDRAM 控制器的解析 |