ARTICLE DETAIL

资讯详情

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

STM32实战:YT8512 PHY芯片RMII接口配置与调试全攻略

STM32实战:YT8512 PHY芯片RMII接口配置与调试全攻略 开头做嵌入式网络设备这么多年RMII接口和PHY芯片配置基本属于家常便饭但每次换一颗新的PHY厂商还是会踩到一堆坑。最近项目里因为国产化选型把原来用的LAN8720A换成了裕太微的YT8512本来以为寄存器兼容性很好结果调RMII模式、自协商、时钟树的时候折腾了两天。网上关于这颗芯片的中文资料确实少大部分还是英文datasheet里能翻出来的零散信息所以我想把这次实战的完整过程整理出来从RMII接口原理、YT8512硬件设计到MDIO驱动代码、常见问题排查一步步写清楚尤其给出可以直接抄的STM32工程代码。不管你是用STM32、国产MCU还是FPGA做百兆以太网这篇文章都能帮你少走弯路。1. 先摸清RMII接口引脚、时序和时钟1.1 RMII接口信号一览RMII全称Reduced Media Independent Interface是IEEE 802.3u里定义的一种MAC层与PHY层之间的标准接口。相比老一代MII它最大的特点就是引脚少。一个完整的RMII接口从MAC到PHY之间只需要这么几根信号线信号名方向作用TXD[1:0]MAC → PHY发送数据线2bit并行TX_ENMAC → PHY发送使能高电平表示TXD上的数据有效RXD[1:0]PHY → MAC接收数据线2bit并行CRS_DVPHY → MAC载波侦听/数据有效相当于MII里的CRS和RX_DV合并REF_CLK双向/共用50MHz参考时钟决定所有信号采样节奏MDCMAC → PHY管理接口时钟用于MDIO总线MDIO双向管理接口数据线用来读写PHY寄存器RESET_NMAC → PHY硬件复位低有效这里有个很多人初学容易忽略的点RMII模式下没有独立的RX_CLK接收数据是靠REF_CLK来采样的。所以REF_CLK的稳定性和相位关系直接决定了链路能不能正常工作。TXD和RXD都只有2bit在100M速率下配合50MHz时钟刚好做到2bit × 50MHz 100Mbps。1.2 MII与RMII为什么二选一既然MII是老标准为什么后来RMII能普及关键就在引脚数量上。MII需要TXD[3:0]、RXD[3:0]、TX_CLK、RX_CLK、TX_EN、RX_DV、CRS、COL、TX_ER、RX_ER等一系列信号算下来20根左右。RMII砍到7根核心信号线对于MCU这类引脚资源紧张、本身又没有专门以太网MAC外设的芯片来说优势非常明显。特性MIIRMII数据线宽度4bit TX 4bit RX2bit TX 2bit RX参考时钟25MHz100M/ 2.5MHz10M固定50MHz信号线数量约20根约7根是否独立RX_CLK是否适合场景FPGA/高性能交换芯片MCU、低引脚数SoC代价是RMII对时钟要求更严格50MHz的REF_CLK必须始终存在哪怕10M速率下也不能像MII那样降低时钟频率。另外由于数据位宽减小信号变化频率提高对PCB走线等长、时钟质量要求也略高。但对STM32这种芯片来说RMII明显是更现实的选择我项目里也基本只用RMII。1.3 REF_CLK的50MHz到底谁来提供这是新手高频踩坑点。RMII的REF_CLK可以由PHY芯片产生也可以由MAC侧产生两种方案各有前提。如果PHY芯片接的是25MHz晶振PHY内部PLL会把25MHz倍频到50MHz然后从REF_CLK引脚输出给MAC这种叫PHY提供时钟MAC的RMII接口工作在从模式。如果MAC侧的RMII时钟由外部有源晶振或者主控芯片时钟模块直接产生50MHz再同时送给MAC和PHY这种叫外部时钟源模式PHY的REF_CLK变成输入。对STM32来说常用的CubeMX配置里ETH外设的RMII时钟源一般选MCO引脚输出50MHz或者由外部PHY来提供。YT8512我实际用的方案是外部25MHz晶振接在PHY的XI/XO引脚上PHY内部倍频出50MHz然后通过REF_CLK引脚送到STM32的ETH_CLK引脚。这样STM32只负责接收时钟不用额外配置MCO输出省了一个引脚也减少了一路高频信号。需要注意STM32的ETH外设RMII模式对REF_CLK是输入所以这种情况下刚好像MAC从模式一样工作。2. YT8512这颗PHY的选型与硬件设计2.1 为什么选YT8512YT8512是裕太微电子推出的一颗10/100M自适应以太网PHY芯片支持RMII和MII两种MAC接口内部集成LDO稳压外围电路非常精简。国产化替代趋势下这颗芯片在不少开发板和工控设备上出现得很频繁我接触到的飞凌、正点原子部分板卡都开始用这颗替换LAN8720A。从功能上看YT8512支持IEEE 802.3/802.3u标准支持自动协商、交叉网线自动检测、MDI/MDIX自适应这些对实际调试很有帮助。它内部有完整的DSP均衡器链路信号质量比老芯片稳定极端温度下工作也算可靠工业级场景能接受。关键的是它在硬件设计上基本和LAN8720A引脚兼容很多现成电路可以直接替换对正在做替代方案的人来说省事不少。2.2 YT8512关键引脚和启动配置YT8512有几个关键引脚在硬件设计时就得定下来软件再折腾也改不了硬件strap的状态PHYAD[2:0]PHY地址配置脚一般默认接成000对应PHY地址0x00。如果I2C/SMI总线上挂了多个PHY得用电阻上下拉改成不同地址。MODE/RMII_MODE相关的strap脚决定PHY工作在RMII还是MII模式有些芯片手册叫Interface Mode Select。这个比寄存器优先级高硬件上接对了软件才谈得上后续配置。CLK_OUT_EN决定是否把50MHz参考时钟从REF_CLK引脚输出我们项目里要让PHY给MAC供时钟所以这个脚要让输出使能。LED_0、LED_1链路/活动指示灯调试时接两个LED能直观看到Link状态变化强烈建议预留。YT8512的strap引脚通常通过外部上下拉电阻在复位释放时被锁存所以硬件定型后就不能轻易改了。如果遇到板子layout已经固定但模式不对只能靠飞线或者割线改strap非常麻烦。我建议原理图阶段就把这些脚用0欧电阻连接到电源或地方便调试期切换。2.3 外围电路设计要点PHY芯片的硬件设计不算复杂但细节决定成败。网络变压器加RJ45是标准方案变压器中心抽头、终端电阻、共模电感这些都要按datasheet参考电路来接。YT8512和LAN8720A的参考设计很接近我一般是把官方demo的原理图导出来然后按自己板子的电源域做微调。电源方面YT8512内部有LDO通常3.3V单电源供电模拟电源和数字电源引脚分别加RC滤波。PHY芯片对电源纹波比较敏感我用LDO给PHY单供电实测比DCDC直供更稳。滤波电容要尽量靠近电源引脚每个电源引脚至少放一个0.1uF和一个1uF电容组合。PCB走线里TXD[1:0]、RXD[1:0]这些数字信号要控制等长CRS_DV和REF_CLK这跟线尤其要注意尽量短并且远离其他高速信号。如果REF_CLK走线过长相位噪声会直接影响数据采样。网络变压器到RJ45之间的差分线要严格按照差分阻抗100欧来走间距与线宽同时控制走线离板边要留足够距离防止串扰。这些做好了后面调试会省掉一半的麻烦。3. 软件配置实战从零驱动YT85123.1 先搞定MDIO总线读写所有PHY寄存器操作都走MDIO管理总线这是IEEE 802.3 Clause 22定义的标准协议。一条完整MDIO帧长64bit包括32bit前导码、2bit起始码、2bit操作码、5bit PHY地址、5bit寄存器地址、2bit转发状态以及16bit数据。读操作时最后2bit是高阻态由PHY芯片驱动数据线把寄存器值返回给MAC写操作时数据由MAC侧发出。如果MCU自带MDC/MDIO控制器直接用底层驱动就好。但很多场景下需要用GPIO模拟比如国产MCU没有以太网MAC外设只是用SPI接了W5500这类芯片那就不涉及PHY寄存器。但在STM32裸机工程里我习惯直接写GPIO模拟MDIO一是方便移植二是调试时可以随时在任意引脚上重现时序。下面是GPIO模拟MDIO读写的核心代码参考了常见开源驱动我整理成了可以直接用的版本#define MDIO_DELAY() for(volatile int _i0;_i20;_i) // MDIO读 uint16_t mdio_read(uint8_t phyaddr, uint8_t regaddr) { uint16_t val 0; // 前导码至少32个连续1 for (int i 0; i 32; i) { MDC_L(); MDIO_W(1); MDC_H(); } // 起始码 读操作码 (01 10) // 实际封装的逻辑是逐bit发送 write_bits(0x01, 2); // 起始码 write_bits(0x02, 2); // 读操作码 write_bits(phyaddr, 5); write_bits(regaddr, 5); // 2bit TA读时第1个clk高阻第2个clk为0 MDC_L(); MDIO_W(1); MDC_H(); // 高阻时间 MDC_L(); MDIO_W(0); MDC_H(); // turn around // 读16bit数据 for (int i 0; i 16; i) { MDC_L(); val 1; if (MDIO_R()) val | 1; MDC_H(); } // 释放总线 MDIO_W(1); return val; }写操作结构和读类似只是操作码是01TA里两个bit直接输出01然后跟16bit数据。这里要注意MDIO时序里电平切换必须在MDC低电平期间做好MDC上升到高电平后PHY/MAC才采样数据这个顺序反了很容易读到随机值。3.2 PHY复位与ID识别硬件上电会自动复位但软件更稳妥的做法是控制RESET_N引脚做一次完整复位然后延时等待PHY内部稳定。我一般给PHY芯片至少留100ms的上电稳定时间软件复位后再延时20ms左右等内部DSP和模拟电路完全就绪。复位完成后第一步就是读PHY ID确认SMI总线上挂的确实是YT8512且地址正确。标准寄存器0x02和0x03存放PHY ID其中0x02高16位、0x03低16位。我实际读取YT8512时有些批次寄存器2读到0x0000寄存器3读到类似0x0A13这类型号ID具体数值建议以你手里的手册为准。关键是先判断读回来的值不是0xFFFF也不是全0否则先不要往下走优先排查硬件。uint16_t id1 mdio_read(PHY_ADDR, 0x02); uint16_t id2 mdio_read(PHY_ADDR, 0x03); printf(PHY ID: 0x%04X 0x%04X\r\n, id1, id2); if (id1 0xFFFF || id1 0x0000) { // 检查PHY地址和MDIO上拉电阻 }3.3 软复位与RMII模式确认PHY ID正常后下一步是软复位。寄存器0x00的bit15是软复位位写1触发复位复位完成后硬件自动清零。软复位期间不要读写其他寄存器等待100ms比较稳定。mdio_write(PHY_ADDR, 0x00, 0x8000); HAL_Delay(100);关键的RMII接口模式配置得看YT8512的手册。在我拿到的版本里YT8512默认根据strap引脚决定接口模式软件可以通过扩展寄存器再次确认或切换。很多YT8512资料里提到厂商特定寄存器0x1F等位置有接口选择位我这边工程里是通过硬件strap把模式锁死为RMII所以软件里只做了读取确认没有强行改写。如果你手头的板子没有正确strap软件里就需要找到对应的interface mode寄存器去设置这个一定要以datasheet里的寄存器定义为准不同批次定义可能存在差异。这里建议加一个自检逻辑初始化完成后把寄存器0x00的值读出来打印看看bit8全双工使能、bit13速度选择是否符合预期。如果寄存器0x00的读写不正常后面的自动协商配置根本没有意义。3.4 自动协商与链路状态读取YT8512上电默认开启自动协商一般不需要改寄存器就能和交换机协商出100M全双工。但为了稳定性我还是会在代码里显式开启ANEAuto-Negotiation Enable。// 标准控制寄存器0x00 // bit12: 自动协商使能 // bit13: 速度选择(1100M) // bit8: 全双工 uint16_t ctrl mdio_read(PHY_ADDR, 0x00); ctrl ~(1 12); ctrl | (1 12) | (1 13) | (1 8); // 100M全双工 自协商 mdio_write(PHY_ADDR, 0x00, ctrl); // 读取状态寄存器0x01bit2是Link Status uint16_t status 0; for (int i 0; i 100; i) { status mdio_read(PHY_ADDR, 0x01); if (status (1 2)) { // 链路已建立 break; } HAL_Delay(10); }Link Status这个bit有个特点它是锁存性的只要发生过一次断链会一直保持0必须读一次寄存器或者重新读才能反映当前真实状态。所以我判断链路时习惯连续读两次第一次清锁存位第二次才是当前状态。这也是很多人明明插着网线却每次都读到链路down的原因。STM32HAL库工程里如果你的MCU自带MAC也可以用HAL_ETH_ReadPHYRegister这类现成函数但底层逻辑和上面GPIO模拟是一样的寄存器地址和PHY地址匹配就行。3.5 完整初始化代码串起来把上面的逻辑合并成一个初始化函数便于工程直接引用核心流程包括硬件复位、延时、读ID、软复位、确认RMII模式、开启自动协商、等待Link Up、最后配置MAC的RMII模式并启用收发。下面是简化但可用的版本uint8_t yt8512_init(void) { uint16_t reg; // 1. 硬件复位 PHY_RESET_GPIO 0; HAL_Delay(50); PHY_RESET_GPIO 1; HAL_Delay(100); // 2. 读取ID确认挂在正确地址 uint16_t phy_id_high mdio_read(PHY_ADDR, 0x02); uint16_t phy_id_low mdio_read(PHY_ADDR, 0x03); if (phy_id_high 0xFFFF || phy_id_high 0x0000) { return 1; } // 3. 软复位 mdio_write(PHY_ADDR, 0x00, 0x8000); HAL_Delay(100); // 4. 设置100M全双工 自动协商 reg mdio_read(PHY_ADDR, 0x00); reg | (1 12) | (1 13) | (1 8); mdio_write(PHY_ADDR, 0x00, reg); // 5. 等待Link Up for (int i 0; i 200; i) { reg mdio_read(PHY_ADDR, 0x01); // 第一次读清锁存 HAL_Delay(1); reg mdio_read(PHY_ADDR, 0x01); // 第二次读当前状态 if (reg (1 2)) { // 链路OK return 0; } HAL_Delay(10); } return 2; }实际工程中初始化函数返回值要区分没有检测到PHYLink超时等不同错误方便串口定位。我不建议把初始化搞得特别多分支嵌入式里越简单越可靠出错时靠串口日志和硬件测量来定位比较快。4. 实战中常见问题与排查技巧4.1 现象PHY ID读不到或读到0xFFFF这是最基础也是最常见的现象。排查顺序我一般固定为先量PHY的供电电压确认3.3V正常再用示波器看25MHz晶振有没有起振幅度够不够然后查PHYAD strap引脚的电平确认SMI地址没配错最后看MDC/MDIO这两根线上有没有上拉电阻MDIO是开漏输出必须有上拉才能被拉高一般用10k上拉到3.3V。如果上面都正常还要考虑RESET引脚是否一直被拉低。我曾经遇到板子因为RC复位电路时间常数太大导致PHY迟迟没有释放复位MDIO自然读不到任何响应。后来直接把RESET_N改由单片机GPIO控制复位时序完全可控问题就消失了。4.2 现象Link能够Up但Ping不通链路指示灯都亮了自动协商也完成了但ping却不通。这种问题多半在MAC侧RMII配置和时钟相位上而不是PHY芯片本身。先确认STM32或MCU的ETH外设是不是真的配置成了RMII模式有些代码从别的项目拷过来MII和RMII配置混在一起初始化时自带矛盾。其次确认REF_CLK的频率用示波器量50MHz是否稳定如果PHY输出给MAC波形幅度和抖动是否在可接受范围内。还有一个容易被忽略的点是CRS_DV信号在RMII模式下这个信号由PHY产生如果MAC的GPIO复用没配好或者板子飞线接错数据路径就不通。这时候抓包Wireshark很有效。把电脑网卡和板子直连或者经过交换机抓包看看板子上电后有没有发出ARP广播。如果VLAN/网络抓包看到ARP但PC不回包多半是MAC地址问题或者IP配置在同一个子网里如果板子根本没发包问题大概率集中在RMII数据通路上。也可以先在板子上做自环测试MAC发送模式改成内部回环看收发计数是否有变化快速定位是MAC侧还是PHY侧故障。4.3 现象速率协商成10M而不是100M有时候插上交换机后速率只有10M。这种情况先确认网线是超五类以上且线序正常然后用ethtool看协商结果。YT8512的自动协商能力要看两个地方一个是0x04寄存器Auto-Negotiation Advertisement要确保bit7和bit6都置1分别表示100Base-TX全双工和半双工能力被通告另一个是0x00控制寄存器不能手动强制成10M模式。如果芯片默认通告能力存在问题可以尝试先关闭自动协商强制写100M全双工模式工作看链路是否变为100M。我之前遇到过一次是PHY的strap脚把速率上限限制在了10M硬件电路上的下拉电阻和软件愿望不一致改软件没用最后用烙铁挪了0欧电阻才解决。所以排查这类问题要有耐心先从硬件层面下手。4.4 现象Link偶尔Down、Ping延迟忽高忽低表象是网络不稳定实际多半是电源纹波大、PCB信号质量差或者网线接触不良。我遇到过YT8512布局离DCDC电感太近开关噪声耦合到REF_CLK上导致数据采样随机出错表现为ping延迟波动大、偶尔丢包。解决办法是把PHY供电和REF_CLK走线远离DCDC加磁珠和电容隔离。另外晶振精度也会导致长时间传输后出现CRC错误。RMII的REF_CLK通常要求50ppm以内的精度普通晶振尽量选±30ppm的不要为了省钱用廉价谐振器。如果发现发出去的报文在交换机侧抓包看到CRC错误很多时钟抖动基本是头号嫌疑。软件层面还可以降低MDC时钟频率MDC一般不超过2.5MHz时钟太快容易误采样。4.5 Linux下快速验证PHY状态和回环测试如果你的平台跑的是Linux调试百兆PHY会比裸机方便得多。用ethtool直接看寄存器# 查看协商速率、双工、Link状态 ethtool eth0 # 查看PHY寄存器原始值 ethtool -d eth0 # 查看PHY ID ethtool -e eth0自环测试的话Linux内核自带PHY回环测试接口可以用ethtool触发不过不同驱动支持程度不一样。我常用的土办法是先用ifconfig把IP配上然后板子上ping自己确认协议栈基本通。再用PC和板子互ping配不同IP方便路由区分看丢包和延迟。需要抓包分析时用tcpdump在板子上抓tcpdump -i eth0 -XX能看到完整帧头和MAC地址比盲猜要快得多。4.6 排查技巧速查表现象检查方向快速定位手段读不到PHY ID供电、晶振、复位、MDIO上拉、PHY地址万用表量电压、示波器看晶振波形Link Up但Ping不通RMII模式配置、REF_CLK、CRS_DV、MAC侧复用示波器量REF_CLK、Wireshark抓PC端数据协商成10M网线、通告寄存器、strap限速ethtool、读取0x04寄存器丢包延迟高电源噪声、晶振精度、线缆质量抓包看CRC、换独立电源测试一插网线就复位网口隔离、防雷器件、地弹断开RJ45测试、电源加磁珠隔离结尾回头再看这次YT8512的实战调试很多问题其实不是芯片本身复杂而是RMII接口的时钟关系、寄存器配置和硬件设计之间的耦合。我个人操作中的体会是拿到一块新PHY板子先花半小时把硬件原理图、strap脚状态、PHY地址和时钟来源理顺再写软件比直接闷头敲代码要快得多。另外调试时严格由底向上走供电、晶振、MDIO读写、PHY ID、Link状态、数据通路每层都有可观测的证据再往上层走。最后补一句YT8512这类国产芯片的资料对比境外芯片确实少一些但遇到问题时多翻datasheet的寄存器表多量波形基本都能解决用熟了反而觉得它性价比很高。
返回列表