ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ESP32接LAN8720以太网模块:RMII接口、接线与调试避坑指南

ESP32接LAN8720以太网模块:RMII接口、接线与调试避坑指南 最近在项目里折腾ESP32接LAN8720以太网模块发现一个很有意思的现象这颗百兆网络接口芯片几乎是IoT有线联网的默认选择网上教程多如牛毛但绝大多数只扔给你一张接线图就完了。结果真到了自己画板、打样、调试的时候问题一个接一个初始化失败、ping不通、隔三差五断流、甚至程序都下载不进去。这篇文章就把我实际踩过的坑和排查思路完整捋一遍围绕ESP32连接LAN8720/LAN8742的完整流程展开从RMII接口原理、硬件接线、驱动初始化到高频问题定位尽量让拿到模块的人少走弯路。如果你正准备用ESP32做带以太网的产品或者手里有一块LAN8720模块想快速跑起来这篇内容应该能直接帮上忙。我会把接线表、初始化代码、排查方法和寄存器读法都放出来不是让你照着抄而是告诉你每个引脚为什么这么接、出了问题从哪里查。1. 为什么是LAN8720一颗PHY芯片解决有线联网1.1 先搞清楚PHY芯片在系统里的角色很多新手容易把“PHY芯片”和“网卡芯片”搞混。以ESP32为例芯片内部其实已经继承了一个以太网MAC控制器负责数据链路层的封装、解封装、地址过滤这些工作但它发不出去物理信号。PHY芯片的作用就是承担物理层的工作把MAC传来的数字信号编码成能在网线上传输的电平信号同时把收到的模拟信号解码成数字信号给MAC。简单类比一下MAC是快递公司的分拣中心PHY是楼下送货的快递员两者必须配合才能完成整个寄件流程。LAN8720就是这样一颗成本很低、外围电路非常简单的百兆PHY芯片。它支持10Mbps和100Mbps两种速率自适应交叉网线内部还集成了1.2V稳压器所以整个芯片只需要一路3.3V供电不需要额外电源。这个特性在做小模块时特别友好很多所谓的“ESP32以太网模块”其实就是一颗LAN8720加几个电阻电容和RJ45座子。1.2 RMII接口让MCU和PHY沟通的关键MCU的MAC和PHY之间有两种常见的连接方式MII和RMII。MII是老的并行接口标准需要16根数据线加控制线引脚占用太多嵌入式场景基本没人用。RMII即缩略版MII把数据线压缩到2根发送、2根接收加上控制信号一共7根线就能跑通。这7根线分别是TXD0、TXD1、TX_EN、RXD0、RXD1、CRS_DV和REF_CLK。其中REF_CLK是50MHz参考时钟所有数据线都对齐这个时钟传输。这里有个容易忽略的细节RMII的时钟有几种提供方式可以由MAC输出给PHY、可以由外部50MHz振荡器给两个芯片、也可以由PHY从25MHz晶振倍频后输出给MAC。ESP32的方案通常走“GPIO0输出50MHz给PHY”的方式但GPIO0刚好是芯片的BOOT引脚这就埋下了一个大坑后面我会专门展开。1.3 LAN8720和LAN8742怎么选Lan8720和LAN8742在功能上基本是同一代产品寄存器兼容性很好很多应用代码可以不做修改直接跑。LAN8742主要是在功耗上做了优化静态电流更低适合对功耗敏感的设备。价格差异不大买模块时哪个有货就买哪个。唯一要留意的是芯片后缀LAN8720A是老版本有些淘宝模块上丝印写的是LAN8720A驱动和寄存器跟LAN8720是兼容的不用太纠结。真正要注意的是区分“LAN8720模块”和“带网络变压器的模组”前者往往需要自己配RJ45和网络变压器后者直接插网线就能用。2. 硬件接线与PCB设计核心细节2.1 ESP32与LAN8720的完整接线表网上能搜到很多版本的接线图但不同ESP32开发板、不同LAN8720模块的引脚定义有细微差别。下面这张表是我实际验证过的组合基于ESP32 DevKitC和最常见的蓝色LAN8720模块如果你用的是其他板子务必对着原理图核对。信号方向ESP32引脚LAN8720模块引脚说明时钟GPIO0REF_CLK50MHz参考时钟ESP32输出发送使能GPIO21TX_EN发送有效信号发送数据0GPIO19TXD0发送位0发送数据1GPIO18TXD1发送位1接收数据0GPIO25RXD0接收位0接收数据1GPIO26RXD1接收位1载波监听GPIO27CRS_DV接收有效管理时钟GPIO23MDC配置PHY寄存器用的时钟管理数据GPIO22MDIO配置PHY寄存器用的数据复位GPIO16nRST低电平复位PHY地址选择GNDPHYAD0接低为地址0接高为地址1电源3V3VDD模块供电地GNDGND共地接线一定要注意一点模块上如果自带Power Enable引脚有些蓝色小板有需要接到高电平或由GPIO控制否则PHY上不了电。我最初调试时就是漏了这个引脚折腾了很久才发现模块根本没供电。2.2 复位、时钟和PHY地址最容易翻车的三个引脚先说复位。LAN8720的nRST是低有效复位引脚手册要求复位低电平至少保持25微秒。很多廉价模块把这个引脚直接接一个上拉电阻到3.3V完全依赖芯片内部的上电复位电路这在电源爬坡缓慢或者有干扰时会出现复位不彻底的情况。稳妥的做法是用一个GPIO控制复位或者用一个简单的RC复位电路10k电阻上拉到3.3V0.1uF电容到地。上电时电容充电引脚先低后高刚好满足复位时序。但RC复位有个问题如果电源快速通断RC时间常数可能不够所以量产板最好还是让MCU控制复位软件初始化之前先拉低50ms再拉高。再说时钟。RMII模式下REF_CLK必须是精确的50MHz。ESP32官方推荐的接法是让GPIO0输出50MHz时钟给PHY的REF_CLK引脚这也是Arduino库里ETH_CLOCK_GPIO0_OUT模式的默认行为。但GPIO0同时是BOOT模式选择引脚如果PHY模块在REF_CLK线上有较大的电容负载或者你的电路板上GPIO0被外部设备拉到了一个尴尬的电平就可能导致ESP32上电后进入下载模式或启动异常。最后是PHY地址。LAN8720的PHYAD0引脚决定芯片ID悬空时内部下拉为0所以大多数模块默认PHY地址是0x00。但有些厂商把PHYAD0通过10k电阻上拉到3.3V默认地址变成了0x01。如果你的初始化代码写死地址0却发现识别不到PHY大概率就是这里出了问题。后面第4节我会详细讲怎么排查。2.3 电源、去耦与Layout注意事项LAN8720内部集成了1.2V LDO但对外部电源质量还是有要求的。3.3V引脚旁边要放一个10uF的钽电容或陶瓷电容做储能再放几个100nF高频去耦电容尽量靠近芯片电源引脚。我看到过不少DIY板子在这上面省料结果表现为网络一跑大流量就重启。Layout上RMII信号线虽然不像USB那样严格要求差分等长但REF_CLK这条时钟线必须尽量短避免与TX/RX数据线平行走线太长。数据线长度差尽量控制在25mm以内每根信号线旁边都要有连续的地平面作为回流路径。网口变压器到RJ45之间的差分对要按差分规则布线间距和线宽保持一致变压器下方不要铺地铜皮。另外还要注意RJ45的金属外壳接地处理。如果外壳直接接地可能会引入共地噪声如果悬空ESD防护又不足。常规做法是通过一个1M电阻并联高压电容接地这个电容通常选1000V以上的防止静电打坏PHY。3. 软件初始化与驱动配置实操3.1 Arduino环境下最简初始化流程Arduino-ESP32核心库自带了ETH库使用非常直接。需要先引入ETH.h然后在setup里调用ETH.begin。但不同版本的库参数差异很大我当前用的是以ETH_CLOCK_GPIO0_OUT作为最后参数的写法#include ETH.h void setup() { Serial.begin(115200); delay(1000); // PHY地址0不用指定电源控制引脚传-1MDCGPIO23MDIOGPIO22 // PHY类型用ETH_PHY_LAN8720时钟模式由GPIO0输出50MHz bool ok ETH.begin(0, -1, 23, 22, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT); if (ok) { Serial.println(ETH init ok); } else { Serial.println(ETH init failed); return; } // 等待网线插入和DHCP获取 while (!ETH.isConnected()) { delay(200); Serial.print(.); } while (ETH.localIP() IPAddress(0, 0, 0, 0)) { delay(200); Serial.print(); } Serial.printf(IP: %s\n, ETH.localIP().toString().c_str()); }如果你用的Arduino-ESP32版本比较老编译报参数数量不匹配可以去掉最后两个参数写成ETH.begin(0, -1, 23, 22, ETH_PHY_LAN8720)这时库会使用默认时钟配置但要注意默认配置可能不是GPIO0输出50MHz的模式这样就很可能初始化失败。建议下载模块之前先确认自己用的是哪个版本的Arduino-ESP32核心库然后去对应的ETH.h头文件里看begin函数的定义别盲目抄网上的代码。3.2 ESP-IDF环境下的驱动配置ESP-IDF的以太网驱动走的是esp_eth组件代码结构稍微复杂一些但可控性更强。关键点在于配置esp_eth_mac和esp_eth_phy两个对象然后安装驱动。下面是一个适配LAN8720的最小初始化片段#include esp_eth.h #include eth_phy/phy_lan8720.h #include eth_mac/eth_mac_esp32.h esp_eth_handle_t eth_handle NULL; void ethernet_init(void) { // 配置MAC使用内部EMACGPIO0输出50MHz时钟 eth_mac_config_t mac_config ETH_MAC_DEFAULT_CONFIG(); mac_config.smi_mdc_gpio_num 23; mac_config.smi_mdio_gpio_num 22; mac_config.clock_config.clk_mode EMAC_CLK_GPIO_OUT; esp_eth_mac_t *mac esp_eth_mac_new_esp32(mac_config); // 配置PHY地址0复位引脚GPIO16 eth_phy_config_t phy_config ETH_PHY_DEFAULT_CONFIG(); phy_config.phy_addr 0; phy_config.reset_gpio_num 16; esp_eth_phy_t *phy esp_eth_phy_new_lan8720(phy_config); esp_eth_config_t eth_config ETH_DEFAULT_CONFIG(mac, phy); if (esp_eth_driver_install(eth_config, eth_handle) ! ESP_OK) { ESP_LOGE(ETH, driver install failed); return; } // 注册网络接口并启动 esp_netif_config_t netif_cfg ESP_NETIF_DEFAULT_ETH(); esp_netif_t *eth_netif esp_netif_new(netif_cfg); esp_eth_attach_netif(eth_handle, eth_netif); esp_eth_start(eth_handle); }这里最需要注意的是EMAC_CLK_GPIO_OUT模式。ESP32内部MAC外设可以输出50MHz时钟到GPIO0这跟Arduino库里的ETH_CLOCK_GPIO0_OUT是一个意思。如果你选了EMAC_CLK_EXT就得自己提供外部50MHz时钟到某个输入引脚很多模块上并没有预留这个输入所以默认用输出模式最省事。3.3 验证链路是否真正跑通初始化完成后不要急着写业务代码先在串口日志里确认几个状态以太网控制器是否link up、是否获取到IP。Arduino环境下可以用ETH.linkUp()和ETH.localIP()检查ESP-IDF环境下可以在esp_netif的定时回调里看event。下面这些日志是我正常跑通时看到的典型输出ETH init ok ......................... ETH connected IP: 192.168.1.108如果卡在ETH init failed优先检查PHY地址和时钟配置。如果卡在等待connected那个位置就得怀疑网线是否插好、网口指示灯是否正常、PHY有没有检测到link。如果拿到IP了但ping网关不通多半是RMII信号有一根线接错或者虚焊。链路层跑通后可以用iperf工具跑一下吞吐测试。正常情况下百兆口单向吞吐可以到90Mbps以上如果只有几Mbps或者掉包严重先排查REF_CLK时钟质量和电源噪声再排查网线是不是被压坏了。我遇到过“能ping通但大包不通”的情况最后发现是RJ45座子的一对线虚焊。4. ESP32连接LAN8720常遇到的3个问题及解决方法4.1 问题一PHY地址配置错误导致初始化失败现象描述ETH.begin返回false或者ESP-IDF日志里出现“cannot read PHY”之类的错误但硬件接线看起来完全正确。原因分析前面提到过LAN8720的PHYAD0引脚控制PHY地址模块设计不同默认地址可能是0也可能是1。如果你的代码里写死了0而模块实际地址是1MDIO管理接口就找不到PHY初始化自然失败。还有一部分模块在PHYAD0上做了跳线或者电阻选择同一个型号不同批次可能都不一样这个坑很隐蔽。解决方法先用万用表量一下模块上PHYAD0引脚的电压接近0V就是地址0接近3.3V就是地址1。也可以直接从软件角度探一下把初始化代码中的PHY地址逐一改成0和1各试一次看哪一次能成功。更专业的方式是写一个小函数读PHY的ID寄存器LAN8720的PHYIDR1寄存器地址是0x02读出来的值应该是0x0007PHYIDR2寄存器地址是0x03读出来是0xC0F1。如果哪个地址能读出这个组合那个地址就是对的。我的建议是量引脚电压最直观也最快。我踩过一次坑是在某块定制板上PHYAD0被厂家默认接高而网上教程和库默认都是0查了一天才发现是这个原因。4.2 问题二复位时序不正常导致偶尔连不上现象描述上电后有时候能正常拿到IP有时候卡死在初始化按一下板子上的复位键可能又好一阵子但过段时间又断。原因分析LAN8720的nRST引脚如果只是简单接上拉完全依赖内部上电复位在电源上电斜率缓慢或存在多个大电容时复位脉冲可能不满足最小时间要求。还有一种情况是nRST接到了系统复位线上导致PHY和MCU同时复位但MCU启动起来后立刻初始化ETH此时PHY可能还没完成内部校准初始化就会失败。解决方法把nRST接到一个独立GPIO控制初始化前先拉低至少50ms再拉高。示波器验证一下复位引脚波形确保低电平时间足够。我在量产板上用的方案是GPIO16接nRST上电时保持低电平约100ms然后拉高再延时200ms执行ETH.begin稳定性和热插拔测试都通过。另外要注意nRST不能悬空。悬空时静电干扰很容易导致PHY状态不确定表现就是时好时坏。如果预算有限不想占用GPIO至少也要用10k上拉加0.1uF电容到地的RC电路。4.3 问题三时钟与RMII信号异常导致丢包或完全不通现象描述初始化看起来成功了但ping不通或者能通但大包丢包严重吞吐低得离谱。原因分析时钟这块影响面最大。如果ESP32的GPIO0输出50MHz给PHY而GPIO0同时被其他外设占用或者PCB上这条时钟线走线过长、过孔太多信号质量会严重劣化。另一个常见问题是GPIO0作为BOOT引脚的冲突如果PHY模块在REF_CLK线上对地接了较大的电容导致GPIO0电平异常ESP32会无法正常启动表现就是程序跑不了甚至串口下载都困难。解决方法优先检查时钟模式配置是否正确确保是GPIO0输出50MHz而不是PHY自己出时钟。其次用示波器看REF_CLK的波形频率应为50MHz幅度应接近3.3V上升沿不能有明显塌陷。如果波形不行把时钟线的负载电容减小走线加粗改短。GPIO0冲突的问题最有效的办法是板子上给GPIO0留一个0欧电阻跳线需要下载程序时断开PHY方向烧录完再接回。RMII信号的走线也不能忽视。TXD0/TXD1、RXD0/RXD1这几根线要尽量等长TX_EN和CRS_DV不要跨分割区走线。如果这些信号线过长且互相平行数据建立保持时间会变差出现间歇性丢包。还有一点很多人忽略RJ45的地要和PCB地处理好最好使用网络变压器自带的中心抽头通过RC到机壳地别让网线侧的噪声灌进PHY的地平面。5. 调试工具、查询手册与工程经验补充5.1 从日志与寄存器入手快速定位问题遇到PHY层故障时光看网络层结果是不够的。我建议在代码里加一个读取PHY基础状态的功能把寄存器0x01基本状态寄存器和寄存器0x1FLAN8720的状态寄存器打印出来。状态寄存器里link status位、negotiation complete位都能直接反映物理链路情况比盲猜网线有没有插好靠谱得多。如果你用的是ESP-IDF可以通过esp_eth_ioctl接口命令读取寄存器或者直接封装一个MDIO读写函数。Arduino环境下没有现成的公开接口但可以在ETH库底层看到它调用的是esp_eth驱动自己写MDIO读写也不难GPIO 23拉时钟、GPIO 22拉数据按IEEE 802.3的SMI协议时序操作即可。我调试时一般先把姿态放低只要能读到PHY芯片ID说明MDIO物理通路是好的后面再逐步查网络层。5.2 样板调试的几个实用习惯样片回来后先别急着上系统用镊子轻轻拨动每个引脚排查虚焊。LAN8720是QFN封装焊盘在底部手工焊接很容易连锡或假焊。我第一次打样就是RXD1虚焊看起来引脚都对上了但网口死活不通补焊后才解决。调试顺序建议从电源开始先量3.3V有没有短路再量LAN8720内部1.2V是不是正常。很多模块上预留了1.2V测试点确认这个电压存在基本能断定芯片已经正常工作。然后量REF_CLK有没有50MHz时钟再量MDC/MDIO通信波形一环扣一环不跳步能省下大量猜谜时间。5.3 量产阶段的注意事项如果这个方案要走到量产有些细节就不得不提前考虑。GPIO0作为REF_CLK输出和BOOT脚冲突的问题在量产板上更不能含糊。我的做法是板子上做两个电阻位一个串联在GPIO0到PHY之间一个从GPIO0下拉到地生产测试时可以通过软件或工装控制是否连通既能保证时钟输出又能避免模块影响BOOT模式。量产还要关注物料一致性。不同批次的LAN8720模块PHYAD0上拉电阻可能不一样电源去耦电容容值也不一样。下单前要求模块厂提供原理图和贴片清单把关键电阻电容的位号核对一遍。最怕的是小批量产时换了物料地址从0变1又没有测试工装几十片板子全部初始化失败。另外网络变压器型号对链路质量影响很大。如果模块不带变压器你自己选型时要注意中心抽头接法、隔离耐压和共模电感参数这个细节直接决定产品能不能过EMI测试也影响长时间运行的稳定性。从我实际做过的几个项目来看LAN8720本身是一颗很皮实的芯片绝大多数问题都出在周边的复位、时钟和地址配置上。把这些外围电路理顺软件层多做一步状态检查整个以太网链路基本就能稳定跑起来。如果你现在正卡在某一环建议先从PHYAD0电平量起十有八九能发现问题。
返回列表