
1. 项目背景与核心需求拆解RK3566这颗芯片在嵌入式圈子里热度一直不低四核A55、Mali-G52 GPU、内置NPU加上双千兆以太网的配置让它成了不少工控板、NAS、软路由方案的首选。但很多人在实际调试时会遇到一个很典型的问题板子跑起来了系统也正常但以太网就是不稳定——要么千兆协商不上要么跑着跑着丢包要么干脆ping不通。翻遍手册发现RGMII接口的时序参数没配对尤其是那个让人头大的延迟线Delay Line配置。RGMII这个接口本身设计得挺巧妙用4位数据线在时钟的上下沿同时采样把25MHz的时钟变成了125MHz的有效数据率实现了千兆传输。但代价是时序窗口非常窄数据眼图可能只有几百皮秒。RK3566的GMAC控制器内置了可编程延迟线用来微调TX和RX方向的时钟与数据之间的相位关系。这个延迟线配不好链路质量就全看运气了。这篇文章面向的是正在用RK3566做产品开发、遇到以太网稳定性问题的嵌入式工程师也适合那些想深入理解RGMII时序原理的硬件爱好者。我会从延迟线的工作原理讲起把配置参数的计算逻辑、DTS里的写法、实测调试方法、以及我踩过的坑都摊开来说。目标很明确让你看完之后能自己动手把RK3566的以太网调稳而不是靠反复试参数碰运气。2. RGMII接口时序与延迟线原理剖析2.1 RGMII为什么需要延迟线先把这个问题的根源说清楚。RGMII接口在千兆模式下时钟频率是125MHz周期8ns。数据在时钟的上升沿和下降沿都被采样所以每个时钟周期传输2位数据4根数据线加起来就是8位刚好凑成一个字节。问题在于发送端和接收端对时钟与数据的相位关系理解不一致。标准RGMII协议里TX方向的数据和时钟是同相的接收端需要在时钟边沿的中间位置采样数据才能保证稳定。但实际PCB走线长度不同、芯片内部延迟不同到达接收端时数据和时钟的相位关系已经偏了。RX方向同理PHY发出的数据和时钟到达MAC时也有偏移。解决思路有两个一是在PCB设计时严格控制走线等长但这在实际项目中很难做到完美二是利用芯片内置的延迟线在内部对时钟或数据进行相位调整把采样点挪到数据眼图的中心。RK3566的GMAC控制器就提供了这个能力TX和RX方向各有可配置的延迟线。2.2 RK3566延迟线的硬件实现机制RK3566的GMAC内部延迟线本质上是一串缓冲器链每个缓冲器提供固定的延迟量通过寄存器选择经过多少个缓冲器来调节总延迟。TX方向的延迟线作用在时钟上可以调整时钟相对于数据的相位RX方向的延迟线同样作用在时钟上用来对齐接收时钟和接收数据。具体来说TX延迟线有多个档位可选每个档位对应一个延迟步进。根据RK3566的TRM手册TX延迟线的可调范围大约在0到2ns左右步进约150ps到200ps具体值不同批次可能略有差异。RX延迟线的调节范围类似。这个精度对于8ns的时钟周期来说已经足够把采样点调到比较理想的位置了。关键点在于延迟线不是越大越好也不是越小越好。你需要根据实际的PCB走线延迟、PHY芯片的内部延迟、以及工作温度来选择一个合适的值。选对了眼图张开度大误码率低选错了可能在某些温度下能跑换个环境就挂了。2.3 延迟线与PHY工作模式的关系这里有个容易混淆的地方RGMII有两种PHY工作模式——延时模式Delay Mode和非延时模式Non-Delay Mode。有些PHY芯片内部自带延迟可以自己调整时钟和数据的关系有些则完全透传需要MAC端来做延迟补偿。如果你的PHY配置成了延时模式它会在内部给TX时钟加一个约2ns的延迟给RX时钟也加类似延迟。这时候MAC端的延迟线就应该设小一点甚至设为零否则双重延迟会导致采样点偏移过大。反过来如果PHY是非延时模式MAC端就必须配置足够的延迟来补偿。实际项目中我建议先查清楚所用PHY的数据手册确认它的默认模式和可配置选项。比如常见的RTL8211F它支持通过寄存器配置内部延迟而YT8511则相对简单。这个信息决定了你在RK3566的DTS里该怎么写延迟线参数。3. RK3566以太网DTS配置与延迟线参数详解3.1 设备树中GMAC节点的关键属性RK3566的以太网配置主要在设备树的gmac节点里完成。先看一个典型的配置骨架gmac1 { phy-mode rgmii; clock_in_out output; snps,reset-gpio gpio3 RK_PB7 GPIO_ACTIVE_LOW; snps,reset-active-low; snps,reset-delays-us 0 20000 100000; assigned-clocks cru SCLK_GMAC1_RX_TX, cru SCLK_GMAC1_RGMII_SPEED; assigned-clock-parents cru SCLK_GMAC1_RGMII_SPEED, cru SCLK_GMAC1; pinctrl-names default; pinctrl-0 gmac1m1_miim gmac1m1_tx_bus2 gmac1m1_rx_bus2 gmac1m1_rgmii_clk gmac1m1_rgmii_bus; tx_delay 0x3c; rx_delay 0x2e; phy-handle rgmii_phy1; status okay; };这里面tx_delay和rx_delay就是延迟线的配置值。注意不同内核版本的属性名可能略有差异有的用tx_delay/rx_delay有的用tx-delay/rx-delay还有的放在snps前缀下。RK3566的BSP内核通常用的是下划线形式。clock_in_out这个属性也很关键。设成output表示RK3566的GMAC输出RGMII时钟给PHY设成input则表示时钟由PHY提供。大多数设计里用的是output也就是MAC做主时钟源。3.2 tx_delay和rx_delay的取值逻辑这两个值的单位不是皮秒而是延迟线的档位编号。RK3566的GMAC延迟线寄存器通常是8位宽但实际有效的档位范围要看具体实现。根据Rockchip的BSP文档和实际测试TX延迟线的有效范围大约在0x00到0x7f之间每个档位对应的延迟量约为20ps到30ps这个数字来自实测反推不是手册直接给出的。那怎么确定该填多少理论计算只能给个大概方向最终还是要靠实测。但理论计算能帮你缩小范围避免盲目试。假设你的PCB走线延迟约为150ps/inchPHY内部TX延迟为0非延时模式MAC输出时钟到PHY的走线长度为2英寸那么走线带来的延迟约300ps。为了让PHY在数据眼图中心采样你需要让时钟相对数据延迟约半个数据有效窗口。千兆RGMII的数据有效窗口约4ns半个时钟周期中心点就是2ns。所以需要的总延迟约2ns减去走线延迟300ps约1.7ns。如果每个档位约25ps那大概需要68个档位也就是0x44左右。当然这只是个粗略估算。实际中PHY内部延迟、芯片工艺偏差、温度影响都会让最优值偏移。所以我的做法是先按理论算个初值然后在0x30到0x60之间扫一遍找误码率最低的点。3.3 不同PHY模式的配置差异前面提到了PHY的延时模式和非延时模式这里具体说下配置差异。PHY模式TX延迟线建议值RX延迟线建议值说明PHY非延时模式0x40~0x600x30~0x50MAC端需要补偿全部延迟PHY延时模式TXRX0x00~0x100x00~0x10PHY已做补偿MAC端微调即可PHY仅TX延时0x00~0x100x30~0x50TX由PHY补偿RX需MAC补偿PHY仅RX延时0x40~0x600x00~0x10RX由PHY补偿TX需MAC补偿这个表格给的是经验范围具体值还是要实测。但至少能让你知道往哪个方向调。如果你发现千兆模式下丢包严重但百兆正常大概率是延迟线没配好因为百兆模式下时钟频率低时序窗口宽对延迟不敏感。4. 延迟线调试实操与优化方法4.1 调试环境搭建与工具准备调延迟线不能靠猜得有手段观测链路质量。我常用的工具组合是这样的示波器带宽至少500MHz最好1GHz以上用来直接看RGMII时钟和数据的眼图。探头要用高带宽差分探头或者至少是低电容探头否则探头本身的负载就会影响信号。iperf3跑吞吐量测试看是否稳定跑满千兆。ping大包ping -s 65507 -f强制不分片发最大包能快速暴露丢包问题。ethtool查看链路状态、协商速率、误码统计。温度箱如果有验证不同温度下的稳定性。软件方面RK3566的BSP内核里GMAC驱动通常会暴露一些调试节点比如/sys/kernel/debug/eth0/下面可能有寄存器读写接口。如果没有也可以直接用devmem命令读写GMAC寄存器来动态调整延迟线不用反复重启。4.2 动态调整延迟线的实操步骤动态调试的好处是快不用每次改DTS重新编译内核。步骤如下先确认GMAC寄存器的基地址。在RK3566的TRM里查GMAC1的基地址通常是0xfe010000。延迟线寄存器在GMAC的MAC控制寄存器组里具体偏移量查手册。用devmem读取当前值devmem 0xfe010000偏移量 32写入新值devmem 0xfe010000偏移量 32 0x44每次改完值后先ifconfig eth0 down再up让链路重新协商然后跑iperf3测试。记录不同延迟线值对应的吞吐量和丢包率画成曲线找最优区间。我一般会从0x20开始每次加0x08一直试到0x70。找到吞吐量最高的区间后再在这个区间内以0x02为步进细化。整个过程大概需要半小时到一小时。4.3 用示波器验证眼图质量动态调试只能告诉你哪个值吞吐量高但不知道为什么高。示波器能给你直观的答案。把差分探头接到RGMII的TX_CLK和TX_CTL上触发方式设为TX_CTL的上升沿。调整示波器的余辉模式累积一段时间后就能看到眼图。理想情况下眼图的张开度应该尽可能大交叉点清晰。如果眼图闭合严重说明采样点落在了数据跳变区域。这时候调整TX延迟线观察眼图变化。你会发现随着延迟线值增加采样点会慢慢从数据跳变区移到数据稳定区。找到眼图张开度最大的那个点就是最优值。RX方向的眼图观测稍微麻烦一点因为RX时钟是PHY发过来的。但方法类似把探头接到RX_CLK和RX_CTL上即可。注意示波器探头的地线要尽量短最好用弹簧地针否则引入的寄生电感会让高频信号失真看到的眼图不准确。4.4 温度与电压变化下的稳定性验证实验室常温下调好的参数到了现场可能就不行了。原因很简单温度和电压会影响芯片内部延迟线的实际延迟量。温度升高时CMOS电路的延迟通常会增加电压降低时延迟也会增加。我的做法是在高低温箱里跑长时间压力测试。设置温度从-20°C到70°C循环变化每个温度点保温30分钟然后跑10分钟iperf3。如果某个温度点出现丢包就说明延迟线余量不够需要重新调整到更居中的值。电压方面如果有可编程电源可以把核心电压拉偏±5%观察链路是否稳定。RK3566的GMAC延迟线对电压的敏感度不算特别高但如果你的余量本来就不大电压波动就可能成为压垮骆驼的最后一根稻草。5. 常见问题排查与避坑经验5.1 千兆协商不上或频繁降速这是最常见的问题。现象是ethtool eth0显示链路速率在100M和1000M之间跳变或者干脆只能跑100M。排查思路先确认PHY的延时模式配置是否正确。如果PHY是非延时模式但MAC端延迟线设成了0千兆肯定协商不上。把TX和RX延迟线都调到中间值试试。另外检查clock_in_out属性设错了时钟方向也会导致协商失败。还有一个容易忽略的点PHY的复位时序。snps,reset-delays-us这个属性如果设得太短PHY可能还没准备好就被初始化了。我一般设成0 20000 100000也就是复位拉低后等20ms拉高后等100ms。5.2 大包丢包但小包正常这个现象很有迷惑性。小包能通说明链路基本正常但大包丢包说明时序余量不足。因为大包传输时数据线翻转更密集对时序的要求更高。解决办法是把延迟线往眼图中心调。如果你没有示波器可以用二分法先在一个较宽的范围内粗调找到能稳定跑大包的大致区间然后在这个区间内细调。每次调整后跑ping -s 65507 -f -c 1000看丢包率。5.3 不同板子表现不一致同一批PCB有的板子千兆稳定有的不行。这通常是PCB走线一致性不够好导致的。RGMII的走线等长控制要求很高通常要求时钟和数据线的长度差在5mil以内。如果做不到就只能靠延迟线来补偿。但这种补偿是有限的。如果走线偏差太大延迟线也救不回来。所以硬件设计阶段就要重视RGMII走线尽量做到等长、包地、少过孔。5.4 常见问题速查表现象可能原因排查方法解决措施千兆协商不上延迟线配置错误检查PHY模式和延迟线值调整tx_delay/rx_delay大包丢包时序余量不足ping大包测试延迟线往眼图中心调百兆正常千兆异常延迟线不匹配对比百兆千兆差异重点调TX延迟线温度变化后丢包延迟线余量不够高低温测试选更居中的延迟值部分板子正常部分异常PCB走线偏差测量走线长度优化PCB设计或单独调参链路频繁up/downPHY复位时序问题检查reset-delays-us增加复位等待时间5.5 几个容易踩的坑第一个坑是只看DTS不看驱动。有些RK3566的BSP内核里GMAC驱动会在初始化时覆盖DTS里的延迟线值。如果你发现改了DTS没效果去驱动代码里搜一下tx_delay看看是不是被硬编码了。第二个坑是忽略PHY的寄存器配置。有些PHY上电默认是延时模式但驱动可能没去配置它。你需要确认PHY的strapping引脚状态或者通过MDIO读写PHY寄存器来确认实际模式。第三个坑是用错单位。DTS里的tx_delay是档位值不是皮秒值别把计算出来的皮秒数直接填进去。我见过有人填了2000进去结果延迟线溢出链路直接挂了。第四个坑是忘记重新协商。改完延迟线后一定要ifconfig down/up或者重启PHY否则新配置不会生效。有些驱动支持动态更新但大多数需要重新初始化链路。6. 性能优化与进阶调优6.1 中断合并与NAPI调优延迟线调好之后链路稳定性基本没问题了。但如果想进一步优化吞吐量和CPU占用率可以调一下GMAC的中断合并参数。RK3566的GMAC支持RX和TX中断合并通过调整合并阈值可以减少中断次数降低CPU负载。在ethtool -c eth0里可以看到当前的合并参数。对于千兆满速场景我一般把RX中断合并设成rx-usecs 50、rx-frames 32TX设成tx-usecs 50、tx-frames 32。这样既能保证低延迟又能减少中断风暴。6.2 多队列与RPS配置RK3566是四核CPU如果只用一个队列处理网络收包很容易出现单核跑满其他核围观的情况。开启RPSReceive Packet Steering可以把收包任务分散到多个核上。配置方法echo f /sys/class/net/eth0/queues/rx-0/rps_cpus这表示把RX队列0的软中断分散到CPU 0-3上。对于千兆场景RPS能明显降低单核占用率提升整体吞吐。6.3 延迟线与其他参数的协同优化延迟线不是孤立的它和驱动里的其他参数会相互影响。比如rx_delay和RGMII的RX时钟反相配置就有关系。有些PHY支持RX时钟反相输出如果PHY做了反相MAC端的RX延迟线就要相应调整。另外GMAC的速率自适应模式也会影响延迟线的表现。在百兆模式下RGMII时钟降到25MHz时序窗口宽了4倍延迟线的敏感度大大降低。所以如果你只在百兆下用延迟线随便配配都能跑。但千兆下就必须认真调。6.4 长期稳定性监控产品出货后怎么知道以太网会不会出问题可以在系统里加一个简单的监控脚本定期检查ethtool -S eth0里的误码统计。如果发现RX CRC错误或RX FIFO溢出计数在增长就说明链路质量在下降可能需要重新评估延迟线配置。#!/bin/bash while true; do rx_err$(ethtool -S eth0 | grep rx_crc_errors | awk {print $2}) echo $(date): RX CRC errors $rx_err sleep 3600 done这个脚本每小时记录一次误码计数方便后期分析。7. 个人实操体会与建议调RK3566的RGMII延迟线这件事说难不难说简单也不简单。核心就一句话理解原理实测为准留足余量。理论计算能帮你找到方向但最终值一定是测出来的。而且不要只盯着常温下的最优值要选一个在温度、电压变化范围内都能稳定工作的值哪怕它不是吞吐量最高的那个点。我自己的习惯是在眼图张开度最大的点附近往两边各留20%的余量取中间值。这样虽然牺牲了一点点性能但换来了更好的环境适应性。毕竟产品是要出货的稳定性比跑分重要得多。另外硬件设计阶段一定要重视RGMII走线。我见过太多项目因为走线没做好后期靠延迟线硬补补得非常痛苦。如果能在PCB阶段就把等长控制好后期调试会轻松很多。RGMII的走线规则不复杂时钟和数据线等长差分对内部等长参考平面完整远离干扰源。做到这几点延迟线基本只需要微调。最后分享一个小技巧如果你手头没有高带宽示波器可以用误码率来间接判断眼图质量。把延迟线从低到高扫一遍记录每个值下的误码率画成曲线。曲线的最低点就是最优值曲线的宽度反映了时序余量。这个方法虽然不如示波器直观但足够实用而且成本低。