ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

DDR高速偶发错误:时序余量、DQS训练与PCB等长排查

DDR高速偶发错误:时序余量、DQS训练与PCB等长排查 DDR 内存跑不起来十有八九不是颗粒坏了。我见过太多板子800MT/s 下跑一整天没事拉到 1600MT/s 就开始半小时崩一次错误位置还每次都不一样——这种低速稳、高速飘的现象基本可以断定问题出在时序余量上而不是功能本身出错。前面已经把存储阵列、Bank 结构、引脚定义和基本读写流程过了一遍这一篇往下再挖一层命令总线怎么用四根线编出十几条指令、tRCD/tRAS/tRP 这些数字背后到底是什么物理过程、Bank Group 和预取把速率堆上去的代价落在哪、DQS 训练到底在训练什么、落到 PCB 上等长该怎么算以及控制器侧拿 AXI 和 DDR 对接时最容易忽略的几个环节。这篇文章面向的是需要把 DDR 真正跑通的人写 FPGA 逻辑的、做硬件 layout 的、调 SoC 启动的或者纯粹想把内存时序搞清楚再去看控制器手册的。内容不依赖某一家的工具链原理部分是通用的。1. 四根控制线编出的指令集DDR 命令总线怎么工作DDR 颗粒上并没有地址总线 数据总线 读使能 写使能这种直觉化的接口。它给外部的是四根低有效控制线 CS#、RAS#、CAS#、WE#外加一组复用地址线 A0~A17不同代位宽不同和 BA/BG 用来选 Bank。控制器就是在每个时钟上升沿把这四根线的电平组合成一条命令送出去。理解了这张真值表后面所有时序参数才有落脚点。1.1 CS#/RAS#/CAS#/WE# 的十六种组合里只有八种有意义四根线理论上有 16 种组合实际用到的只有下面这些CS#RAS#CAS#WE#命令作用LLHHACT激活一行把整行读进敏感放大器LLHLPRE预充电关闭当前行并均衡位线LHLHREAD列读LHLLWRITE列写LLLHREF刷新LLLLMRS写模式寄存器LHHLZQ CAL阻抗校准LHHHNOP空操作HXXXDES芯片未选中等同空闲这里有个细节新手很容易忽略地址线在命令里是复用的。发出 ACT 的时候A0~A17 代表行地址BA/BG 代表 Bank 号发出 READ/WRITE 的时候同一组线代表列地址BA/BG 还是 Bank 号。颗粒靠当前收到的是哪条命令来决定把这组电平解释成行地址还是列地址。所以 ACT 之前绝对不能有别的命令插进来打断否则地址就被覆盖了。还有一根特殊的线是 A10。它在 READ/WRITE 命令里是自动预充电开关A101 表示这次访问结束后自动 PRE在 PRE 命令里则表示预充电所有 Bank还是只充当前 Bank。同一根线在不同命令下语义完全不一样这种复用设计在 DDR 里到处都是看手册时必须先确认上下文。1.2 ACT 到 READ 之间那段空白tRCD 到底在等什么tRCDRAS to CAS Delay是激活命令到读命令之间必须隔开的时钟数。很多人把它当成一个查表得来的数字其实它的物理来源很明确。DDR 的每个存储单元就是一个电容加一个晶体管电容容量大约在几十飞法的量级充放电带来的电压差只有几十毫伏。ACT 命令把字线拉高之后整行的电荷被倒到位线上位线电压只会产生一个非常微弱的偏移。必须靠敏感放大器把这个微小偏移和参考电平比较、放大最终恢复成全摆幅的逻辑电平这一行的数据才算真正读出来了。tRCD 等的主要就是这段放大和恢复的时间再加上字线从一端走到另一端的传播时间。关键的一点是读操作是破坏性的。位线上的电荷被消耗掉之后敏感放大器必须把放大后的结果重新写回电容里。如果在这之前就把行关掉数据就丢了——这也是 tRAS 存在的原因后面细说。所以 tRCD 不是一个可以随便压的数字它由工艺、阵列密度和电压决定。而且它虽然用纳秒标称实际是按时钟数配置的控制器必须向上取整。举个具体例子某颗 DDR4-3200 的 tRCD 标称 13.75nstCK 0.625ns正好 22 个时钟。如果标称值是 13.9ns那就只能配 23 个时钟多出来的 0.35ns 白等因为硬件没有半个时钟的概念。这就是为什么你按数据手册算出来的绝对延迟总比实测值小一点点。1.3 命令只在一个边沿采样所以地址线的时序压力比数据线小得多命令、地址、Bank 选择这些信号是单沿采样的只在时钟上升沿有效而 DQ 数据线是双沿DDR 的本意就是 Double Data Rate上下沿都用。这个差别直接决定了两类信号线的布线难度完全不同。以 DDR4-3200 为例时钟周期是 0.625ns那么地址线上相邻两个有效采样点之间隔了 625ps而数据线上一共只有 312.5ps 的位宽。在 PCB 上FR-4 微带线的传播延迟大约 150~180 ps/inch也就是说 100mil 的长度差大约对应 15~20ps 的时序偏差。放在地址线上这 20ps 只占采样窗口的 3%属于可接受范围放在数据线上占位宽的 6% 以上如果 Setup/Hold 窗口本身已经被各种抖动吃掉一大半这点偏差就会开始啃余量。这就解释了为什么 layout 规范里地址线的等长要求普遍比数据线松一个数量级——不是设计者偷懒是两类信号的采样窗口本来就不一样宽。看到地址线等长控制在几百 mil 就行、DQ 要控制在几个 mil这种规范时背后的账就是这么算的。2. 激活、读写、预充电、刷新四个动作构成的循环单条命令好理解真正麻烦的是它们之间的约束关系。tRAS、tRP、tRC、tRFC 这几个参数不是各管各的它们互相咬合任何一个配错都会表现为偶发错误这种最难查的症状。2.1 tRAS、tRP、tRC 三者是一笔算得出来的账tRAS 是行激活到预充电之间的最短时间。前面说过读是破坏性的敏感放大器把数据恢复回电容需要时间tRAS 就是保证这个恢复过程完整结束的最短时间。如果提前关闭行电容上恢复到的电压不够等下一轮刷新或者再次激活读出来的时候就可能变成错误的值——而且这种错误往往是间歇性的温度高的时候概率更大。tRP 是预充电时间。PRE 命令发出后位线需要被均衡回 VDD/2 附近为下一次激活做好准备。位线从全摆幅回到中间电平需要时间这就是 tRP。tRC 就是 tRAS tRP也就是同一个 Bank 里两次连续激活之间的最小间隔。这三个数字不是独立的看任何一份数据手册都能验证这层加法关系。拿一组常见的 DDR4-3200 时序 22-22-22-52 举例参数含义时钟数换算成纳秒tCK0.625nstCL读命令到首笔数据2213.75nstRCD激活到读写命令2213.75nstRP预充电到下次激活2213.75nstRAS激活到预充电最短时间5232.5nstRC两次激活间隔7446.25ns从这张表能直接读出一个结论在同一行里连续访问很便宜跨行访问很贵。如果一行数据全部读完再换行摊到每次访问的开销就很小如果访问模式是随机的每次都命中不同 Bank 的不同行那么 46.25ns 的 tRC 就是硬性天花板。这也是为什么顺序访问和随机访问的实测带宽能差出好几倍——不是控制器不给力是 DRAM 的物理结构决定的。2.2 刷新电容会漏电所以必须定期抄一遍DRAM 的存储单元是电容电容会漏电。行业里通常按 64ms 的保持时间来设计也就是说 64ms 之内必须把每一行都读出来重新写一遍否则数据就没了。这个动作叫刷新由控制器定期发 REF 命令触发。tREFI 是两次刷新命令之间的间隔。8Gb 的 DDR4 在常温下大约是 7.8µs 一次64ms 里刷 8192 次。注意温度的影响保持时间对温度极其敏感温度每升高 10°C 大约减半。所以主流器件都规定在 85°C 以上要把刷新频率加倍tREFI 变成 3.9µs。控制器必须根据 DRAM 上报的温度DDR4 里通过 MR4 相关的寄存器配置温度范围调整刷新节奏这一点如果漏了表现就是常温跑一天没事机箱一闷就出错。tRFC 是刷新命令占用的时间这段时间里目标 Bank 完全不可访问。8Gb 颗粒的 tRFC 大约 350ns16Gb 会更大一些。粗算一下350ns / 7.8µs ≈ 4.5%也就是说不做任何优化的情况下光刷新就要吃掉接近 5% 的带宽温升到 85°C 以上这个比例翻倍到 9% 左右。为了缓解这个问题DDR4 开始支持细粒度刷新FGR把一次刷新拆成 2 次或 4 次每次刷 1/2 或 1/4 的行间隔相应缩短。还有 Per-Bank Refresh一次只刷一个 Bank其他 Bank 照常读写。对延迟敏感的实时性业务这两个特性带来的差别非常明显。2.3 CL22 不等于 22ns把时序参数换成绝对值才有可比性新手最容易犯的错误是拿 CL 数字直接比大小。CL 是时钟数不同频率下同一个 CL 对应的绝对时间完全不同。正确的算法是绝对延迟 CL × tCK其中 tCK 2 / 数据速率因为双沿传输。规格tCK典型 CL绝对读延迟DDR4-24000.833ns1613.33nsDDR4-32000.625ns2213.75nsDDR5-48000.417ns4016.67nsDDR5-56000.357ns4616.43nsDDR5-64000.313ns5216.25ns这张表里最值得注意的是从 DDR4-2400 到 DDR5-6400数据速率涨了将近 1.7 倍但单次访问的绝对延迟几乎没变甚至在 DDR5 上还略微变差了。原因是内部阵列的核心频率并没有跟着涨下一节会算这笔账而且信号在片内走线的物理延迟也不会因为频率提高而缩短。这解释了一个很多人有体感但说不清的现象换更快的内存跑大文件拷贝、视频编码这类吞吐型任务效果明显但打开一个软件、点一下按钮的响应速度几乎感觉不到差别——因为那类操作主要受单次访问延迟支配。3. 预取和 Bank Group速率堆上去之后代价落在哪里如果只看数据速率从 DDR3-1600 到 DDR5-6400 是四倍的增长。但存储阵列本身的速度并没有翻四倍中间的差距全靠架构技巧填。搞清楚这些技巧各自的代价才能理解为什么有些访问模式在 DDR5 上反而更慢。3.1 预取位数决定了核心频率能压到多低先明确一个换算关系数据速率 阵列核心频率 × 预取位数 × 2。这里的 2 是双沿传输。DDR1预取 2nDDR-400 的核心频率 400 / (2×2) 100MHzDDR2预取 4nDDR2-800 的核心频率 800 / (4×2) 100MHzDDR3预取 8nDDR3-1600 的核心频率 1600 / (8×2) 100MHzDDR4预取 8nDDR4-3200 的核心频率 3200 / (8×2) 200MHzDDR5预取 16nDDR5-4800 的核心频率 4800 / (16×2) 150MHz这个账算完你会发现一件反直觉的事核心阵列的频率增长极其缓慢DDR5 甚至比 DDR4 还低。速率增长的大头靠的是一次从阵列里搬更多数据出来摆在 I/O 缓冲里慢慢往外送。预取的本质是一次从阵列里读出一大块比如 8 位宽或 16 位宽转换为并行数据再用一个很宽的内部总线送到 I/O 端在 I/O 端串行化输出。这个宽进窄出的转换全靠 I/O 端的时钟倍频所以 DDR 的功耗大头在 I/O 而不在阵列这也是为什么提高数据速率带来的功耗增长远比线性关系要猛。预取同样带来一个副作用最小访问粒度变大。DDR4 是 64bit × BL8 512bit 64 字节DDR5 是 32bit × BL16 512bit 64 字节。两者都精确对齐一条缓存行。这个设计不是巧合是为了让一次内存事务刚好等于一次缓存填充不浪费任何传输周期。如果你的访问模式是零散的小块写比如每次只写 4 字节那么控制器要么做写合并攒够 64 字节要么就得动用写掩码效率会明显下降。3.2 DDR4 引入 Bank Group 是为解决内部数据通路打架DDR4 把 Bank 组织成 4 个 Bank Group每组 4 个 Bank一共 16 个 Bank。为什么要多一层分组问题出在列命令的间隔上。在同一个 Bank 里连续发读命令需要等 tCCD_L这个值比较长通常 5~8 个时钟原因是同一个 Bank Group 内的列访问共享同一条内部数据通路和同一组敏感放大器输出前后两次访问必须在时间上错开。如果所有 Bank 都挤在一条通路上那么 I/O 端速率再高也没用内部通路供不上数据。Bank Group 的做法是给每组配一套独立的内部数据通路。这样访问不同 Bank Group 时只需要等较短的 tCCD_S通常 2~4 个时钟。控制器的任务就变成了把连续的访问尽量均匀地撒到不同 Bank Group 上让内部通路的切换开销被隐藏掉。参数含义典型值范围tCCD_S不同 Bank Group 的列命令间隔2~4 tCKtCCD_L同 Bank Group 的列命令间隔5~8 tCKtRRD_S不同 Bank Group 的激活间隔4~6 tCKtRRD_L同 Bank Group 的激活间隔6~8 tCKtFAW四激活窗口20~35nstFAW 这个参数值得单独说一下。它限制的是任意 4 次激活命令必须落在一个时间窗口之外本质是限制瞬时电流。DRAM 的激活动作会瞬间拉很大电流如果多个 Bank 同时激活电源网络上的压降会影响到敏感放大器的判断。tFAW 就是给电源留恢复时间。做高频设计时如果电源去耦做得不好tFAW 就得往大配带宽直接受损。3.3 DDR5 拆成两个 32bit 子通道代价是地址映射要重算DDR5 的结构变化比 DDR4 更大它把一个 64bit 通道拆成两个互相独立的 32bit 子通道每个子通道有自己的命令/地址总线、自己的 Bank 阵列8 个 Bank Group × 4 Bank 32 个 Bank、自己的刷新节奏。这么做的动机很直接I/O 引脚速率的提升已经越来越吃力与其继续把单根线的速率往上推不如多开几条窄通道并行。总带宽是两根 32bit × 4800 对一根 64bit × 3200明显更划算。但代价也很实在命令总线和刷新开销翻倍。以前一套 CA 总线和一套刷新逻辑现在要两套。前面算过刷新会吃掉 4.5% 的带宽现在这个开销在两个子通道上各自发生。地址交织策略要重新设计。DDR4 时代的交织粒度通常按 64 字节一条缓存行跨 Bank 打散DDR5 上如果还是这么打会出现连续两个缓存行落在同一个子通道、另一个子通道闲置的情况。合理做法是在子通道之间也做一层交织通常是按 256 字节或更大的块在子通道间轮转块内再按 Bank 交织。训练项变多了。每个子通道要独立训练训练时间在启动阶段会明显变长。如果拿 DDR4 的地址映射表直接套到 DDR5 上最常见的症状是带宽只有理论值的一半左右而且用带宽测试工具测出来的曲线是台阶状的——说明交织粒度和子通道边界对不上。4. DQS 是双向信号写均衡和读门控各解决一半问题把线接上、频率对上DDR 就能跑不是。DDR 接口里有一根特殊的信号叫 DQS它跟 DQ 一起走是数据采样的节拍器。麻烦在于它对 DQ 的相位关系在 DRAM 侧和控制器侧要求完全不同而且两个方向的要求还不一样。这一节的训练逻辑是 DDR 接口能不能跑起来的关键。4.1 写方向DRAM 需要 DQS 对齐 CK控制器却只能给居中相位写数据的时候控制器同时输出 DQ 和 DQS并且保证 DQS 的边沿落在 DQ 数据眼的正中间——这样 DRAM 用 DQS 去采样 DQ 才最稳。这是控制器侧的视角。但 DRAM 那边还有另一个需求它内部要用 DQS 来同步自己的时钟域所以要求 DQS 的边沿和 CK 的边沿对齐。CK 是控制器发出来的走的是 fly-by 拓扑一路经过每颗颗粒DQS 的走线则是点对点长度和 CK 完全不同。结果就是控制器按 DQ 中心对齐发出的 DQS到了 DRAM 引脚上和 CK 的相位关系是错乱的。解决这个问题的机制就是写均衡Write Leveling。过程是这样控制器把 DRAM 切到一个特殊的模式DRAM 用收到的 DQS 去采样 CK把采样结果从 DQ 引脚送回控制器控制器一点一点调整每个字节组 DQS 的延时直到从返回的 DQ 上观察到符合预期的跳变位置。找到这个位置之后控制器的 DQS 发射延时就算标定了。这里有个关键细节写均衡是逐字节组per byte lane做的。因为每一组 DQS 走线长度可能不同CK 到每颗颗粒的延时也不同所以要分开调。DIMM 上颗粒多的时候你会看到训练日志里每个字节组的延时值都不太一样差个几十皮秒很正常。还有一点常被忽略写均衡只能解决 DQS 和 CK 的对齐问题它不负责把 DQS 重新挪回 DQ 眼中心。控制器内部在写完均衡之后还要把 DQS 的相位平移回去这一步靠的是内部延时链不是走线。4.2 读方向DRAM 送出来的 DQS 是边沿对齐的读方向反过来。DRAM 输出数据时DQS 和 DQ 是边沿对齐的DQS 的跳变沿和数据的跳变沿差不多同时发生这是器件规格里明确规定的。控制器拿到这根边沿对齐的 DQS如果直接拿它采样 DQ采到的就是数据的跳变沿全是错的。所以控制器必须自己把 DQS 延迟一段让它落到 DQ 的眼中心这个动作叫读门控训练Read Gate / DQS Gate Training。它分两步第一步是粗调也就是门控本身——找到 DQS 前导码Preamble出现的大致位置确定控制器内部的采样窗口什么时候打开。DQS 在两个 burst 之间会回到中间电平然后有一个前导码拉低再开始正常翻转。速率越高前导码越短DDR4 是 2 个时钟DDR5 缩到 1 个时钟窗口越窄粗调出错的概率就越大。第二步是细调扫描 DQS 的延时找一个能让所有 DQ 都稳定采到的位置。DDR4 及以上还支持逐位per-bit的 DQ 延时调整和参考电压调整能在单个字节组内部再抠出一点余量。提示读训练的延时扫描一定要在两个方向都留余量不要取刚好能过的边界值。边界值在常温下能过温度一变就挂而且症状是偶发单比特错误非常难定位。4.3 ODT 和驱动强度反射和过冲之间的交易DDR 的走线是高速传输线不是理想导线。信号在末端如果阻抗不匹配就会反射回来叠加在原始波形上形成过冲或者台阶直接吃掉眼图。解决办法是在接收端加端接。DDR 的端接做在片内叫 ODTOn-Die Termination通过模式寄存器配置阻值。参考电阻 RZQ 通常是 240Ω可选的 ODT 值就是 RZQ 的若干分之一配置阻值常见用途RZQ/460Ω轻负载走线较长RZQ/548Ω通用RZQ/640Ω匹配 40Ω 单端走线RZQ/734Ω主流的写 ODT 设置这里有个容易搞混的地方ODT 不能一直开着。写的时候DRAM 是接收方需要开 ODT 来吸收控制器的驱动信号读的时候DRAM 是发送方它的 ODT 必须关掉否则等于把自己的输出短接到端接上此时端接责任转移到控制器一侧的输入 ODT。DDR4 用专门的 ODT 引脚做动态控制DDR5 则通过命令总线上的命令来切换。驱动强度Drive Strength是同一个交易的另一面。控制器输出阻抗调得太低上升沿很陡但过冲严重调得太高边沿变缓眼高变小。一般会让驱动阻抗和走线特征阻抗大致匹配单端 40~50Ω 范围再通过 ODT 微调。DDR4 开始DQ 的参考电压 VrefDQ 也变成片内生成不再是外部 VREF 引脚所以多了一项 VrefDQ 训练——扫描参考电压找眼图的垂直中心。这项训练和延时训练合起来构成一个二维扫描最后选出来的是一个点这个点周围能容错的范围就是训练余量。5. 落到板子上地址线等长、fly-by 拓扑和仿真怎么用原理清楚了接下来是把账算到 PCB 上。这一节讲的都是能被实测验证的东西不是经验口诀。5.1 等长规则在匹配什么能算出来先统一单位FR-4 板材上微带线的传播延迟大约 150~180 ps/inch带状线内层大约 170~200 ps/inch。取中间值 175 ps/inch那么10 mil 长度差 ≈ 1.75ps100 mil 长度差 ≈ 17.5ps1000 mil 长度差 ≈ 175ps再对照采样窗口。DDR4-3200 的 CK 周期 625psDQ 位宽 312.5ps。地址线单沿采样有效窗口按 625ps 算数据线双沿采样按 312.5ps 算再扣掉控制器和 DRAM 各自的 Setup/Hold 要求、时钟抖动、电源噪声实际留给走线偏差的余量可能只剩 150~200ps。按这个账推地址线之间的偏差控制在 500mil 以内换算约 87ps占 625ps 窗口的 14%属于可以接受的范围。业界常见规范是地址组内控制在 ±50~200mil量级是对得上的。数据线组内DQ 相对 DQS偏差要严格得多。常见的规范是 ±5~10mil换算只有 1~2ps看起来过分严格但这是给训练留余量不是不够用就会错。训练电路的延时链范围有限、分辨率有限走线越整齐训练出来的眼图越宽高温和电压波动下的失效概率就越低。所以正确的心态是等长规范不是过线就行的红线而是余量预算。压着边界过等于把所有余量都押在训练电路上长期可靠性没法保证。还有个容易踩的坑差分时钟对的组内偏差要单独控制。CK 的 P/N 两根线如果差得多占空比就失真有效的采样窗口会直接缩水而且这种失真在示波器上看波形还不太明显只有做眼图或者跑高频测试才会暴露。通常要求 P/N 等长控制在 ±5mil 以内。5.2 Fly-by 拓扑决定了哪些信号需要训练DDR4/DDR5 的 DIMM 上地址、命令、控制、时钟走的是 fly-by菊花链拓扑从控制器出来依次经过每一颗颗粒末端接一个端接电阻到 VTT。数据线则是点对点一个字节组只连一颗颗粒。这个拓扑差异带来两个后果第一每一颗颗粒看到的地址信号时刻不同。靠控制器的 fly-by 端那颗粒最早收到最远的那颗最晚。这个差值可能达到几百皮秒。所以前面讲的写均衡不是可选项是必需品——它补偿的正是这个差异。第二数据线不需要处理 fly-by 差异。因为一个字节组只连一颗颗粒走线可以做得很短很直不需要为了迁就拓扑去绕等长。这也是为什么看 DIMM 布线图时DQ 走线又短又整齐而 ADDR 走线绕来绕去。反过来说如果你在设计一块板子发现地址线被迫绕得很长那要注意的是绕线带来的阻抗不连续而不是长度差本身。过孔、拐角、线宽变化都会引起反射单纯追求等长而堆一堆蛇形绕线实际效果可能比不绕还差。5.3 IBIS 仿真和 IDD 测试各自能告诉你什么做 DDR 这类高速接口投板前跑一次信号完整性仿真是常规动作。IBIS 模型用 I/V 曲线和 V/t 曲线描述引脚行为不包含晶体管级信息所以仿真速度快适合扫大量的拓扑组合。仿真时最容易被低估的是模型本身的准确性尤其是 ODT 和驱动强度的各个 corner。同一颗颗粒在不同 ODT 设置下的 I/V 曲线完全不同如果仿真时用的是默认 corner而实际板子上配的是另一档 ODT那仿真结果基本参考价值有限。跑之前一定要确认模型版本和实际器件对得上仿真里配的 ODT、驱动强度、Vref 和控制器最终配置一致。IDD 测试是另一条线它测的是功耗不是信号质量。JEDEC 定义了一组标准化的电流测量项用来横向比较不同器件的功耗特性项目测量条件用途IDD0单 Bank 激活-预充电循环评估频繁换行的功耗IDD2N预充电待机评估空闲功耗IDD3N激活待机评估行保持的静态功耗IDD4R读突发评估读带宽下的功耗IDD4W写突发评估写带宽下的功耗IDD5刷新评估刷新功耗IDD6自刷新评估低功耗状态IDD7全 Bank 交错评估最坏情况峰值功耗做电源设计时最该关注的是 IDD7 和 IDD4W因为这两个场景下瞬时电流最大。电源网络的去耦没做好表现出来的症状和时序问题一模一样——偶发错误而且高温下更容易出现。很多工程师花几天时间查时序最后发现是去耦电容选错了这类案例不少见。6. 控制器一侧从 AXI 事务到 DRAM 命令中间隔了什么FPGA 和 SoC 上做 DDR通常不需要自己写 DRAM 命令序列控制器 IP 会处理。但控制器怎么把上层的访问翻译成 DRAM 命令直接决定了你能拿到多少实际带宽。这一节讲的是接口层最容易忽略的几个环节。6.1 AXI burst 长度和地址连续性决定了 Bank 交织效率AXI4 协议允许最长 256 拍的 burst而 DRAM 侧一次 burst 只有 8 拍DDR4或 16 拍DDR5。控制器要做的第一件事就是拆包和地址映射。这里有几个实际影响很大的点4KB 边界限制。AXI4 规定一次 burst 不能跨越 4KB 地址边界所以一个大的连续传输会被拆成多段。如果上层软件传的缓冲区没有页对齐拆出来的跨页 burst 会比较碎控制器的重排能力就受限。写合并。前面提过64 字节是一次完整 DRAM burst 的长度。如果上层发来的是零散的 4 字节写控制器要么等攒够再发要么使用写掩码。DDR4 用 DM 信号做字节粒度掩码还可以到了 DDR5掩码能力的可用性和粒度要查具体器件规格某些配置下干脆没有掩码功能那控制器只能做 read-modify-write——先把 64 字节读回来改掉几个字节再整体写回去。带宽直接砍一半延迟还增加了一个来回。所以让写操作凑成完整且对齐的 64 字节是性价比最高的一次优化。这件事软件侧就能做数据结构按缓存行对齐、避免跨行更新、批量提交而不是逐条提交。做了之后带宽曲线会明显变化。outstanding 事务数。控制器内部有事务队列队列深度决定了它能同时打开多少个 Bank、隐藏多少行激活延迟。AXI 互连上的 QoS 配置、仲裁策略会直接影响队列的填充效率。如果多个主设备通过同一个互连访问 DDR轮转仲裁看起来很公平实际上可能导致每路的事务都太短控制器来不及重排效率反而下降。这种情况下按带宽需求做加权仲裁比平均分配效果更好。6.2 上电初始化顺序错了后面全是坑控制器 IP 通常会自动跑初始化流程但知道它每一步在干什么出问题时才能定位。以 DDR4 为例大致顺序是电源稳定CK 开始输出CKE 保持低电平。等待 tINIT500µs 量级让颗粒内部的电源和参考电路完全稳定。CKE 拉高发 MRS 命令配置模式寄存器突发长度、CL、写恢复时间、ODT、驱动强度等。发 ZQCL 命令做阻抗校准这个过程需要几百个时钟。进入训练流程命令总线训练、写均衡、读门控、读写延时和参考电压扫描。训练结果写回控制器寄存器进入正常读写。这里面最容易出问题的是第 2 步和第 3 步之间的边界。如果 CKE 拉高的时刻不对或者在 MRS 序列中间被 CS 的毛刺打断颗粒会处于一个未定义的状态。症状是初始化能过但训练结果异常或者跑一会儿就失联从日志上很难看出来。还有一个常见的坑是复位信号的时序。很多板子把颗粒的复位和系统的上电复位接在一起或者干脆靠 CKE 来做隐式复位。如果复位释放的时刻和 CK 起振的时刻关系不对颗粒可能采到几个无效时钟。稳妥的做法是严格按手册的时序要求控制复位和 CKE 的相对关系而不是依赖上电之后自然就好。6.3 用 JTAG 固化 Flash 到底需不需要 DDR这个问题在嵌入式项目里问得特别多答案是取决于烧写工具和镜像大小但标准流程通常需要。以常见的 ARM SoC 方案为例芯片内部有一块片上存储器OCM容量通常只有几百 KB 量级可用部分更少。BootROM 启动后把第一阶段引导程序拷到 OCM 里运行这部分不依赖 DDR。但从第二阶段开始就不一样了要把 bitstream、应用程序、文件系统这些动辄几 MB 的内容从 Flash 里搬出来OCM 显然放不下必须先把 DDR 初始化好把数据暂存在 DDR 里再搬运。所以标准的分区镜像流程里DDR 初始化是必经环节。至于用 JTAG 直接烧写 Flash多数工具的做法是先加载一个辅助设计到芯片上运行这个辅助设计负责接收 JTAG 传来的数据、解包、写 Flash。如果辅助设计本身和待写数据都放在 DDR 里那就必须要求 DDR 能正常工作。理论上可以写一个完全跑在 OCM 里的小型烧写器但那是特例需要自己裁剪容量和功能都受限。我的建议是先让 DDR 的初始化和内存自检跑通再做 Flash 相关的操作。顺序反过来一旦烧写失败你很难判断是 Flash 时序问题还是 DDR 问题排查成本翻好几倍。顺带说一下怎么确认板子上的 DDR 是哪一版。最可靠的办法是读 SPD——DIMM 条上有一颗 I2C EEPROM通常挂在 SMBus 上通过特定的从机地址可以读出容量、速度等级、时序参数、制造商等完整信息。焊接在板上的颗粒没有 SPD只能看丝印丝印上会标注容量和速度等级。还有一个办法是让控制器把初始化时写入的模式寄存器读回来比对但这只能验证你配了什么不能告诉你颗粒实际支持什么。7. 排错现场从完全不启动到高频偶发DDR 的问题分成明显两类一类是初始化就过不去一类是跑起来之后偶发出错。前者好定位后者是真正耗时间的。下面按排查顺序讲。7.1 初始化卡住的排查链路遇到初始化不通过不要一上来就怀疑颗粒按这个顺序走第一步量电源和参考电压。DDR4/DDR5 的电源不止一路除了主电源还有 VPP 等辅助电源每一路的容差要求都很紧。用示波器看纹波和上电斜率特别注意多路电源之间的上电顺序是否满足手册要求。这一步用万用表看不出来必须用示波器。第二步看时钟。CK 有没有起振、频率对不对、占空比是否接近 50%、幅度是否够。差分时钟要用差分探头看单端探头测出来的波形会失真。占空比失真会直接导致训练窗口缩到几乎没有症状是训练一直不收敛。第三步看复位和 CKE 的时序关系。前面提过这两者的相对时刻不对颗粒可能处于未定义状态。对照手册的时序图逐项核对。第四步看 MRS 序列有没有被打断。这个需要逻辑分析仪抓命令总线或者看控制器 IP 提供的调试输出。如果在 MRS 期间出现意外的 CS 有效脉冲模式寄存器就会被写脏。第五步看 ZQ 校准有没有完成。校准不完成ODT 和驱动强度就是错的后面训练出来的结果全是假的。走完这五步如果都正常再怀疑颗粒本身。直接换一颗同型号的交叉验证是最快的判断方式。7.2 只在高温或者长时间运行时才错误这类问题的本质是余量不足不是功能缺失。常见的几个诱因刷新率没跟上温度。前面算过85°C 以上 tREFI 要减半。如果控制器的温度补偿没配好或者 DRAM 侧的 MR4 温度范围设置和实际工作温度对不上高温下就会丢数据。这类错误的特征是错误地址随机分布和访问模式无关而且跑内存测试时错误数量随时间线性增加。参考电压随温度漂移。DDR4 之后 VrefDQ 是片内生成的训练时定下来的值在温度变化后会偏离最优点。很多控制器支持周期性重训periodic retraining在温度变化超过阈值时重新跑一遍 Vref 和延时扫描。这项功能如果关着高低温循环测试很容易出问题。数据总线反转DBI没开。DBI 的作用是统计一次传输里有多少位发生翻转如果超过一半就整组取反再发这样能减少同时开关的位数降低电源噪声。开启 DBI 之后眼图通常会明显干净一些代价是增加一点点编解码延迟。在高频下这个延迟换来的稳定性是值得的。去耦设计不足。这个最难查因为症状和时序问题一模一样。判断方法如果错误率和访问模式强相关比如集中在某种突发写模式下更可能是时序如果错误率和访问强度相关但不挑模式更应该怀疑电源。7.3 训练余量怎么量化才算够不要只看训练通过没通过要看余量有多大。主流控制器都支持眼图扫描eye scan把 DQ 的采样延时在一个位宽范围内扫一遍同时把参考电压也扫一遍记录每个组合的通过与否画出来就是一张二维的眼图。判读这张图有几个经验点写方向眼宽通常要求在 20%~30% 位宽以上。DDR4-3200 的位宽是 312.5ps30% 就是约 94ps。读方向要求类似因为读方向除了走线还叠加了 DRAM 输出的抖动。看每个字节组的一致性。如果某一个字节组明显比其他差那大概率是那一组的走线、焊接或者颗粒个体问题而不是全局配置问题。这种情况针对性地调那一组的延时设置比全局调参有效得多。看眼图的形状。如果眼图不是对称的菱形而是偏向一侧说明占空比或者参考电压有系统性偏差。对称性问题用延时或者电压单个维度去调都解决不了得两个维度一起看。还有一个容易被忽略的点训练余量要在最坏条件下测。常温下测出来的余量好看不代表什么把板子加热到工作温度上限、电源拉到容差下限再跑一遍扫描这时候看到的余量才是真实的。我见过太多设计常温下眼图很漂亮一进高温箱就只剩几个点的宽度这种设计量产之后返修率一定高。我自己在做板子时养成了一个习惯每次改完 layout 或者换批次颗粒都跑一遍全温度范围的余量扫描把结果记下来。看起来多花半天时间但能省掉后面几周的救火。尤其是那种我们这边测试都没问题客户那边偶尔死机的场景十有八九就是余量在不同的电源和温度组合下被吃穿了。
返回列表