3、DDR3初始化流程:上电顺序、复位时序、模式寄存器配置(MR0/MR1/MR2/MR3)、ZQ校准
DDR3的初始化,说白了就是让颗粒从“断电状态”进入“待命状态”的过程。这个过程有严格的时序要求,一步错,后面全白搭。我刚开始调DDR3的时候,就吃过这个亏——上电顺序没搞对,颗粒死活不响应,折腾了两天才发现是电源纹波太大导致复位失败。嗯,咱们今天就把这个流程掰开揉碎了讲清楚。
3.1 上电顺序:先给谁供电?
DDR3颗粒需要三种电源:VDD(核心电压1.5V)、VDDQ(IO电压1.5V)、VREF(参考电压,通常是VDDQ的一半)。上电顺序有讲究:
- VDD和VDDQ必须同时上电,或者VDD先于VDDQ。绝对不能VDDQ先于VDD上电,否则IO电路可能闩锁损坏。
- VREF必须在VDDQ稳定之后再建立。VREF是差分信号的参考点,如果VREF先于VDDQ稳定,接收器会看到错误的逻辑电平。
- 所有电源的上升时间建议控制在20μs到200μs之间。太快了容易产生过冲,太慢了颗粒可能进入不确定状态。
关键参数:
- VDD和VDDQ从0V上升到0.9V的时间:≤ 200μs
- VDD和VDDQ从0.9V上升到1.5V的时间:≤ 200μs
- VREF建立时间:VDDQ稳定后至少100ns
我个人习惯在FPGA上电后先等200μs再开始操作DDR3,用个计数器延时一下,简单粗暴但可靠。
3.2 复位时序:CKE和RESET#的配合
上电完成后,接下来是复位操作。DDR3的复位引脚是RESET#(低电平有效),配合CKE(时钟使能)一起控制颗粒的状态机。
标准流程是这样的:
- 上电完成后,保持RESET#为低电平至少200μs(JEDEC标准要求)。
- RESET#拉高后,等待至少500μs,让内部PLL锁定。
- 然后拉高CKE,颗粒开始进入初始化状态机。
- CKE拉高后,必须提供至少5个稳定的时钟周期,才能开始后续操作。
注意:RESET#拉高后,CKE必须保持低电平至少100ns才能拉高。这个时序我踩过坑——有一次RESET#拉高后立刻拉CKE,结果颗粒初始化失败,查了半天才发现是CKE拉高太快了。
你想想看,复位时序其实就是在给颗粒内部电路一个“热身”的时间。PLL需要锁定,DLL需要校准,这些都需要时间。别急着操作,让子弹飞一会儿。
3.3 模式寄存器配置:MR0/MR1/MR2/MR3
复位完成后,颗粒进入“模式寄存器配置”阶段。DDR3有4个模式寄存器:MR0、MR1、MR2、MR3。每个寄存器控制不同的功能,通过MRS(Mode Register Set)命令写入。
MRS命令的格式:在时钟上升沿,CS#、RAS#、CAS#、WE#同时为低电平,地址线A[15:0]携带寄存器地址和数据。
| 寄存器 | 地址位BA[2:0] | 主要功能 |
|---|---|---|
| MR0 | 000 | 突发长度、突发类型、CAS延迟、测试模式 |
| MR1 | 001 | DLL使能、输出驱动强度、ODT阻抗、附加延迟 |
| MR2 | 010 | CAS写延迟、自刷新温度范围、部分阵列自刷新 |
| MR3 | 011 | MPR(多用途寄存器)使能、数据格式选择 |
3.3.1 MR0配置
MR0是最常用的寄存器。我一般这样配:
- 突发长度(BL):固定为8(A[1:0]=00)。DDR3不支持4突发,除非用“突发截断”模式。
- 突发类型:顺序(A3=0)。交叉模式用得少,除非你特别需要地址交错。
- CAS延迟(CL):根据频率选择。比如DDR3-1066选CL=7,DDR3-1333选CL=9,DDR3-1600选CL=11。这个值必须和颗粒的时序参数匹配。
- 测试模式:正常模式(A7=0)。测试模式是厂商用的,咱们别碰。
小技巧:配置MR0时,建议先写一次“DLL复位”(A8=1),然后再写一次“DLL正常模式”(A8=0)。这样能确保DLL重新锁定到当前时钟频率。我每次初始化都会做这个操作,从来没出过问题。
3.3.2 MR1配置
MR1控制DLL使能和输出驱动强度:
- DLL使能:必须使能(A0=0)。DLL是DDR3正常工作的核心,关掉DLL的话颗粒只能跑在低速模式。
- 输出驱动强度:根据PCB走线阻抗选择。常见的是30Ω(A[5:1]=00000)或40Ω(A[5:1]=00001)。我习惯用40Ω,兼容性更好。
- ODT阻抗:RZQ/4(60Ω)或RZQ/2(120Ω)。DDR3的ODT典型值是60Ω(A[9,6,2]=010)。
- 附加延迟(AL):通常设为0(A[4:3]=00)。除非你跑高频需要加延迟来补偿。
3.3.3 MR2配置
MR2相对简单:
- CAS写延迟(CWL):根据频率选择。DDR3-1066选CWL=5,DDR3-1333选CWL=6,DDR3-1600选CWL=7。CWL通常比CL小2-3个周期。
- 自刷新温度范围:商业级选0(A7=0),工业级选1(A7=1)。
- 部分阵列自刷新:通常禁用(A[6:4]=000)。除非你有低功耗需求。
3.3.4 MR3配置
MR3用得最少,主要控制MPR(多用途寄存器):
- MPR使能:正常模式(A2=0)。MPR是用于读校准的,平时不用开。
- 数据格式:默认即可(A[1:0]=00)。
配置顺序有讲究:先配MR2,再配MR3,然后配MR1,最后配MR0。为什么?因为MR0包含DLL复位,而DLL复位需要在其他寄存器配置完成后才执行。我曾经按顺序乱配过一次,结果颗粒初始化后读写数据全是错的,后来查JEDEC标准才发现顺序有要求。
3.4 ZQ校准:让输出阻抗匹配
ZQ校准是DDR3特有的功能。颗粒通过一个240Ω的外部电阻(接在ZQ引脚上)来校准内部输出驱动和ODT的阻抗。
校准过程:
- 初始化完成后,发送ZQCL(ZQ校准长命令)。这个命令会触发一次完整的校准,耗时约512个时钟周期。
- 校准完成后,颗粒内部会存储校准结果。之后每隔一段时间(建议40ms)发送一次ZQCS(ZQ校准短命令)来更新校准值。
- ZQCS耗时约64个时钟周期,比ZQCL快很多。
ZQ校准命令格式:
- ZQCL:CS#=L, RAS#=H, CAS#=H, WE#=L, A10=H
- ZQCS:CS#=L, RAS#=H, CAS#=H, WE#=L, A10=L
我在项目中遇到过一个问题:ZQ电阻的精度直接影响校准结果。如果电阻精度不够(比如±5%),校准后的阻抗偏差会很大,导致信号质量变差。所以我建议用±1%精度的电阻,虽然贵一点,但省心。
另外,ZQ校准必须在初始化完成后立即执行。如果跳过这一步,颗粒的输出驱动和ODT会使用默认值,这个默认值通常不准,信号完整性会很差。我曾经见过有人为了省时间跳过ZQ校准,结果DDR3跑在400MHz都出错,加上校准后稳稳跑到800MHz。
3.5 初始化完整流程总结
好了,把上面这些串起来,一个完整的DDR3初始化流程是这样的:
- 上电:VDD和VDDQ同时上电,VREF随后建立。
- 复位:RESET#拉低至少200μs,然后拉高。
- 等待:RESET#拉高后等500μs,让PLL锁定。
- CKE拉高:提供至少5个稳定时钟周期。
- 配置MR2:设置CWL和自刷新参数。
- 配置MR3:通常保持默认。
- 配置MR1:设置DLL使能、驱动强度、ODT。
- 配置MR0:设置BL、CL,并执行DLL复位。
- 等待DLL复位完成:至少200个时钟周期。
- 执行ZQCL:完成阻抗校准。
- 等待ZQCL完成:至少512个时钟周期。
- 初始化完成,可以开始正常读写操作。
避坑指南:我曾经在配置MR0时忘记设置DLL复位,结果颗粒初始化后读写延迟总是不对。后来加上DLL复位,问题就解决了。所以,DLL复位这一步千万别省。
嗯,DDR3初始化流程就讲到这里。说白了,就是按照JEDEC标准一步步来,别跳步,别省时间。FPGA上实现时,建议用状态机来控制这些步骤,每个状态对应一个操作,状态之间加计数器延时。这样代码清晰,时序也容易保证。