上个月调一块Zynq-7020的采集板两片美光DDR3 x16颗粒挂在PS端第一版打样回来初始化偶尔卡在DDR training跑Linux压力测试十几分钟就随机死机。抓波形发现地址线的过冲几乎顶到1.9V振铃幅度接近500mVDQS与DQ之间的相位偏差也在临界值。这块板子的原理图其实没画错问题全出在PCB设计阶段的阻抗匹配和端接电阻策略没做透。这篇文章把我在Zynq7系列DDR3 PCB设计里踩过的坑、算过的数、实测过的方案完整捋一遍覆盖目标阻抗怎么定、叠层怎么选、端接电阻该不该加、加在哪儿以及板子回来后怎么用仿真和示波器验证。适合正在画Zynq7板子、或者对DDR3高速布线还想深挖的人看就算你用的是别的SoC里面的思路也一样能搬过去用。1. 先想清楚Zynq7的DDR3接口到底在跑多快的信号1.1 PS侧和PL侧是两套完全不同的DDR3玩法Zynq7是一个ARMFPGA的异构SoCDDR3接口分两种PS端的硬核DDR控制器和PL端的MIG IP软核。PS端是ARM Cortex-A9访问内存的通道引脚在BGA上是固定死的数据线、地址线、控制线的物理分配不能改你只能顺着引脚去布线不能在PCB上做字节通道交换。PL端用MIG生成DDR3控制器灵活性高得多MIG IP里可以配置字节通道交换和数据位交换布线上能省掉不少绕线的麻烦。我这两年经手的Zynq板子大多数走PS端因为要跑操作系统DDR3是系统的内存。板子上的DDR3-1066接口实际数据率是1066MT/sDQS时钟533MHz这和DDR2时代400MT/s的时序预算完全不是一个量级。很多人画过DDR2板子觉得DDR3也就是换颗粒、改供电结果一上板就翻车就是因为没意识到速率翻倍之后PCB寄生参数对时序的影响也从“可以忽略”变成了“决定成败”。1.2 阻抗失配是怎么一点一点吃掉时序裕量的DDR3是源同步接口数据信号不是靠独立的系统时钟对齐而是跟着DQS strobe一起走。写操作时控制器发DQS数据以DQS为中心对齐读操作时颗粒发DQSZynq用DQS采样DQ。整个系统能正常工作靠的是接收端能在DQS的某一边沿稳定采到数据这个稳定窗口就是时序裕量。问题来了如果走线阻抗和驱动端、接收端的阻抗不匹配信号到达接收端时会产生反射。反射叠加在原信号上轻则造成振铃重则过冲超过输入阈值让接收端在该判0的时候判1、该判1的时候判0。更隐蔽的是反射造成的波形畸变会让数据有效窗口变窄本来有300ps的裕量反射一折腾可能就剩下50ps再加上温度漂移、电压波动偶发错误就成了必然。DDR3的电平标准是SSTL-15JEDEC规范里对走线阻抗的推荐值是单端40Ω、差分80Ω。为什么是40Ω而不是50Ω因为DDR3颗粒的输出驱动阻抗和片内ODT端接都是围绕40Ω设计的。你可以用ZQ校准把驱动强度调成RZQ/6约40Ω或RZQ/7约34ΩODT也可以选RZQ/2、RZQ/4、RZQ/6。这些值都和40Ω的传输线配合时反射系数最小。1.3 速率等级不同设计投入完全不同Zynq-7000不同速度等级、不同型号PS端DDR3的支持速率有差异。我用的Z-7020速度等级是-2搭配DDR3-1066颗粒按533MHz时钟设计。这个速率下信号上升沿大概150~250ps信号带宽约1.5GHz对应在FR4板材里的波长也就4英寸左右。只要走线超过波长的十分之一也就是0.4英寸就必须按传输线来处理不能再拿它当普通连线。如果你选的是-3速度等级的片子把DDR3跑到1600MT/s甚至更高那对阻抗控制的误差要求会成倍收紧。40Ω目标阻抗如果实际做成48ΩDDR3-1066可能只是波形难看点到了1600时序直接崩。所以做设计之前先把你的Zynq型号、速度等级、DDR3颗粒速率对上再决定后续投入多少精力在阻抗和端接上。2. 叠层设计与阻抗计算把理论落到具体的板材上2.1 六层板还是八层板参考平面的完整性才是一切的前提DDR3走线必须有连续完整的参考平面这是阻抗控制的物理基础。最理想的情况是DDR3信号全部走内层带状线上下都有地平面夹着这样阻抗可控、抗干扰好、对外辐射也小。四层板做DDR3不是不行但信号基本只能走外层微带线参考平面还不一定完整除非板面积特别小、走线特别短否则我不建议拿四层板去赌DDR3的稳定性。六层板是性价比比较高的方案。我常用的叠层是L1信号、L2地、L3内层带状线、L4电源、L5地、L6信号。DDR3的主要信号全部放L3这样L3的上下参考是L2和L4虽然L4是电源平面但只要能保证DDR3走线下方对应区域是完整的电源平面、不去跨越其他电源分割问题就不大。有条件的话我会把L3下面那层也改成地平面形成真正的对称带状线这种叠层用八层板实现。八层板比六层板贵的部分在高密度、大批量的产品上可能要拉扯一下成本但对ZynqDDR3这种组合我个人的态度很明确如果板子上DDR3走线超过1.5英寸或者挂了4片以上颗粒直接上八层板别在叠层上抠钱省下的那点PCB费用不够你多调两周板子的时间成本。2.2 微带线和带状线的取舍以及一个Polar计算实例外层微带线的好处是过孔少、走线方便坏处是阻抗受阻焊层影响大、容易受外部干扰。内层带状线则相反参考平面夹得很死阻抗稳定串扰也好控制所以DDR3的数据线、DQS、时钟我基本都安排在内层走。阻抗计算我都是用Polar Si9000这类工具做的不建议拿网上那些近似公式手算公式算出来的值和实际板材的差异很容易超过10%在DDR3这种场合不够看。这里给一组我最近一块板子的实际参数板材是生益S1000-2MEr约4.21GHz板厚1.6mm六层板L2到L3间距0.12mmL3到L4间距0.12mm铜厚1oz。在这个叠层下Polar算出来的单端40Ω带状线线宽大约是0.15mm6mil。差分80Ω线宽0.13mm、线距0.20mm算出来约82Ω正好在±10%范围内。板厂加工回来实际用TDR测单端阻抗基本落在38~42Ω之间和仿真基本一致。需要强调一点同样的线宽在不同板材、不同介质厚度下的阻抗可以差出十万八千里。所以定叠层的时候就要把目标阻抗告诉板厂让板厂按你的目标做阻抗测试条而不是你自己画一个线宽就指望板厂一定能做出来。我一般在发板文件里专门给一页“阻抗叠层要求”标注每层目标阻抗、线宽、参考平面板厂按这个控制生产回来的板子一致性才会好。2.3 阻抗误差和板材参数波动设计时就得留余量FR4的介电常数不是固定值不同批次、不同频率下Er会在3.8到4.5之间波动。板厂生产时介质厚度也有公差铜厚也有波动。所以阻抗控制不可能做到绝对精准JEDEC对DDR3阻抗的容差要求是±10%算下来单端36~44Ω、差分72~88Ω都在合格范围。实际设计里我给自己的内部目标是控制在±8%以内也就是单端37~43Ω。因为端接电阻本身也有1%精度误差驱动强度设置也有档位漂移每项都往极端走叠起来就能吃掉全部裕量。留一点余量后面调试时你会感谢自己。还有一点容易踩坑DDR3的地址线、命令线、控制线如果走线层不同或者参考平面不同实际阻抗也会有差异。尽量让同一组信号走在同一个层、使用同一组参考平面保证它们阻抗一致比单一根线绝对阻抗多准更重要。3. 端接电阻方案不是所有信号都该加端接3.1 数据信号主角是ODT板级端接反而容易帮倒忙DDR3的数据线DQ、数据选通DQS和掩码DM在设计上走的是点对点连接Zynq的引脚通过走线直接连到DDR3颗粒的对应引脚。这种拓扑天生适合用ODT做端接。写操作时Zynq输出数据DDR3颗粒内部的ODT开启阻抗匹配在颗粒端完成。DDR3颗粒的ODT可以配置成40Ω、60Ω、120Ω或者禁用配合40Ω走线阻抗反射很小。很多新手一看到“端接”两个字就在DQ线上加串联电阻或者并联到VTT这反而是画蛇添足串阻会分压降低到达颗粒的信号摆幅并联到VTT的电阻会大幅增加驱动电流SSTL-15的驱动能力可经不起这么折腾。我在第一块DDR3板子上就吃过这个亏DQ线上串了22Ω电阻结果写操作眼图幅度掉到不到400mV颗粒端采样裕量惨不忍睹。那Zynq这一侧什么时候需要外接端接读操作时DDR3颗粒输出数据Zynq接收。Zynq PS端的DDR接口本身没有像颗粒那样丰富的ODT配置如果读波形在Zynq侧振铃明显可以在布局时预留一个并联到VTT的电阻位比如每根DQ线上预留一个68Ω到0.75V的0201电阻位。先不贴实测振铃超标再贴用0欧跳线或者直接焊上比较。我实测过贴了之后读操作的眼图过冲确实有所收敛但代价是静态电流增加所以这个电阻位宁可有、不用也不要没有。3.2 地址、命令、控制线VTT上拉端接才是真正的关键地址线、片选、行选、列选、写使能这类信号在DDR3里是单向多负载的接收端是颗粒而且没有ODT。这类信号在走线末端的反射非常严重尤其是走线较长、挂了多片颗粒的时候。业界标准的做法是末端接VTT上拉电阻电阻阻值一般用39Ω到68Ω根据走线阻抗和驱动能力折中。VTT电压是0.75V正好是VDD的一半这样端接电阻不会引入直流偏置问题。电阻的另一端接VTT电源平面。我最初做Zynq两片DDR3时听别人说两片颗粒走线短可以省掉VTT端接就在地址线上只加了22Ω源端串阻。结果就是开头说的情况-40℃到85℃温度循环下常温勉强能跑高温时地址线过冲超过1.9V长时间运行出现了偶发的training失败。后来在地址线末端加了一排47Ω到VTT的电阻过冲直接削到1.6V以内振铃明显收敛问题彻底消失。但要不要加VTT端接还取决于你的布局和走线长度。如果是两片颗粒、走线短于1.5英寸、板子工作在常温环境确实有一些量产产品不加VTT也能稳定过测。我的建议是原理图上预留端接电阻位第一版先不贴或贴上通过实测决定。如果空间紧张预留位置不一定非得放但一定得有测试机会。另外还有一个细节VTT端接电阻的放置位置必须在信号链路的末端也就是最后一颗DDR3颗粒的后面电阻到颗粒引脚的stub越短越好。我把这排电阻放在DDR3颗粒的背面对应区域过孔直接落到端接电阻焊盘电阻到VTT平面的过孔紧挨电阻本体保证端接点的寄生电感最小。3.3 差分时钟对的端接和我的一次实测对比DDR3的差分时钟CK/CK#是全局走线到达每颗颗粒。对于差分信号标准的端接是在接收端跨接一个100Ω差分电阻。问题在于有些DDR3颗粒内部已经把差分端接做进去了规格书里会明确写内部差分端接的阻值有些则没有。我做第一版板子时因为不确定颗粒是否内置差分端接干脆在原理图上预留了100Ω跨接电阻位放在最后一颗颗粒附近。实测结果很有意思贴了这颗电阻CK差分信号的眼图更干净差分幅度略微下降但完全满足SSTL-15要求去掉这颗电阻波形上升沿出现轻微过冲。最终我选择保留这颗电阻。对差分时钟对的端接不能照抄别人的原理图要结合你选的DDR3颗粒型号去看规格书。如果颗粒已经内置100Ω差分端接外接电阻就是多余的反而增加功耗如果没有就必须靠外部电阻补上。3.4 ZQ电阻和VTT电源两个最容易被忽略的隐性角色DDR3颗粒的ZQ引脚需要一颗240Ω±1%电阻到地这是ODT和输出驱动强度的校准基准。如果这颗电阻精度不够或者位置不对颗粒内部的校准结果就会偏移数据信号质量会莫名其妙变差。我见过有人用5%精度的240Ω电阻训练时好时坏查到最后就是ZQ电阻精度不够。现在我一律用0402封装、1%精度、低温漂的电阻放在颗粒ZQ引脚旁边接地过孔紧邻电阻。VTT电源是另一个被轻视的角色。VTT端接电阻在工作时要持续灌入和吸收电流地址线翻转越频繁、端接电阻越小VTT电源的瞬态电流冲击越大。我用的VTT稳压器是TI的TPS51200专门为DDR设计的可以灌电流和拉电流。VTT输出端放了4个0.1μF和2个10μF陶瓷电容紧挨端接电阻组。VTT的纹波控制在±15mV以内是底线如果VTT本身噪声大端接电阻就会把这个噪声直接耦合到信号上。VREF电压一般由颗粒内部产生有些设计用电阻分压从VDD取0.75V这个分压点必须加0.1μF去耦电容VREF引脚本身也要求极低的噪声否则输入判定的阈值会抖动等于直接吃掉时序裕量。4. 布局布线实操Zynq7 DDR3走线怎么走才算数4.1 先把引脚分组和颗粒选型理清楚再动手拉线Zynq PS端的DDR引脚是按字节通道组织的每个字节通道包含8根DQ、1根DQS差分对、1根DM。引脚在BGA上已经排好布局时要先把每个字节通道的引脚扇出关系理出来不能把不同字节通道的信号混在一起布线否则等长和串扰控制会非常痛苦。DDR3颗粒选x16还是x8直接决定布线复杂度。30位地址、32位数据我通常选两片x16颗粒组成32位DDR3这样每个颗粒自己就是一个字节通道的邻居颗粒放在Zynq DDR引脚对应的BGA扇出方向数据线走线长度最短。布局顺序是先放Zynq再放DDR3颗粒最后放端接电阻和去耦电容。DDR3颗粒离Zynq的DDR Bank越近越好我一般控制在500~900mil以内这样走线短、过孔少、等长好做。两片颗粒并排放在Zynq同一侧地址线往一个方向走数据线分别走向两侧形成清晰的布线通道。4.2 数据总线等长策略和组内分组规则数据线组内等长是最硬的要求。DDR3-1066下我的经验值是同一字节通道内DQ、DM相对DQS的等长控制在±20mil以内。FR4里信号传播速度大约163ps/inch20mil对应约3.3ps的skew对这个速率完全够用。不同字节通道之间的相对偏差可以放宽到±50mil因为控制器内部对每个字节通道分别做training。DQS差分对内两根线要严格等长误差控制在±5mil以内。DQS到DQ的等长以DQS为基准在布线时我会先走DQS拉好蛇形线定一个基准长度然后其他DQ冲着这个基准去绕。不要每根线都单独绕蛇形那样浪费面积还容易造成相邻线间串扰蛇形线的间距要保持在3倍线宽以上。数据线换层时每根线尽量只换一次层而且DQ和对应的DQS最好在同一层走避免因为层间传播速度不同带来额外的skew。我在布线时会让整个字节通道都固定在一个布线层上从一个方向进出颗粒。4.3 地址命令总线fly-by拓扑和组内等长控制DDR3标准推荐地址、命令、控制总线采用fly-by拓扑。所谓fly-by就是走线像串糖葫芦一样从Zynq出发先经过颗粒1再经过颗粒2而不是像DDR2的T型拓扑那样从中间分叉到每颗颗粒。fly-by的好处是末端阻抗更容易控制坏处是每颗颗粒收到的地址信号到达时间不一样控制器通过write leveling功能去补偿这个时间差。所以地址线组内部的相对等长不用做到数据线那么严我一般控制整组地址、片选、时钟使能、写使能等信号的长度差在±150~200mil以内。但地址线组整体相对DQS/时钟的关系要留意。因为地址线走fly-by链CKE、CS#、ODT这些控制信号也要跟着地址线一起走不能让它们单独绕远路。所有地址组的走线尽量走在同一层、用同一组参考平面保证传播速度一致。末端VTT端接电阻排在fly-by链的终点每个信号线到末端颗粒的stub尽量短最好直接打过孔到电阻。4.4 过孔、换层和回流路径这些细节决定成败DDR3-1066速率下单个过孔的寄生电容约0.3~0.5pF寄生电感约0.5~1nH对信号本身影响有限但过孔的stub如果太长会在信号路径上形成阻抗不连续点。内层走线从L3换到L1或者L6时过孔残桩会像一个短截线在1.5GHz附近产生谐振实测表现就是眼图中间出现毛刺。我的做法是DDR3信号换层时信号过孔旁边务必放一个地过孔距离不超过40mil给返回电流提供低阻抗换层路径。换层的过孔不要用贯穿板厚的通孔而是尽量把走线安排在顶层以内两层之间切换减少残桩长度。如果板厂支持背钻对DDR3关键信号过孔做背钻处理把残桩打掉信号质量还能再上一个台阶。走线间距方面同层相邻信号线间距保持3W原则是底线数据线和数据线之间如果密度实在不够2W也勉强能接受但DQS这类差分对两侧的间距必须给足至少3W以上。地址线这种多负载总线间距不够容易产生耦合串扰串扰出来的噪声会叠加在振铃上问题很难排查。5. 板子回来后仿真验证、实测波形和训练失败排查5.1 打样前先用HyperLynx把端接方案扫一遍很多硬件工程师习惯板子画完直接发出去等板子回来再调这是最浪费时间的做法。DDR3的端接参数完全可以在打样前用仿真扫一遍成本很低收益极高。我常用的流程是从DDR3颗粒厂商官网下载IBIS模型Zynq这边从官网下载PS DDR引脚的IBIS模型导入HyperLynx的LineSim环境。把叠层参数、走线长度、拓扑结构搭好选好驱动强度和ODT配置然后用Terminator Wizard对端接电阻的阻值做参数扫描。扫描目标是让接收端波形过冲小于VDD0.3V振铃幅度小于信号的20%眼图的建立时间和保持时间都留出足够的余量。这样做一遍至少能避免两类低级错误一类是端接方式选错比如该用VTT上拉的结果用了下拉另一类是端接阻值偏差太大比如地址线需要47Ω结果放了33Ω。仿真结果和实测通常有出入但大方向基本一致仿真通过的设计再打样回来直接进入调试环节而不是反复烧钱改版。5.2 实测第一步不是跑系统而是测阻抗和看波形板子贴片回来先别急着烧写FSBL启动Linux。先用万用表确认ZQ电阻、VTT电源、VREF电压都正常再用示波器看DDR3的供电纹波波形上电时序是否正确。确认电源没问题后用TDR模式测关键走线的阻抗看看第一批板子的阻抗是否在生产公差内。TDR测试要选择DDR3颗粒引脚附近的测试点或者BGA背面过孔。如果测出来单端阻抗只有30Ω说明叠层或者线宽设计出了问题后面再怎么调端接都没用必须改版。如果阻抗在37~43Ω范围内接下来测时钟波形和数据波形才有意义。示波器带宽至少要1.5GHz最好2.5GHz以上配差分有源探头测DQS和差分时钟。这里有一个探头阻抗匹配的坑普通无源探头输入阻抗10MΩ但地线夹子很长在1.5GHz频段寄生电感很大测出来的波形全是假的振铃。我见过有人拿无源探头测DDR3时钟测出来上升沿全是台阶误判成阻抗不匹配折腾了好几天换差分探头之后波形干干净净。测DDR3信号必须用差分有源探头或者专门的SMA测试夹具探头焊在测试点上不要用探针手持去戳。5.3 初始化训练失败的排查顺序按链路从后往前查如果Zynq在FSBL阶段打印DDR training失败或者训练通过但运行不稳定别一上来就怀疑芯片或者软件按这个顺序排查先看ZQ电阻。ZQ电阻没焊、虚焊、贴错阻值DDR3颗粒的校准基准就错所有ODT和驱动强度配置全部作废。用万用表量一下240Ω是否准确这是我认为优先级最高的检查项。再看VREF和VTT电压。VREF应该是0.75V左右VTT也是0.75V左右。VTT如果偏高或者偏低端接点的直流工作点就偏移信号的高电平和低电平阈值都会受影响。然后查差分时钟的极性和等长。CK和CK#如果反相DDR3颗粒直接罢工DQS差分对内两根线如果不等长采样点就会偏移。示波器确认时钟频率和幅度再确认DQS和DQ之间的相对相位。如果这些都正常就要考虑地址线和数据线的等长问题了尤其是用两片颗粒的时候第一片颗粒和第二片颗粒的地址到达时间差是否过大。DDR3的write leveling可以补偿一部分但如果走线差异超过500mil训练算法经常会失败。最后才去怀疑驱动强度配置和ODT的软件参数因为软件参数可以通过调整来临时缓解但硬件层面的问题改软件是解决不了的。5.4 实测中的常见波形问题和对应解法我实测DDR3波形时总结过一张对照表遇到问题按波形形态分类处理会快很多波形现象可能原因处理方向过冲超过VDD0.4V端接电阻缺失或阻值偏大减小VTT端接电阻或打开颗粒ODT振铃持续时间长走线阻抗偏高源端反射未吸收检查阻抗是否在公差内考虑加源端串阻眼图幅度偏低串阻过大或ODT过小去掉串阻调大ODT阻值上升沿出现台阶探头地线过长或过孔stub谐振换差分探头考虑背钻训练时好时坏ZQ电阻漂移或VTT噪声大检查ZQ电阻精度优化VTT电源去耦这里有个经验之谈DDR3的地址线过冲问题很多时候不是靠加更强的端接解决的而是靠降低驱动强度。Zynq PS端DDR控制器的地址线驱动强度可以配置改小一档过冲和振铃都会有改善。但驱动强度太低信号幅度又不够所以这个参数要配合端接电阻一起调不能单方面追求信号干净。6. 几块板子踩出来的端接与阻抗自检清单做过的Zynq7 DDR3板子多了后来我形成了一套固定的自检流程每次发板前过一遍能挡掉大部分低级错误。这里直接分享出来供大家参考。第一电源网络检查。VDD、VDDQ、VTT、VREF这四路电源各自的电压、纹波、去耦电容是否满足要求。VTT电源必须有拉灌双向能力不能拿普通LDO代替。VREF如果是电阻分压分压电阻精度不低于1%分压点必须加去耦电容。第二ZQ电阻检查。每个DDR3颗粒的ZQ引脚都有独立的240Ω±1%电阻到地阻值、封装、位置都要确认。ZQ电阻不能共用也不能用排阻替代这是DDR3的硬性要求。第三端接方案确认。数据线依赖ODT不搞外部端接地址线末端VTT上拉电阻预留到位阻值根据仿真结果确定差分时钟端接预留所有端接电阻的摆放位置都在信号链路末端stub最短。第四阻抗设计确认。叠层和目标阻抗已发给板厂确认线宽、线距和参考平面完整。所有的DDR3信号是否都在参考平面连续的区域内走线有没有跨越电源分割。如果发现跨分割要么换层要么把这个区域的地平面合并成完整的一块。第五等长规则确认。每个字节通道的DQ/DM相对DQS控制在±20mil以内DQS差分对内±5mil地址线组内±150~200milDDR3信号整体换层次数不超过两次。第六测量条件确认。板子上有没有预留DDR3测试点测试点位置是否方便差分探头焊接TDR测试的过孔是否引出。这一步很多人嫌麻烦省略了等到板子调试时才发现没地方下探头临时飞线又破坏了信号完整性非常被动。再分享一个实际体会。我前几块板子习惯模仿开发板的参考设计看到ZedBoard的DDR3电路没加VTT端接也照样跑得好好的就以为可以照搬。后来才想明白参考设计之所以能省掉这些端接是因为它的布局极度紧凑、走线极短、层叠极干净。你的板子如果空间没那么宽裕颗粒位置没那么理想就必须老老实实按信号完整性的逻辑去加端接。参考设计是起点不是终点。还有一个小技巧DDR3的故障复现往往需要时间单纯跑一个Linux启动看不出来我会在调试阶段用特定的内存压力测试工具做全地址空间的读写校验连续跑4小时以上同时监控板载温度传感器。如果这个测试能过说明时序裕量基本充足如果跑到某个温度阈值附近开始报错大概率是过冲、振铃这类和温度强相关的信号完整性问题优先回头检查端接和阻抗。这个方法帮我定位过至少两块板子的偶发性死机问题。Zynq7系列DDR3 PCB设计的核心说到底就两条让走线的特征阻抗稳定在目标值附近把该端接的信号在正确的位置端接掉。这两件事做扎实了DDR3的training和压力测试基本就是一次过的事。如果还在画板阶段希望这篇总结能帮你少走几趟改版的冤枉路。