
1. 项目缘起为什么是LAN8720如果你玩过STM32、ESP32这类微控制器想给它加上一个稳定可靠的以太网功能那你大概率绕不开一个名字LAN8720。这枚小小的PHY芯片几乎是嵌入式以太网入门和中小型项目里的“国民级”选择。我手头这块“LAN8720 ETH Board”就是围绕这颗芯片设计的一块独立以太网模块它能让你那些没有原生以太网MAC的MCU比如STM32F103、ESP32-S2等或者想扩展第二个网口的设备轻松接入有线网络。为什么LAN8720能这么流行简单来说就三个字够用、好买、便宜。它支持标准的RMII接口与绝大多数主流MCU的以太网MAC控制器都能无缝对接功耗和发热控制得不错最关键的是它的数据手册、参考电路、驱动代码在网络上浩如烟海任何你遇到的问题几乎都能找到前人的脚印。相比之下它的“兄弟”LAN8742功能更强大一些比如支持RMIIS但对于90%的10/100Mbps应用场景LAN8720已经完全足够性价比更高。这块评估板的核心价值就是帮你把最繁琐、最容易出错的硬件部分——包括网络变压器、时钟电路、电源滤波、配置电阻——全部集成并优化好了。你不需要再去纠结25MHz晶振的负载电容该选多大或者网络变压器中心抽头该怎么接拿到手就是一个即插即用的“网络外设”。对于开发者而言这极大地降低了硬件门槛让我们能把精力集中在软件和协议栈如LWIP、uIP的调试上。2. 模块硬件拆解从原理图到关键信号拿到一块模块第一件事就是看它的原理图理解设计者的意图。虽然我们手头可能没有官方的原理图但基于LAN8720的典型应用电路和市面上常见模块的设计我们可以还原出它的核心架构。2.1 核心芯片与接口布局模块的核心无疑是LAN8720A这颗PHY芯片。它通过一个标准的RMIIReduced Media Independent Interface接口与主控MCU通信。RMII相比传统的MII引脚数量从16个减少到7个不算时钟和电源非常适合引脚资源紧张的嵌入式MCU。在模块上你会找到一个双排针接口通常包含以下关键信号TXD[1:0]/RXD[1:0] 收发数据线。REF_CLK 50MHz参考时钟。这里有一个至关重要的设计选择这个时钟可以由主控MCU提供也可以由LAN8720内部的PLL产生。模块上通常会有一个跳线帽或焊盘来选择时钟源模式。如果由MCU提供你需要确保你的MCU能输出一个稳定、精确的50MHz时钟给PHY如果由PHY产生则你需要给LAN8720提供一颗25MHz的晶振它内部倍频后产生50MHz的REF_CLK再输出给MCU。绝大多数模块为了通用性会选择后者即板上集成25MHz晶振PHY作为时钟主设备。CRS_DV/RX_ER 载波侦听/数据有效和接收错误指示。MDIO/MDC 管理数据输入输出和时钟用于配置PHY芯片的内部寄存器比如设置速度、双工模式、自协商等。nINT/nRST 中断输出和复位输入低电平有效。3.3V/GND 电源。LAN8720是3.3V供电与多数3.3V MCU电平兼容。模块的另一端就是一个标准的RJ45网络接口内部已经集成了网络变压器Magnetics Module。这是另一个容易踩坑的点网络变压器是必须的它负责信号隔离、阻抗匹配和抗干扰。模块帮你集成好了省去了外接一个“带变压器的RJ45座”的麻烦。2.2 电源与滤波设计LAN8720对电源质量比较敏感尤其是模拟部分。好的模块会在电源入口处设计π型滤波电路如磁珠电容并为芯片的AVDDH模拟电源引脚提供独立的LC滤波。如果你自己设计电路这里偷懒省略滤波电容很可能会导致链路不稳定、丢包甚至无法连接。模块上通常会有几个LED指示灯电源指示灯PWR 常亮表示模块已上电。链路状态指示灯LINK 常亮表示物理链路已接通网线插好且对端设备开机闪烁表示有数据活动。速度指示灯SPD 常亮表示100Mbps熄灭表示10Mbps。这些LED的驱动电路可能集成在RJ45插座内部也可能由LAN8720的LED引脚直接驱动并通过限流电阻连接。通过观察这些灯的状态是硬件调试的第一步。3. 软件驱动集成以STM32和ESP32为例硬件通了接下来就是让软件“认识”这块板子。这里我们以最典型的STM32使用HAL库和热门的ESP32使用ESP-IDF为例讲解集成的核心步骤和思想。3.1 STM32平台以CubeMX配置为例STM32的以太网外设ETH是一个完整的MAC控制器它需要外接一个PHY比如我们的LAN8720模块才能工作。集成过程可以高度自动化地使用STM32CubeMX工具。步骤一引脚与时钟配置在CubeMX中打开你的STM32项目在“Pinout Configuration”标签页找到“Connectivity” - “ETH”。将“Mode”设置为“RMII”。此时软件会自动分配RMII接口所需的所有引脚PA1, PA2, PA7, PC1, PC4, PC5等具体因型号而异。你需要核对这些自动分配的引脚是否与你的模块引脚连接一致如果不一致需要手动重映射。关键的一步配置REF_CLK时钟源。在ETH的“Parameter Settings”中找到“Advanced Parameters” - “RMII Clock Source”。如果你的模块是PHY提供50MHz时钟最常见这里必须选择“REF Clock from PHY”。如果是由STM32提供时钟则选择“REF Clock from MCO”。选错会导致通信完全失败。配置MDIO和MDC引脚通常会自动配置好。在“Clock Configuration”标签页确保为ETH MAC提供正确的时钟通常来自AHB总线。步骤二PHY地址与中断配置在ETH的“Parameter Settings” - “PHY”部分设置“PHY Address”。LAN8720的PHY地址由它的RXER/PHYAD0引脚的上拉或下拉电阻决定。模块通常会将这个引脚接地下拉所以地址是0。如果模块设计不同可能是1。务必根据模块原理图或实测确定。勾选“PHY Interrupt”并指定一个外部中断引脚如PG13连接到LAN8720的nINT引脚。这对于实现链路状态变化回调很有用。步骤三LWIP协议栈集成在“Project Manager” - “Advanced Settings”中确保“LWIP”被勾选。CubeMX会自动生成LWIP的初始化代码和网络接口netif的添加代码。生成代码后你会在Src/ethernetif.c文件中找到底层驱动函数。你需要关注low_level_init函数这里完成了ETH外设和PHY的初始化。通常CubeMX生成的代码已经适配了LAN8720但最好检查一下PHY_Init函数中是否调用了正确的PHY驱动函数如LAN8720_Init。一个关键的实操心得在ethernetif.c的low_level_init函数里默认的PHY复位延时可能不够。LAN8720从上电到稳定可操作需要一定时间。我遇到过因为复位后立即进行读写操作导致初始化失败的情况。稳妥的做法是在HAL_ETH_Init()之后手动添加一个HAL_Delay(100)再开始PHY的软件复位和配置。3.2 ESP32平台以ESP-IDF为例ESP32尤其是ESP32-S2/S3等型号没有内置以太网MAC但它支持通过SPI或RMII接口外接以太网控制器。对于LAN8720这种RMII PHY我们需要一个“中间人”——一个内置MAC的以太网控制器芯片或者使用ESP-IDF的“Ethernet MAC (EMAC)”驱动配合外部PHY。更常见的做法是使用像W5500、ENC28J60这样的SPI接口以太网模块。但如果我们坚持要用LAN8720和RMII就需要用到ESP32的“Ethernet”示例它实际上依赖一个外部的MACPHY一体芯片如KSZ8081或通过GPIO模拟RMII时序这非常复杂且非标准。因此对于ESP32一个更现实、更高效的方案是将LAN8720模块与一个带有MAC的小型MCU如STM32F107结合做成一个“以太网串口透传模块”。ESP32通过UART或SPI与这个MCU通信由MCU负责TCP/IP协议栈处理。这样ESP32就间接拥有了有线网络能力。市面上很多“串口转以太网模块”就是这种架构。如果你在ESP-IDF的编译错误中看到“invalid fqbn: getting build properties for board esp32:esp32:esp32: invalid”这通常与Arduino框架或板型包配置有关与LAN8720直接关系不大但提醒我们选择正确的开发环境和目标板型至关重要。4. 深度调试与排坑指南即使按照上述步骤配置网络不通依然是常态。下面是我总结的一套排查流程从硬件到软件像破案一样逐层深入。4.1 硬件链路层检查上电三灯插电、插网线。观察模块的PWR、LINK、SPD灯。PWR常亮是基础。LINK灯不亮检查网线是否完好对端设备路由器、电脑的网口灯是否亮起。如果双方LINK灯都不亮大概率是物理链路问题网线、端口。测量时钟用示波器测量LAN8720的XI晶振输入引脚应该有25MHz的正弦波。再测量REF_CLK输出引脚应该有50MHz的方波。如果没有检查晶振电路、芯片供电和复位信号。测量信号用逻辑分析仪或示波器抓取RMII数据线TXD[1:0],RXD[1:0]和CRS_DV。在MCU初始化ETH并尝试发送数据时TXD上应该有明显的脉冲信号。如果完全没有说明MCU端的驱动或引脚配置有问题。4.2 软件驱动层检查PHY寄存器读写这是诊断PHY是否“活着”的最直接方法。在MCU初始化代码中添加一个读取PHY标识符寄存器如地址1和2的函数。LAN8720的ID是0x0007C0F1。如果读不出来或者读出来全是0xFF或0x00说明MDIO/MDC通信失败。可能原因A PHY地址不对。尝试地址0和1。可能原因B MDIO/MDC引脚配置错误比如推挽/开漏模式速度。可能原因C PHY处于硬件复位状态。检查nRST引脚是否为高电平。可能原因D 电源问题芯片未正常工作。链路状态获取成功读取PHY ID后读取基本状态寄存器地址1检查链路状态位Bit2。如果为0表示未建立链路。检查自协商是否开启或者尝试强制设置速度/双工模式。中断与回调如果使用了中断确保中断服务函数ISR被正确触发并能清除PHY的中断状态寄存器。链路通断事件可以通过中断及时通知主程序。4.3 协议栈与网络层检查当硬件链路和驱动层都正常后问题就上升到协议栈。LWIP初始化确保netif_add和netif_set_up被成功调用。可以打开LWIP的调试输出在lwipopts.h中定义LWIP_DEBUG查看ARP、DHCP等过程的信息。IP地址获取DHCP模式观察是否成功获取到IP、网关、DNS。可以在程序中定期打印netif的IP地址信息。如果一直获取不到检查路由器DHCP服务是否开启或者尝试设置静态IP。静态IP模式确保IP、掩码、网关设置正确且与局域网内其他设备不冲突。Ping测试这是最关键的验收测试。在电脑上ping你的设备IP。如果“请求超时”但设备IP在局域网内能显示可能是设备的ICMP协议没有正确处理。检查LWIP的ICMP功能是否启用以及数据包收发函数是否正常。数据收发测试尝试建立一个简单的TCP服务器或客户端进行数据回环测试。从Socket连接建立到数据收发一步步定位问题。一个常见的深坑内存不足。LWIP需要一定量的内存池MEM_SIZE。在lwipopts.h中如果分配的PBUF_POOL_SIZE或MEM_SIZE太小在建立连接或传输较大数据时会出现申请内存失败导致连接意外关闭或数据丢失。尤其是在同时处理多个连接时需要根据实际情况调大这些参数。我的经验是对于简单的单连接应用MEM_SIZE至少设为10KBPBUF_POOL_SIZE设为15以上会比较稳妥。5. 进阶应用与性能考量当基本的Ping通和TCP通信实现后我们可以考虑更实际的应用和优化。5.1 集成到实际项目稳定性设计在实际产品中网络环境复杂多变。我们需要增加鲁棒性处理链路状态监控 不仅仅在初始化时检查要定期例如每秒或在PHY中断中监控链路状态。当网线被拔掉或路由器重启时程序应能检测到LINK_DOWN事件并自动停止发送数据、清理Socket连接。当链路恢复LINK_UP时应能重新初始化网络接口、重新获取IP如果是DHCP并尝试恢复通信。热插拔支持 上述的链路监控机制就是热插拔的基础。此外在硬件上LAN8720的nINT引脚在链路变化时会产生中断利用这个特性比轮询更加及时和高效。看门狗与超时 在网络操作如connect,send,recv中设置合理的超时时间并和硬件看门狗配合。防止因为网络阻塞导致整个系统“卡死”。5.2 性能优化点LAN8720是10/100Mbps的PHY对于大多数嵌入式应用绰绰有余。瓶颈往往不在PHY而在MCU和软件协议栈。DMA与零拷贝 确保STM32的ETH外设使用了DMA。在LWIP的ethernetif.c中low_level_output函数应将LWIP的pbuf数据直接传递给ETH的DMA发送描述符避免不必要的内存拷贝。接收亦然。中断与轮询平衡 LWIP推荐使用sys_check_timeouts()轮询超时事件而数据包接收可以使用中断。在ETH中断服务函数中只做唤醒接收任务信号量等轻量级操作将费时的包处理放到低优先级的线程中。避免在中断服务函数中调用malloc或执行过长的协议栈代码。TCP窗口与缓冲区 对于高速数据传输可以适当增大TCP的发送和接收窗口TCP_WND以及Socket的发送和接收缓冲区大小。这能减少小数据包带来的确认开销提升吞吐量。5.3 替代方案与选型思考虽然LAN8720是经典但了解其他选项有助于做出更合适的选择。LAN8742 如前所述它支持RMIIS带信号强度的RMII在信号完整性要求更高的长距离PCB走线中更有优势。如果设计对EMC要求苛刻或者PHY与MAC距离较远可以考虑LAN8742。DP83848 另一款经典的工业级PHY抗干扰能力更强资料同样丰富。在一些环境恶劣的场合是更好的选择。集成MAC的方案 如果你觉得“MCUPHY”的RMII调试还是太麻烦可以考虑使用集成MAC和PHY的单芯片方案比如W5500硬件协议栈或CH395。它们通过SPI接口与MCU通信软件驱动简单至极几乎拿过来就能用代价是成本稍高且性能上限和灵活性不如“MCULWIPPHY”的方案。选择LAN8720模块本质上是在选择一种平衡在成本、开发难度、社区资源、性能之间找到一个最适合当前项目的甜蜜点。对于学习和大多数中小型物联网、工控设备它依然是一个不会出错的高性价比起点。