资讯动态

STM32 RMII参考时钟详解:50MHz来源与调试指南

发布时间:2026/8/29 20:21:39 来源:尧图企业网站定制
做嵌入式以太网调试你大概率经历过这种场面代码在开发板上跑得好好的换成自己画的板子ping 不通PHY ID 读出来全是0xFFFF查了一圈最后用示波器怼到 REF_CLK 引脚上——一片安静。RMII Reference Clock这个看起来只是数据手册里一个引脚的信号其实是整个以太网链路里最先要亮起来的东西。这篇文章就把 STM32 的 RMII 参考时钟彻底讲透为什么必须有它、谁来产生、怎么设计、怎么配置、踩过的坑怎么排。内容面向正在用 STM32F1/F4/H7做以太网板卡的工程师和学生。无论你用的是 LAN8720A、RTL8211F 还是 YT8512只要接口是 RMII这篇文章里的思路都能直接用上。1. RMII 与参考时钟50MHz 到底从哪里来1.1 为什么 RMII 必须带一个外部时钟先把 RMII 和更早的 MII 放在一起看。MIIMedia Independent Interface有 16 根信号线TXD[3:0]、RXD[3:0]、TX_EN、RX_DV、TX_CLK、RX_CLK、CRS、COL外加 MDC/MDIO 管理接口。它的收发时钟是 PHY 给的100Mbps 时跑 25MHz10Mbps 时跑 2.5MHz。MAC 侧并不自己产生时钟属于“PHY 说了算”。RMIIReduced MII把数据线砍到 2 根发送、2 根接收TX_EN 和 RX_DV 合并成一个 CRS_DV总数只剩 9 根左右。省引脚是有代价的收发双方必须共用一个 50MHz 参考时钟所有数据都在这个时钟的上升沿同步。100Mbps 时每个时钟周期传 1 bit10Mbps 时相当于每 10 个周期取 1 bit。这个“公共参考时钟”就是 RMII Reference Clock业界简称 REF_CLK。对比项MIIRMIITXD 数据线42RXD 数据线42发送使能TX_ENTX_EN接收有效RX_DVCRS_DV合并收发时钟TX_CLK/RX_CLK由 PHY 提供REF_CLK50MHz外部公共时钟信号总数约 16约 9所以 RMII 这种接口天生就假设有一个稳定的 50MHz 参考时钟源存在。没有这个时钟MAC 的接收状态机根本不跑发送侧也找不到同步基准后续所有初始化行为都是空转。这里有一个新手特别容易混淆的概念STM32 内部的 MAC 时钟比如 AHB 或 AXI 域的主频跟 RMII REF_CLK 没有直接关系。MAC 的寄存器访问和 DMA 搬运靠系统总线时钟而数据收发同步靠 REF_CLK。就算你的 F407 主频跑到 168MHz如果 REF_CLK 引脚没有 50MHz 信号进来以太网照样不通。1.2 50MHz 时钟的三种供给架构从系统层面看RMII 的 50MHz 参考时钟可以从三个位置产生PHY 内部倍频输出、MAC也就是 STM32侧输出、外部独立时钟源。了解这三种来源后面做选型和布线才有判断依据。第一种是 PHY 自己产生。最典型的做法是在 PHY 旁边放一个 25MHz 无源晶振PHY 内部 PLL 倍频到 50MHz然后通过 REF_CLK 引脚输出给 STM32。LAN8720A、KSZ8081、YT8512 这些 PHY 都支持这种模式。这是目前 STM32 方案里最省事的做法因为 MCU 不需要额外输出时钟只要老老实实接收一个干净的外部时钟就行。第二种是 STM32 通过 MCO 引脚输出 50MHz 给 PHY。F4 系列有 MCO1/MCO2 引脚理论上可以输出主 PLL 的时钟。这个方案看着很香因为它省掉一颗晶振也省掉了 PHY 输出时钟的成本。实际做起来限制很多MCO 输出频率来源于 PLL 配置想要 50MHz 就得让系统主频配合更麻烦的是STM32 自己的 RMII_REF_CLK 引脚也需要时钟。很多参考设计的做法是 MCO 先把 50MHz 送给 PHYPHY 再把自己的 REF_CLK 回送给 STM32形成一条“MCU 产出 → PHY 消费 → PHY 产出 → MCU 消费”的链路。绕一圈问题反而更多所以这个方案我建议谨慎用。第三种是外部有源晶振。50MHz 有源振荡器同时输出给 PHY 的时钟输入引脚和 STM32 的 RMII_REF_CLK 引脚。这个方案信号质量最好源端驱动能力强缺点是成本高、占 PCB 面积。对 H7 这种只能输入 RMII 参考时钟的系列来说这是最稳的选择之一。三种方案的优劣我用表格直接摊开供给方案时钟源对 MCU 的要求优点缺点PHY 自出25MHz 晶振 PHY PLLREF_CLK 引脚输入电路简单、成本低、STM32 负担小依赖 PHY 的 REF_CLK 输出能力MCU MCO 输出STM32 PLLMCO 引脚输出 50MHz少一颗晶振主频配置受限链路绕容易踩坑外部有源晶振50MHz 振铃器REF_CLK 引脚输入信号稳定、调试方便成本高多一颗有源器件1.3 谁产生、谁消费先分清身份再动手做 RMII 时钟设计前建议先画一张非常简单的草图50MHz 信号从谁出发经过谁的引脚最后到达谁的引脚。不要觉得这个动作多余我见过太多人直接照抄别人的原理图结果 PHY 型号变了REF_CLK 方向没跟着变板子回来全废。这里要说清楚一个“身份”问题STM32 的 RMII_REF_CLK 引脚永远是输入方向MAC 是消费者。PHY 在多数场景下是生产者。如果 STM32 用 MCO 做时钟源那 STM32 同时扮演“给 PHY 供时钟”和“消费 RMII 时钟”两个角色但 RMII_REF_CLK 这个引脚本身依然是输入。也就是说你可以让 MCO 输出 50MHz但你还得想办法让这个信号或者 PHY 回送的信号最终进到 RMII_REF_CLK 引脚里。判断一个电路设计是否合理最简单的方法就是看数据通路把 PHY 的 REF_CLK 输出引脚和 STM32 的 RMII_REF_CLK 引脚用一个虚拟箭头连起来如果中间断了那这个设计就有问题。2. 不同 STM32 系列对 RMII 时钟的要求2.1 F1/F4 系列既能输入也能用 MCO 输出先明确哪些型号带以太网 MAC。F1 系列只有 STM32F107 带F4 系列是 STM32F405、F407、F427、F437 等带F401/F411 这类不带。不要看到“STM32F4”就觉得有以太网选型时一定查数据手册里的外设列表。F4 系列的 RMII 参考时钟支持两种用法外部时钟输入或者由内部 PLL 经过 MCO 引脚输出。大多数人用前者因为后者有隐藏约束。我之前专门验证过 MCO 输出 50MHz 的路径F407 的 MCO1 可选源是 HSI、HSE、LSE、PLLCLKPLLCLK 实际是主 PLL 的 P 分频输出也就是系统主频那条线。如果你把系统主频配成 168MHzMCO1 的预分频只有 1~5 档出来的频率是 168、84、56、42、33.6MHz没有一档是 50MHz。想要在 MCO1 上得到 50MHz得把系统主频配成 100MHz比如外部 25MHz 晶振、PLLM25、PLLN200、PLLP2这样 SYSCLK100MHzMCO1 再除 2 得到 50MHz。这个“为了给 PHY 供时钟而改主频”的做法在高性能应用里很难接受。很多项目主频跑 168MHz 是为了算力不可能为了一颗 PHY 降频。所以 F4 平台上我最终几乎全用“PHY 自出 50MHz”方案省心又稳定。F107 的情况更特殊一点。它本身没有 MCO 到 RMII 的成熟便捷路径参考设计基本是让 PHY 侧提供 50MHz 参考时钟。你如果还在维护 F107 的老项目直接按 PHY 出时钟去查电路就对了。2.2 H7 系列ETHREF_CLK 只能输入别想着让 MCU 输出STM32H7H743、H750、H723 等带以太网的型号在 RMII 参考时钟这个问题上有一个非常明确的限制ETHREF_CLK 引脚只能作为输入MCU 内部没有路径可以把这个 50MHz 信号输出到 PHY。参考手册原意就是要求外部时钟源提供 RMII 参考时钟外部源可以是 PHY 的 REF_CLK 输出也可以是独立的 50MHz 有源晶振。这个限制直接让“MCO 输出给 PHY”的方案在 H7 上失效。我最初做 H7 板子时以为可以像 F4 那样用 MCO 绕一下结果仔细读手册才发现 H7 的 RMII 时钟路径里根本没有内部输出选项。后来老老实实把 PHY 的 CLK_OUT 引脚接到 STM32 的 ETHREF_CLK问题才解决。所以如果你的主控是 H7请直接放弃“由 MCU 给 PHY 供时钟”这个念头老老实实选一颗带时钟输出能力的 PHY或者加一颗 50MHz 有源晶振。这里还想多说一句H7 上还有一种常见组合是搭配 RTL8211F。这颗 PHY 本身支持 RMII 模式但需要认真读它的寄存器把 CLK_OUT 相关位配好否则 REF_CLK 引脚上什么都没有。2.3 选型判断时钟方案和 PHY 怎么搭配很多人一开始就被“RMII 需要一个 50MHz 参考时钟”这句话带偏以为只要找个能出 50MHz 的器件就行。实际上不同 PHY 对时钟输入的要求差异很大选 PHY 之前先想清楚你的时钟方案。如果你的方案是“PHY 自出 50MHz 给 MCU”那就得选支持“25MHz 晶振输入 内部倍频 REF_CLK 输出”的 PHY。LAN8720A、KSZ8081、YT8512 都是这一类但注意它们输出 REF_CLK 的引脚可能和中断引脚复用比如 LAN8720A 的 nINT/REFCLK0 引脚就是两用脚上电默认是中断功能需要配置寄存器切换到 REFCLK 输出或者用硬件 Strapping 让它默认输出时钟。PCB 回来后发现 REF_CLK 引脚上是乱七八糟的中断脉冲而不是 50MHz 方波多半就是这里没处理好。如果你的方案是“外部 50MHz 有源晶振”那 PHY 只需支持外部时钟直接输入即可LAN8720A 也支持把 50MHz 接到 XI 脚XT2 悬空。这个方案对 PHY 的 REF_CLK 输出能力要求不高因为 MCU 可以直接从有源晶振取同一个时钟。如果你的方案是“MCU MCO 输出”那 PHY 需要接受外部 50MHz 时钟输入同时最好支持把输入时钟回传给 MCU或者你在 PCB 上把 MCO 网络同时连到 MCU 的 RMII_REF_CLK 和 PHY 的时钟输入。后者等于用一根线拖两个负载对 MCO 驱动能力是考验而且信号反射问题也更突出。能用但没必要。3. 硬件设计实操以 F407 LAN8720A 为例3.1 25MHz 晶振方案让 PHY 自己倍频这套组合是 STM32F407 平台上最普及的LAN8720A 旁边放一颗 25MHz 无源晶振晶振接 XI 和 XO 引脚PHY 内部 PLL 倍频成 50MHz然后从 nINT/REFCLK0 引脚输出给 F407 的 PA1RMII_REF_CLK。无源晶振的匹配电容很关键。LAN8720A 的典型应用里XI/XO 对地各接一个 33pF 左右但实际上要根据晶振的 CL 负载电容换算。我看到很多人直接抄模块原理图结果晶振不起振REF_CLK 完全没有输出。一个简单规则是如果晶振规格书的 CL 是 18pF那么两颗匹配电容各取约 18~22pF如果 CL 是 12pF就取 12~15pF。走线时晶振要尽量靠近 XI/XO 引脚两个负载电容的地要短最好直接打过孔到地平面。这里还有一个硬件 Strapping 的问题LAN8720A 的 nINT/REFCLK0 引脚在空载时默认是中断输出要让它在 RMII 模式下直接输出 50MHz通常需要配置 PHY 的寄存器。有的模块在硬件上通过 Strapping 电阻强制成 REFCLK0 输出这样 MCU 上电就能直接收到 50MHz 时钟不用额外写寄存器。买模块前先问清楚自己画板则要仔细看数据手册的 Strapping 说明。3.2 外部 50MHz 方案有源晶振怎么接如果追求调试方便、信号稳定直接在板子上放一颗 50MHz 有源振荡器输出脚通过一个 33Ω 串阻分成两路一路给 PHY 的时钟输入一路给 STM32 的 RMII_REF_CLK。这里注意两个点。第一有源晶振输出电平要和 PHY 的输入要求匹配。大多数 PHY 是 3.3V 供电直接接 3.3V LVCMOS 输出没问题。如果 PHY 是 2.5V 或者 1.8V I/O最好选对应电平的有源晶振或者加电平转换不要硬接。第二分路点要靠近负载尽量减少 stub 长度。理想情况是有源晶振放在两个负载中间位置输出线先到最近的引脚再到另一个引脚。不要从晶振拉一根很长的线到板子另一端然后又分叉回来。50MHz 不算特别高但反射和振铃足以让 PHY 的输入时钟不满足电平阈值表现为 PHY ID 偶发读不到、丢包率异常。LAN8720A 在这种模式下XI 接 50MHzXO 悬空即可。注意有些 PHY 要求外部时钟输入直接接到 XI而不是 XO接反了一律不通。3.3 PCB 布线和上拉电阻细节RMII_REF_CLK 这条线在 PCB 上的优先级应该排所有以太网信号里的第一位。我的经验是线走内层或表层都可以但一定不要和开关电源、电感、DC-DC 反馈走线并行走长距离不要打太多过孔最好两个以内源端串 22~33Ω 电阻放在时钟输出端。这个串阻不是摆设它吸收反射能让示波器看到的波形上升沿更干净。再回应一个热词里出现频率很高的疑问RMII 接口的 MDC 需不需要接上拉电阻答案是分开看。MDC 是 MAC 输出给 PHY 的时钟信号推挽驱动一般不用上拉。MDIO 是双向开漏信号必须接上拉电阻典型值 2.2kΩ 到 3.3V。如果 MDIO 漏接上拉SMI 总线通信会非常不稳定PHY ID 可能读出来一次、读不出来一次但表现往往不是“完全不通”而是“时通时不通”。这和 REF_CLK 无关但很多人在排查 RMII 失败时把两件事混在一起所以特意提一句。还有一个容易忽略的点PHY 的复位引脚。很多 LAN8720A 模块把 nRST 直接拉高这样做能跑但不规范。建议至少用一个 RC 复位电路或者用一个 GPIO 控制复位复位释放时间要在电源稳定之后。如果复位时序不对PHY 内部寄存器可能处于随机状态REF_CLK 输出配置、Strapping 检测都可能出错问题看起来会非常像时钟故障。4. CubeMX HAL 的软件配置全流程4.1 引脚模式选 RMII不是选 MII在 STM32CubeMX 里使能 Ethernet第一步要选择媒体接口模式。F407 的 ETH 外设界面里会让你选 MII 或 RMII这里不能只看“功能”选 RMII 后引脚分配会完全不同。F407 选 RMII 后CubeMX 自动分配的引脚大致是信号引脚ETH_RMII_REF_CLKPA1ETH_RMII_CRS_DVPA7ETH_RMII_RXD0PC4ETH_RMII_RXD1PC5ETH_RMII_TX_ENPB11ETH_RMII_TXD0PB12ETH_RMII_TXD1PB13ETH_MDIOPA2ETH_MDCPC1如果你用的板子引脚和这个表不一致先检查是否选错了型号或者模式。这里最容易出的问题是用 F407VG 的板子抄了 F407ZE 的引脚分配RXD/TXD 接错位REF_CLK 却接到了对的引脚最后表现就是时钟正常、PHY ID 能读但 ping 不通或者数据全错。排查这种问题比排查缺时钟更费时间因为你会先去怀疑软件。还有一个细节如果 PHY 的复位引脚接了 GPIOCubeMX 里要把它配成 GPIO_Output初始电平设为低然后在初始化代码里先拉低再拉高完成一次硬件复位。不要忘了这一步。4.2 时钟树配置要不要动 PLL先说结论如果使用 PHY 自出时钟方案CubeMX 时钟树里不需要专门为 RMII 配置任何 50MHz 路径。RMII_REF_CLK 引脚上的时钟来自外部和内部的 SYSCLK、HCLK 没有关系。CubeMX 里开着 ETH 外设只要求 AHB 时钟也就是 MAC 和 DMA 的时钟正确即可F407 默认 168MHz 没问题。如果使用 MCO 输出方案这里的时钟树就要单独算。比如外部 25MHz 晶振想从 MCO1PA8输出 50MHz需要让 PLL 分频链条正好落到 100MHz 主频再除 2。PLLM25PLLN200PLLP2VCO200MHzPLLCLK100MHzMCO1 选 PLLCLK 并 div2输出 50MHz。这样 SYSCLK 是 100MHz不是常规的 168MHz。CubeMX 的 Clock Configuration 页里如果你选 MCO1 输出它会实时显示频率但你要注意它计算出来的频率是基于当前 PLL 配置的。一旦你调整 PLL 去迁就 50MHz整个系统主频都会变USB、定时器、串口波特率都可能受影响。这也是我不推荐 MCO 方案的重要原因。H7 平台更简单CubeMX 时钟树里根本没有“给 ETH 输出 RMII 时钟”的选项你只需要确认 PHY 侧的时钟源硬件OK软件配置里没有额外步骤。4.3 初始化代码从 GPIO 到读 PHY IDCubeMX 生成的 HAL 初始化代码核心是MX_ETH_Init。它内部设置 MAC 地址、DMA 描述符、接收/发送缓冲区和媒体接口选择。媒体接口选择对应寄存器是ETH_MACCR里的ECLK相关位生成的代码会通过宏ETH_MII_RMII_SELECTION区分你不必手动改。实际项目里HAL_ETH_Init成功返回后还要做几件事才能让链路真正跑起来。第一步是读 PHY ID验证 MDC/MDIO 通信是否正常。以 LAN8720A 为例它的 PHY ID 寄存器是地址 2 和地址 3通常读到0x0007C0F1这样的值。如果读出来是0xFFFF基本可以断定 MDIO 时序或者物理层供电有问题。第二步是配置 PHY 的基本寄存器比如自动协商、广播速率等。第三步是轮询 PHY 的 Basic Status Register等待 Link Up。下面是一段常用的 PHY ID 读取和 Link 判断代码结构uint32_t id1 0, id2 0; HAL_ETH_ReadPHYRegister(heth, PHY_ID1_REG, id1); HAL_ETH_ReadPHYRegister(heth, PHY_ID2_REG, id2); printf(PHY ID: 0x%04X 0x%04X\r\n, id1, id2); // 等待 Link Up do { HAL_ETH_ReadPHYRegister(heth, PHY_BSR_REG, bsr); } while ((bsr PHY_LINKED_STATUS) 0);不同 PHY 的寄存器地址不一样但思路通用。重点在于如果 PHY ID 读不出来就别继续往下调协议栈先把 50MHz 参考时钟搞定。反过来说如果 PHY ID 能读出来、Link 也能起来REF_CLK 基本就是好的剩下的问题在数据路径和协议栈配置。5. 调试实录常见问题和排查方法5.1 排查顺序先波形、再配置、后布线我自己调试 RMII 以太网时有一套固定的排查顺序可以帮你少走很多弯路。第一步永远是量波形。用示波器探头直接量 STM32 的 RMII_REF_CLK 引脚确认有没有一个稳定、干净的 50MHz 方波幅度接近 3.3V占空比接近 50%。注意要用示波器的短地线弹簧不要用那个长的鳄鱼夹地线否则 50MHz 波形看起来全是振铃根本看不出真实情况。如果 REF_CLK 引脚上没有波形再去量 PHY 的 REF_CLK 输出脚如果 PHY 也没有去量晶振两端看看是不是晶振本身没起振。如果波形是有的但 PHY ID 还是读不到第二步查复位和 MDIO 上拉。确认 PHY nRST 是否已经释放MDIO 上拉是不是接好了MDC 引脚有没有正确连接到 PHY。有时候 PHY 的地址不是 0比如 LAN8720A 的 PHYAD[0] 引脚拉高后地址就是 1程序里用 0 去读当然读不到。如果 PHY ID 能读到但 Link 起不来第三步查 RMII 信号线的映射。用万用表量 PHY 的 TXD0/TXD1/RXD0/RXD1 和 MCU 对应引脚是不是一一对应有没有交叉。这一步很蠢但很有效我至少三次在别人板子上发现 RXD0 和 RXD1 接反了波形全对就是不通。最后才轮到查布线质量和协议栈参数。REF_CLK 的走线太长、过孔太多会产生相位噪声和振铃轻则偶尔丢包重则完全不通。5.2 三个实测案例第一个案例F407 板子用 MCO 输出 50MHz示波器量 MCO 引脚发现是 25MHz 而不是 50MHz。查配置发现 CubeMX 里 PLL 设置是按 168MHz 主频来的MCO1 选了 PLLCLK 分频 4得到 42MHz跟 50MHz 完全不搭边。后来重新按 100MHz 主频配置 PLL 才输出 50MHz。但代价是整个系统的 USB 时钟跟着跑偏最后我放弃了 MCO改成 LAN8720A 自出时钟。这个案例教训很直接不要为了 MCO 方案牺牲主频除非你从一开始就按这个频率设计整个系统。第二个案例H743 板子PHY 是 RTL8211F。上电后 ETHREF_CLK 引脚完全没波形读 PHY ID 超时。我当时以为是 PHY 没配置好反复改寄存器后来才发现 RTL8211F 在 RMII 模式下默认不输出 REF_CLK需要把它的 CLK_OUT_EN 相关寄存器打开并且正确配置时钟源选择。这个问题的本质不是芯片坏了而是 PHY 的时钟输出功能默认关闭。遇到“REF_CLK 没波形”的故障除了检查晶振一定别忘了查 PHY 的寄存器配置。第三个案例一块自绘板REF_CLK 波形量出来有 50MHz但是上升沿很缓幅度只有 2V 左右PHY ID 时好时坏。检查发现是 25MHz 晶振的匹配电容用得不对晶振振荡幅度偏小导致 PHY 内部倍频出来的 50MHz 信号质量差。换了和晶振 CL 匹配的电容后波形改善问题消失。这类问题不量波形根本看不出来你以为软件配置错了实际是模拟域的问题。5.3 排查清单速查表现象可能原因处理办法REF_CLK 引脚无波形PHY 晶振未起振检查晶振匹配电容换晶振REF_CLK 引脚无波形PHY 的 REF_CLK 输出未使能配置 PHY 寄存器使能 CLK_OUTREF_CLK 引脚

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价