ARTICLE DETAIL

资讯详情

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

STM32+KSZ8863调试实录:RMII接口Link不上的排查与解决

STM32+KSZ8863调试实录:RMII接口Link不上的排查与解决 一 个在 STM32F746 上通过 RMII 接口连接 KSZ8863RLL 三端口交换芯片的项目卡了整整三天现象简单得有点“气人”Port 1、Port 2 都能正常 Link唯独 Host 口Port 3在 PHY 寄存器里的 Link Status 始终是 0自动协商也一直不完成。这个组合在工业双网口设备里非常常见——STM32F746 带内置 MAC外接 KSZ8863RLL 做二口交换CPU 通过 Port 3 接入交换机实现“一芯双网口”甚至“三网口”的形态。如果你也正在调 RMII尤其是“MDC 需要上拉电阻吗”“RMII 时钟从哪边给”这类问题还没理清那这篇文章值得你花十分钟看完。我会按实际调试顺序把硬件排查、寄存器初始化、时钟配置和常见坑全部拆开讲每一步都给到可以直接抄的结论和代码。1. 项目背景STM32F746 KSZ8863RLL 的典型架构与 Port 3 定位1.1 为什么要用交换芯片而不是两个 PHY很多人在设计双网口设备时会下意识地选“一颗带双 MAC 的 MCU 两颗 PHY”的方案。但 STM32F746 这类芯片只有一个以太网 MAC若需要两个独立网口常见做法就是外接 KSZ8863RLL 这种“二口交换 一个 Host 接口”的芯片。KSZ8863RLL 的内部结构可以粗略理解为Port 1 和 Port 2 是两个带 PHY 的物理网口直接接 RJ45Port 3 是 Host 端口专门用来接 CPU 的 MAC 侧接口。CPU 通过 RMII/MII 连到 Port 3再加上交换芯片的硬件转发能力就能实现两个物理网口之间的二层交换同时 CPU 也能访问这两个口。这个架构最大的好处是MCU 的以太网 MAC 只需要管理“一条链路”即 MCU 到 Port 3 的链路Port 1 和 Port 2 之间的转发由交换芯片自己完成。对于需要做“网桥”、“工业网关”、“串口服务器”这类产品来说这是个非常经典的硬件拓扑。1.2 问题现象与初步判断我这边具体的故障表现是Port 1、Port 2 接网线后RJ45 的 Link LED 正常亮起。MDIO 总线能正常访问PHY ID 能读出来说明 MCU 与 KSZ8863RLL 之间的 MDIO 通路是通的。但读 Port 3 对应的 PHY 状态寄存器Link Status 一直为 0即使把网线插到 Port 3 对应的外部 PHY 口注意这里的“Port 3 外部口”其实在部分型号里是 Host 口不直接对应 RJ45状态也不变。用示波器看 RMII 的 TX、RX 信号TXD 有数据在跳但 RXD 没有任何反应。这个现象说明问题不在 MDIO 读写层面而更可能在 RMII 接口的物理信号、时钟方向、芯片工作模式或者交换芯片内部对 Host Port 的使能配置上。下面我按调试顺序从硬件讲到寄存器把每一步的“为什么”也一并说清楚。2. RMII 接口硬件排查MDC 上拉、REF_CLK 与信号完整性问题2.1 MDC 到底要不要上拉答案和你想的不一样先从热搜词里最高频的一个问题说起MDC/MDIO 需不需要接上拉电阻。很多新手在画原理图的时候看到 PHY 芯片参考设计里 MDIO 上拉、MDC 没上拉就开始纠结“是不是漏了”。这里直接给结论MDC 是时钟线由 MAC 侧STM32F746推挽输出不需要上拉电阻。MDIO 是双向数据线Open Drain 结构必须要有上拉电阻。通常选 2.2kΩ 到 10kΩ3.3V 电平下单端 4.7kΩ 是通用选择。为什么 MDIO 必须上拉因为 MDIO 总线是半双工三态总线物理层靠“线与”逻辑实现双向通信。如果不上拉当驱动端释放总线时MDIO 会悬空读出来的数据不是 0 就是随机值表现为 PHY 寄存器偶尔能读对、偶尔全 0 或全 1。KSZ8863RLL 的 MDIO 引脚内部没有默认上拉外置上拉是必须的。之前在实际板子上就遇到过原理图里 MDIO 上拉电阻位被预留了但物料贴片时漏贴了 4.7kΩ结果 MDIO 能读但 10 次里有 4 次读回来是 0xFFFF。后来补上电阻后读寄存器 100 次全部稳定。补充一点MDC 虽然不需要上拉但如果 MDC 走线过长建议在源端STM32 引脚附近串一个 22Ω 或 33Ω 的电阻用来减小振铃。MDC 频率不能超过 2.5MHz这是 802.3 Clause 22 的规定STM32 HAL 里可以通过时钟分频配置 MDC 频率后面会讲。2.2 RMII 的 50MHz REF_CLK方向决定成败RMII 接口相比 MII最大的特点就是复用信号、降低引脚数代价是所有信号必须严格以 50MHz REF_CLK 为参考时钟。这颗 50MHz 时钟从哪里来是整个 RMII 调试里最容易出问题、也最容易被忽略的地方。REF_CLK 有三类提供方式MAC 提供STM32F746 通过 MCO 引脚输出 50MHz 给交换芯片。PHY/交换芯片提供KSZ8863RLL 自己产生 50MHz 后输出给 STM32 的 ETH_RMII_REF_CLK。独立外部时钟源用一颗 50MHz 有源晶振同时供给 MAC 和 PHY。不管选哪种核心原则只有一个MAC 和 PHY 必须使用同一个 50MHz 参考时钟源频率误差通常要求 ±50ppm。在 KSZ8863RLL 的 RMII 场景下我建议优先确认“交换芯片是否能作为时钟源输出 50MHz REF_CLK”。如果 KSZ8863RLL 的 X1/X2 引脚被配置为外部时钟输入模式而外部又没有接 50MHz 时钟那 Port 3 是永远不可能 Link 起来的。这点和常见的 LAN8720A 不一样——LAN8720A 用 25MHz 晶振内部倍频出 50MHz REF_CLK 输出给 MCU但 KSZ8863RLL 的 RMII Host 接口对 REF_CLK 的要求需要单独看数据手册确认不能想当然。实测遇到过一种“看似正常但实际错误”的情况做了个外部 50MHz 有源晶振输出同时接到 STM32 的 ETH_RMII_REF_CLK 和 KSZ8863 的 X1看起来没问题但因为选的是 3.3V 有源晶振而 KSZ8863 某些引脚的 IO 电平域是 2.5V导致 X1 引脚输入高电平不够时钟幅度被钳位到 1.8V 左右交换芯片内部 PLL 锁不住最终同样的故障现象Link 不起来。调试时用示波器量 REF_CLK 引脚多数情况下只能看到“有没有波形”但一定要确认幅值是否达到芯片手册要求的 VIH 最低值。RMII 信号线上50MHz REF_CLK 的边沿质量和幅度直接决定 RXD 能不能被正确采样。2.3 容易被忽略的硬件配置RBIAS 和复位时序除了 MDC/MDIO 和 REF_CLK还有几个硬件点会在“Link 不上”时被反复怀疑但真正出问题时又容易被忽略。第一是 RBIAS 电阻。KSZ8863RLL 这类交换芯片通常有一个 RBIAS 引脚需要外接一个 12.4kΩ1%电阻到地用来设置内部 PHY 的偏置电流。如果这个电阻没焊、虚焊或者阻值差太多PHY 的 RX/TX 驱动能力会异常甚至读 PHY ID 都出问题。我排查时第一件事就是用万用表量 RBIAS 对地电阻。第二是复位时序。有的板上直接把 KSZ8863RLL 的复位引脚和 STM32 的复位接到一起问题不大但如果是 MCU GPIO 控制复位必须在初始化时保证复位释放后等待足够时间再开始访问 MDIO。通常要求至少等 10ms 左右保守一点 50ms。如果复位之后立刻读寄存器交换芯片内部还没完成自检读出来的状态会误导排查。第三是 X1/X2 引脚的接法。如果数据手册要求外部输入时钟那 X1 接时钟源、X2 悬空或按要求处理如果用无源晶振则要按晶振负载电容计算匹配电容。这个细节看起来很小但选错接法会直接导致芯片没有参考时钟源Port 3 自然 Link 不上。3. 核心寄存器与初始化配置3.1 KSZ8863RLL 的寄存器体系从哪里看链路状态我习惯把 KSZ8863RLL 的寄存器分成三层看全局寄存器Global Registers控制芯片整体工作模式、RMII/MII 模式选择。Port 寄存器Port Registers控制每个端口的工作模式、速率、双工、流控等。PHY 寄存器PHY Registers通过 MDIO 访问链路状态、自动协商、PHY ID 都在这一层。在 MDIO 通路能正常访问的前提下最直接的链路状态查看方法是读 PHY 寄存器 0x01BMSRBasic Mode Status Register其中 bit 2 就是 Link Status。该位是锁存位读取后会自动清零或需要重新读才会更新所以排查时不要只看第一次读的结果。如果你用 STM32 HAL 库读 PHY 寄存器的代码很简单uint32_t phy_addr 0x16; /* 这个地址取决于你的硬件配置KSZ8863RLL由ID引脚决定下面会讲 */ uint32_t reg_val 0; /* 读 PHY ID 寄存器验证 MDIO 通路 */ HAL_ETH_ReadPHYRegister(heth, phy_addr, 0x02, reg_val); printf(PHY ID1: 0x%04X\n, reg_val); HAL_ETH_ReadPHYRegister(heth, phy_addr, 0x03, reg_val); printf(PHY ID2: 0x%04X\n, reg_val); /* 读 BMSR看 Link Status */ HAL_ETH_ReadPHYRegister(heth, phy_addr, 0x01, reg_val); printf(BMSR: 0x%04X\n, reg_val);如果读出来的 PHY ID 不是 0x0000 也不是 0xFFFF基本可以判断 MDIO 通路没问题接下来就去查模式配置和时钟。有一个细节要特别提醒KSZ8863RLL 的 MDIO 设备地址是由芯片的 ID0~ID3 引脚或者叫做 SMI 地址配置引脚决定的不同板卡可能不同。我这张板上实际是 0x16但有的参考设计会用 0x10、0x18甚至需要把地址左移一位才能读到正确数据。如果你读 PHY ID 一直失败建议把手册里关于 SMI 地址的那一页找出来对着原理图确认一次而不是反复去怀疑硬件接触不良。3.2 必须使能 RMII 模式的几个关键配置KSZ8863RLL 的 Host PortPort 3可以工作在 MII 或 RMII 模式这个模式的选择不一定只靠外部引脚 Strap很可能还需要写全局寄存器。举个例子我手上这个板子芯片上电默认从某个 Strap 引脚读取 Host 接口模式但实际配置寄存器里还有一个全局使能位控制 Host 口是“RMII MAC 接口模式”还是“RMII PHY 接口模式”。如果这个位置错误就算你的 REF_CLK 正常STM32 发出来的 TXD 信号在交换芯片看来也是“完全不可理喻的”Link 自然起不来。所以初始化流程里至少要做三件事通过 MDIO 写全局寄存器把 Host 口配置为 RMII 模式。通过 MII/PHY 寄存器把 Port 3 的自动协商使能打开速率 100M、双工 Full。如果有需要再去配置 Port 1、Port 2 的转发域让 Host 口能和其他端口互通。其中第三点非常容易被忽略KSZ8863 内部是一个带管理功能的交换芯片Port 3 即使物理链路 Link Up但如果端口没有被加入转发数据库或者端口处于隔离状态STM32 依然 ping 不通任何网口。这个问题在现象上很像“RMII 没调通”但本质上已经是“交换机配置”的问题我们后面专门用一节来说。3.3 STM32F746 侧的 RMII 初始化STM32F746 的以太网 MAC 要工作在 RMII 模式CubeMX 里需要做两件事在 ETH 配置里把 Media Interface 选为 RMII。正确初始化 RMII 对应的 GPIO 引脚并启用外部 PHY 或外部时钟路径。RMII 模式下STM32F746 的以太网引脚是固定的我这边用的对应关系如下信号STM32F746 引脚说明ETH_RMII_REF_CLKPA150MHz 参考时钟输入ETH_RMII_CRS_DVPA7载波侦听/数据有效ETH_RMII_RXD0PC4接收数据位 0ETH_RMII_RXD1PC5接收数据位 1ETH_RMII_TX_ENPG11发送使能ETH_RMII_TXD0PG13发送数据位 0ETH_RMII_TXD1PG14发送数据位 1ETH_MDCPC1MDIO 时钟ETH_MDIOPA2MDIO 数据这些引脚的复用功能基本都是 AF11CubeMX 里只要勾选 ETH 外设并选择 RMII它会自动帮你把 GPIO 的 AF 初始化好。但要注意GPIO 模式里ETH_MDIO 通常应配置为 Output Open Drain Pull Up而不是推挽输出。这一项如果不小心设成推挽MDIO 总线会与交换芯片的驱动产生冲突轻则读数据不稳定重则长时间拉低总线。时钟方面有一个常见误区STM32F746 内部并没有专门的 50MHz RMII 时钟源它必须从外部输入 ETH_RMII_REF_CLK。如果你采用“STM32 通过 MCO 输出 50MHz 给 KSZ8863”的方案要特别注意系统时钟分频是否能精确得到 50MHz。举个例子HSE 25MHz、系统主频 216MHz 时PLLCLK 是 216MHzMCO 输出分频系数只有整数216/454MHz216/543.2MHz怎么都凑不出 50MHz。这种情况下如果你还强行用 MCOREF_CLK 频率就是错的Link 永远不可能成功。这也是我后来决定改用“外部 50MHz 有源晶振 同时供给两端”方案的原因。4. 调试实录从 Link Status 不变到稳定 up4.1 先用 MDIO 把“看到”的东西量化拿到故障板之后我习惯先写一段最原始但信息量最大的调试代码上电初始化 ETH然后直接读 PHY ID、BMSR、BMCR打印出来。这个动作能帮我把“软件配置问题”和“芯片工作状态问题”快速分开。我第一次运行时打印如下PHY ID1: 0x0022 PHY ID2: 0x1460 BMSR: 0x0000 BMCR: 0x0000PHY ID 能读出来说明 MDIO 没问题。但 BMSR 是 0说明 PHY 的自动协商能力位、Link 状态位全是 0问题不是“没 Link”而是“PHY 根本没开始工作”。这时候我去读全局寄存器确认 Host 口模式发现 RMII 模式位压根没被使能。原因是我们的电路板把 Host 接口的 Strap 引脚默认接到了“MII 模式”的电平而初始化代码里又没有去覆盖这个配置。这就解释了为什么 Port 1、Port 2 都能 Link唯独 Port 3 起不来——因为 Port 3 的物理接口还在按 MII 模式工作而 STM32 这边已经按 RMII 发送信号了两边根本对不上。遇到这种情况不要心存侥幸直接把正确的 RMII 模式值写进全局寄存器再复位一下 Port 3然后重新读 BMSR。印象很深写完寄存器后再读BMSR: 0x794D BMCR: 0x1000BMSR 的 bit 2Link Status变成了 1自动协商完成。这时候 Port 3 根目录通的物理链路终于起来了。4.2 时钟问题的定位过程链路起来后我以为可以收工了结果发现另一个问题STM32 能收到 RXD 信号但 TX 发出去的数据对端网口收不到任何字节。排查到最后问题还是回到 50MHz REF_CLK 上。我用示波器同时测量 STM32 ETH_RMII_REF_CLK 引脚和 KSZ8863 X1 引脚发现两个引脚上的时钟波形虽然都是 50MHz但相位差已经接近 10ns。RMII 的建立/保持时间一般在納秒级10ns 的偏差虽然看起来不大但对于高速采样就是致命的。这个相位偏移来源有两个一个是 KSZ8863 内部的时钟缓冲路径引入的延迟另一个是 PCB 走线太长又没有做等长处理。解决办法是把 RMII 相关信号线尽量缩短、等长REF_CLK 信号单独走线并包地不要和其他高速信号并行走。如果你在手头还没有改板的条件下调试可以考虑用“交换芯片输出 REF_CLK 给 MCU”的方式让 STM32 完全跟随 KSZ8863 的时钟域这样天然保证同源同相。但前提是 KSZ8863RLL 的型号和配置支持这种时钟输出这一点一定要看数据手册确认不同批次/型号可能有差异。4.3 端口使能和交换域的坑链路 Link Up 之后还有一个容易卡住的大坑Port 3 虽然 Link 了但 STM32 访问不到 Port 1、Port 2 后面的设备也就是“通了但 ping 不通”。这个问题的本质是交换芯片内部的端口转发配置。KSZ8863RLL 内部有端口 VLAN 表、静态 MAC 地址表等。非网管模式下芯片默认行为可能是把 Port 3 排除在转发域之外或者需要你在初始化时把 Port 3 设置为“接受所有帧”、“泛洪到所有端口”。调试这类问题建议先做一个小实验把 Port 1 和 Port 2 互相 ping看是否通——如果不通说明两个物理口之间的转发本来就有问题如果通再拔掉 Port 1/2把 PC 接到 Port 1让 STM32 通过 Port 3 去 ping PC这时抓包观察 KSZ8863 是否把 Port 3 收到的帧转发到 Port 1。我在这个环节踩的坑是某个寄存器里 Port 3 被配置成了“Host Port 特殊模式”只接收特定地址的帧其他普通报文全部丢弃。所以终端上看到的现象是Link 正常、寄存器正常、但业务不通。最终把寄存器改为普通“二端口交换 Host 接入”模式才彻底解决。5. 常见问题与避坑清单5.1 RMII/MDC 常见问题速查表把这次调试遇到的和朋友交流时提到的典型问题整理成一张表方便你排查时对照现象可能原因解决思路MDIO 读 PHY ID 为 0xFFFFMDIO 上拉电阻没贴、设备地址不对、MDC 频率过高检查 MDIO 上拉核对 KSZ8863 SMI 地址降低 MDC 频率到 2.5MHz 以下MDIO 读 PHY ID 为 0x0000芯片复位未释放、供电异常、RBIAS 异常测量电源、复位时序确认 RBIAS 阻值PHY ID 读正常Link Status 始终为 0RMII 模式未使能、REF_CLK 没有或频率不对写全局寄存器使能 RMII示波器确认 50MHz 时钟和幅值Link Status 为 1但 ping 不通Port 3 未加入转发域、VLAN 配置错误检查端口转发寄存器确保 Port 3 与 Port 1/2 在同一个交换域偶发启动后 Link 不稳定MDC/MDIO 走线噪声、REF_CLK 相位偏移串阻、等长走线、REF_CLK 单独走线检查上拉电平RMII 的 RXD 完全无数据REF_CLK 方向/相位问题、CRS_DV 信号异常确认时钟同源测量 CRS_DV 是否正常拉高5.2 我踩过的三个坑第一个坑RBIAS 电阻漏贴。改版后的第一批样板贴出来结果 5 块板子全部读不到 PHY ID排查了很久最后发现是 BOM 里把 RBIAS 电阻漏掉了。这里想说的是KSZ8863RLL 这类芯片的“静默失败”很多不会给你报错只会表现为“Link 不上”或“MDIO 异常”。所以画原理图时一定要把 RBIAS 器件标得显眼一点评审时专门核对。第二个坑MDIO 的 GPIO 模式。STM32 的 HAL 库在 CubeMX 里生成代码时ETH_MDIO 引脚如果没有手工配置为 Open Drain 模式默认可能是推挽输出。这在读寄存器时偶尔能成功但非常容易在总线上产生冲突。我后来在代码排查时加了一句检查确认 GPIOA PIN2 的模式寄存器有没有配置为 OTYPER 开漏。很多网上案例说“MDIO 需要上拉”根源就在这里。第三个坑SMI 设备地址对不上。KSZ8863 系列的 MDIO 地址硬件上往往有一个“地址偏移”的设计有些板子上的地址是 0x16但如果你按 0x16 去读始终返回 0xFFFF而左移一位变成 0x2C 后反而能读通。这类地址映射问题和芯片的数据手册描述方式有关。建议直接去翻手册“SMI Interface”章节不要用“某个现成代码里的地址”硬套。5.3 给还没有画板的人的建议如果你现在还处于原理图设计阶段下面几条建议可以帮你省掉不少调试时间MDIO 上拉电阻位一定要预留4.7kΩ 起步。REF_CLK 方案优先选择“交换芯片或 PHY 输出 50MHz 给 MCU”减少 MCU 侧 MCO 频率凑不整的风险。RMII 信号线务必等长REF_CLK 走线尽量单独敷地包起来。在 KSZ8863 的 RESET、MDIO、MDC、RBIAS 附近预留测试点方便示波器勾波形。在初始化代码里把“读 PHY ID”作为第一条自检日志串口打印出来能省掉大量的“盲猜”时间。6. 调试过程中的经验补充这次的问题最终总共改了三个地方补 MDIO 上拉、正确配置 KSZ8863 的 RMII 模式寄存器、以及重新处理了 REF_CLK 的走线。三者叠加才让 Port 3 真正稳定 Link。说句实在话这类问题的难点不在某个寄存器多难理解而在于“硬件和软件夹在一起现象又很单一”。我个人的习惯是先把问题按协议分层拆开时钟和电气层、MDIO 管理通道层、MAC 配置层、交换芯片转发层逐层验证每一层都要有明确的观测数据比如波形、寄存器值、打印日志。不要因为看到了一个“Link Status 为 0”就一头扎进寄存器配置里反复改先花十分钟搞清楚时钟到底有没有MDIO 到底稳不稳定。最后分享一个小技巧算是我调网络接口多年的习惯在系统上电初始化的最开始用串口打印出 PHY ID、BMSR、BMCR 三个值作为“网口硬件健康自检”的第一条日志。每次改板、换料、更新驱动之后先看这条日志异常一眼就能看出来。这个习惯让我避免了很多“明明硬件有问题却在调软件”的无效加班你也可以试试。
返回列表