ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

DDR协议、时序与PHY实战:MIG配置到AXI带宽优化

DDR协议、时序与PHY实战:MIG配置到AXI带宽优化 1. 从一次“读不出数据”的现场说起去年帮一个做工业相机的团队看板子现象很有意思Zynq 7020 的 DDR3 初始化状态寄存器读回来是 0但示波器抓 DQS 上有信号DQ 线上也有翻转怎么看都“像在工作”。他们前后折腾了两周最后发现是 VREF 的分压电阻选错了一个量级。这件事让我意识到很多人做 DDR 时卡住的地方不是不懂“什么是 DDR”而是不懂 DDR 在物理层和协议层到底怎么配合把一次读操作完成——也就是DDR 内存基本原理里最容易被跳过的那部分。这篇是 DDR 系列的第三篇前两篇把颗粒内部的存储阵列、行地址列地址、Bank 结构这些底层概念过了一遍。这一篇往协议和实现走DDR 协议怎么发命令、时序参数到底怎么算、DDR PHY 在里面扮演什么角色、AXI 读写 DDR 为什么带宽上不去、以及 FPGA 平台上从仿真到固化的几个真实坑点。内容偏硬件和 FPGA 方向但做过 MCU 外扩内存、做过嵌入式系统内存优化的朋友同样能对上号。看完你应该能做到拿到一份 JEDEC 时序表会自己换算看到 MIG 配置界面不慌板子起不来时有明确的排查顺序。DDR 这个东西芯片手册几十上百页但真正决定成败的就那么几个点。把机理搞清楚剩下的就是对着参数核对而不是碰运气。2. DDR 命令真值表协议层的第一张地图2.1 CS/RAS/CAS/WE 四个信号如何组合出全部命令DDR 的协议层其实非常“老派”——它没有复杂的报文结构而是靠在时钟上升沿用四根信号线的电平组合来编码命令。这四根线是CS#片选、RAS#行地址选通、CAS#列地址选通、WE#写使能注意都是低有效。同一时刻的四个电平一组合就确定了这是什么命令。下面这张表要背下来调试的时候脑子里要能直接映射CS#RAS#CAS#WE#命令作用LLHHACT激活一行锁存行地址LHLHREAD从已激活行读数据LHLLWRITE向已激活行写数据LLHLPRE预充电关闭当前行LLLHREF刷新由控制器定期发起LLLLMRS写模式寄存器HXXXDES空操作/取消选择为什么这么设计因为 DDR 是并行总线多颗颗粒挂在同一组地址和数据线上必须用最少的信号线完成最多的事。四个信号能编出 16 种组合实际用到 7 种左右效率很高。理解这张表的意义在于当你用逻辑分析仪抓 DDR 总线时你是能直接“读”出控制器在干什么的。比如你看到连续几拍 CS#L、RAS#H、CAS#L、WE#L那就是一连串写命令配合地址线能判断它在写哪个 Bank 的哪个区域。这里有个实操要点DDR 的地址线是复用的。ACT 命令时地址线承载行地址Row AddressREAD/WRITE 命令时同一组地址线承载列地址Column Address。区分靠的是命令类型不是额外的地址线。所以抓波形定位问题时必须先确定当前拍是什么命令再看地址线的含义否则会算错访问的物理位置——这个坑我在早期调试时踩过抓了半天地址对不上其实是把 PRE 命令的地址线当成了列地址在读。2.2 突发传输为什么 DDR 一次要搬 8 拍数据DDR 全称 Double Data Rate双边沿采样一个时钟周期传两次数据。但真正让 DDR 区别于早期 SDR 的另一个关键设计是突发传输Burst。DDR3 的默认突发长度 BL8也就是一次 READ/WRITE 命令会连续输出 8 个数据占用 4 个时钟周期双沿。DDR4 支持 BL8 和 BC4Burst Chop 4两种模式。为什么要有突发因为 DDR 的列地址访问开销很大——发命令、等 CAS 延迟、数据回来前面这一堆固定的等待时间如果只为传 1 个数据效率低得没法看。突发就是把“开口成本”摊薄。打个比方你去仓库取货光走到货架前就要 5 分钟如果只搬 1 箱就回来太亏干脆一次搬 8 箱。BL8 就是这个“一次搬 8 箱”。突发带来的直接工程约束是控制器读写 DDR 的最小粒度就是 8 个数据宽度。如果数据位宽是 32bit最小访问就是 32 字节64bit 位宽则是 64 字节。这就是为什么你在 FPGA 里做 AXI 传输时AXI 的突发长度和 DDR 的突发长度需要匹配否则会出现“读回来一堆没用的数据”或者“写不满一个突发”的浪费。很多新手在 MIG 配置里看到 BL8 不知道什么意思其实就是这个。在实际调优里如果你做的是大量顺序访问比如图像帧缓冲、大数组遍历BL8 的带宽利用率能到 90% 以上但如果是随机小访问比如链表遍历、哈希查找每个访问都要重新 ACT 一行突发还没跑满就被打断有效带宽可能掉到 20% 以下。我做过一个实测同样一块 DDR3顺序读 12.8GB/s 理论带宽下能跑到 10.5GB/s随机 64 字节访问只有 1.8GB/s 左右。所以做内存敏感的设计时先想清楚访问模式再谈带宽优化比盲目调时序有用得多。3. 时序参数把“时钟数”翻译成“纳秒”的那件事3.1 CL / tRCD / tRP / tRAS 四个核心参数到底在管什么DDR 手册里最劝退的就是那一大列时序参数。但真正决定一次读操作能不能成功、性能高不高的核心就四个tRCDRAS to CAS Delay从 ACT 激活一行到可以对该行发 READ/WRITE 命令的最短间隔。因为激活一行本质是把整行电容的数据搬到感应放大器里这个过程需要时间稳定。CLCAS Latency从 READ 命令发出到第一个数据出现在 DQ 线上的延迟。这是读路径上最大的一块固定开销。tRPRAS Precharge从 PRE 命令发出到下一次 ACT 可以开始的最短时间。预充电是把感应放大器复位为下一次激活做准备。tRASRAS Active Time一行从激活到必须预充电的最短保持时间。太短了行数据还没稳定太长了浪费。通常 tRAS ≥ tRCD CL 突发时间。这四个参数串起来就是一次完整的“行切换读”Row Miss Read时间tRCD CL BL/2 tRP然后才能开始下一行的访问。如果命中同一行Row Hit只要 CL 突发时间如果命中同一 Bank 不同行就得加上 tRP tRCD。为什么要算这个因为我见过太多人优化内存性能只知道加频率不知道开页命中率Row Hit Rate才是顺序访问性能的真正决定因素。同一行内的连续访问省掉了 ACT 和 PRE开销只有 CL。所以做大数据吞吐时把访问尽量聚在连续地址上比超频有效。3.2 从 MT/s 到 tCK手算一遍就懂了DDR 的频率标法有讲究。DDR3-1600 里的 1600 是数据速率MT/s兆次传输每秒不是时钟频率。因为双沿传输实际时钟频率是 800MHz时钟周期 tCK 1/800MHz 1.25ns。时序参数在手册里通常以时钟数给出比如 CL11、tRCD11、tRP11、tRAS28。要换算成时间乘 tCK参数时钟数DDR3-1600tCK实际时间CL111.25ns13.75nstRCD111.25ns13.75nstRP111.25ns13.75nstRAS281.25ns35.0ns再对比 DDR4-3200tCK 1/1600MHz 0.625ns典型 CL2222 × 0.625 13.75ns。看到没时间上其实一样。这就是为什么“频率翻倍后 CL 也翻倍”是正常的厂商花力气做高频真正收益在于单位时间能塞进更多的命令而不是单个访问变快。这个换算我在选型时必做一次。因为很多 FPGA 的 MIG 配置界面要求你填纳秒或皮秒而手册给你的是时钟数全靠自己算。曾经有个项目同事直接把“CL11”填到了以 ns 为单位的框里结果配置出来的时序完全不对初始化状态机一直卡在某个阶段。手工换算虽然笨但比出错强。需要说明的是不同厂商颗粒的实际 tRCD/tRP 会有细微差异一定要以自己板子上那颗颗粒的 datasheet 为准不能拿同容量同频率的替代。我吃过这个亏换了一批颗粒没重新核对时序顺序读正常一跑压力测试就偶发错误。4. DDR PHY 与信号完整性看不见但决定生死的一层4.1 DDR PHY 内部到底做了什么很多人以为控制器直接连颗粒其实中间还有一层DDR PHY。控制器是数字逻辑颗粒是模拟器件两边电平、时序、驱动能力都不匹配PHY 就是那道翻译层。它内部大致分三块数字控制部分接收控制器的命令生成符合 DDR 协议的信号序列包含训练逻辑。模拟前端驱动器Driver、接收器Receiver、延迟锁相环DLL/PLL、可调延迟线。训练/校准单元上电时通过写特定 pattern 并读回来自动对齐 DQS 与 DQ 的相位关系。为什么要有训练因为 DDR 频率高到一定程度后PCB 走线延迟、芯片内部延迟、工艺角差异会让 DQS 采样沿和 DQ 数据眼错位。固定延迟根本保证不了正确采样。所以 PHY 上电要做 Write Leveling、Read Gate Training、Read/Write DQ-DQS Training 一整套。这些词在 MIG 的日志里能直接看到如果训练失败会打印类似 “Read calibration failed” 的信息。4.2 地址线等长、DQS 分组PCB 上那几个不能省的规则DDR 走线有个经典要求叫**“地址线等长设置”**这是很多 layout 新手最头疼的地方。规则背后的逻辑是地址/命令/控制信号是一组同时被采样的信号如果它们之间走线长度差异太大到达颗粒的时间就不一致采样窗口被压缩高频下直接采错。常见经验值具体以所用器件手册为准地址/命令/控制组内等长误差控制在 ±25mil 以内DDR3DDR4 要求更严。DQ 与 DQS 之间这是数据组要求更严组内误差通常 ±5mil 甚至更小。DQS 差分对内部两根线长度差要求最严通常 ±5mil 以内。分组原则每个字节 lane8 根 DQ 1 对 DQS自成一个等长组不同 lane 之间不要求互等长。为什么 DQS 要跟 DQ 严格配对因为DQS 是数据采样时钟它在读的时候由颗粒发出跟随 DQ 数据一起走。两者走线长度差多少采样沿就偏多少。地址线是控制器发出的公共时钟同步的所以地址组内等长即可不要求和 DQ 组等长。我见过一个板子DQ 组内等长做到了 ±3mil结果地址线有一根差了 200mil低频率能跑一上到 1066 就各种错误。这就是典型的“数据组做得漂亮公共组偷懒”。所以做 DDR 布线时两类等长要分开盯。注意等长要求的具体数值因颗粒型号、速率、层叠结构不同而不同务必以官方 datasheet 或 FPGA 厂商的 PCB 设计指南为准不要照搬网上数字。5. FPGA 平台实战从 MIG 配置到 AXI 带宽压榨5.1 Vivado MIG 配置里那几个容易填错的框以 Xilinx Zynq 7020 为例用 MIGMemory Interface GeneratorIP 连 DDR3 是标准做法。配置界面里有几个参数真的容易踩坑第一Memory Type 和 Speed Grade 要跟颗粒一致。MIG 里让你选 DDR3、速率等级如 -1066、-1333、-1600这决定它内部用哪套时序模板。如果颗粒是 1600 的但你选了 1066性能损失一大截反过来选了 1600 但颗粒实际跑不到就是初始化失败。第二数据位宽和数据掩码。32bit 位宽对应 4 个 byte lane如果你只接了一半DM/TDQS 这些信号会浮空或者接错训练必挂。第三Input Clock Period。这个填的是 PHY 参考时钟周期不是 DDR 时钟。很多人把 DDR 时钟周期填进去结果 PLL 参数算错根本出不来正确频率。一般看板子上的晶振Zynq 开发板常用 200MHz 或 100MHz 参考。配置完成后MIG 会输出一份.prj 工程和示例的仿真 testbench。我强烈建议任何新板子上电前先用 MIG 自带仿真跑一遍。仿真里它会做一遍完整初始化上电、复位、MRS、ZQ 校准、训练序列如果仿真都过不了硬件上一定过不了。仿真能过再看硬件问题就要往 PCB 和电源方向找。这一步能省掉大量示波器排查时间。关于 Zynq 7020 用 JTAG 固化 Flash 是否需要 DDR——答案是基本需要。因为 BOOT.BIN 通常体积超过 OCM约 256KB容量FSBL 会先把它搬到 DDR 里再解压运行。如果你的设计完全不依赖 DDR、且镜像足够小能塞进 OCM理论上可以不初始化 DDR但这是极其受限的场景。正常做法是把 DDR 初始化做好固化流程才顺。5.2 AXI 读写 DDR为什么带宽只有理论值的一半Zynq 上 PL 侧访问 DDR 一般走 AXI HPHigh Performance接口接到 MIG。理论带宽怎么算以 64bit AXI 150MHz 为例64/8 × 150M × 2双沿不对AXI 是单沿的所以是8 × 150M 1.2GB/s。但其实 HP 口位宽和时钟可以更高。真正的瓶颈往往不在 AXI 口本身而在几个地方DDR 控制器仲裁AXI 有多个端口时MIG 内部要仲裁冲突时带宽被瓜分。访问模式前面说过随机访问会让行命中率崩溃。突发对齐AXI 突发长度和 DDR BL8 不匹配会造成浪费。64bit AXI 一次传 8 拍正好是 64 字节刚好一个 BL8效率最高。如果突发长度是 1 拍或 3 拍效率就惨了。读写切换DDR 总线读和写之间要切换方向有 tWTR、tRTW 等惩罚频繁切换会掉带宽。我做过一组实测对比同样 32bit DDR3-1066 硬件理论 8.5GB/s访问模式实测有效带宽利用率顺序读AXI 突发 64 字节6.8GB/s80%顺序读AXI 突发 16 字节4.1GB/s48%随机读64 字节1.6GB/s19%读写交替各 64 字节3.2GB/s38%结论很清楚做高带宽设计第一件事是让访问顺序化第二件事是让 AXI 突发长度和 DDR 突发对齐第三才是调时序。很多人一上来就想超频 DDR方向就错了。6. 常见问题排查一份能救命的速查表6.1 初始化失败的排查顺序DDR 起不来别乱抓按这个顺序走现象优先排查方向具体动作初始化状态机卡在复位阶段电源、复位、时钟量 VDD/VDDQ/VPP、复位电平、参考时钟是否有卡在 MRS/ZQ 校准VREF、ZQ 电阻量 VREF 电压是否在 VDDQ/2、ZQ 电阻是否 240Ω训练失败PCB 走线、等长核对 DQS/DQ 等长、地址组等长、端接电阻训练过但读写错时序参数、VREF 裕量用 MIG 的读写校准报告看 margin调 VREF低频率能跑高频不行信号完整性、端接降频验证、加端接、检查参考层完整性VREF 那个坑我在开头提过。DDR3 的 VREF 一般是 VDDQ 的一半用两个等值电阻分压得到。如果电阻选错一个量级分压出来的电压偏离采样门限全错DQS 有信号但数据全是错的。量 VREF 应该是上电后的第一个动作比抓波形快得多。6.2 IDD 测试与功耗别忽略那几毫安的差别做低功耗产品时DDR 的电流测试IDD很重要。常见的几个 IDD 参数IDD2N预充电待机电流所有 Bank 都关闭。IDD3N激活待机电流有 Bank 打开着。IDD4R/IDD4W连续读写电流。IDD5B刷新电流突发刷新。IDD6自刷新电流最低功耗状态。为什么要区分因为如果你的应用大部分时间 DDR 是空闲的应该让它进自刷新功耗能降一个数量级。很多嵌入式设备默认让 DDR 一直激活待机白白耗电。做电池供电产品时在空闲时调用自刷新是个立竿见影的优化。测试方法上可以用 MIG 的 IDD 测试模式或者自己写逻辑持续发读写命令用电流探头量。需要提醒的是IDD 参数和温度强相关手册给的通常是常温值高温下会明显上升。做功耗预算时要留够裕量。7. 我个人的几个实操心得DDR 这玩意儿文档看再多不动手都白搭。分享几个从踩坑里换来的经验。第一新板子第一件事是拿 MIG 的仿真跑通别急着上电。仿真里初始化序列、训练流程都走一遍能过说明配置和逻辑没问题剩下的都是硬件的事。这一步能帮你快速区分“设计错”还是“板子错”。第二抓波形先看命令再看数据。CS/RAS/CAS/WE 的组合能告诉你控制器在干什么比盯着 DQ 线瞎看有效得多。定位访问错位问题时先确认命令序列里 ACT 和 READ/WRITE 的配对对不对再看地址。第三带宽优化先改访问模式后调时序。这个顺序我强调过多次因为改代码结构顺序化、对齐突发的收益远大于超频而且风险更低。第四VREF 和端接电阻是高频下的两个隐形杀手。很多“低频正常高频出错”的问题根子都在这里。备一个精度高的万用表上电先量这几个点。第五不同批次的颗粒要重新核对时序。同型号不同批次tRCD/tRP 可能有细微差异批量化产品换料时务必验证。这个系列后面还可以往 DDR4/DDR5 的新特性走比如 Bank Group 怎么提升并行度、DDR5 的片上 ECC 和子通道设计、以及 LPDDR 在移动端的低功耗策略。如果你现在正在调 DDR先从上面那张排查表走一遍多半能定位到问题。真卡住了把命令波形和 VREF 电压发出来基本就能判断个八九不离十。
返回列表