做嵌入式网络开发这几年,调试PHY芯片算是绕不开的硬骨头。尤其是国产PHY,价格香、供货稳,但资料和调试经验往往比国际大厂少一大截,SR8201F就是典型代表。这颗芯片在不少国产板卡和降本方案里出镜率很高,但我发现很多人第一次调它时,都卡在同一个地方:明明硬件照着参考设计画的,寄存器也能读写,可网络就是不通,或者通了一会儿又掉线。这篇文章我就把从硬件设计到LWIP移植的完整流程捋一遍,把我实际踩过的坑和验证过的方案都写出来,给正在折腾这颗芯片的朋友做个参考。
SR8201F是一颗10/100M自适应以太网PHY芯片,支持RMII和MII两种MAC接口,内部集成LDO和阻抗匹配电阻,外围电路比老一代PHY简洁很多。它和瑞昱的RTL8201F在寄存器层面基本兼容,很多ST官方评估板上用的就是这颗芯,所以只要你会调RTL8201F,SR8201F基本能无缝上手。但“基本兼容”不等于“完全一样”,实际调试中还是有几个坑,后面会专门说。
这篇内容适合正在做STM32、GD32等MCU以太网方案的朋友,也适合想把板子从进口PHY换成国产PHY的硬件工程师。软件部分我会以STM32H723+LWIP为例,因为H7系列带硬件MAC,配合SR8201F做RMII接口是当前很常见的组合。读完你至少能搞清楚三件事:硬件上哪些引脚和外围不能省,寄存器调试时每一步在看什么,以及LWIP移植后ping不通到底该从哪儿查起。
1. 整体方案设计与芯片选型思路
1.1 为什么选择SR8201F而不是进口PHY
做产品选PHY芯片,核心就三个字:稳、省、快。SR8201F在这三个维度上表现都不错。稳定性方面,它和RTL8201F寄存器兼容,软件栈可以直接复用,不用从零适配;成本方面,国产芯片在同等性能下价格优势明显,在大批量出货的场景下,一颗能省几块钱,一年下来就是可观的利润;供货方面,现在大家都有体会,进口芯片交期说不好,国产芯片至少不用担心突然断供。
但这颗芯片也有它的脾气。我实测下来,它对电源纹波比进口PHY敏感,对RMII参考时钟的精度要求也更高。如果你直接把进口PHY的电路原封不动搬过来,不加任何调整,大概率会出现链路能起来但吞吐量上不去,或者长时间运行后偶发断连的情况。所以选它之前,你得确认团队有没有能力处理这些细节问题。
1.2 整体架构:从MCU到网络的完整链路
一个典型的以太网应用,数据通路长这样:MCU内核把IP数据包交给内部MAC,MAC通过RMII接口把数据送到PHY芯片,PHY把并行数据串行化后通过差分对送到网口变压器,最后从RJ45出去。反向路径同理。
MCU (STM32H723) ├── 内部MAC (支持RMII/MII) ├── RMII接口: TXD[1:0], TX_EN, RXD[1:0], CRS_DV, REF_CLK, MDC, MDIO ├── 外部PHY: SR8201F └── 网络变压器 + RJ45这个链路里,每一个环节都可能成为瓶颈。很多人在PHY芯片上反复折腾,最后发现问题出在MAC配置上。所以调试时要把问题分层:先确认PHY寄存器能正常读写,再确认PHY是否完成自协商,最后才看MAC收发数据的正确性。顺序反了,很容易陷入死循环。
RMII接口的信号就7根,看起来不复杂,但有两个关键点:一是REF_CLK必须由外部时钟源或MAC提供,PHY不能自己产生;二是RXD和TXD的数据线只有2位,意味着数据是在50MHz时钟下双沿采样的,对信号完整性要求比MII高。SR8201F的datasheet里明确写了RMII模式下REFO_CLK既可以做输入也可以做输出,具体怎么接,后面章节详细说。
2. 硬件设计要点:从原理图到PCB的坑
2.1 电源设计:别在LDO上省钱
SR8201F内部集成了LDO,但如果外部电源质量太差,内部LDO也救不了。我见过不少板子,为了省成本用MCU的3.3V直接给PHY供电,结果就是网络时好时坏。正确做法是PHY的AVDD和DVDD分别用磁珠隔离,AVDD的滤波电容要靠近PHY芯片的电源引脚放置,至少用10uF+100nF的组合,有条件再加一个1uF。
另外一个很多人忽略的点是:如果板子上同时有DC-DC和LDO,DC-DC的开关频率正好落在PHY工作频段附近,辐射噪声会通过电源网络耦合到PHY,导致接收灵敏度下降。排查这种问题很痛苦,因为用示波器看电源纹波可能看不出问题,但网络性能就是上不去。我的建议是,PHY供电优先选择低噪声LDO,如果必须用DC-DC,输出端一定要加LC滤波。
2.2 RMII接口引脚分配与复用冲突
RMII模式下SR8201F需要一个50MHz的参考时钟。有三种接法:一是外部25MHz晶振+PHY内部倍频输出50MHz给MAC;二是外部50MHz有源晶振直接给PHY和MAC;三是MAC输出50MHz给PHY。STM32H723的RMII接口推荐第一种,即PHY的XI/XO接25MHz晶振,PHY的REFO_CLK输出50MHz给MAC的ETH_REF_CLK。
这里有个大坑:有些MCU的ETH_REF_CLK引脚不允许作为RMII参考时钟输入,比如某些型号要求REF_CLK只能由外部提供,或者只能由MAC输出。STM32H723的RMII接口是支持外部PHY提供50MHz时钟的,但你必须确保PHY的REFO_CLK配置正确。SR8201F默认情况下REFO_CLK是输出的,但如果你在寄存器配置阶段不小心把它改成了输入模式,MAC就收不到时钟,网络直接瘫痪。
引脚复用方面,STM32H723的ETH引脚可选映射有好几组,但有些引脚和SDMMC、FMC等功能冲突。设计原理图前一定要翻一遍H723的datasheet,把PA1、PA2、PC1等常用引脚确认好,别画完板子发现两个外设抢同一个引脚,那就只能飞线了。
2.3 网络变压器与RJ45的选型与接法
网络变压器的作用有三个:电气隔离、共模抑制、阻抗匹配。SR8201F的PHY侧需要阻抗匹配电阻,通常是在TXP/TXN、RXP/RXN上各串一个49.9欧电阻,并在差分线中间接一个1kV的电容到地。这些阻容元件的精度要选1%的,位置要靠近PHY芯片放置。
RJ45选型上有两种方案:分离式变压器+普通RJ45,或者带变压器的RJ45网口座。后者集成度高,Layout更省事,但变压器参数是定死的,灵活性差。前者调试方便,如果发现信号质量问题可以单独换变压器试验。我习惯用后者,因为集成座子经过大厂验证,性能有保障,但一定要选正规品牌,杂牌座子的变压器绕制工艺参差不齐,容易埋雷。
调试时最好在网口座旁预留一个测试点,方便用示波器或者网线测试仪检查链路物理层状态。有一个取巧的办法是看PHY的Link灯和Activity灯,如果Link灯不亮,问题大概率在硬件;如果Link灯亮了但ping不通,问题多半在软件配置。
2.4 PCB Layout的差分走线与地平面处理
RMII接口只有2位数据线,速率不高,按理说Layout难度不大。但REF_CLK是50MHz信号,如果走线过长或者参考地平面不连续,时钟抖动会直接导致数据采样出错。我实测过,REF_CLK走线超过3厘米且周围没有包地,网络延迟就会明显增大,极端情况下直接不通。
差分对TXP/TXN、RXP/RXN要走100欧差分阻抗,注意以下几点:差分对内部等长,误差控制在5mil以内;差分对之间拉开距离,至少3倍线宽;走线下方地平面完整,不要跨分割;PHY芯片到变压器之间的距离越短越好,最好不要超过15毫米。
还有一个细节:PHY芯片的散热焊盘一定要接地,这既是散热需求也是电气需求。不接地的话,地回路阻抗升高,导致EMI辐射增大,信号质量变差。这个位置用万用表是测不出来的,但做EMC测试时会让你欲哭无泪。
3. PHY寄存器调试:把每一步都看明白
3.1 基本寄存器读写验证
拿到板子第一步,先验证MCU能不能通过MDIO总线正确读写PHY寄存器。SR8201F的PHY地址由RX_ER/PHYAD0引脚的电平决定,常见配置是接地,所以地址为0x00。STM32H723的HAL库里有HAL_ETH_ReadPHYRegister函数,可以直接调用。
读寄存器0(Basic Control Register),如果读到0x1000到0x3FFF之间的值,说明MDIO通信正常。如果读到0xFFFF,说明PHY没有响应,大概率是PHY地址不对、MDIO引脚复用配置错误,或者PHY芯片供电有问题。如果读到全0,可能PHY芯片本身就没工作,查一下复位引脚电平是否正常。
之前遇到一个奇葩问题:用STM32CubeMX生成的代码,MDC时钟配置在2.5MHz以下,但MDIO没有配置上拉电阻,导致读出来的数据在0和0xFFFF之间跳变。加上10K上拉后问题消失。STM32的MDIO引脚内部上拉可能不够强,硬件上最好外部加一个上拉电阻。
寄存器读写验证通过后,顺手把PHY的ID寄存器读出来:寄存器2(PHYIDR1)和寄存器3(PHYIDR2)。SR8201F的ID是0x0018和0x8201,合起来是0x00188201。如果读出来是这个值,说明PHY芯片工作正常。如果ID读出来不对,先怀疑芯片型号是不是贴错了,再检查电路连接。
3.2 PHY地址配置与自协商状态检查
PHY地址引脚在芯片上电时被采样,采样完成后功能复用为其他信号。很多原理图上PHYAD引脚悬空,靠内部下拉把地址设为0,但悬空引脚容易受干扰,最好外部下拉4.7K电阻固定地址。
自协商功能是PHY芯片自动和交换机协商速率和双工模式的过程。芯片上电后,PHY会自动开始自协商,通常需要1到3秒完成。读寄存器1(Basic Status Register),如果bit5为1,表示自协商完成;如果bit5一直为0,说明自协商没成功。再读寄存器4(Auto-Negotiation Advertisement Register),确认PHY广播了哪些能力,正常应该包含10M半双工、10M全双工、100M半双工、100M全双工四项。
注意一个坑:SR8201F的自协商过程和RTL8201F有一些细微区别,具体体现在寄存器5和寄存器6的默认值上。如果你是从RTL8201F移植过来的驱动,最好在初始化时重新写一遍这两个寄存器的推荐值,而不是依赖芯片默认值。这个问题的典型症状是:网络能通,但速率协商出来总是10M而不是100M。
3.3 环回模式验证物理层通路
自协商完成后,下一步验证PHY物理层收发电通路的正确性,方法是开启PHY芯片的环回模式。寄存器0的bit14写1,PHY芯片就会把发送的数据直接环回到接收路径上,不经过网线。
这个功能非常实用,可以用它来验证MCU的MAC和PHY之间的RMII接口是否正常。操作方法是:开启环回后,MCU发一个特殊的数据帧,然后检查是否能收到相同的数据。如果能收到,说明MAC到PHY之间的数据通路没问题;如果收不到,问题就锁定在RMII接口的硬件连接或配置上。
我在实际项目中用这个方法排查过一次RXD引脚虚焊的问题。当时网络工具显示链路已连接,但MCU收不到任何数据,用示波器看RXD引脚有波形,但数据不对。开启环回后,发现即使不接网线也能收到发出去的数据,说明PHY工作正常,问题在MAC接收路径上。进一步排查,发现RXD1引脚和另外一个功能复用了,CubeMX配置时没有正确初始化。
3.4 中断引脚与LED状态的利用
SR8201F有一个中断输出引脚(INT),可以配置为链接状态变化、自协商完成等事件触发。在调试阶段,我强烈建议把中断引脚接到MCU的一个空闲GPIO上,哪怕不写中断处理函数,只是用逻辑分析仪观察引脚电平变化,也能帮你快速判断PHY状态。
LED引脚也很有用。SR8201F有两个LED输出,默认配置是LED0指示链接状态,LED1指示活动状态。如果Link灯不亮,第一件事检查网线两端是不是都是千兆交换机——SR8201F是10/100M PHY,插上千兆口时,只要交换机支持百兆协商,Link灯应该亮。如果Link灯亮了但Activity灯不闪,说明有数据包收发,问题在MAC层或协议栈。
值得注意的是,SR8201F的LED极性可以通过寄存器配置,有的模组上LED是高电平点亮,有的是低电平点亮。如果你从网上下载的例程里读LED状态寄存器的逻辑和你的硬件不匹配,会出现状态判断反的情况,调试时容易误导判断。
4. LWIP协议栈移植流程与参数配置
4.1 STM32CubeMX里LWIP配置的完整步骤
使用STM32H723时,我习惯先用CubeMX生成初始化代码,再手动修改底层驱动适配SR8201F。CubeMX的配置步骤如下:
第一,使能ETH外设,选择RMII接口。H723的RMII和MII是互斥的,只能选一个,RMII需要的引脚更少,推荐使用。
第二,配置ETH参数。在ETH的Parameter Settings里,重点检查PHY Address,默认是0,如果你的PHY硬件地址改了,这里要同步改。另一个重点是PHY Clock,即MDC的时钟分频,要求MDC不能超过2.5MHz,H723的HCLK通常是240MHz,分频系数至少要选96以上。
第三,软件包选择LWIP。在Middleware and Software Packs里勾选LWIP,然后在LWIP配置界面里选择DHCP模式或者Static模式。调试阶段建议用Static模式,手动设一个IP地址,避免DHCP交互链路出问题时还要排查两遍。
第四,配置FreeRTOS。如果要在以太网栈上跑RTOS,先在Middleware里勾选FreeRTOS,再使能LWIP的RTOS接口。
CubeMX生成的代码默认支持几个常见PHY,但SR8201F不在默认列表里。你需要在eth.c或类似文件里找到PHY ID匹配的那段逻辑,把SR8201F的ID 0x00188201加进去,或者改成直接跳过PHY ID校验。
4.2 底层驱动适配SR8201F的关键改动
CubeMX生成了HAL库的ETH驱动,理论上只要PHY芯片寄存器兼容,就可以直接用HAL_ETH_Init和HAL_ETH_Start函数。但针对SR8201F,我建议做这几个改动:
第一,PHY初始化序列。SR8201F的datasheet里有一个推荐的寄存器配置序列,主要是为了优化功耗和EMI性能。比如有的版本需要关闭EEE功能、调整LED模式、设置Class A/B驱动电流等。把这些配置放在HAL_ETH_Init之后、PHY自协商开始之前执行。
第二,链接状态检查。HAL库里有一个ETH_Start_IT的接口,如果使能了MAC中断,可以收到链接状态变化事件。但有的HAL版本对PHY中断处理不完整,需要自己在PHY中断处理函数里读寄存器1确认链接状态。更简单的方式是直接周期性轮询,虽然浪费一点CPU时间,但逻辑简单不容易出bug。
第三,RMII参考时钟配置。如果是PHY输出50MHz时钟给MAC的模式,需要在PHY初始化时确认REF_CLK引脚工作在输出模式。如果是外部晶振直接给MAC供时钟,需要检查CubeMX里是否把ETH_REF_CLK引脚配置为普通GPIO输入模式,并确认外部时钟源已经稳定输出。
4.3 FreeRTOS和LWIP的中断优先级设置
SW(软件)和ETH中断优先级的设置,在FreeRTOS+LWIP场景下容易出问题。FreeRTOS要求中断服务函数里不能调用阻塞API,而LWIP的底层驱动中断里可能会触发接收信号量,这个信号量的处理函数必须在FreeRTOS能管理的优先级范围内。
STM32H723的NVIC优先级分组通常配置为抢占优先级4位、子优先级0位。ETH中断优先级建议设置为5到7之间,不要比SysTick的优先级高,否则时间片轮转会被网络中断阻塞。如果中断优先级设置不当,典型症状是系统跑一会儿就死机,而且死机位置随机,很难复现。
CubeMX里还有一个参数叫LWIP的Thread Safe机制,如果使用了FreeRTOS,必须开启。这个选项会在LWIP内核里加锁,避免多线程访问协议栈时出现数据竞争。很多人自认为没有多线程访问需求就不开,但TCP/IP协议栈内部本身就创建了tcpip_thread线程,所以这个选项一定要开。
4.4 性能调优:内存池、描述符与DMA缓冲
LWIP移植后的性能,很大程度取决于配置而不是代码。下面几个参数需要重点关注:
MEM_SIZE指定了整个协议堆可以使用的内存池大小,默认值通常偏小,在H723上建议配置到10KB以上,不然处理稍大的HTTP请求就会报内存不足。PBUF_POOL_SIZE和PBUF_POOL_BUFSIZE则决定了收发数据缓冲的数量和大小。如果同时有多个TCP连接,建议把PBUF_POOL_SIZE设大一些,比如8个或更多,每个缓冲默认1520字节即可。
STM32H723的MAC自带DMA,描述符数量影响DMA传输效率。CubeMX里默认的接收描述符和发送描述符各有4个,如果网络吞吐量要求高,可以增加到8个以上。但要注意DMA描述符必须4字节对齐,CubeMX生成的代码已经处理好了,如果你手动修改描述符结构体定义,一定要加对齐属性。
如果网络速度上不去,排查顺序是:先看PHY协商到的速率和双工模式,再看MAC的DMA描述符数量,最后看LWIP的内存池配置。千万不要一开始就调LWIP窗口大小,那属于应用层优化,等网络基本通再考虑。
5. 常见问题与排查技巧实录
5.1 PHY寄存器读不到正确的ID
这个问题我很早就在论坛上看到过好几次,自己也遇到过。如果读寄存器2和寄存器3得到的不是0x00188201,先别怀疑芯片,按这个顺序排查:电源是否正常,复位引脚是否处于释放状态,MDC/MDIO引脚是否接对,PHY地址引脚配置是否正确,RMII参考时钟是否存在。
一个再补充一下:如果你用的是GD32或者其他国产MCU,它们的ETH外设和STM32是兼容的,但内部寄存器的地址映射可能略有差异。我之前遇到过一次,读PHY寄存器一直超时,后来发现是GD32的MDC时钟分频寄存器的位域定义和STM32不一样,需要参考GD32自己的库函数说明来初始化。
5.2 Link灯亮但ping不通
以太网物理层OK、协议层不通,这类问题要按层排查。先在MCU里确认ETH外设初始化时是否读取到了PHY自协商状态,如果没有,MAC可能会以错误的速率和双工模式工作。然后检查RMII接口的数据线,尤其RXD0和RXD1,需要看MCU里有没把这两根引脚配置为复用功能。
还有一个常见原因是MAC地址设置问题。有的以太网协议栈要求MAC地址第一个字节最低位为0,表示单播地址,如果你随便填了一个多播地址,交换机或电脑端的ARP请求根本不会回复。这个坑特别隐蔽,我在一个项目中换了3个驱动版本都没解决,最后发现是MAC地址写错了。
如果确认物理层和MAC地址都没问题,就用Wireshark抓包看电脑端发出的ARP请求,再用逻辑分析仪看RMII接口上是否有对应响应。这样可以精确定位是PHY没收到包、还是收到了但MAC没处理、还是MAC处理了但协议栈没回应。
5.3 速率协商不稳定,时快时慢
链路速率不稳定,通常是硬件信号质量问题。第一步看电源纹波,第二步看REF_CLK时钟波形,第三步看差分对走线。这三个方面,前两个可以定量测量,第三个只能靠检查和改板验证。
如果是REF_CLK时钟抖动太大,可以检查PHY芯片的晶振负载电容是否匹配。25MHz晶振的负载电容通常在18pF到22pF之间,选小了时钟频率偏高,选大了偏低,都会导致信号质量下降。这个可以用示波器量晶振波形确认,但要注意示波器探头的电容会影响振荡频率,测量结果只能做参考。
还有一类问题是由PCB走线的串扰导致的。RMII数据线D0/D1和REF_CLK在布线时如果靠得太近,时钟信号的高频分量会耦合到数据线上,导致数据采样错误。这个在高速数字设计里是很常见的现象,解决办法是时钟线和数据线之间加地线隔离,或者至少拉开2到3倍线宽的距离。
5.4 Keil调试技巧:结构体变量查看与DMA缓冲监控
在Keil里调试LWIP协议栈,最常用的操作就是查看结构体变量和内存缓冲内容。Debug模式下,在Watch窗口输入结构体变量的名字,展开可以看到所有成员。但如果结构体指针被优化掉了,可以用Memory窗口直接输入地址查看内容。
看DMA描述符时,我习惯在Watch窗口里直接监视描述符结构体里的Status成员。发送完成时,Status里的对应标志位会被硬件置位。接收描述符的Status成员则包含接收帧长度,可以确认收到的数据长度是否正确。如果你在以太网调试中收到的数据长度和实际发送的不一致,大概率是DMA描述符的大小配置不对。
LWIP的网络接口结构体struct netif在调试点很关键,可以看到IP地址、网关、子网掩码等信息。如果发现netif->flags里的LINK_UP标志位一直是0,说明MAC层没有检测到链路,问题多半在PHY;如果地址信息不对,检查DHCP状态机是否跑通。
另一个调试技巧是在Keil的Command窗口里调用函数,比如手动调用tcpip_thread等任务的调度,或者直接给某变量赋一个特殊值,触发协议栈里的错误分支。这些操作在单步调试时很有用,可以快速定位逻辑错误。
5.5 常见问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 读PHY寄存器全0xFF | MDC/MDIO连接错误或PHY未上电 | 万用表量PHY引脚供电,示波器看MDC波形 |
| 读PHY寄存器全0x00 | PHY复位未释放或芯片损坏 | 检查复位引脚电平,更换芯片测试 |
| PHY ID读取不正确 | 芯片型号贴错或引脚虚焊 | 目检PHY丝印,用热风枪补焊 |
| Link灯不亮 | 网线接口接触不良、变压器损坏、协商失败 | 更换网线,用网线测试仪查线序 |
| Link灯亮但收不到数据 | RMII接口配置错误、引脚复用冲突 | 示波器看RXD引脚波形,检查CubeMX引脚配置 |
| ping通但传输速度慢 | 协商到10M半双工、DMA描述符不足、协议栈内存不足 | 读PHY寄存器确认协商结果,调整lwipopts.h参数 |
| 一段时间后断连 | 电源纹波过大、PHY芯片过热、变压器阻抗不匹配 | 示波器看电源纹波,触摸芯片温度,更换变压器验证 |
| 大量丢包 | 描述符溢出、协议栈内存池耗尽、DMA中断优先级不当 | 查看描述符溢出标志,检查PBUF池使用率 |
6. 调试工具与效率方法
6.1 硬件工具配备建议
调以太网PHY,有些工具几乎是必需品。USB转RJ45的调试网口卡不贵,但能帮你快速验证板子的物理层是否正常,尤其是手边没有交换机的时候。逻辑分析仪最好有16通道以上,带宽100MHz起步,可以同时抓RMII接口的7根信号和PHY的LED状态信号。
示波器最好是带宽200MHz以上的,主要用来量REF_CLK时钟波形和差分信号质量。带宽不够的话,高频分量被衰减,看到的是严重失真的波形,会误导判断。数字万用表就不用说了,测电源、测地线、测虚焊都靠它。
我的习惯是先把所有工具准备好,再上电调试。因为网络问题很多时候是间歇性的,如果手忙脚乱地去翻工具,很可能错过关键的复现时机。调试记录也很重要,每次修改了什么寄存器、改了什么配置、现象如何,都随手记下来。这看起来很简单,但实际调网络问题时,往往要回溯好多步才能定位问题。
6.2 软件调试流程的标准化
经过几个项目的沉淀,我总结了一套标准化的PHY+LWIP调试流程:先硬件自检、再PHY寄存器验证、然后MAC环回测试、接着PHY环回测试、最后协议栈连通性验证。每一步有明确的通过标准,上一步没过就不进入下一步。
协议栈连通性验证时,先用静态IP在局域网内ping通,再测大包传输,比如ping -l 1472 192.168.1.100,确认DMA缓冲和TCP/IP分片逻辑是否正确。然后跑一遍UDP收发测试,再跑TCP下载测吞吐量。这个顺序下来,基本能覆盖90%的常见问题。
如果调试中遇到问题,我一般用二分法缩小范围:先看物理层(PHY状态),再看数据链路层(MAC收发),最后看网络层(IP/ARP)。物理层问题用寄存器状态和示波器定位,数据链路层用环回测试和逻辑分析仪定位,网络层问题用抓包工具和ping命令定位。这样做的好处是,每一步的排查范围都很明确,不会东一榔头西一棒子。
6.3 在FreeRTOS环境下的调试技巧
FreeRTOS环境下调LWIP,一个常见问题是网络中断里无法调用任何阻塞函数。LWIP的底层接收中断里通常只做一件事:把数据搬进描述符,释放一个信号量通知tcpip_thread去处理。如果在这里调用了osDelay或类似阻塞API,轻则影响实时性,重则死机。
另外要注意FreeRTOS的堆栈分配。tcpip_thread和各个网络应用任务的栈大小要足够,如果栈溢出,系统会运行一段时间后随机崩溃。在FreeRTOSConfig.h里开启栈溢出检测,或者用任务栈高水位标记挨个检查任务堆栈的使用量,都能提前发现问题。
中断服务函数里如果需要打印调试信息,不要直接调用printf,因为printf是阻塞的,而且可能进入临界区导致中断卡死。我一般用一个环形缓冲来暂存调试信息,在后台任务里统一输出。这个方法在处理高频网络事件时尤其好用。
7. 一次性把坑踩完的完整调试实录
最后分享一个完整案例。某项目需要把一块STM32H723板卡的以太网功能跑起来,PHY是SR8201F,软件用CubeMX生成LWIP工程,目标是实现TCP Server功能。
第一次上电,PHY寄存器读取正常,ID正确,自协商也完成了,Link灯亮。但电脑端ping不通。我用Wireshark抓包,看到电脑持续发ARP请求,但板卡没有回应。问题锁定在板卡没有正确响应ARP请求,也就是要么MAC收到了但协议栈没处理,要么MAC根本没收到。
用逻辑分析仪抓RMII接口,发现RXD0和RXD1上有数据,但CRS_DV信号异常,电平不是稳定高或低,而是一串毛刺。查了原理图发现CRS_DV引脚和另一个GPIO共用了一个焊盘,焊接时连锡了。处理完连锡问题后,ping通了。
接着测试TCP下载速度,发现最大只有3MB/s左右,和百兆理论的11MB/s差距很明显。检查PHY寄存器,协商结果是100M全双工,正常。检查DMA描述符数量,默认4个,增加到8个网络处理能力有所提升但速度还是上不去。最后查看CubeMX的LWIP配置,发现TCP_SND_BUF和TCP_WND这两个参数用的是默认值,限制了两个TCP窗口的大小。把它们从默认的几千字节调到16KB,配合描述符数量增加到16个,速度稳定到了9MB/s以上。
这个案例说明,以太网调试的每一步都是连环的,硬件问题会表现为协议栈异常,软件配置问题会表现为吞吐量不足。只有把从物理层到应用层的每一层都摸透,才能真正把方案做稳定。
我个人的体会是,SR8201F这颗芯片本身不复杂,但它对硬件设计细节的要求并不低。严格照着参考设计来是底线,关键信号走线、电源滤波、时钟精度这些都不能偷懒。软件部分,HAL库和CubeMX已经帮你挡掉了绝大部分寄存器操作门槛,真正决定你能不能稳定跑通的,是你对PHY状态机、DMA工作方式和LWIP内存管理的理解深度。把这几个点吃透,国产PHY完全可以成为你产品降本的得力选择。