拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

STM32F407VET6最小系统与以太网实战:RMII+LAN8720A+LWIP方案详解

STM32F407VET6最小系统与以太网实战:RMII+LAN8720A+LWIP方案详解

做了这么多年嵌入式,兜兜转转最后还是绕不开STM32F407这棵常青树。尤其是在需要跑以太网、又不想上Linux、还得控制成本的场景里,F407VET6几乎是绕不开的选择。最近又用这颗芯片从零搭了一套带网口的最小系统板,把这中间的设计思路、硬件细节、软件配置和踩过的坑一起整理出来。这篇东西适合刚入门想自己画板子的朋友,也适合那些手上拿到F407VET6却不知道怎么把以太网跑起来的人,我会尽可能把原理讲透、把参数落到具体值上,保证你照着做能出活。

先说清楚一件事:F407VET6和F407ZGT6最大的区别是引脚数和Flash大小。VET6是100脚LQFP封装,512KB Flash,192KB RAM,内置Cortex-M4F内核带FPU,主频能到168MHz。100脚封装的代价是很多外设引脚被复用或者干脆没有引出。比如USB OTG FS的D+/D-是PA11/PA12,100脚封装里还在,但USB HS需要的ULPI接口那些引脚就砍掉了,这个后面讲USB和以太网方案时会重点提到。对于绝大部分工控、数据采集、通信网关类应用来说,VET6的引脚资源完全够用,而且价格比ZGT6便宜不少,这也是它成为经典款的核心原因。

以太网这块,F407内置了MAC层,但物理层PHY必须外接。常用的方案有两种:一是用RMII接口接一颗LAN8720A,引脚少、价格低,适合自己做板子;二是用MII接口接DP83848这类PHY,引脚多、性能稳,适合复杂工业场景。我这次选的是RMII + LAN8720A,原因很简单:100脚封装下MII接口的16根信号线实在有点挤,而RMII只要7根线,布线压力小很多。后面会把这7根线的每一个细节和时钟方案讲透。

这里先给一个整体的硬件架构图,方便你理解后面的内容:

STM32F407VET6 (内置以太网MAC) | |--- RMII接口: TXD[1:0], RXD[1:0], TX_EN, CRS_DV, MDC, MDIO | LAN8720A (外部PHY芯片) | |--- 网络变压器 HR911105A (带RJ45座) | 网线 -> 交换机/路由器/PC

在动手写代码之前,一定要把最小系统和以太网硬件这部分吃透。我见过太多人一上来就抄别人的例程下载到板子里,结果ping不通就怀疑代码有问题,其实十有八九是硬件设计埋了雷。这篇博文会从最小系统的电源、时钟、复位、启动模式讲起,再重点拆解以太网PHY的硬件设计和软件配置,最后把LWIP协议栈跑起来,整个过程一步步来。

1. 内容整体设计与思路拆解

1.1 为什么选F407VET6而不选F103或F429

芯片选型这事很容易纠结,尤其是新手。如果你正在几个型号之间犹豫,我给一个比较实在的判断标准:看你要不要跑以太网、要不要做浮点运算、以及IO口够不够用。

F103系列,比如最常见的C8T6,主频72MHz,没有FPU,没有以太网MAC。想跑网络只能用SPI接口外挂ENC28J60这种不带MAC的PHY,速率上限10Mbps,实际吞吐量能跑到3~4Mbps就算不错。做个小数据采集勉强能忍,但稍微上点流量就露馅。C8T6的ROM只有64KB,跑个轻量级RTOS加协议栈就快满了,扩成F103ZET6倒是够,但价格也不便宜了。

再看F429系列。它比F407多了LCD控制器和SDRAM控制器,主频一样是168MHz,但LQFP100封装的F429VIT6价格比F407VET6贵30%以上。如果你不需要屏幕和外部SDRAM,这部分成本就成了纯浪费。而且F429的以太网MAC、USB、DCMI这些外设在100脚封装下的引脚布局和F407几乎一致,F407能做的事F429基本也都做,反过来也一样。

剩下的F407VET6就显得很能打:168MHz带FPU的Cortex-M4F,512KB Flash,192KB RAM,内置10/100M以太网MAC,支持MII和RMII两种接口,还带两个I2C、三个USART、两个CAN、一个USB OTG FS、三个SPI、一个DCMI摄像头接口,以及一大堆定时器和ADC。这个外设组合对多数嵌入式联网设备来说,属于“够用但不过剩”的甜点区间。

我自己选型时会做一张对比表贴在实验室墙上,这里也整理出来给你参考:

项目STM32F103C8T6STM32F407VET6STM32F429VIT6
内核Cortex-M3 @72MHzCortex-M4F @168MHzCortex-M4F @168MHz
FPU无单精度单精度
Flash/RAM64KB/20KB512KB/192KB2MB/256KB
以太网MAC无有(10/100M)有(10/100M)
封装LQFP48LQFP100LQFP100
价格区间(参考)低中高
典型场景简单控制、传感采集联网网关、电机控制带屏显控一体

选F407VET6还有一个隐性优势是生态。网上关于这块芯片的资料、例程、问题解答数量非常庞大,踩坑成本比冷门芯片低得多。Keil、IAR、STM32CubeMX全都完美支持,连开源社区里RT-Thread、FreeRTOS、lwIP的适配都很成熟。这意味着一半的开发工作其实已经有现成的轮子了,你只需要理解怎么用。

1.2 最小系统的本质:供电、时钟、复位、启动模式与调试接口

一个MCU要跑起来,核心就五件事:供电要稳定、时钟要起振、复位要可靠、启动模式要正确、调试接口要能连上。很多人买核心板用着挺好,一到自己画板子就出各种稀奇古怪的问题,基本都是这五件事里有某个环节没做到位。

先看供电。F407VET6需要三组电源:VDD主电源(1.8V~3.6V,典型3.3V)、VDDA模拟电源(必须和VDD电压一致)、以及VBAT备份电源(1.65V~3.6V,不接电池时直接和VDD接一起就行)。100脚封装下面有VDD/VSS引脚十几对,每一个引脚旁边都要放一个100nF的MLCC去耦电容,这是底线,不能偷懒。另外至少要在板级放一个4.7uF~10uF的钽电容或大容量陶瓷电容压住低频纹波。

VDDA引脚必须额外串一个10R的小电阻再接3.3V,电阻后端再放一组100nF + 1uF的滤波电容,最后还有一个2.2uF电容接VREF+引脚。这一套滤波组合是数据手册明确推荐的模拟参考电源方案。你如果直接用一根飞线把3.3V怼到VDDA上,ADC采样出来的数据会抖动得让你怀疑人生,以太网PHY的模拟部分也会受影响,虽然不至于完全不通,但丢包率会偏高。

时钟是紧接着的一个大坑。F407系统时钟主频168MHz需要外部高速晶振HSE和PLL共同作用。典型的做法是接一颗8MHz无源晶振,配两个20pF负载电容。晶振的两个引脚分别是PH0-OSC_IN和PH1-OSC_OUT,注意不要把这两个引脚当普通IO用,它们被占用了。晶振下面最好不要走其他信号线,晶振本体周围画一圈地孔做屏蔽,这个习惯能省掉很多电磁干扰的麻烦。

外部低速晶振LSE是给RTC用的32.768KHz,如果项目里不用RTC,可以不焊,直接通过软件配置让RTC跑在LSI内部时钟上。以太网PHY的时钟源后面会专门讲,它和MCU的HSE不是同一路,千万别搞混。

复位电路最简单也最容易出错。NRST引脚内部有上拉,外部再接一个100nF电容到地就够用,要求高的话再并联一颗按键到地实现手动复位。这里有个容易忽略的点:如果板上同时有调试器,比如ST-LINK/V2的复位线SWDIO接口里的NRST也要连到MCU的NRST上。有些人偷懒不连复位线,大多数时候也能下载程序,但遇到“Cannot access target”这种调试器连不上的情况时,有复位线会好排查得多。

启动模式BOOT0和BOOT1两个引脚决定芯片上电后从哪里执行代码。正常工作模式BOOT0=0从Flash启动,BOOT0=1且BOOT1=0从系统存储器启动(也就是进入Bootloader,可以用串口ISP下载固件)。BOOT1引脚同时复用为PB2,所以设计时最简单的方式是BOOT0接一个10K下拉电阻到地,BOOT1不用管,留空或者也接地都行。只有在需要串口下载固件时才把BOOT0跳线拨到高电平,平时都保持接地。

最后是调试接口。F407的SWD只需要SWDIO(PA13)和SWCLK(PA14)两根线,加上GND和NRST,四根线就能完成烧录和调试。100脚封装里这两根引脚没有和其他外设复用冲突的话,建议直接把SWD接口做成4pin或5pin的排针放在板边,调试器好插,比JTAG省出一大堆引脚。我之前见过有人为了省事只留了串口下载接口,结果每次调试都要拔跳线、按复位、开ISP软件,效率低到崩溃。

2. 最小系统电路设计与硬件要点

2.1 电源树设计与去耦电容布局

很多人画最小系统时最容易犯错的地方不是原理图,而是PCB布局。原理图上每一对VDD/VSS都放了100nF电容,但布局时全堆在芯片同一侧,那效果和没放差不多。去耦电容的目的是为每个电源引脚提供低阻抗的交流回流路径,这个路径越短越好,所以100nF电容必须紧挨着对应的VDD/VSS引脚放置,最好放在同一层、走线不超过2mm。

F407VET6在LQFP100封装下,电源引脚分布比较均匀,四个角附近都有。我习惯的做法是这样的:

  • 先在原理图上把所有VDD/VSS、VDDA、VREF+引脚列出来,逐个编号
  • 每个VDD/VSS对旁边放置一个100nF的0402封装电容,LQFP100这种引脚间距0.5mm的封装,0402电容刚好能放在焊盘内侧或者外侧紧贴的位置
  • VDDA单独接10R电阻后再接3.3V,电阻后端放100nF+1uF两个电容到地
  • VREF+引脚再接一个2.2uF电容到地,这个电容建议用X7R材质的,温度稳定性好
  • 板级输入端放一个10uF的陶瓷电容或者钽电容,位置在电源入口处
  • 如果板上接了LAN8720A以太网PHY,它的每个电源引脚也要单独放100nF去耦,而且PHY的模拟电源AVDD最好用磁珠或者0R电阻和数字电源隔离

实际Layout建议:

项目建议值备注
主电源3.3V ± 5%纹波控制在50mV以内
VDD去耦100nF × N(每引脚一个)0402/0603封装
板级储能10uF电源入口附近
VDDA10R + 100nF + 1uF模拟电源滤波
VREF+2.2uFX7R陶瓷电容
地平面完整地平面双层板至少保证底层完整

电源设计做好之后,系统的稳定性至少完成了一半。以太网这种高频模拟信号对电源非常敏感,如果VDD上的纹波超过100mV,PHY的接收灵敏度会下降,表现出来就是链路能建立但传输质量差、偶发丢包。

2.2 晶振电路:8MHz HSE与32.768KHz LSE的处理方式

MCU主时钟HSE的8MHz晶振是整个系统的心脏,它的稳定性直接决定以太网能否正常工作。LAN8720A的RMII接口需要50MHz的参考时钟,这个时钟可以由外部25MHz晶振倍频产生,也可以由MCU的MCO引脚直接提供,后面以太网章节会展开讲。这里先说HSE本身。

8MHz无源晶振的两个引脚接PH0/PH1,负载电容CL通常选10pF~22pF,具体要看晶振的规格书。一般常见的8MHz贴片晶振负载电容是20pF,你就焊两个20pF到地就行。计算方式是:CL = (C1 * C2) / (C1 + C2) + 寄生电容(约2~5pF)。当C1 = C2 = 20pF时,等效负载约10pF+寄生,接近20pF的标称值。这个精度要求不算苛刻,但如果你希望PLL出来的168MHz主频误差在万分之几以内,就必须按这个来配。

还有一个容易踩的坑:STM32的HSE起振需要时间,如果晶振的ESR(等效串联电阻)太大或者负载电容配得不合适,上电后可能起振失败,程序会卡死在HSE超时等待里。排查方法很简单:用示波器看PH0引脚有没有振荡波形。如果没有波形,先确认电容极性(无源晶振没有极性)、焊接是否虚焊,然后换一颗晶振试。我遇到过一批晶振批次不良,导致十块板子里有三块无法启动,最后全换晶振才解决。所以批量做板子时,晶振千万不要买杂牌,一定要用大厂的料。

LSE的32.768KHz晶振如果不做RTC或低功耗待机唤醒,可以直接省掉。省掉之后CubeMX默认配置LSE就会报错,你需要在RCC配置里把LSE设为Disabled,然后RTC时钟源选LSI。如果你要做一个带时间戳的数据记录仪,那就必须焊LSE。LSE的负载电容一般是6pF~12.5pF,需要按照晶振规格书配,常见的有6pF和12.5pF两种。32.768KHz晶振对负载电容非常敏感,配不对会导致RTC每天快慢几十秒甚至停振,而且它的振荡幅度很小,示波器探头一搭上去可能就把它压停了,所以调试LSE时要用高阻探头或者X10档。

HSE除了给PLL当参考源外,还有一个隐藏用途:可以作为MCO1引脚的输出来源。PA8复用为MCO1,可以输出HSE、PLL分频或HSI,最大能输出到50MHz。这个功能后面给LAN8720A提供50MHz时钟时会用到,搞明白这个关联,整个以太网时钟链路就通了。

2.3 BOOT模式、复位与SWD调试接口的细节

最小系统里BOOT、复位和调试接口这三个模块看起来简单,实际上每个都有讲究。

BOOT0和BOOT1的配置我在前面提过,正常工作下BOOT0接地。这里要强调的是,BOOT0引脚内部没有上拉或下拉,悬空时电平不确定,可能会导致芯片随机从错误地址启动。所以BOOT0必须接一个明确的下拉电阻,10K就行。如果你想让板子支持串口ISP下载,可以做成一个2.54mm跳线帽或者拨码开关,一端接3.3V,一端接BOOT0,中间串联一个1K电阻限制电流。这样量产时用SWD烧录,维修时可以用串口救砖,灵活度更高。

复位电路有一个容易忽略的细节:NRST引脚内部已经有上拉了,外部再接100nF电容到地即可。但是当你外接调试器时,ST-LINK的NRST输出是开漏的,需要和MCU的NRST直接连接。有些人会在中间串联一个电阻或者二极管做保护,反而影响了复位信号的完整性。我实测下来,直接短接是最可靠的方案,只要保证调试器接口的线序没错就行。

SWD调试接口还有一个调试接口供电的问题。如果你用4pin SWD接口(SWDIO、SWCLK、GND、NRST)连ST-LINK,ST-LINK的3.3V输出一般不接到目标板上,除非目标板本身没有供电。但很多廉价调试器,比如某些克隆的ST-LINK/V2,3.3V输出能力很弱,直接给整板供电会掉电压,导致调试时MCU频繁复位。正确做法是:目标板自己供电,调试器只提供数据和复位信号,两边共地。如果你的VET6系统板要从调试器取电,那就要限制功耗,别在板上再接大功率外设。

再讲一个很多新手会忽略的问题:下载完程序之后,调试器Release状态下MCU跑飞了,重新上电之后程序还在吗?在的,程序烧进Flash之后掉电不丢失。但是如果你用的是RAM运行模式(比如Keil里配置为Download to RAM),那掉电就没了。F407VET6有192KB的SRAM,小工程确实可以直接在RAM里调试,速度快、不磨损Flash,但量产时一定要改回Flash下载模式,否则断电后板子就是砖头。这是一个很典型的“能跑但不知道为什么会跑”的问题源头。

SWD的走线也有要求。SWCLK和SWDIO最好不要长距离平行走线,否则信号串扰可能导致调试器连接不稳定。PCB上尽量让这两根线短而粗,中间夹一根地线做隔离。如果实在没办法要走层,那就加一个33R左右的串联电阻靠近MCU端,能压一压振铃。这些细节做好之后,调试器连接的问题会少很多。

3. 以太网硬件实战:从PHY选型到RMII接口设计

3.1 STM32的以太网MAC与外部PHY的分工

首先要弄清楚一个概念:STM32F407内置的以太网模块只包含数据链路层(MAC)和DMA控制器,物理层(PHY)需要用外部芯片实现。MAC负责的事情包括:组帧、拆帧、CRC校验、流量控制和DMA传输。PHY负责的事情则是:把MAC给它的并行数据转换为串行的差分信号发到网线上,同时把网线上收到的差分信号解调回并行数据给MAC。这两层之间通过MII或RMII接口连接。

用个生活化的类比,MAC是快递分拣中心,处理包裹(数据帧)的分拣和贴单,PHY是运输车队,负责把包裹从仓库运到目的地。分拣中心发出的每一辆车都要遵守交通规则,这里的规则就是MII或RMII接口协议。

STM32F407的以太网MAC支持10M/100M速率,支持全双工和半双工,内置了站管理接口(SMI,也就是MDC/MDIO),用来读写PHY的寄存器。所以你只需要外接一颗PHY芯片,配置好MDIO接口就能控制它。

选择PHY芯片时,需要注意几点:一是速率匹配,必须支持10/100M;二是接口匹配,要支持RMII或MII;三是供电和封装是否好焊接;四是手册资料是不是齐全,寄存器定义是否清晰。目前市场上最常用的F407配PHY方案有这几颗:

PHY芯片接口支持RMII参考时钟封装备注
LAN8720ARMII50MHz外部输入QFN24最常用、便宜、引脚少
DP83848MII/RMII50MHz外部输入LQFP48稳定、工业级、稍贵
KSZ8081MII/RMII50MHz外部输入QFN24/LQFP48Microchip家,兼容性好

LAN8720A是目前DIY和工业小批量项目里的网红方案,QFN24封装,体积小,外围电路简单,而且数据手册把参考设计画得很详细。我这次的实战用的就是它,下面重点讲它的硬件设计。

3.2 MII与RMII接口对比:为什么100脚封装首选RMII

MII和RMII是MAC和PHY之间的两种标准接口,核心区别在于数据通道宽度和时钟频率。

MII模式下,数据通道是4位宽的,发送和接收各占4根线,加上TX_CLK、RX_CLK、TX_EN、RX_DV、CRS、COL等控制信号,总共需要约16根信号线。发送和接收时钟独立,都是25MHz(100M速率)或2.5MHz(10M速率)。

RMII模式则把数据通道压缩到2位宽,发送和接收各2根线,合并了时钟和控制信号,总共只需要7根信号线(TXD[1:0]、RXD[1:0]、TX_EN、CRS_DV、REF_CLK)。这7根线里,TX_EN兼做发送使能,CRS_DV兼做载波侦听和数据有效指示,REF_CLK则是收发共用的50MHz参考时钟。

把这两种接口放在STM32F407VET6的100脚封装下看,差距就很明显了。MII接口把PA、PB、PC、PE、PD的十几个引脚全占了,剩下还能用的外设引脚捉襟见肘。RMII接口只需要PA1、PA2、PA3(TXD0/TXD1/TX_EN)、PA7(CRS_DV)、PC4(RXD0)、PC5(RXD1)、PA0(MDIO)、PC1(MDC),外加一个PB11或PA8提供REF_CLK。释放出来的引脚可以用来接CAN、接USART、接DCMI摄像头,实用性大增。

对比项MIIRMII
数据位宽4位2位
信号线数量约16根约7根
TX/RX时钟独立25MHz共用50MHz
10M时钟2.5MHz50MHz(数据被拉宽)
引脚占用多少
适合封装LQFP144/176LQFP100
带宽损耗无几乎无(100M下够用)

注意细节:RMII的REF_CLK是50MHz,这个频率比MII的25MHz高很多,所以在PCB布线时REF_CLK要当作高速信号来处理,走线尽量短、要包地或者旁边有完整地平面,不要和其他慢速信号线靠太近。另外,RMII模式下MAC和PHY必须使用同一个50MHz参考时钟源,否则收发时序会对不上,这是新手最容易搞错的地方。

3.3 LAN8720A硬件设计:引脚分配、变压器与走线要点

LAN8720A的RMII参考设计其实不复杂,但每一个细节都决定成败。先看它的引脚分组。LAN8720A是QFN24封装,引脚不多,核心功能包括:

  • XI/XO:25MHz晶振引脚,LAN8720A内部有PLL,外部25MHz晶振经过内部倍频后生成50MHz REF_CLK
  • REF_CLKOUT(pin 2):可以输出50MHz时钟,给STM32的MAC做参考时钟
  • RMII接口:TXD[1:0]、RXD[1:0]、TX_EN、CRS_DV
  • MDC/MDIO:管理接口
  • TXP/TXN、RXP/RXN:差分数据对,接网络变压器
  • LED0/LED1:状态指示灯,可以配置为链路状态和活动状态
  • nINT/RMII:中断输出/模式选择引脚
  • MODE0~2:接口模式配置(本次设置为RMII模式)

我自己画的原理图里,LAN8720A的RMII接线和STM32F407VET6的对应关系是这样的:

LAN8720A引脚功能连接STM32F407VET6引脚说明
TXD0发送数据位0PA1RMII_TXD0
TXD1发送数据位1PA2RMII_TXD1
TX_EN发送使能PA3RMII_TX_EN
RXD0接收数据位0PC4RMII_RXD0
RXD1接收数据位1PC5RMII_RXD1
CRS_DV载波/数据有效PA7RMII_CRS_DV
REF_CLKOUT50MHz时钟输出PA8 (MCO1) 或 PB11提供RMII参考时钟
MDC管理时钟PC1由MAC驱动
MDIO管理数据PA0双向管理数据线

这里有一个非常关键的选择:REF_CLK从哪来。有两种接法:

  • 接法A:LAN8720A的XI/XO接25MHz晶振,然后REF_CLKOUT引脚输出50MHz给STM32的RMII_REF_CLK引脚。优点是PHY自己产生时钟,MCU侧不用额外配置MCO,但缺点是这个时钟是PHY产生的,MAC要被动跟随。
  • 接法B:STM32的PA8复用为MCO1,输出50MHz时钟直接给LAN8720A的REF_CLK引脚,此时LAN8720A的XI/XO不接晶振或接25MHz晶振但工作在时钟输入模式。这种接法由MAC主导时钟,PHY跟随。

两种方案市场上都有人用,但我实测下来,接法A(PHY产生时钟)更稳定。因为LAN8720A内部PLL的输出精度足够满足100M以太网的抖动要求,而STM32的MCO输出50MHz时走线如果稍微长一点,信号质量会下降,反过来影响PHY的时钟恢复。我这次板子采用的就是接法A:LAN8720A外接25MHz晶振,REF_CLKOUT接STM32的PA8(配置为RMII_REF_CLK输入)。

网络变压器和RJ45座子的选择也直接影响链路质量。我这次用的是带网络变压器的RJ45一体座HR911105A,它内部已经集成了变压器和共模电感,还把两个LED灯的限流电阻都做好了,外围电路省了很多事。如果你选的是RJ45座子加独立网络变压器那种分体方案,那就要注意变压器中心抽头的接法——100M以太网通常中心抽头不接或按PHY手册要求接电压,LAN8720A的手册要求中心抽头通过100nF电容接地,这个不能省。HR911105A这种一体座已经把内部处理好了,直接用即可。

PCB走线时,TXP/TXN和RXP/RXN这两对差分线要等长、对称、贴近地平面走,差分阻抗控制在100欧姆±10%。手工焊接演示板上不必太苛刻,但批量做板子时一定要让板厂做阻抗控制。差分线之间不要打孔,如果跨层走线,必须保证回流地连续。我以前画过一版偷懒的板子,把差分线走了好几层并且中间打了过孔切换,结果link debug时发现CRC错误率很高,后来重新画才解决。以太网这块,差分线质量基本决定成败。

3.4 时钟链路的坑:MCO、25MHz晶振与REF_CLK的准确用法

以太网硬件设计里,时钟链路的坑最多,也是最容易让板子“看起来正常但就是不通”的地方。一个完整的RMII时钟链路包括两部分:MCU侧的系统时钟和以太网侧的RMII参考时钟。

先说MCU侧。F407的以太网MAC模块使用一个独立的时钟域,这个时钟来源于APB2外设时钟(HCLK)的同步时钟。配置CubeMX时,以太网的时钟源默认挂在AHB1上,它会自动跟随168MHz主频做分频处理,一般不需要手动干预。真正需要手动配置的,是RMII接口的50MHz REF_CLK。

接法A对应的软件配置是:在CubeMX的GPIO配置里,把PA8配置为复用功能AF11(RMII_REF_CLK),同时不要启用MCO输出功能。因为这种接法下,REF_CLK是LAN8720A给的,MCU这边的PA8只是输入接收。有人会在这里搞反,把PA8配成MCO输出,结果两个时钟源在线上打架,链路完全起不来。我见过不止一次这种问题,症状是:MDIO能读到PHY寄存器,但链路指示灯不亮,因为PHY没有拿到有效的时钟输入。

接法B则是启用MCO1功能:在CubeMX的RCC配置里选择MCO1输出时钟源,把它设为PLLCLK/2(168MHz / 2 = 84MHz?不对,MCO1要50MHz,需要用PLL的另一个分频值)——实际上F407的MCO1输出选项包括HSE、HSI、PLLCLK和LSE,通过预分频器可以配置到50MHz。一个常见配置是:MCO1选择HSE(8MHz),预分频器选/1,不行,要的是50MHz。更实际的做法是让PLL的Q输出或PLLCLK经过适当分频后得到50MHz,要么就直接让HSE的8MHz经过内部PLL倍频到50MHz输出。

这个配置比较绕,而且一旦MCO的输出能力不够或者走线太长,50MHz方波的边沿会变缓,PHY采样就会出错。这也是我强烈推荐用接法A的原因——让PHY自己产生时钟,把MCO的麻烦留给需要它的人。这个知识点在面试或者和同行交流时很能体现水平,很多人一说RMII时钟就会提到MCO,但真正常用的其实是PHY的REF_CLKOUT。

避坑清单:

  • REF_CLK的走线尽量短,尽量控制在20mm以内,如果超过30mm,建议在源端串联22R电阻
  • REF_CLK线不要和任何高速数字信号平行长距离走线
  • LAN8720A的25MHz晶振,负载电容按10pF~22pF配,具体看晶振规格书
  • 如果板上同时有MCU和PHY,务必先确认两边共地,否则MDIO/MDC通信是无效的
  • 焊接QFN24的LAN8720A时,底部散热焊盘必须接地,否则芯片会莫名其妙的复位或链路不稳定

4. 软件实现:从CubeMX配置到LWIP协议栈跑通

4.1 CubeMX配置以太网外设的完整步骤

硬件搞定之后,软件部分就顺理成章了。我用的是STM32CubeMX配合HAL库,版本不重要,重要的是配置每一步的逻辑。

打开CubeMX,芯片选STM32F407VET6,系统时钟配置到168MHz。具体步骤是:RCC的HSE选Crystal/Ceramic Resonator,主频在Clock Configuration里把HCLK拉到168MHz,系统会自动调整PLL分频参数。如果你用的外部晶振不是8MHz,需要手动改HSE的输入频率值,CubeMX里默认是8MHz。这里一键配置会帮你生成正确的PLL参数,不用自己手算。

以太网配置在Connectivity目录下找到ETH外设。选择RMII模式,然后CubeMX会自动把PA1/PA2/PA3/PA7/PC1/PC4/PC5这些引脚分配好。如果你选择的是MII模式,引脚分配会更多。对于100脚封装,RMII是默认推荐的。同时,ETH外设使能后,CubeMX会多出MDC/MDIO引脚的自动分配,一般MDIO在PA0,MDC在PC1。

紧接着需要配置PHY地址。LAN8720A的PHY地址由它的PHYAD0~2引脚的电平决定。LAN8720A的默认PHY地址是0x01,数据手册里约定PHYAD0引脚内部下拉,所以默认地址为00001(二进制)。如果你的原理图上把PHYAD0接了上拉,那地址就变成00000,此时需要在CubeMX里把PHY Address改成0x00。这是我碰到过最多的软件配置不一致问题——PHY地址不对,MDIO读写全部失败,但程序不会报错,只是网络完全不通。

ETH配置界面的几个关键参数:

  • MAC地址:任填一个不冲突的,比如2C:F7:12:03:3A:BC
  • PHY Address:默认1,如果你的板子上PHYAD引脚接法不同就改
  • PHY Clock:MDC时钟,选择HCLK/64,也就是168MHz/64=2.625MHz,符合MDC最大2.5MHz要求
  • 内部PHY寄存器地址:针对不同的PHY芯片选择对应的驱动,CubeMX自带LAN8720A的驱动选项,没有的话选Generic

GPIO配置完成后,在中间件Middleware里勾选LWIP。LWIP的配置可以先保持默认,后面再调内存池大小。默认配置下DHCP是开启的,也可以改用静态IP,两种方式在开发阶段各有好处:DHCP适合板子插路由器,静态IP适合板子和PC直连。

生成代码之后,需要验证两个点:一是LAN8720A的复位引脚是否正确控制。很多原理图把PHY的复位引脚和MCU的NRST连在一起,这样MCU复位时PHY也会复位,反过来PHY复位时MCU也复位,会产生连带反应。更好的设计是用一个普通GPIO控制PHY的复位,比如PB12接LAN8720A的NRST,软件里上电延时后拉高,让PHY完整走完上电复位流程。如果这个时序不对,PHY可能处于半配置状态,MDIO能通但RMII数据总是错。

4.2 LWIP协议栈的内存池、PBUF与线程安全

LWIP是个轻量级TCP/IP协议栈,它对资源的占用是可配置的。F407VET6有192KB RAM,跑LWIP绰绰有余,但配置不当依然会出问题,尤其是内存池大小的设置。

LWIP的内存管理有两种模式:内存池(memp)和堆内存(mem)。PBUF是LWIP里描述网络数据包的核心结构,它分为三种:PBUF_RAM(数据包缓冲,存放在RAM堆里)、PBUF_ROM(数据包只读,常用于发送静态数据)、PBUF_POOL(内存池分配的缓冲,接收数据常用)。CubeMX的LWIP配置页里,有几个参数是必调的:

  • MEM_SIZE:堆内存大小,默认1600字节太小,建议调到101024或更大,如果你要处理大包数据或者同时开多条TCP连接,161024比较稳妥
  • PBUF_POOL_SIZE:接收缓冲池的数量,默认16个,每个缓冲区大小由PBUF_POOL_BUFSIZE决定。建议至少16个,如果并发量大开到32
  • PBUF_POOL_BUFSIZE:单个接收缓冲区大小,默认1518字节,刚好能容纳一个标准以太网帧,不用动
  • MEMP_NUM_TCP_SEG:TCP段描述符数量,默认128,如果你只开一路TCP连接,可以降到32省内存
  • TCP_WND:TCP接收窗口大小,默认4096字节,如果你希望大吞吐量,改成161024甚至321024
  • TCP_SND_BUF:TCP发送缓冲大小,默认4096,改成16*1024

这几个参数直接影响内存占用和吞吐量。我实测过一组数据:默认配置下TCP吞吐量只有约2~3Mbps,把TCP_WND和TCP_SND_BUF调到16*1024之后,吞吐量能提升到8~9Mbps。对于100M以太网,F407的DMA和CPU能力限制下,实际跑到这个水平已经接近理论极限了。

线程安全问题是跑LWIP时很容易忽略的一点。LWIP的核心API(tcp_write、tcp_output、tcp_connect等)都不是线程安全的,必须在一个线程上下文中调用。如果你在FreeRTOS下使用,最简单的办法是把所有LWIP调用都放到同一个线程里,或者使用LWIP自带的tcpip_thread和一个邮箱接口(tcpip_input、tcpip_callback)。不要在每个线程里直接调用netconn或者raw API,否则迟早会遇到死机、数据错乱或者内存泄漏。

CubeMX默认生成的LWIP例程在main函数里做初始化,然后轮询处理链路状态。实际项目中我建议新建一个专门的网络线程,用信号量等待ETH接收中断,收到数据就调tcpip_input交给LWIP的tcpip_thread处理。发送数据时通过消息队列把要发的内容传给网络线程,由它统一调用tcp_write和tcp_output。这种设计能避免大量死锁和优先级反转问题。

4.3 ping通只是第一步:TCP服务器与UDP上报的实战示例

当你能ping通板子,说明TCP/IP协议栈的最小路径已经通了:链路层OK、ARP解析OK、IP和ICMP处理OK。但这只是第一步,实际项目里你更需要的是TCP服务器(比如网页配置界面、数据上传通道)和UDP上报(比如设备状态广播、传感器数据推送)。

我以LWIP的RAW API为例,讲一个最简单的TCP服务器写法。RAW API比netconn API更底层,但性能更好、内存占用更少。它的核心思路是:注册一个回调函数,LWIP在收到连接请求、收到数据、连接关闭时调用你注册的这些回调。

TCP服务器的回调是tcp_accept,表示有客户端连接进来。在新连接到达时,你会得到一个struct tcp_pcb指针,然后对这个连接注册tcp_recv回调,每当这个连接收到数据,LWIP会调用你的tcp_recv函数。在tcp_recv里,用tcp_recved函数告诉LWIP“我已经把数据处理完了,你可以释放缓冲了”,然后调用tcp_write把应答数据写回客户端。

static err_t echo_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { if (p != NULL) { tcp_recved(pcb, p->tot_len); tcp_write(pcb, p->payload, p->tot_len, 1); pbuf_free(p); } else { tcp_close(pcb); } return ERR_OK; } static err_t echo_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { tcp_recv(newpcb, echo_recv); return ERR_OK; }

这段代码实现的是一个回显服务器,收到什么就回什么。实际项目里,你可以在echo_recv里解析收到的命令,比如收到“GET_TEMP”就返回温度传感器的读数,收到“SET_PWM”就执行PWM控制。把数据格式定义好,一个简单的TCP远程控制就完成了。

UDP上报的实现比TCP简单很多,因为UDP无连接,不需要三次握手和序号管理。用udp_new创建一个PCB,绑定端口,然后发送数据用udp_sendto指定目标IP和端口即可。UDP常见的坑是丢包,它在网络拥塞时不重传,所以不能用于必须可靠传输的场景。但设备状态广播这类数据丢了也无所谓的场景,UDP比TCP高效很多。

struct udp_pcb *upcb = udp_new(); udp_bind(upcb, IP_ADDR_ANY, 5000); ip_addr_t remote; IP_ADDR4(&remote, 192, 168, 1, 100); udp_sendto(upcb, pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM), &remote, 8080);

运行结果参考:我板子上跑TCP回显和UDP广播,用PC端工具测试,TCP单连接上千字节数据包,吞吐量约8Mbps,UDP每秒可以发500个100字节左右的包,发送间隔稳定在2ms左右。对多数数据采集和远程控制类项目,这个性能完全够用。

5. 常见问题与排查技巧实录

5.1 以太网不通的四个典型故障现象与定位方法

做以太网调试时,几乎所有问题都能归到四类:芯片上电没正常工作、RMII时钟链路有问题、PHY没被正确初始化、MAC无法访问PHY。下面是我整理出来的排障方法,每个都是实际踩过坑之后的总结。

第一类:MDIO读写失败,程序读取PHY寄存器全为0xFFFF。这个最容易定位,先用示波器抓MDC引脚有没有时钟信号,再抓MDIO引脚有没有数据翻转。如果没有MDC输出,说明MAC侧没起来,检查ETH外设时钟是否使能、引脚复用是否配置正确。如果有MDC但MDIO没有回应,优先怀疑PHY地址不对。LAN8720A的PHY地址默认是0x01,如果你的PHYAD引脚配置不同,地址可能是0x00。用HAL_ETH_ReadPHYRegister不断读0号寄存器值,如果返回非0xFFFF,说明地址正确。另外别忘了检查PHY的复位引脚是否拉高,很多设计用GPIO控制复位,上电后软件必须延时并拉高,没有这一步PHY永远在复位状态。

第二类:MDIO正常,但链路指示灯不亮。这说明PHY没有从网络变压器拿到有效的接收信号。先检查网线另一头是不是真的在发包,比如接路由器或交换机,确认端口是好的。再看RJ45座和PHY之间差分线的焊接,HR911105A一体座上TXP/TXN、RXP/RXN四个脚特别容易虚焊,用万用表测一下变压器引脚到PHY对应引脚的导通性。最后看PHY的供电:LAN8720A的VDD和AVDD相对独立,如果AVDD没接,PHY接收模拟部分不工作,链路灯就起不来。

第三类:链路指示灯亮,但ping不通,抓包看到ARP请求没人应答。这说明PHY之间物理链路已经建立,但IP层还没起来。ARp请求是从PC发的,板子没回应,说明LWIP协议栈没正确处理ARP请求。先看板子的IP地址配置是否和PC在同一网段,子网掩码是否一致。再看LWIP初始化是否完成,以太网DMA是否在接收状态。一个常见问题是ETH DMA的接收描述符没有正确初始化,此时接收中断不触发,LWIP永远不会收到数据包。检查HAL_ETH_Start_IT是否被调用,以及ETH的DMA中断优先级是否配得太低被其他中断饿死。

第四类:ping偶尔通偶尔不通,丢包严重。这个问题优先怀疑时钟和电源。RMII的REF_CLK如果抖动过大,PHY的接收数据会偶发CRC错误。用示波器看REF_CLK引脚波形,正常应该是50MHz的方波,边沿陡峭,抖动小。如果波形有严重毛刺,检查REF_CLK走线和地平面。电源问题同样常见:PHY的3.3V上去耦不足,会导致突发流量下电压跌落,表现为高带宽时丢包。此时在该电源引脚旁边补焊一个大电容,比如47uF钽电容,能立竿见影。

5.2 MCU没有USB差分信号数据引脚怎么办

F407VET6是100脚封装,它的USB OTG FS的D+/D-引脚在PA11/PA12上,这两个脚是有的,但要注意:PA11在100脚封装里还复用了USB_DM和CAN_RX,PA12复用了USB_DP和CAN_TX。如果你同时要用USB和CAN,就必须选择PIN REMAP或者外部MUX,这在实际项目里非常麻烦。

那么问题来了:如果USBD+和USBD-引脚被其他功能占用了,或者你选了一个引脚没有引出的芯片,比如某些F405型号,怎么办?答案是用外部USB PHY。F407的USB OTG HS接口支持ULPI接口,你可以外接一颗USB3300或者USB3320作为高速USB PHY。不过需要明确,F407VET6的100脚封装没有把ULPI接口的所有引脚引出来,所以USB_HS高速模式在VET6上基本不可用。

那USB_OTG_FS呢?FS模式不需要外部PHY芯片,PA11/PA12直接接USB座子的D+/D-,再配两个15K下拉电阻到地(这是USB设备模式规定的上拉/下拉要求,D+上拉用于全速设备识别)。如果你的应用只需要低速USB设备,比如虚拟串口、HID键盘,PA11/PA12完全够用。如果PA11/PA12被CAN占用了,方案是切换到USB_HS接口配合外部PHY用,但VET6引脚不够,所以实际上推荐两个方案:要么放弃同时用USB和CAN这个组合,要么换LQFP144封装的F407ZGT6。

USB_FS设备模式的最小电路:

组件参数说明
D+/D-PA11/PA12直接连接到USB座
DP上拉1.5K ± 5%D+到3.3V,用于全速识别
串联电阻22R±5%靠近MCU,串在D+/D-上
电源去耦100nF+10uF靠近USB座
ESD保护USBLC6-2SC6如果不加,批量产品很容易返修

这里再回答一个常见困惑:有人说F407VET6没有USB差分管脚,其实可以仔细看一下数据手册的引脚定义,PA11=USB_DM,PA12=USB_DP是存在的,只是被很多开发板的CAN功能占用。如果你确定这一版只是做USB转串口调试,那直接用PA11/PA12没问题。如果你需要同时支持CAN总线通信和USB debug,建议去做引脚复用仲裁,但更稳妥的还是换封装大的芯片。

5.3 网络变压器、RJ45座与PCB布线的“隐形坑”

很多人画以太网接口时只注意原理图对不对,PCB布线的细节往往被忽略。我这里不说教科书上的理论,只讲实际测试中发现的问题。

第一个坑是RJ45座下方的净空区。HR911105A这种变压器一体座,变压器部分在RJ45座正下方,PCB对应区域不能铺铜或者走线,否则变压器磁场会在铜箔上感应出涡流,导致信号质量下降。正确做法是给RJ45座底部留一个净空区,所有层都不要铺铜,过孔也要避开。这个做法在EMC测试时尤其重要,能显著改善辐射骚扰和抗扰度表现。

第二个坑是LED指示灯引脚不要接反。HR911105A内部的LED通常是共阳的,两个LED阳极通过排针引出接3.3V或通过限流电阻接3.3V,阴极分别连接到LAN8720A的LED0/LED1引脚。LAN8720A的LED引脚是开漏输出,所以正确接法是:LED阳极接3.3V,阴极经限流电阻接到PHY的LED引脚(限流电阻在PHY手册中一般是2.2K左右,实际根据LED压降和亮度需求选择)。如果你把LED接反,不仅灯不亮,LED0引脚的电平还可能被异常拉低,影响PHY的模式配置引脚的分压,导致PHY工作模式错误。这个坑很隐蔽,排查起来费时费力。

第三个坑是MDC/MDIO的上拉电阻。MDC和MDIO是标准的双向开漏管理接口,MCU侧需要上拉电阻。STM32的PA0和PC1在复用为MDIO/MDC时,内部没有使能上拉,所以板级必须加两个4.7K上拉电阻到3.3V。漏了这两个电阻,MDIO通信会时好时坏,尤其在环境温度低时更容易出问题。这个细节在ST官方评估板的原理图里可以看到,抄作业时注意别抄漏。

还有一个不太容易想到的点:RJ45座子的外壳接地。金属外壳的RJ45座,屏蔽层要接到PCB的机壳地(通常是通过电容和电阻并联接到数字地),这样可以泄放静电和共模干扰。如果直接不接或者直接接地,EMC测试时会有麻烦。HR911105A的外壳引脚是金属外壳本身,设计时在原理图里留一个独立的网络CHASSIS_GND,通过1M电阻和1nF电容并联接到数字GND。这个做法兼顾了高频干扰泄放和低频安全隔离。

6. 实测数据与稳定性调优

6.1 一次完整的以太网吞吐量与丢包率测试

板子做好之后,稳定性不能凭感觉说,必须跑过一轮完整测试。我的测试环境是:F407VET6系统板直连PC网口,PC用iperf或者简单的socket工具打流量。这里分享一下实测结果和测试方法。

用iperf测试TCP吞吐量的命令是:

iperf -c 192.168.1.10 -t 30 -i 1

客户端是PC,服务器是板子(板子上跑TCP回显或者TCP server)。实测下来,默认LWIP配置下,TCP吞吐量大约2.4Mbps,UDP发送吞吐量大约3.0Mbps。经过前面说的LWIP参数调整(TCP_WND=16384、TCP_SND_BUF=16384、PBUF_POOL_SIZE=32)后,TCP吞吐量到了8.5Mbps,UDP到了9.1Mbps。这个数字在100M网口下看起来不算高,但对于168MHz的MCU来说已经接近瓶颈,毕竟LWIP的协议处理、内存拷贝和中断开销都在消耗CPU。

用ping测丢包率的方法是:

ping 192.168.1.10 -l 1400 -n 1000

一次发1000个1400字节的包,正常情况下丢包率为0%。如果出现零星丢包,先看是不是PC侧的防火墙或杀毒软件干扰,再看板子的供电和时钟质量。批量测试时,我把板子连续ping了一整夜,8小时丢包0个,说明硬件和协议栈配合得不错。

测试网络稳定性时还有一个结果值得记录:当板子同时跑TCP回显和UDP广播时,峰值CPU占用率大概在70%左右,剩余30%还能跑些简单的控制逻辑。如果需要更高的网络吞吐,比如跑数据采集网关同时处理多路TCP连接,那就要考虑用STM32H7或者带硬件网络加速的芯片了,F407的定位是“够用”,不是“极致”。

6.2 从稳定到可靠:几个软件层面的优化建议

硬件没问题之后,软件层面的调优决定整个系统能跑多久、多稳。这里分享几个我实测下来效果明显的小改动。

第一个是LWIP的轮询间隔和DHCP重试机制。DHCP获取IP需要一定时间,如果路由器响应慢,LWIP默认的DHCP超时可能导致获取失败。建议把DHCP的超时时间调长,或者在DHCP失败后做指数退避重试,而不是反复快速请求。另外,如果板子固定接入同一个局域网,直接用静态IP更省心,减少DHCP协议栈的复杂度,也减少了故障点。

第二个是链路断开重连机制。以太网最怕的是网线松动后恢复,PHY的link状态变了,协议栈不会自动恢复。建议用netif_set_link_up和netif_set_link_down这两个接口监听PHY中断或定时轮询PHY的基本状态寄存器(寄存器1,Bit2表示link status)。当检测到link down时,停止所有TCP连接,调用netif_set_down并把ARP缓存清掉,link up时再重新应用IP地址。我实测过,不做这个处理的板子在拔插网线后,TCP连接会一直卡在等待状态,而加了重连机制的板子,拔插后10秒内能自动恢复。

第三个是TCP连接的心跳与超时。嵌入式设备做TCP服务器时,如果客户端掉线但TCP连接没有正常关闭,LWIP会一直保持这个连接占用内存。建议在应用层增加心跳机制:客户端定时发送心跳包,服务器端如果在超时时间内没收到心跳,就主动tcp_close该连接。这是最简单的连接保活方式,比TCP keepalive的开销更可控,也更符合嵌入式设备的使用习惯。

再提一个软件上的坑:中断优先级。ETH的DMA接收中断优先级应该设置为较高优先级,比如抢占优先级2、子优先级0。如果优先级过低,在大量接收数据时,中断可能被其他高频中断(比如定时器)抢占,导致DMA接收描述符不能及时处理,丢包随之而来。我遇到过一次诡异的现象:板子单独跑网络测试一切正常,一旦同时开启ADC采样中断,ping就开始丢包,就是中断优先级冲突导致的。把ETH中断优先级提升之后,问题消失。

6.3 量产烧录与生产测试注意事项

硬件和软件都跑通之后,量产阶段同样有一些容易忽视的问题。

第一点是芯片的唯一ID。F407每颗芯片都有96位的唯一ID,存储在0x1FFFF7E8起三个32位字里。生产时可以用来生成每台的默认MAC地址,避免所有板子出厂时MAC都一样。局域网里两台相同MAC的设备会导致ARP混乱,表现为通信时通时断。所以量产必须为每台设备烧录唯一MAC地址。

第二点是Flash读保护和JTAG/SWD口保护。如果不希望别人通过调试器读出固件,量产烧录时最后一步要设置Flash读保护级别。ST的烧录工具可以通过option byte设置RDP级别,设置为Level 1后,SWD口还能连接调试但无法读取Flash内容。注意RDP从Level 1降到Level 0会执行一次Flash全片擦除,这是安全机制,不要在生产时误触。

第三点是出厂测试脚本。我在小批量生产时习惯写一个简单的PC端测试工具,板子烧录后自动发送一个测试指令,板端回传板卡ID、固件版本、MAC地址和网络状态。这样在生产线上用一台电脑加一台交换机就能完成所有板子的基础测试,效率很高。这个测试固件和正式固件分开维护,测试固件里可以保留调试打印和自检逻辑。测试通过后再烧正式固件,并开启读保护。流程上多一步,但能挡掉不少PCB焊接问题。

7. 经验总结与扩展思路

7.1 这套方案能怎么扩展:从单机联网到物联网网关

当你在F407VET6上跑通了以太网,很多以前做起来很别扭的功能都能顺手完成了。最常见的扩展方向是做一个边缘物联网关:用SPI或I2C接几个传感器,比如温湿度、光照、空气质量传感器,采集数据后通过TCP/MQTT上报到服务器。F407的192KB RAM和512KB Flash,加上FPU,跑CANOpen、Modbus TCP、MQTT这些协议完全没压力。我做过一个项目,F407VET6同时跑Modbus RTU从站(控制几个电机驱动)和Modbus TCP主站(把数据上送给工控机),CPU占用率不到50%,运行半年没重启过一次。

另一个扩展方向是结合FreeRTOS和文件系统。以太网最常见的应用之一就是基于FTP或HTTP做固件升级。F407的Flash是512KB,分成几个区域:Bootloader区放一个极简的以太网升级程序,App区放正式固件,运行时通过HTTP下载新固件到剩余Flash区,校验无误后跳转。这个方案利用现有以太网物理链路,省去了串口升级的麻烦,在设备部署现场非常实用。

如果要加无线能力,可以再外接一个ESP8266或ESP32模块,让F407通过串口或SDIO连接WiFi模块,以太网作为有线通信通道,WiFi作为无线通道,两块链路间做数据转发。F407的DCMI摄像头接口还能接OV2640之类的小摄像头,配合以太网做图像传输。这些扩展都建立在最小系统和以太网稳定的基础上。

7.2 常见的成本控制与采购建议

F407VET6这颗料现在的行情比较稳定,但要买到真货还需要一些经验。我的建议是优先在正规代理渠道或者知名电商平台购买,不要贪便宜买那种十几块钱的散新片。识别原装片最直接的办法是看丝印和引脚光泽度,原装LQFP100的丝印清晰、引脚明亮均匀。如果实在没有采购渠道,可以先用市场上成熟的F407VET6核心板做开发验证,等方案稳定后再考虑自己贴片量产,这样风险和成本都更可控。

相比之下,LAN8720A的价格波动比较大,不同批次做工差异明显。我遇到过一批LAN8720A烙铁焊接后正常,但回流焊后偶发链路不稳定的情况,很可能是芯片本身批次问题。批量采购时建议小批量试产,确认焊接工艺没问题后再放大订单。QFN24封装对焊接工艺要求高,手工焊接时注意风枪温度不能过高,一般350度、风速中等,快速加热到焊锡熔化后撤离。如果锡膏涂抹不均匀,容易造成底部焊盘虚焊,这时MDIO能通但数据链路不稳定,排查起来很痛苦。

核心板和自制板之间的选择也是成本控制的一部分。学习阶段买一块现成的F407VET6核心板,几十块钱,能快速跑例程积累经验。到了项目阶段,自己画板子把最小系统和以太网接口集成在一起,单板BOM成本可以做到百元以内,对于量产项目来说省的不是一点半点。

7.3 最后几个顺手的小建议

文章写到这里,核心内容基本讲完了,最后分享几个实际操作中沉淀下来的细节建议,希望对你有帮助。

建议一:画板子时一定要预留测试点。把SWD四根线、UART_TX/RX、PHY的REF_CLK、MDC/MDIO这几个关键信号做成测试焊盘或者2.54mm排针。调试阶段没有这些测试点,出了问题就只能拿烙铁飞线,那体验非常痛苦。我画板子时习惯把UART1和UART2都引出,一个用于调试日志,一个留作自定义通信接口,这样即使网络起不来,也能通过串口看到以太网初始化的每一步状态。

建议二:CubeMX生成代码后,不要直接在上面改业务逻辑。把HAL库生成的初始化代码留在原文件中,自己的业务代码独立建模块,比如eth_app.c、tcp_server.c、sensor_read.c这种。原因很简单,CubeMX重新生成代码时会覆盖原文件内容,如果你在main.c里加了大量业务代码,每次调整引脚配置后都要手动合并,容易出错。模块化之后,重新生成的只是底层初始化,你的业务代码不受影响,这个习惯能省去大量重复劳动。

建议三:首次上电调试不要直接跑网络。先把最小系统的串口跑通,发送个“hello world”确认MCU工作正常,再逐步使能ETH、LWIP。如果一上来就同时开所有外设,出了问题你会很难定位是MCU还是PHY还是LWIP的锅。分步调试,每一步都确认无误,最后整体联调时出问题的概率低很多。我的调试顺序是:电源灯亮 -> SWD能连接 -> 串口输出 -> GPIO翻转正常 -> MDIO读到PHY ID -> 链路灯亮 -> ping通 -> TCP通信 -> 业务逻辑。

建议四:在工程里保留一份“已知问题记录”文档。每踩一个坑就记下来,写上现象、原因、解决方法和预防措施。这个文档的价值会随着时间越来越大,尤其是过几个月后再回头维护旧项目时,它就是你最宝贵的检索目录。我自己整理这篇博文时翻出了过去几份同样的文档,很多细节之所以能写清楚,全是当时记录下来的。

做技术就是这样,很多问题解决之后回头看会觉得很简单,但当时排查的过程确实费了不少功夫。STM32F407VET6这颗芯片虽然看着老,但其外设丰富度、生态成熟度和成本综合下来,在联网型嵌入式设备里依然很有生命力。希望这篇文章能帮你少走一点弯路,把最小系统和以太网这条路走通。以后如果再有人问我“F407能不能做以太网”,我会说:不仅能,而且做得很好。

返回列表