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(时钟使能)一起控制颗粒的状态机。

标准流程是这样的:

  1. 上电完成后,保持RESET#为低电平至少200μs(JEDEC标准要求)。
  2. RESET#拉高后,等待至少500μs,让内部PLL锁定。
  3. 然后拉高CKE,颗粒开始进入初始化状态机。
  4. 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的阻抗。

校准过程:

  1. 初始化完成后,发送ZQCL(ZQ校准长命令)。这个命令会触发一次完整的校准,耗时约512个时钟周期。
  2. 校准完成后,颗粒内部会存储校准结果。之后每隔一段时间(建议40ms)发送一次ZQCS(ZQ校准短命令)来更新校准值。
  3. 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初始化流程是这样的:

  1. 上电:VDD和VDDQ同时上电,VREF随后建立。
  2. 复位:RESET#拉低至少200μs,然后拉高。
  3. 等待:RESET#拉高后等500μs,让PLL锁定。
  4. CKE拉高:提供至少5个稳定时钟周期。
  5. 配置MR2:设置CWL和自刷新参数。
  6. 配置MR3:通常保持默认。
  7. 配置MR1:设置DLL使能、驱动强度、ODT。
  8. 配置MR0:设置BL、CL,并执行DLL复位。
  9. 等待DLL复位完成:至少200个时钟周期。
  10. 执行ZQCL:完成阻抗校准。
  11. 等待ZQCL完成:至少512个时钟周期。
  12. 初始化完成,可以开始正常读写操作。

避坑指南:我曾经在配置MR0时忘记设置DLL复位,结果颗粒初始化后读写延迟总是不对。后来加上DLL复位,问题就解决了。所以,DLL复位这一步千万别省。

嗯,DDR3初始化流程就讲到这里。说白了,就是按照JEDEC标准一步步来,别跳步,别省时间。FPGA上实现时,建议用状态机来控制这些步骤,每个状态对应一个操作,状态之间加计数器延时。这样代码清晰,时序也容易保证。