ARTICLE DETAIL

资讯详情

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

STM32以太网RMII参考时钟详解:从硬件接法到排查流程

STM32以太网RMII参考时钟详解:从硬件接法到排查流程 前阵子调一块STM32F407LAN8720A的网口板子遇到了一个非常典型的毛病代码是CubeMX生成的网线插上后LINK灯死活不亮PHY ID读出来一直是0xFFFF。折腾到快周末最后才发现问题出在RMII Reference Clock上。别看它只是一个时钟引脚在STM32的RMII接口体系里这个50MHz参考时钟的来源、接法和布线基本决定了以太网链路能不能稳定建立。这篇文章就把这个点彻底讲透覆盖时钟来源选型、硬件接法、PCB布线、MDC/MDIO上拉、以及一套可以直接照搬的排查流程给正在做STM32以太网项目的朋友一个完整的参考。1. 为什么RMII参考时钟会成为STM32以太网设计的“翻车点”1.1 RMII接口与MII的本质差异以太网MAC和PHY之间的接口在STM32上最常见的是MII和RMII两种。MII是经典接口数据线有16根100Mbps时时钟是25MHzRMII是精简版数据线被砍到4根——TXD[1:0]、RXD[1:0]再加上TX_EN、CRS_DV、REF_CLK总共也没几个引脚。为了让数据速率不降低RMII在100Mbps模式下把时钟提到了50MHz用双倍速率去补位宽减半带来的吞吐损失。RMII这个名字里的“Reduced”本质是靠提高时钟频率来换引脚数量。而REF_CLK这根50MHz时钟是整个RMII接口运行的基准。MAC用它来采样发送和接收数据PHY内部也用它来同步收发状态机。如果这根线有问题后续所有信号都不可信。1.2 STM32参考手册的硬性规定很多人第一次做STM32以太网直觉上会认为“时钟当然由MCU产生然后分给PHY”但在RMII模式下事情正好反过来。STM32参考手册Ethernet章节里写得很明确RMII_REF_CLK必须由外部时钟源提供MCU内部不负责产生这个50MHz参考时钟。这并不是芯片偷工减料而是时序架构决定的。RMII的数据采样关系是MAC以REF_CLK为基准去采集PHY发来的RXD信号以及PHY以REF_CLK为基准去采集MAC发来的TXD信号。如果这个时钟由MCU内部PLL产生时钟边沿的抖动和相位噪声以及从MCU到PHY的长距离传输延迟都可能破坏接收端的建立/保持时间窗口。所以芯片设计时干脆把PA1ETH_RMII_REF_CLK做成纯输入外部给你什么时钟RMII就用什么时钟。1.3 时钟异常时的典型表现时钟没接对最常见的是下面这几种现象网上一搜一大片PHY ID读出来是0xFFFF或0x0000MDIO通信看起来完全不通LINK状态一直在down插不插网线LED都没反应偶尔能Ping通一次但紧接着就断反复无常网速异常100M协商成10M或者干脆协商失败上电能通跑一段时间发热后开始丢包换了块板子同样代码就正常莫名奇妙其中“偶尔能Ping通一次”最坑人会让人怀疑是协议栈问题、中断配置问题、还是DMA问题实际上时钟源没到位时数据采样本来就是在错误边缘挣扎结果当然不稳定。2. 50MHz参考时钟的三种来源方案怎么选、怎么接2.1 方案一独立有源晶振直供最直接的办法是一颗50MHz有源晶振同时把时钟送给PHY和STM32。有源晶振是四脚器件VCC、GND、OUT、NC有些带使能脚EN内部集成了振荡电路输出已经是干净的方波或削波正弦波不需要外部负载电容。接法上有源晶振的OUT脚接到PHY的REF_CLK/XI引脚同时并一根线到STM32的PA1ETH_RMII_REF_CLK。注意PA1在这个模式下配置为复用功能输入CubeMX会自动处理。选型时注意几件事供电电压要和IO电平匹配常用3.3V输出电平也要在接收端可接受范围内LVCMOS是比较通用的选择频率精度选±30ppm以内足够。这种方案我测试下来是最稳的。时钟源完全独立PHY和MAC拿到的是同一个源的同步时钟不存在“两个芯片各自依赖不同晶振频率漂移互相拉扯”的问题。缺点是成本高一点而且PCB上要预留一个有源晶振的位置。2.2 方案二通过PHY内部电路产生由CLKOUT输出给MAC如果你用的是带时钟输出的PHY芯片比如最常见的LAN8720A事情会更简单。LAN8720A的XI/XO脚外接一个25MHz无源晶振PHY内部通过PLL倍频到50MHz然后从CLKOUT引脚输出50MHz时钟直接接到STM32的PA1。这种接法的关键在于PHY内部PLL倍频出来的时钟和PHY内部所有收发逻辑天然同步再把这个时钟送给MACMAC和PHY也是同源。另外25MHz无源晶振比50MHz有源晶振便宜PCB上占的地方也小所以大量开发板和商品模块都采用这种方式。接线要点25MHz晶振接LAN8720A的XI/XO两个负载电容常见18pF或22pF按晶振规格选择分别到地CLKOUT引脚接STM32的PA1如果模块上已经焊好了晶振确认模块是否把CLKOUT引出来了买模块的时候要留意市场上LAN8720A模块有两种版本一种板上已经带了25MHz晶振并把CLKOUT引到某个排针另一种没有晶振需要你从外部输入时钟。买之前先看原理图省得拿到手才发现缺一堆东西。2.3 方案三MCO输出——看起来可行实际不建议用CubeMX里能看到PA8可以输出MCO1或MCO2STM32主频168MHz时很容易用PLL分频得到50MHz。于是有人想能不能用MCO输出50MHz给PHY的REF_CLK省掉一颗有源晶振这个思路不能说错但STM32参考手册明确不推荐。核心问题有两个一个来自抖动。MCO的时钟源是MCU内部PLLPLL输出本身就有一定的抖动和相位噪声RMII接口对REF_CLK的相位抖动是有要求的PLL直接输出的时钟在长时间运行中不一定能满足这个指标。另一个来自时钟同步。MCO输出的时钟和PHY正常工作时使用的时钟源不是同一个源头即使频率都是50MHz两个时钟之间的相位偏移会随着温度、电压变化而漂移最终导致采样边沿和数据变化沿逼近临界点。也有人试过MCO方式确实能跑通短时间、低负载、室温环境下看起来一切正常。但做产品不能赌这个运气温度一变、电压波动一大丢包就开始了。我的建议是MCO这个方案最多用来做实验室原型验证量产产品一律用独立晶振或PHY时钟输出。2.4 方案对比与选型建议方案成本可靠性布线复杂度适用场景独立50MHz有源晶振中高低对稳定性要求高的批量产品PHY内部晶振CLKOUT低高低开发板、大多数项目MCO输出无低低仅验证不建议量产看这张表应该很清楚了不用纠结首选方案二用PHY自己的晶振电路加CLKOUT输出如果你用的PHY不支持时钟输出或者你想把时钟源和PHY解耦得彻底一点就用方案一。方案三拿来应急可以别带到产品里去。3. 系统时钟树、晶振精度和抖动这些细节不达标也白搭3.1 100BASE-TX对时钟精度到底要求多少以太网100BASE-TX标准里对时钟精度的要求是±50ppm。ppm是百万分之一所以50MHz允许的误差是50MHz乘以50再除以1000000等于2500Hz。普通无源晶振的精度在±10ppm到±50ppm之间选±30ppm以内的晶振就足够满足要求。要注意的是温度和老化会让晶振频率发生偏移。室内环境用普通晶振没问题如果产品要工作在室外高温或低温环境建议选工业级晶振条件允许的话用温补晶振TCXO把温漂对时钟精度的影响压到最小。我处理过一个室外网关夏天LINK灯偶尔会闪断换温补晶振之后再没出现过。3.2 抖动为什么是RMII的隐形杀手精度管的是长期频率误差抖动管的是每个时钟边沿的短期位置偏移。RMII在50MHz下一个时钟周期是20ns数据必须在时钟边沿附近保持稳定建立时间和保持时间通常只有几纳秒。如果参考时钟的抖动大边沿位置忽前忽后采样点就可能落在数据变化沿附近导致采到的数据不确定。有源晶振的抖动一般能做到皮秒级PHY内部PLL的抖动也在可控范围。而MCU内部PLL因为要同时给CPU、总线、外设供时钟负载变化会引起锁相环环路波动抖动的绝对数值可能比独立晶振大一个数量级。这就是为什么MCO方案虽然频率对了但实际容易出问题。3.3 STM32不同系列的差异提醒不是所有STM32都强制要求RMII参考时钟来自外部。STM32H7系列在RMII模式下可以通过寄存器选择内部PLL作为参考时钟源这是芯片设计层面的不同。如果你用的是H7可以打开这个选项但我测过H743的板子最终还是优先走外部时钟源原因很简单内部PLL在系统负载变化时抖动还是会跟着变外置时钟源把不确定性降到最低。F4系列内核最高168MHzF7系列更高H7更是跑到了480MHz但无论系统主频多高RMII的50MHz参考时钟该从外部来还是从外部来。系统时钟和RMII时钟不是同一个域别因为主频高就以为RMII时钟可以顺便产生。4. MDC/MDIO上拉电阻到底接不接、接多大、什么时候接4.1 MDC和MDIO在RMII里的角色RMII除了数据线和时钟线还有两根管理线MDC和MDIO。MDC是管理时钟由MAC产生频率通常2.5MHzMDIO是双向数据线用来读写PHY的寄存器。这两根线合起来叫SMI接口STM32通过它来读PHY ID、配置PHY工作模式、查询LINK状态。网上经常有人问“RMII接口MDC需要接上拉电阻吗”说明这里确实是个高频困惑点。答案要先分清角色MDC是时钟线由MAC推挽驱动MDIO是数据线双向传输协议上采用漏极开路/三态方式。4.2 结论MDC通常不用上拉MDIO必须上拉MDC既然由MAC推挽输出逻辑电平由MCU直接驱动本身不需要外部上拉。走线短、环境干净的情况下MDC悬空完全没问题。极个别PHY手册会建议在MDC上串一个几十欧电阻改善边沿但和上拉不是一回事。有些开发板在MDC上也放10kΩ上拉那是为了兼容某些特殊PHY或者抗静电不是RMII协议的普遍要求。MDIO则必须上拉。它是开漏结构没有外部上拉的话高电平根本没能力被拉起来读PHY寄存器大概率返回0xFFFF。上拉电阻选择1kΩ到10kΩ推荐2.2kΩ或4.7kΩ上拉到PHY的VDDIO常见3.3V。走线长或者SMI总线上挂了多个PHY选小一点比如2.2kΩ单PHY短走线10kΩ也行。4.3 一个真实排查案例之前自绘的一块板子MDIO没加上拉结果现象很随机上电10次有7次读不到PHY ID剩下3次能读到。用示波器量MDIO波形低电平能被拉下去但上升沿爬得非常慢慢到快到下一个采样点还没稳定。补了一颗4.7kΩ上拉后波形上升沿明显变陡PHY ID每次都能稳定读到。教训是不要觉得PHY内部有弱上拉就万事大吉内部弱上拉在短走线和低速情况下可能够用但PCB走线一长寄生电容变大弱上拉的驱动力就不够了。MDIO外部放一颗4.7kΩ成本一毛钱不到能省掉一整天的排查时间。5. PCB布局布线50MHz时钟线不是随便拉一根飞线就能跑的5.1 从晶振到PHY布线的几条硬规矩参考时钟是高频模拟信号虽然50MHz不算特别高但现代晶振的边沿很陡处理不好既容易辐射干扰别的信号也容易被别的信号干扰。晶振要放在PHY芯片旁边离REF_CLK输入引脚越近越好。时钟线不要走太长不要跨过地平面分割不要和电源开关节点、PWM信号、电机驱动线之类的高干扰信号平行走线。晶振下方的地平面要完整最好在晶振正下方铺一块完整地铜给时钟信号提供清晰的回流路径。如果走线超过10mm串一颗33Ω电阻在时钟源输出端可以吸收反射让波形更干净。5.2 从PHY到STM32REF_CLK走线的处理从PHY的CLKOUT或独立有源晶振的OUT到STM32的PA1这段走线同样重要。尽量短、尽量直避免过多过孔过孔会引入额外的寄生电容和电感影响时钟边沿完整性。如果空间允许把这条时钟线两侧包地即在线两边铺地铜并打上过孔把时钟信号和其他数字信号隔开。它和数据线之间至少留出3倍线宽的距离。RMII的其他信号线——TXD[1:0]、RXD[1:0]、TX_EN、CRS_DV——一组走线内部尽量保持等长和REF_CLK的走向尽量一致减少组内偏斜。5.3 电源去耦和地平面PHY的电源引脚去耦电容要靠近引脚放置典型做法是每个电源引脚放一个100nF靠近芯片根部。LAN8720A这类PHY还有内部稳压输出引脚比如VDDCR它的外接电容一定不能省而且要走线短直接回到PHY地。晶振的负载电容也不能随意更换换大了不起振换小了频率偏高按PHY数据手册和晶振规格书来选。这些细节单独看都不起眼但叠加起来就是“为什么同样的电路别人画的板子稳如老狗你画的板子一摸就死机”的差别。6. 实战排查插上网线不通如何一步步定位到参考时钟6.1 排查链路从现象到根因如果你是照着别人的原理图做的板子或者用开发板改了改插上网线不通别急着怀疑协议栈按下面这个顺序排查第一步量PHY的晶振引脚。用示波器10x探头看25MHz晶振两端有没有振荡波形。有振荡、幅度正常说明晶振起振没问题。如果完全没有波形或者幅度异常先查晶振负载电容、并联电阻、供电这是最基础的。第二步量CLKOUT或REF_CLK引脚确认有没有50MHz时钟。LAN8720A的CLKOUT如果有输出说明PHY内部PLL工作正常。如果没有输出再看XI/XO有没有25MHz波形有的话说明PHY没正常进入RMII模式或者PHY的复位/配置引脚状态不对。第三步量STM32的PA1引脚确认50MHz信号确实到了MCU的引脚。这一步很关键很多飞线方案在PHY那边有50MHz但线断了或者没接到PA1MCU这边根本没有时钟系统当然跑不起来。第四步跑一个最小的ETH初始化代码读PHY的寄存器。如果PHY ID读出来还是0xFFFF再回头查MDIO/MDC信号、上拉电阻、PHY地址配置。第五步用逻辑分析仪或者示波器看RMII信号线。插上网线后PHY应该能检测到LINK状态变化CRS_DV应该有电平变化。如果LINK信号都完全没有问题大概率在PHY相关电路而不在MAC。这个顺序是从时钟到数据、从底层到上层一步一步缩小范围10分钟左右就能定位出到底是“时钟没过来”还是“PHY没起来”还是“MDIO链路断了”。6.2 用PHY寄存器验证链路是否正常读PHY寄存器是验证RMII链路最直接的手段。在HAL库环境下PHY ID的读取代码大概长这样uint32_t id1 0, id2 0; if (HAL_ETH_ReadPHYRegister(heth, PHY_PHYSID1, id1) ! HAL_OK) { printf(Read PHY ID1 failed\r\n); } if (HAL_ETH_ReadPHYRegister(heth, PHY_PHYSID2, id2) ! HAL_OK) { printf(Read PHY ID2 failed\r\n); } printf(PHY ID: 0x%04X 0x%04X\r\n, id1, id2);不同HAL库版本里PHY_PHYSID1这些宏定义可能不一样有时候需要自己写寄存器地址。PHY寄存器2和3存放的是PHY IDLAN8720A读出来一般是0x0007和0x0000。如果读出来不对要么MDIO链路有硬件问题要么PHY根本没工作。6.3 模块电路的坑买现成LAN8720A模块时要注意区分版本。我看到过的模块就有两种一种板上焊了25MHz晶振并且把CLKOUT引脚引出来了另一种没有晶振只能靠外部输入时钟。如果买了第二种还按第一种去接自然跑不通。还有一种情况是模块把CLKOUT留在中间的焊盘上产品上用就很麻烦。自己画板时如果用了LAN8720A务必把CLKOUT引出来哪怕当前设计用独立有源晶振也多一个备选方案。另外确认模块供电是3.3V别用5V把PHY烧了。7. CubeMX与软件配合把硬件时钟接到位之后7.1 CubeMX中打开ETH的RMII配置在STM32CubeMX里Connectivity-ETH使能外设Interface选择RMIIExternal PHY Address按实际PHY地址填写LAN8720A默认是0。CubeMX会自动把PA1映射成ETH_RMII_REF_CLK并配置为复用功能输入不用手动去改GPIO模式。时钟树配置里ETH外设的时钟选项一般保持默认即可因为RMII的50MHz参考时钟来自外部不走MCU内部PLL所以系统主频怎么配置都不会直接影响这个50MHz。但系统主频如果太低MAC自身的时钟也可能受限保持系统时钟在合理范围即可。7.2 初始化顺序与验证代码一个常见的坑是ETH初始化代码在PHY复位后马上执行PHY的晶振还没稳定读寄存器自然失败。正确做法是上电后延时几百毫秒让PHY和晶振先稳定下来再执行HAL_ETH_Init然后再通过MDIO读取PHY ID验证链路。比较好的模式是写一个检查函数把读PHY ID、读PHY BSR寄存器、判断LINK状态这些动作封装起来初始化时多试几次失败就打印错误信息。这样既能快速定位问题也让产品上电过程更健壮。7.3 延伸应用提醒当你把RMII参考时钟的硬件链路搞稳定之后再往上跑LWIP、HTTP Server、MQTT这些协议栈才会省心。很多人在移植STM32 HTTP库或者用LWIP做数据上报时频繁掉线第一反应是查协议栈配置实际上根源往往在底层——RMII参考时钟的波形不好、幅度不够、或者时钟源不稳定。我在几个联网采集项目里总结出的规律是上层协议不稳定先回头量一下PA1上的50MHz波形比翻协议栈代码快得多。如果你的产品用在条件比较苛刻的场合比如室外、高温、长距离网线优先考虑方案一独立有源晶振或带温补的晶振别在时钟上省成本。这套RMII Reference Clock的问题排查完了以太网基本就能站稳了。
返回列表