Write Leveling 基本原理:控制器如何发送训练模式,DRAM 如何反馈相位信息

咱们直接从问题切入:为什么需要 Write Leveling?

DDR4/DDR5 的 DQS 和 CK 是异步的,也就是说,控制器和 DRAM 各自的时钟域是独立的。初次上电时,DQS 的相位相对于 CK 是未知的。如果你直接发写命令,数据眼根本没落在 DQ 捕获窗口上,写数据全错。Write Leveling 就是用来解决这个相位问题的。

说白了,它让 DRAM 告诉控制器:“你发过来的 DQS 到我这边时,相位对不对?” 然后控制器根据反馈慢慢调整 DQS 的延迟,直到对齐。

核心目标: 把 DQS 的上升沿对准 DRAM 内部时钟 CK 的上升沿。精度要求一般在 1/4 tCK 以内。

3.1 控制器发送的训练模式

我习惯把训练过程分成三步:进入模式、发送 DQS 脉冲、解析反馈。

  1. 进入 Write Leveling 模式:往 MR[1] 的 bit 7 写 1。DRAM 收到后,把 DQ 引脚变成输入引脚,专门用来回馈相位信息。
  2. 发送 DQS 脉冲:控制器以固定的频率 toggle DQS,持续 64 个周期(具体数量取决于 JEDEC 规范)。CK 保持稳定。注意,这里不发送写命令,只发 DQS。
  3. 采样反馈:DRAM 在内部用 CK 采样 DQS 的上升沿。如果 DQS 上升沿在 CK 的建立保持窗口内,DQ 输出高电平;否则输出低电平。

你想想看,控制器只需要读 DQ 引脚的电平,就知道 DQS 是早了还是晚了。

关键信号时序参数(JEDEC 规范)
参数 全称 典型值(DDR4-3200) 说明
tDQSS DQS to CK setup/hold ±0.25 tCK DQS 上升沿必须落入此窗口
tDSS DQS falling edge to CK setup 0.75 tCK DRAM 内部采样时间
tDSH DQS falling edge to CK hold 0.75 tCK 保持时间
tWL Write Leveling delay 可编程(0~63) 控制器调整 DQS 延迟步长
// 伪代码:控制器侧 Write Leveling 调整流程
for (delay = 0; delay < 64; delay++) {
    setDqsDelay(delay);
    toggleDqs(64);        // 发 64 个 DQS 脉冲
    status = readDqPin(); // 0 = 早,1 = 晚(或相反,取决于设计)
    if (status == TARGET) {
        lockDqsDelay(delay);
        break;
    }
}
实际项目里的小细节: 不同颗粒厂家的反馈极性可能不同。有的 DRAM 在 DQS 超前时 DQ 输出 0,滞后时输出 1;有的刚好反过来。我建议你在初始化代码里加一个 “极性探测” 步骤,先固定一个 delay,如果读到的 DQ 状态和预期不符,就取反极性再跑一遍。

3.2 DRAM 如何反馈相位信息

DRAM 内部的反馈机制,其实是个简单的边沿比较器。它会用 CK 去抓 DQS 的上升沿。抓得住就输出高,抓不住就输出低。

为什么只输出高低?因为只需要知道相对相位,不需要知道具体偏移量。控制器通过二分法或线性扫描,找到跳变沿的边界,然后把 DQS 延迟设在窗口中间。

我遇到过一个问题:有些弱颗粒在 DQS 上升沿落在 CK 窗口边界时,DQ 输出会抖动,一会高一会低。扫出来的边沿不平滑。后来发现是 Vref 没调好,内部比较器进入亚稳态了。

注意: 反馈信号 DQ 是单比特 pin,训练期间不可用做数据。必须在训练结束后退出 Write Leveling 模式(MR[1] bit 7 写 0),否则不能发送正常写命令。

3.3 整个信号流程

下面这张图帮你看清控制器、DQS、CK 和 DRAM 之间的交互关系:

Write Leveling 相位对齐流程 Write Leveling 训练序列 控制器 发送 DQS toggle DRAM 用 CK 采样 DQS DRAM 内部采样窗口 DQS 脉冲 CK 时钟 / 内部锁相 采样结果 反馈 DQ 电平(0/1) 调整 DQS 延迟 二分法/线性扫描 迭代 当 DQ 输出从 0→1 或 1→0 表示找到跳变边界

3.4 常见问题与避坑指南

  • 跳变边沿模糊:扫出来的 DQ 边沿在多个 delay 值之间来回跳。我曾经遇到过这种情况,最后发现是 PCB 上 Vref 走线有噪声,影响了 DRAM 内部比较器。加了一个 100nF 去耦电容后,边沿立刻稳定了。
  • 温度漂移:DQS 延迟会随温度和电压变化。即使训练时完美对齐,系统跑一段时间后可能又偏了。解决办法是做周期性的 Write Leveling 重训练(比如每 1 秒重训练一次,或者检测到温度变化超过 10°C 时触发)。
  • 多颗粒选优:多通道或多 rank 的系统,每个 DRAM 的相位延迟不同。我习惯在每个颗粒单独训练后,取所有延迟值的中间值作为全局延迟,避免一个颗粒拖垮全系统。
实战小技巧: 有些控制器的 Write Leveling 硬件自动完成,但会暴露 “pre-fail” 标志位。你可以读这个标志,如果置位了就手动增加 tDQSS 窗口的余量,或者增加训练阈值宽度。我在某量产项目中就用这个方法,把良率从 95% 提到了 99.7%。

说白了,Write Leveling 就是个简单的闭环反馈:发脉冲,看反馈,调延迟。但真正在板上跑起来,那些工艺偏差、噪声耦合、温度漂移才是让你头疼的地方。掌握原理后,剩下的就是多积累经验,多 debug。