ARTICLE DETAIL

资讯详情

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

STM32F407+LAN8720网口调试全攻略:RMII配置与排查链路

STM32F407+LAN8720网口调试全攻略:RMII配置与排查链路 先说结论在STM32F407LAN8720这套组合里网口不通的锅大半不在lwIP代码而在时钟、复位、PHY地址这三样东西上。我在帮朋友排查和做自己项目时遇到过代码拷来拷去、CubeMX配了半天、网口灯死活不亮的情况也遇到过Link灯明明亮了但ping不通的怪事。这篇文章就把我这几年在F407LAN8720上积累的RMII配置和调试经验完整写出来包括CubeMX关键配置项的解释、硬件上容易忽略的几个坑、以及一套从底层硬件到上层协议栈的排查链路。适合刚入门STM32以太网、画过板子但没调通过网口、以及被网口调试折磨得头大的朋友照着这个思路走能省下不少时间。1. 先别急着改代码一条RMII链路上来就有六个环节很多人一听到网口不通就打开网络调试助手或者盯着lwIP的初始化代码不放。我的建议是先停下来把整条链路在脑子里过一遍。RMII这个名字听着唬人其实就是一个MAC和PHY之间的精简接口F407内部自带MACLAN8720是PHY芯片负责把MAC出来的数字信号转成差分信号送上网络变压器和RJ45。这条链路上任何一个环节断了表象都是“网口不通”但不同环节断掉以后的表现差别很大。1.1 RMII到底在“传”什么F407 MAC与LAN8720的接口信号先看一下F407和LAN8720之间最常见的RMII信号连接这也是CubeMX配置时对应的引脚功能STM32F407引脚说明REF_CLKPA150MHz参考时钟由PHY提供给MACMDIOPA2管理接口数据线读写PHY寄存器CRS_DVPA7载波侦听/数据有效MDCPC1管理接口时钟线RXD0PC4接收数据位0RXD1PC5接收数据位1TX_ENPB11发送使能TXD0PB12发送数据位0TXD1PB13发送数据位1这九根线看起来不多但每一根都有严格的时序要求。其中REF_CLK是最核心的它决定了RMII所有信号的节奏。PA1这个引脚在CubeMX里必须被配置成ETH_RMII_REF_CLK复用功能如果配置错误或者没有信号输入MAC的收发逻辑根本没法跑起来。1.2 “看灯诊断”的心得与边界Link灯亮不代表网口通LAN8720芯片上有两个LED指示引脚分别可以接在RJ45座的Link/Activity指示上。很多人的调试习惯是看灯灯不亮就怀疑PHY灯亮了就怀疑代码。这个思路方向没问题但边界要划清楚。Link灯亮只能说明PHY芯片和对端设备路由器、交换机、电脑网口通过网线完成了物理层协商说明PHY的供电、晶振、复位这些基础条件基本是正常的。但灯亮完全不代表MAC已经拿到了数据也不代表DMA把数据包交到了lwIP协议栈。反过来如果灯都不亮那多半还没到代码层面先回去查PHY供电、晶振、复位、网线和对端设备。我见过最典型的场景是Link灯常亮但PC端ping一直超时。这种时候很多人在lwIP里折腾半天最后发现是MDC/MDIO配置问题导致读不到PHY状态或者DMA描述符没有初始化好数据压根没进MAC。所以看灯只能作为初步判断不能作为定位依据后面的排查链路才是重点。2. CubeMX里最容易“看着对、实际错”的三处配置CubeMX确实是好工具但配置完生成的代码能不能直接跑起来取决于你有没有把几个隐藏的关键点配对。下面这三点是我见过出问题的重灾区。2.1 时钟源选型为什么绝大多数板子选“25MHz晶振LAN8720 CLKOUT”RMII模式下MAC需要50MHz的REF_CLK参考时钟。这个50MHz信号怎么来直接决定了硬件的稳定性和调试难度。目前最常见的方案是在LAN8720旁边放一颗25MHz无源晶振PHY内部PLL倍频到50MHz然后从LAN8720的CLKOUT引脚输出给F407的PA1。这个方案有一个很大的好处REF_CLK的产生完全由PHY自己完成不依赖MCU的时钟状态。只要PHY供电正常、晶振正常起振CLKOUT就会稳定输出50MHzMCU侧只管当作输入收下即可。调试的时候少了一个变量出问题的概率低很多。还有一种方案是用F407的PA8引脚的MCO1功能直接输出50MHz给PHY。这个方案看起来省了一颗晶振实际用起来麻烦不少。F407要输出精确的50MHz并不是随便配一个分频系数就能做到的和外部HSE频率、PLL配置都有关系而且PA8在不少板子上还和Type-C的VBUS检测、SDIO、I2C3等外设复用。我见过一块板子PA8接了VBUS分压检测电路MCO输出直接被拉成了直流电平PHY完全没有REF_CLK网口必然不通。所以如果你不是自己设计的板子也没有仔细核算过时钟树老老实实用25MHz晶振加CLKOUT方案就好。还有一点容易被忽略CubeMX时钟树配置中ETH外设的AHB1时钟必须使能生成代码后你会看到__HAL_RCC_ETH_CLK_ENABLE()这句。如果是从标准库手改到HAL库经常有人漏掉时钟使能结果HAL_ETH_Init()一直返回HAL_ERROR等了半天才发现是时钟没开。2.2 ETH外设参数的隐藏细节PHY地址与DMA初始值CubeMX在Connectivity分类下有ETH配置页这里需要把工作模式选成RMII。很多人只改了模式就生成代码结果MDIO读写一直失败网口状态读不出来。这里有个关键参数PHY Address。LAN8720的PHY地址由PHYAD0引脚在复位时的电平决定。绝大多数开发板上这个引脚默认下拉所以PHY地址是0x00。如果你在CubeMX里填的PHY Address和硬件上的实际地址不一致比如填了0x01但硬件是0x00那么MDIO读出来基本全是0xFFFF网口必然不通。这里分享个经验如果你不确定地址是几可以先默认填0x00然后用最下面的PHY ID读取函数验证读出来如果厂商ID不对再改0x01试。DMA描述符数量和缓冲区大小先用CubeMX的默认值即可比如接收描述符4个、发送描述符4个跑通之后再去调。接收和发送描述符必须使用32位对齐的内存地址CubeMX自动生成的代码是没问题的但如果你是自己移植的比如把缓冲区定义在结构体里就要小心编译器对齐问题。2.3 GPIO复用与PA8“撞车”问题MCO、Type-C VBUS、SDIO之间的引脚冲突CubeMX生成代码后引脚分配图看起来全是绿色很多人就以为万事大吉了。实际上有几个RMII引脚如果没被正确配置成复用功能会出现一个完全无法理解的“半通不通”状态。逐个检查PA1、PA2、PA7、PC1、PC4、PC5、PB11、PB12、PB13这九个引脚确认它们都显示为ETH的复用功能。尤其是PC4和PC5这两个RXD引脚如果它们被配置成了普通GPIO输出或者处于悬空状态接收路径就废了。症状是lwIP初始化正常、PHY也正常、Link灯也亮但收不到任何包因为数据根本没送到MAC里。PA8的冲突问题在前面提过。如果你想用MCO方式给PHY提供REF_CLKPA8必须复用为MCO1同时不能有其他外设占用。但在实际项目里PA8经常被连到Type-C的VBUS检测网络、SDIO数据线、或者其他用途。一旦发生这种复用冲突MCO输出波形会被破坏而且这种问题用万用表很难发现必须用示波器看波形才能确认。3. LAN8720硬件上三个不容易注意到的坑软件配置正确但网口还是不通那就要把眼睛移到原理图和PCB上。LAN8720有几个非常典型的硬件坑网上讨论不多但一旦踩中就是大半天时间没了。3.1 PHY地址不是随便定的PHYAD0引脚的上电采样前面提到PHY地址在CubeMX里要填对这里再往深挖一层。LAN8720的PHYAD0同时也是RXER引脚的复用脚它的电平在PHY上电复位时被采样决定芯片的PHY地址。如果这个引脚通过下拉电阻接地地址是0x00如果通过上拉电阻接VDD地址是0x01。关键是这个引脚上不应该有别的信号干扰复位瞬间的电平。有的设计图省事把这个引脚直接连到了MCU的GPIO上想通过GPIO控制地址。如果GPIO在上电瞬间输出高电平而CubeMX里填的又是0x00MDIO就会一直找不到PHY。更隐蔽的是GPIO默认状态和PHY上电采样窗口并不总是一致导致每次上电结果都不一样。我建议硬件上直接用固定电阻拉低或拉高不要用MCU引脚控制PHYAD0别有那种“想在软件里切地址”的想法实际调试时只会增加不确定性。3.2 REGOFF/nINT悬空还是一起拉低寄存器关断模式的“假死”这个坑我印象极深。LAN8720A的REGOFF/nINT引脚REGOFF代表Regulator Off低有效的中断引脚。当REGOFF被拉为高电平时芯片内部稳压器会被关闭数字核心需要由外部单独提供1.2V电源才能工作。如果你的板子没有外部1.2V供电PHY就进入一个“假死”状态有3.3V供电、晶振也在震荡但MDIO读不到任何有效寄存器Link灯也不亮。很多照抄参考设计的板子在这里会出问题。参考设计里这个引脚通常接一个下拉电阻到地但有些原理图为了保留中断功能把这个引脚连到MCU的GPIO上。上电瞬间GPIO如果处于高电平或者浮空PHY就可能被关断。处理方式很简单如果你不需要PHY中断功能直接把REGOFF/nINT用10k电阻下拉到地一劳永逸。如果确实要用中断在硬件上要保证GPIO复位期间输出低并且注意上电时序。3.3 复位时序和电源滤波按下复位键偶尔活过来的原因网口出现“冷启动第一次能通断电马上重新上电就通不了”这种怪现象大概率是复位时序不对。LAN8720的nRST复位引脚需要在上电后保持一段时间的低电平给内部电源轨稳定和晶振起振留时间。很多开发板用RC电路实现复位如果RC时间常数太小3.3V还没完全稳定PHY就开始运行内部逻辑容易进入一个不确定状态。判断这个问题的方法很简单如果每次按一下MCU的复位键或者断电等几秒再上电网口就正常了那基本就是PHY复位时序的问题。解决办法是把复位RC电路的时间常数加大比如把复位电容从0.1uF换成1uF配合10k到47k的上拉电阻让复位释放时间延后几十毫秒。电源滤波方面LAN8720的模拟电源和数字电源引脚建议都放置0.1uF陶瓷电容加10uF钽电容组合去耦REF_CLK走线尽量短远离晶振和电感。我遇到过一块板子软件怎么查都没问题就是网口偶尔断流最后用示波器一看PHY电源纹波快到50mV了CLKOUT信号被纹波调制得乱七八糟。这种问题在软件层根本没法定位只能回到硬件去解决。4. 上电后先动手量这几个点比瞎猜快半天排查硬件问题示波器比瞎猜靠谱得多。每次处理网口不通我都是按固定的顺序去测量关键信号哪个点不对一眼就能看出来。4.1 示波器探针顺序3.3V、25MHz晶振、CLKOUT、nRST、MDC/MDIO下面是我常用的测量顺序和期望值可以照着这个表格来测量点期望波形/数值异常表现对应的方向PHY VDD3.3V纹波尽量小于50mV电压偏低查电源电路纹波大查去耦电容晶振XI/XO25MHz正弦波幅度约0.8到1.2V不起振查晶振负载电容和焊接CLKOUT50MHz方波0至3.3V摆幅无输出则PHY没工作或REGOFF拉高nRST上电时低脉冲然后拉高到3.3V一直低电平说明复位没释放MDC有持续脉冲频率几百kHz到2.5MHz无脉冲说明MAC没在对PHY操作MDIO读写时有不规则数据波形只有高电平或只有低电平说明通信异常测晶振有一点要特别注意探头要用10倍衰减档因为探头本身有电容直接挂上去可能导致晶振停振或者幅度失真。如果看到晶振幅度明显偏低不要急着下结论先拿掉探头再确认一次。CLKOUT是判断PHY是否真正工作的关键信号。如果你用的是25MHz晶振方案PHY上电后CLKOUT应该立刻输出50MHz方波。如果这个信号没有说明PHY的电源、晶振、REGOFF这些环节里有问题连MAC都不用去查。4.2 静态检查网络变压器与RJ45的端接软件和信号都查完了还是找不到问题就得回头看看网络变压器和RJ45部分的电路。LAN8720的发送输出是TXP/TXN差分对经过网络变压器后再接到RJ45。变压器中心抽头的处理方式、共模电阻和端接电容取值不同PHY芯片的要求不完全一样。经常有人把原来给DP83848设计的电路直接改成LAN8720结果出现Link能协商上但数据全错的情况。这通常就是变压器中心抽头和端接参数不匹配导致的。这种问题示波器在RMII侧很难看出来因为MAC和PHY之间的信号都是正常的问题出在PHY到RJ45的模拟链路上。这种问题只能靠对照LAN8720数据手册的参考电路重新核对原理图。5. 软硬联调的排查链路从PHY ID到lwIP回包硬件信号都测过了还是不通或者Link灯正常但ping不通这时候就要沿着软件链路一层一层往上查。我的习惯是先把PHY寄存器读通再查MAC和DMA最后才看lwIP。5.1 先读PHY寄存器验证MDIO链路是否活着不要一上来就初始化lwIP先写一个简单的函数去读PHY芯片的ID寄存器确认MDIO管理链路是通的。HAL库提供了现成的读寄存器函数代码很简单#include main.h extern ETH_HandleTypeDef heth; static int lan8720_check_phy(void) { uint32_t id1 0, id2 0, bsr 0; if (HAL_ETH_ReadPHYRegister(heth, 0x00, 2, id1) ! HAL_OK) { printf(read PHY ID1 failed\r\n); return -1; } if (HAL_ETH_ReadPHYRegister(heth, 0x00, 3, id2) ! HAL_OK) { printf(read PHY ID2 failed\r\n); return -2; } printf(PHY ID1 0x%04X, ID2 0x%04X\r\n, (unsigned)id1, (unsigned)id2); if (HAL_ETH_ReadPHYRegister(heth, 0x00, 1, bsr) HAL_OK) { printf(PHY BSR 0x%04X\r\n, (unsigned)bsr); if (bsr (1UL 2)) { printf(Link is UP\r\n); } else { printf(Link is DOWN\r\n); } } return 0; }注意这段代码必须在HAL_ETH_Init()成功之后才能调用因为MDC/MDIO引脚的硬件初始化是在Init里面完成的。正常情况读出来的ID1是0x0007ID2是0x13F4左右不同批次可能有细微差异。如果读出来是全0或者全F先查PHY地址、MDIO引脚配置、REGOFF是否被拉高。如果打印都没有先确认串口通没通别笑我曾见过一个人调了半天PHY最后发现串口波特率配错了输出全是乱码他以为程序死掉了。BSR寄存器第2位是Link Status读出来为1表示物理链路已经建立。如果ID读得出来但Link Status为0说明MDIO链路是好的问题出在网线、对端设备、网络变压器或者PHY的协商配置上。5.2 Link正常却ping不通MAC/DMA/lwIP的检查顺序ID正常、Link也正常、但ping依然不通这时候问题集中在MAC初始化、DMA接收、lwIP收包这几层。我的排查顺序很固定先确认ETH中断已经使能并且在中断服务函数ETH_IRQHandler里调用了HAL_ETH_IRQHandler(heth)。如果中断没进来收到的数据包就永远没有人处理。确认lwIP初始化时ethernetif_input被正确调用。用CubeMX加FreeRTOS的组合时常见的做法是在HAL_ETH_RxCpltCallback回调里把收到的数据包投递到线程消息队列。检查MAC地址。给lwIP使用的网卡MAC地址不要全0有些网卡驱动对全0的MAC会有问题。虽然理论上全0也能发但实际调试时各种奇怪问题都有。如果有串口调试信息打开lwIP的DEBUG选项在PC端ping的同时启动Wireshark抓包看PC发出去的ARP请求有没有进到MCU侧。一个特别隐蔽的问题如果你的板子跑到了低功耗模式比如进入了STOP模式ETH的AHB1时钟可能被关掉。恢复后如果没重新使能ETH时钟和重新初始化DMA网口就会一直“假死”。嵌入式开发里常遇到“程序跑飞断电重启就正常”的情况排查手段就是把所有可能被低功耗关闭的外设查一遍。5.3 实在不行就上逻辑分析仪抓RMII当整个代码链路看起来都没问题但数据就是不通逻辑分析仪是最好的工具。RMII信号也就九根线用逻辑分析仪把TXD0、TXD1、TX_EN这三根信号挂上然后在PC端ping一个包。如果看到TX_EN拉高并且TXD上有电平变化说明MAC确实把数据发出来了。如果TX_EN一直保持低电平说明MAC侧没有数据在发送问题大概率还在初始化或者上层没触发发送。查接收方向就抓CRS_DV、RXD0、RXD1。如果CRS_DV拉高并且RXD上有电平翻转说明PHY把接收数据送出来了。如果RXD始终是0那数据根本没有从PHY到MAC这条线上问题在PHY或物理链路。逻辑分析仪采样率不用太高100MHz以上就行抓几十毫秒就够判断问题方向了。这个方法看着土但定位效率非常高省得反复猜测是MAC问题还是PHY问题。6. 量产/自绘板常见的“看似正常但网口抽风”的延展排查如果你的板子已经能ping通了但时不时的出点小毛病或者从开发板搬到自绘板上之后出现各种奇葩现象那恭喜你进入了下半场这些问题的根因往往在PCB和信号完整性上。6.1 能通但不稳定、掉包先查REF_CLK抖动最典型的就是网口能通但Ping大包或者长时间通信会掉包。先用示波器看PA1上的50MHz REF_CLK波形如果能看到明显的抖动或者毛刺很大概率是时钟被干扰了。检查一下25MHz晶振附近有没有走开关电源的线晶振的负载电容是不是和数据手册一致LAN8720的模拟电源引脚有没有加磁珠和电容滤波。如果是两层板REF_CLK走线旁边尽量不要有长距离的电源平行走线。如果是四层板晶振正下方的地层要完整不要被信号线割裂。这些PCB层面的问题在开发板上通常不明显因为开发板布线质量普遍比较讲究一到自己的板子上问题就暴露了。6.2 只有10M能Link、100M起不来多半是差分信号质量问题10M能协商上100M起不来这是RMII接口最常见的高速问题。100M以太网的UI只有10ns每一个REF_CLK周期要采两个数据位任何一根TXD或RXD走线过长、阻抗不连续、串联电阻过大都会让100M模式下误码率飙升。自查思路检查PC4、PC5、PB12、PB13这几根线上的串联电阻有的人为加泪滴或走线修补导致走线长度差异过大。虽然RMII不像差分对那样严格但TXD0和TXD1之间、RXD0和RXD1之间的走线长度最好控制在一个厘米量级以内。软件上有一个缓解手段把CubeMX里ETH接收DMA描述符的数量从默认的4个加大到8个或16个压力大时能减少因为描述符耗尽导致的丢包。但话说回来这只是治标信号质量的问题不解决数据量一上来照样出问题。6.3 温度、静电和线缆对RMII信号的影响最后说两个平时很少注意、但量产最容易爆雷的场景。低温环境下网口偶尔握手失败可以先查晶振起振。晶振和负载电容匹配不好时低温下起振时间会变长甚至完全起不来。如果产品要过-20度低温建议低温摸底测试时把网口上电握手这部分重点盯一下。ESD静电测试把网口打挂先检查LAN8720的复位脚和REGOFF/nINT脚有没有加保护。这两个脚一旦被静电打进去芯片可能就锁死了。软件上可以在主循环里定时读PHY的Link状态发现异常时自动重新初始化PHY算是一个兜底方案。我自己的项目里就有类似的看门狗逻辑读PHY寄存器连续失败几次就整个重新初始化ETH和lwIP虽然不能解决硬件问题但至少设备不用断电重启。调试网口这套东西最忌讳的就是没有章法地瞎试。先量硬件信号再读PHY寄存器然后查MAC和DMA最后才动协议栈按这个顺序走下来你会发现大部分问题都能定位到具体那一层。拿我个人经验来说只要把REF_CLK、复位时序和PHY地址这三个东西确认好F407加LAN8720的组合基本就能稳了。
返回列表