DDR3 控制器初始化与训练实战:一块板子”冷启动正常、热启动跑飞”,逼我把 DDR 初始化时序从头啃了一遍

2026年9月24日 0 By admin

现象先摆出来:一块 STM32MP1 + DDR3L 的板子,冷启动(断电再上电)一万次都没事,但只要按复位键热启动,十次里有两三次内核在 DDR 里跑飞。现场返修更邪门——南方夏天的产线机房挂,空调开足就好。最后定位到根因,是我对 DDR3 初始化和训练流程的理解一直停留在”调库跑通就行”的层面。这篇文章把我补的课完整记下来。

一、先建立框架:DDR3 上电后到底发生了什么

很多人(包括以前的我)以为 DDR 初始化就是”控制器初始化函数跑一遍”。实际上从电源上电到能可靠读写数据,中间是一条严格的时序链,任何一环不满足 datasheet 要求,问题都会以”随机、难复现”的形式冒出来。

完整的链路是这样的:

  1. 电源上电与斜坡控制:VDD/VDDQ 按要求上电,RESET 拉低保持;
  2. 复位释放:RESET 拉高后,等待 200 μs(tINIT1)时钟才能稳定,CKE 保持低;
  3. CKE 拉高:时钟稳定后至少 500 μs(tINIT3)后拉高 CKE;
  4. 等待 tINIT4(500 μs)后开始发 MRS;
  5. 模式寄存器配置:MR2 → MR3 → MR1 → MR0(顺序固定,先配置次要寄存器再进 MR0 使能 DLL);
  6. DLL 复位:MR0 的 DLL Reset 位,然后等 tDLLK(约 512 个时钟周期);
  7. ZQ 校准:发 ZQCL 长校准命令,等 tZQinit;
  8. 写均衡(Write Leveling):校准 DQS 与 CK 的相位关系;
  9. 读训练(Read Gate / Read Training):校准 DQS 与 DQ 的读采样窗口;
  10. 之后才能正常收发数据。

后面 8、9 两步就是通常说的”训练(Training)”,它本质上是在测量并补偿芯片内部到颗粒的飞行时间偏移。记住一个核心认知:训练结果依赖当时的温度和电压——这是本文所有诡异问题的根源。

二、第一坑:热启动没有真正”复位”DDR

回到开头的现象。热启动跑飞、冷启动正常,这个组合几乎可以直接指向一个结论:复位时 DDR 颗粒没有跟着 MCU 一起复位,控制器以为颗粒是干净的,实际上颗粒里还留着上一次的状态(部分 bank 处于激活态、模式寄存器被改过、或者正处在 self-refresh)。

检查我们的硬件:MCU 的 NRST 只复位了 MCU,DDR3 的 RESET# 引脚接的是电源监控芯片——上电时它会有复位输出,但按键复位/软件复位时它不会有任何动作。也就是说热启动时颗粒从来没被复位过。

两种修法:

硬件修法(推荐):把 DDR3 RESET# 改为由 MCU GPIO 控制,复位流程里先把 RESET# 拉低至少 tINIT1 要求的时间再释放。STM32MP1 的 DDR 控制卡(DDRC)文档里甚至专门有章节讲这个顺序。

软件修法(硬件已定型时):初始化前先对颗粒执行一次完整的”救回”序列——重新走 MRS 流程,把所有 bank precharge 一遍。这条路依赖颗粒当前状态可预期,风险比硬件复位高,属于下策。

/* 硬件可控 RESET# 时的正确上电序列(伪代码,对应 DDR3 datasheet 时序) */
ddr_pwr_ctrl_reset_pin(0);          /* RESET# 拉低 */
ddr_delay_us(200);                  /* 覆盖 tINIT1,200us 内时钟必须稳定 */
ddr_phyc_start();                   /* 启动 PHY/PLL,等时钟锁定 */
ddr_delay_us(500);                  /* tINIT3:CKE 保持低至少 500us */
ddr_pwr_ctrl_cke(1);
ddr_delay_us(500);                  /* tINIT4 */
ddr_ctrl_init_mrs();                /* 控制器发 MR2->MR3->MR1->MR0 + ZQCL */

改完后热启动跑飞率从 ~25% 降到 0,这一条就值回票价。

三、第二坑:写均衡和读训练做了一次就”信一辈子”

训练是动态补偿,但我们把它当成了静态配置:量产固件里训练只在上电时跑一次,结果直接写死。于是:

  • 温度漂移:机房夏天 45 ℃、冬天 5 ℃,颗粒的 tDQSS、飞行时间都会漂。训练窗口余量小的板子,夏天就会出数据错误;
  • 电压漂移:DCDC 负载变化时 VDDQ 波动 ±2%,采样窗口跟着移;
  • 老化:颗粒参数逐年漂移,训练余量不足的设备两三年后”越用越容易挂”。

正确做法分三层:

  1. 上电必训练:每次初始化(包括热启动)都完整跑写均衡 + 读训练,不许用保存的历史结果”偷懒”;
  2. 余量检查:训练结束后读取 PHY 报告的窗口左右边界,窗口宽度低于阈值(比如单边余量 < 0.15 UI)就报警甚至拒绝启动——训练通过不代表余量够;
  3. 运行时监控:对有条件的产品,在空闲周期做在线重训练(比如每 30 分钟、或温度跨过 5 ℃ 阈值时触发一次)。
/* 训练后余量检查示例 */
struct ddr_train_result tr;
ddr_phyc_get_train_result(&tr);

if (tr.read_eye_left_margin < MIN_MARGIN_UI ||
    tr.read_eye_right_margin < MIN_MARGIN_UI) {
    log_err("DDR read eye margin too small: L=%d R=%d UI",
            tr.read_eye_left_margin, tr.read_eye_right_margin);
    /* 记录序列号与现场温度,出厂前就该拦下来 */
    mark_board_as_marginal();
}

当年那台”南方机房挂、空调开足就好”的设备,就是读窗口余量只剩 0.1 UI 左右,温度一漂就出界。整改方案:换用窗口余量更大的同规格颗粒批次 + 固件加余量自检。

四、第三坑:MR0 的 DLL 使能与 DLL Reset 顺序反了

这是个纯粹时序细节坑,但踩过的人不少。MR0 里有两个相关位:DLL 使能位(MR0[0]) 和 DLL Reset 位(MR0[8])。规则是:

  • DLL 必须在 MR0 写入时就已使能(DLL Enable = 1),DLL Reset 与使能必须通过同一次 MR0 写入完成(A8 与 A0 同写);
  • DLL Reset 后必须等待 tDLLK = 512 × tCK + 2 × tRFC 之后才能发下一条需要 DLL 稳定的命令;
  • 如果你的代码先写 MR0(DLL 使能)再单独写一次 MR0(DLL Reset),中间的间隔其实违反时序,大部分时候”看起来能跑”,但在极限温度下偶发出错。

我们的驱动库默认序列是对的,但为了”缩短启动时间”被前人改过——把 tDLLK 等待从固定 512 周期改成了 128 周期,启动快了几百微秒,代价就是低温批次偶发训练失败。这种”优化”没有 datasheet 依据,纯属赌博。

五、调试手段:出错时先问”颗粒到底收到了什么”

DDR 调试最大的难点是颗粒内部状态不可见。几年下来我总结了一套由软到硬的排查顺序:

  1. 读控制器状态寄存器:DDRC 的 STAT/MRSTAT 能告诉你控制器当前认为自己处于什么状态,是否卡在等 MRS 完成等 ZQ 校准结束;
  2. 训练报告:几乎所有 PHY(Synopsys、Cadence、Xilinx MIG)都能输出训练每一步的结果,失败在哪一步、窗口多大,先看这个,比盲目改时序参数强十倍;
  3. walking-1 / MemTest:数据线错误模式能反推物理层问题——固定 bit 错偏硬件(虚焊/串阻/参考平面),随机错偏时序/训练余量;
  4. 降频验证:把 DDR 频率降到标称的 60%,如果错误消失,基本排除硬件焊接,聚焦在时序余量上;
  5. 温度/电压扫描:热风枪加热颗粒 + 可调电源压 VDDQ,把”难复现”变成”可复现”,这是定位训练余量问题最快的方法;
  6. 示波器:上电序列抓 RESET/CKE/CK 三个信号,一眼确认 tINIT1/tINIT3 是否满足。很多”玄学”问题就是 CKE 比时钟稳定早了 100 μs 这种低级时序错误。

六、自查清单

把这一课浓缩成一张表,新板 DDR bring-up 时逐条过:

# 检查项 说明
1 RESET# 由可控信号(GPIO/监控芯片)控制 不能只依赖电源上电,热启动必须能复位颗粒
2 tINIT1(200us)/ tINIT3(500us)/ tINIT4 满足 示波器实测,不要信代码注释
3 MRS 顺序 MR2→MR3→MR1→MR0 顺序错颗粒会忽略部分配置
4 DLL Reset 与使能同次写入,等满 tDLLK 512 tCK + 2 tRFC,不许缩短
5 ZQ 长校准(ZQCL)在初始化时执行 运行中周期性短校准(ZQCS)按温度变化率安排
6 每次启动(含热启动)完整训练 不使用历史训练结果
7 训练后检查眼图余量,低于阈值报警/拦截 出厂测试必含此项
8 运行时按温度/电压漂移触发重训练(可选) 高低温产品建议做
9 数据线错误模式分类(固定 bit vs 随机) 硬件问题与时序问题分诊
10 降频/加温/调压三招复现手段具备 建议写进 bring-up 流程文档

DDR 这东西,bring-up 通过只是及格线,余量管理才是产品能稳定跑五年的关键。

—

下一篇预告:EMC 整改的另一半——传导发射(CE)排查实战,辐射达标了传导超标是什么体验。