ARTICLE DETAIL

资讯详情

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

RMII接口与PHY芯片配置实战:以YT8512为例的初始化与调试指南

RMII接口与PHY芯片配置实战:以YT8512为例的初始化与调试指南 最近在给一块带以太网MAC的MCU板子配PHY芯片接口选了RMIIPHY选了国产的YT8512。虽然RMII接口在百兆以太网里已经很常见真正上手配置的时候还是踩了坑——上电读不到ID、协商完链路不通折腾了几天才把整个流程理顺。这篇文章就把从RMII接口原理到YT8512初始化代码的完整过程写出来给同样在调百兆网口的同行省点时间。这套内容的适用范围很明确MCU自带以太网MAC、需要外接PHY芯片的板子尤其是STM32这类以RMII模式出线的方案。无论你是第一次接触PHY配置还是已经会用LAN8720A想切国产芯片这篇都能直接对着改。文中代码基于GPIO模拟MDIO不依赖具体MCU型号移植性很强。1. 先理清RMII接口为什么是百兆方案的主流选择1.1 MII和RMII的差异以太网MAC和PHY之间的数据接口最常见的就是MII和RMII。MII是原始标准数据线有8根TXD[3:0]发送4位、RXD[3:0]接收4位100Mbps时时钟25MHz10Mbps时时钟2.5MHz每个时钟周期传4位所以100Mbps对应25MHz×4位。RMII全称Reduced Media Independent Interface由思科、朗讯等公司联合提出目的很直接把引脚数量砍掉一半。数据线从8根变成4根TXD[1:0]和RXD[1:0]用50MHz固定参考时钟每个时钟沿传2位同样是100Mbps带宽或者说这个接口本身固定跑在100M的速率上10Mbps是通过在MAC内部做采样处理来兼容的。接口类型数据线时钟频率引脚数量(不含管理)适用速率MIITXD[3:0], RXD[3:0]25MHz/2.5MHz约8根10/100MbpsRMIITXD[1:0], RXD[1:0]50MHz固定约4根10/100MbpsGMII16根数据线125MHz约16根1000MbpsRGMII8根数据线125MHz DDR约8根1000Mbps实际项目里百兆方案用RMII的占绝大多数。原因就是一个MCU引脚太紧张。一个RMII接口需要占用TX_EN、TXD[1:0]、RX_DV、RXD[1:0]、REF_CLK这6根数据信号线加上MDIO和MDC两根管理线总共8根比MII省了一半还多。对于100引脚以下的MCU这个差别很可能决定方案能不能成立。1.2 RMII的时钟方案决定了后续配置方式RMII和MII最大的区别不在数据线数量而在参考时钟的提供方式。MII的TX_CLK和RX_CLK分别由MAC和PHY各自产生互不干扰。RMII只有一个REF_CLK50MHz必须同时作为MAC和PHY的收发时钟源。这里有三种典型接法外部50MHz有源晶振同时给MAC和PHY这是我最推荐的方式。两边都吃同样的时钟源相位一致时序最简单也最容易排查问题。MAC侧输出50MHz给PHY需要MAC芯片有专用的REF_CLK输出引脚且驱动能力足够。PHY内部PLL产生50MHz输出给MACPHY的XI/XO引脚接25MHz晶振内部PLL倍频到50MHz后通过REF_CLK引脚送给MAC。这种方案省一个有源晶振但PHY的PLL会引入额外抖动对板级走线要求更高。选择哪种方案直接决定了你在MAC侧怎么配置时钟方向和使能。STM32F4系列在RMII模式下PA1引脚是RMII_REF_CLK这个引脚必须是外部输入的50MHz时钟——它内部不产生这个时钟。也就是说F4系列实际上只支持上面第1和第3种接法。有些新出的MCU型号内部可以提供REF_CLK输出具体要看芯片手册的时钟树不能想当然。从调试角度看外部有源晶振方案有个隐形优势示波器量REF_CLK引脚就能看到稳定50MHz方波能快速排除时钟问题。PHY内部PLL输出的时钟有时候因为晶振起振慢PHY还没就绪MAC已经完成初始化开始等时钟了这时候就会出现看起来配置都对但就是不通的诡异现象。这个坑后面排查部分还会再提。2. YT8512的硬件连接与启动配置上电之前先核对这几处2.1 电源、时钟和复位YT8512这样的国产百兆PHY外围电路说简单也简单电源、晶振、网络变压器、几个配置电阻。但恰恰是这几个配置电阻决定了很多行为。电源方面百兆PHY通常有3.3V主电源和1.8V/1.2V内核电源。YT8512内部集成LDO可以直接用3.3V供电内核电压由内部产生。原理图上要特别注意PHY芯片下方和每个电源引脚旁边的去耦电容建议0.1uF加10uF组合且尽量靠近引脚。这类高速模拟器件对电源纹波敏感电源不稳直接体现在link不稳定、丢包率高。时钟部分RMII模式下PHY需要25MHz晶振还是50MHz时钟取决于它内部有没有PLL。YT8512的做法是用25MHz晶振内部倍频出50MHz参考时钟给RMII接口。也就是说25MHz晶振接在XI/XO之间通过配置让PHY把REF_CLK引脚作为输出送给MAC侧。这种情况下晶振的起振时间是上电后首先要熬过去的一段等待期。复位引脚RESET_N低有效一般由MCU的GPIO控制也是调试时最常用的手段。硬件复位时序上要注意复位信号拉低时间至少保证10ms以上彻底释放后还要等待至少50ms再开始MDIO访问。有些PHY在复位释放后还需要一段时间加载strap配置马上去读寄存器很容易读到0xFFFF。2.2 PHY地址和RMII模式靠strap引脚定死这是新手最容易忽视的部分。PHY地址不是软件里随随便便写个数字就行的它是由芯片引脚的上下拉电阻决定的。YT8512这类芯片通常在PHYAD[1:0]或类似引脚上有内部下拉外部通过上拉电阻可以改变地址。上电瞬间这些引脚的电平会被锁存之后软件里MDIO访问的PHY地址必须和strap确定的地址一致否则读寄存器全是0xFFFF。同理PHY工作在RMII模式还是其他模式也是通过strap引脚确定的。有些PHY把Mode配置引脚和PHY地址引脚复用用不同阻值或组合来区分。这就需要你对着自己的原理图确认PHY地址是多少0x00~0x1F之间的某个值是否已经配置成RMII模式是否使能了自动协商参考时钟是输入还是输出方向这些全部要在上电之前核对完。因为strap是硬件行为改配置就得改电阻代码里无法变通。我在第一版板子里就吃过亏——原理图上PHY地址画的是0x00但引脚实际因为某个上拉电阻没贴地址变成了0x01软件怎么读都读不到后来用万用表量strap引脚电压才发现的。2.3 典型RMII信号连接与50MHz参考时钟给法下面这张表是我建议的MAC侧与YT8512侧信号对应关系。不同厂家的引脚命名可能略有差别但功能定义是一致的对着原理图逐个核对就行。功能MCU侧引脚YT8512侧引脚方向参考时钟RMII_REF_CLKREF_CLKMAC ← PHY或外部晶振发送数据位0ETH_TXD0TXD0MAC → PHY发送数据位1ETH_TXD1TXD1MAC → PHY发送使能ETH_TX_ENTX_ENMAC → PHY接收数据位0ETH_RXD0RXD0MAC ← PHY接收数据位1ETH_RXD1RXD1MAC ← PHY载波/接收有效ETH_CRS_DVCRS_DVMAC ← PHY管理时钟ETH_MDCMDCMAC → PHY管理数据ETH_MDIOMDIOMAC ↔ PHY复位任意GPIORESET_NMAC → PHY地址配置-PHYAD[1:0]strap模式配置-MODE引脚strap特别注意CRS_DV这个信号。在MII接口里CRS和RX_DV是两个独立信号RMII把它们合并成一个CRS_DV。PHY在检测到介质上有载波或者正在接收数据时把这个引脚拉高。MAC通过这个引脚的持续拉高状态来判断当前是否在接收帧。如果这个信号接错了或者漏接了会出现link灯正常但收不到数据的情况。50MHz参考时钟的给法如果选择外部有源晶振方案要保证时钟源同时连到MAC的REF_CLK引脚和PHY的REF_CLK输入引脚如果有的话或者说MAC吃外部时钟、PHY也吃外部时钟两边完全独立。如果选择PHY内部PLL方案则PHY接25MHz晶振REF_CLK方向为输出连接到MAC的RMII_REF_CLK引脚。时钟源只有一个切记不要出现两个时钟同时驱动一条线的情况。3. 寄存器层面的初始化流程MDIO时序与自动协商3.1 MDIO/MDC管理接口怎么工作MDIOManagement Data Input/Output和MDCManagement Data Clock是MAC管理PHY的串行接口IEEE 802.3 Clause 22规定了帧格式。MDC作为时钟MDIO为双向数据线标准规定MDC最大频率是2.5MHz。一次完整的MDIO操作格式是这样的前导码32个连续的1用于同步起始码01操作码读为10写为01PHY地址5位寄存器地址5位转换态写操作是10读操作是高阻Z加0数据16位读和写的区别在最关键的转换态。写操作是MAC直接驱动MDIO发送10读操作则是MAC先把MDIO释放为高阻态让PHY接管数据线MDC时钟继续走PHY在第一个时钟周期输出高阻第二个时钟周期开始输出16位数据。这个细节在GPIO模拟时会遇到一个坑读操作的第32位前导码发完后必须把MDIO引脚从输出模式切换成输入模式否则你一直在驱动数据线PHY没法把数据送回来。很多手写MDIO驱动的代码问题就出在这一步。3.2 标准寄存器里我们只关心这几个IEEE标准规定了PHY的0到6号寄存器这些在几乎所有PHY芯片上都是通用的YT8512也不例外。用来看状态和做基本配置这几个寄存器够用地址名称关键位作用0x00BMCR控制寄存器bit15 软复位bit12 自动协商使能bit9 重启协商bit13 速率bit8 双工配置PHY工作模式0x01BMSR状态寄存器bit5 协商完成bit2 链路状态查询link状态0x02PHY ID高字节bit15:0识别PHY型号0x03PHY ID低字节bit15:0识别PHY型号0x04ANAR协商通告bit9:5 通告能力配置支持的能力0x05ANLPAR对端能力bit9:5 对端通告的能力读取协商结果BMCR的bit13是速率选择1代表100Mbps0代表10Mbpsbit8是全双工使能。但要注意当bit12自动协商使能为1时bit13和bit8是被忽略的实际速率和双工由协商结果决定。只有在关闭自动协商、手动强制速率时这两个位才真正生效。BMSR的bit2链路状态位有个经典坑按照IEEE定义这个位是锁存低状态的。意思是说一旦链路断过这个位会保持为0即使链路已经恢复你读到的仍然是0必须读两次寄存器第二次才是当前真实状态。所以在代码里判断link状态我习惯连续读两次BMSR取第二次的bit2。后面代码部分会体现这个习惯。3.3 YT8512上电后的推荐初始化序列结合手上的板子和YT8512这种百兆PHY的实际表现我总结了一套初始化顺序基本兼容市面上大多数Clause 22 PHY上电等待电源稳定后如果做了硬件复位等待100ms以上确保PHY内部状态机和strap锁存完成。软复位可选但推荐向BMCR写入0x8000触发PHY内部软复位。写完后延时100ms。有些PHY软复位需要的时间更长实测等待150ms比较稳妥。读取PHY ID读寄存器0x02和0x03验证MDIO通路正常。如果读出来是0xFFFF或0x0000说明通路有问题先停下查硬件不要往下走。配置自动协商向BMCR写入0x1000使能自动协商。如果要主动通告能力先写ANAR0x04再重启协商。重启协商向BMCR写入0x1200bit9置1触发重启协商。这里有个细节如果只写0x1200相当于把自动协商使能和重启协商同时写入有些PHY对这种操作处理不一致稳妥起见先写0x1000延时100ms后再写0x1200。等待协商完成循环读BMSR判断bit5是否置1同时判断bit2链路状态是否稳定。带超时退出一般5秒内要完成如果超时打印BMSR原始值便于后续分析。读取协商结果读ANLPAR0x05解析对端能力确认实际的速率和双工模式。简单方法bit13或者bit12对应速率其实要看ANLPAR规范或者直接看BMSR和厂商寄存器。这里更通用的做法是读ANAR和ANLPAR做与运算再和PHY支持的速率映射表对比。初始化本身不难麻烦的是各种异常状态。为什么要读两次BMSR为什么要带超时这些都是在真实板子上踩过坑之后才加进去的。建议你的代码从一开始就按这个防御性写法来别贪图看起来简洁。4. 实战代码MDIO驱动与YT8512初始化可直接移植4.1 GPIO模拟MDIO底层如果你的MCU带硬件MDIO控制器直接用硬件外设。但GPIO模拟方式有最大的通用性换MCU只要改三个函数引脚方向设置、引脚输出、引脚输入。下面这段代码的核心逻辑可以直接搬到任何平台。#include stdint.h /* 平台相关函数需要根据你的MCU实现 */ extern void bsp_mdio_pin_set_dir(int output); // 1输出, 0输入 extern void bsp_mdio_pin_write(int level); // 写MDIO引脚电平 extern int bsp_mdio_pin_read(void); // 读MDIO引脚电平 extern void bsp_mdc_pin_write(int level); // 写MDC引脚电平 extern void bsp_delay_200ns(void); // 延时约200ns /* MDIO底层时序 */ #define MDIO_WRITE 0 #define MDIO_READ 1 static void mdio_mdc_cycle(void) { bsp_mdc_pin_write(1); bsp_delay_200ns(); bsp_mdc_pin_write(0); bsp_delay_200ns(); } static void mdio_out_bit(int bit) { bsp_mdio_pin_set_dir(MDIO_WRITE); bsp_mdio_pin_write(bit); mdio_mdc_cycle(); } static int mdio_in_bit(void) { int val; bsp_mdio_pin_set_dir(MDIO_READ); bsp_mdc_pin_write(1); bsp_delay_200ns(); val bsp_mdio_pin_read(); bsp_mdc_pin_write(0); bsp_delay_200ns(); return val; }MDC时钟频率的标准上限是2.5MHz对应半周期200ns。如果MCU主频高建议在延时函数里多插入几个空操作别让MDC跑太快。有些新PHY支持最高25MHz的MDC但为了兼容性保证在2.5MHz以下是安全的选择。4.2 PHY寄存器读写函数有了底层时序寄存器读写就是按帧格式拼数据的过程。写操作比较简单全程输出模式按顺序把前导码、起始码、操作码、地址、数据发出去。#define PHY_ADDR 0x01 /* 由板子strap决定常见值0x00/0x01/0x04 */ void phy_reg_write(uint8_t phyaddr, uint8_t regaddr, uint16_t data) { int i; /* 32位前导码全部为1 */ for (i 0; i 32; i) mdio_out_bit(1); /* 起始码 01 */ mdio_out_bit(0); mdio_out_bit(1); /* 操作码 01 写 */ mdio_out_bit(0); mdio_out_bit(1); /* PHY地址 5位 */ for (i 4; i 0; i--) mdio_out_bit((phyaddr i) 1); /* 寄存器地址 5位 */ for (i 4; i 0; i--) mdio_out_bit((regaddr i) 1); /* 转换态 10 */ mdio_out_bit(1); mdio_out_bit(0); /* 数据 16位 */ for (i 15; i 0; i--) mdio_out_bit((data i) 1); } uint16_t phy_reg_read(uint8_t phyaddr, uint8_t regaddr) { int i; uint16_t val 0; /* 前导码和地址部分与写操作相同 */ for (i 0; i 32; i) mdio_out_bit(1); mdio_out_bit(0); mdio_out_bit(1); /* 操作码 10 读 */ mdio_out_bit(1); mdio_out_bit(0); for (i 4; i 0; i--) mdio_out_bit((phyaddr i) 1); for (i 4; i 0; i--) mdio_out_bit((regaddr i) 1); /* 转换态先释放总线再拉低一个周期 */ bsp_mdio_pin_set_dir(MDIO_READ); bsp_mdc_pin_write(1); bsp_delay_200ns(); bsp_mdc_pin_write(0); bsp_delay_200ns(); bsp_mdio_pin_set_dir(MDIO_WRITE); bsp_mdio_pin_write(0); mdio_mdc_cycle(); /* 读取16位数据 */ for (i 15; i 0; i--) { val (val 1) | mdio_in_bit(); } return val; }读函数的转换态部分就是前面讲的容易出问题的位置。这里先切输入模式读完一个周期的高阻态再切回输出模式把MDIO拉低等一个时钟周期然后再开始读数据位。这种写法保证和PHY的时序要求对齐。4.3 YT8512初始化函数初始化函数把前面讲的流程串起来。代码里加了一些调试打印方便在串口上看执行进度。#include stdio.h void phy_yt8512_init(void) { uint16_t id1, id2, bmsr; int i, timeout; /* 1. 硬件上电后等待strap锁存完成 */ bsp_delay_ms(100); /* 2. 软复位 */ phy_reg_write(PHY_ADDR, 0x00, 0x8000); bsp_delay_ms(150); /* 3. 读取PHY ID验证MDIO通路 */ id1 phy_reg_read(PHY_ADDR, 0x02); id2 phy_reg_read(PHY_ADDR, 0x03); printf(PHY ID: 0x%04X 0x%04X\r\n, id1, id2); if ((id1 0x0000) || (id1 0xFFFF)) { printf(MDIO read PHY ID failed, check hardware!\r\n); return; } /* 4. 使能自动协商等待一段时间后再重启协商 */ phy_reg_write(PHY_ADDR, 0x00, 0x1000); bsp_delay_ms(100); phy_reg_write(PHY_ADDR, 0x00, 0x1200); /* 5. 等待协商完成带超时 */ timeout 0; while (timeout 50) { bsp_delay_ms(100); bmsr phy_reg_read(PHY_ADDR, 0x01); if (bmsr 0x0020) { printf(Auto-negotiation complete\r\n); break; } timeout; } if (timeout 50) { printf(Auto-negotiation timeout, BMSR0x%04X\r\n, bmsr); } /* 6. 读两次BMSR确认最终link状态 */ bmsr phy_reg_read(PHY_ADDR, 0x01); bmsr phy_reg_read(PHY_ADDR, 0x01); printf(BMSR0x%04X, Link %s\r\n, bmsr, (bmsr 0x0004) ? UP : DOWN); }这段代码里的延时函数bsp_delay_ms也需要你自己实现。注意协商等待的循环里我每次读BMSR前先延时100ms避免太频繁访问MDIO。50次循环也就是最多5秒足够协商完成也不会让程序卡太久。有两点要说明PHY_ADDR这个宏一定要改成你板子上strap确定的实际地址。另外一个就是初始化完成后如果link还是DOWN不一定就是PHY配置的问题也可能是对端设备没接、网线坏了、网络变压器那边的问题。这个在后面排查部分展开。4.4 在STM32 HAL和Linux中的对接STM32平台如果不想用GPIO模拟HAL库提供了硬件MDIO支持。在HAL_ETH_Init之前需要先配置好ETH外设的基本参数。以STM32F407为例关键代码在MX_ETH_Init里heth.Instance ETH; heth.Init.MediaInterface HAL_ETH_RMII_MODE; heth.Init.AutoNegotiation ETH_AUTONEGOTIATION_ENABLE; heth.Init.Speed ETH_SPEED_100M; heth.Init.DuplexMode ETH_MODE_FULLDUPLEX; heth.Init.PhyAddress PHY_ADDR; if (HAL_ETH_Init(heth) ! HAL_OK) { Error_Handler(); }使用硬件MDIO的好处是CPU不用管时序细节HAL库会处理好。但这也意味着你要确认HAL库依赖的底层GPIO复用配置正确特别是PA1的RMII_REF_CLK必须有时钟输入。如果用的PHY是YT8512这类需要PHY提供50MHz时钟的方案检查PHY的REF_CLK有没有真正连接到STM32的PA1。Linux平台相对简单设备树里把phy-mode设置成rmii指定phy-handle指向PHY节点然后在内核里注册PHY驱动。YT8512这种标准Clause 22 PHY通常可以由内核的Generic PHY驱动直接接管不需要额外写驱动。设备树关键字段参考mac { pinctrl-names default; pinctrl-0 eth_rmii_pins; phy-mode rmii; phy-handle eth_phy; status okay; eth_phy: ethernet-phy1 { reg 1; reset-gpios gpioi 8 GPIO_ACTIVE_LOW; }; };reg 1这个值就是PHY地址必须和硬件strap对上。reset-gpios对应PHY的复位引脚。内核起来后用ethtool eth0查看协商结果和link状态用mii-tool eth0也能看到基本状态这些命令在调试阶段非常有用。5. 联调阶段最常见的三类故障与排查链路5.1 读不到PHY ID症状初始化代码里id1读出来是0xFFFF或者一直返回0x0000。这是整个调试链路里第一个可能挡路的故障。排查链路按照从简单到复杂的顺序来测量PHY供电电压。用万用表量YT8512各电源引脚3.3V是否正常纹波是否过大。有时候原理图没问题但焊接虚焊会导致某个引脚没供上电。检查复位引脚电平。确认RESET_N确实被拉高而不是还停在低电平。如果复位引脚由MCU的GPIO控制检查GPIO初始化是否为推挽输出高电平。有些PHY有复位延时要求MCU启动时如果GPIO默认输出低会让PHY一直处于复位状态直到软件把它拉高。处理好时序。核对strap地址与代码PHY_ADDR是否一致。用万用表量PHYAD引脚电压对照数据手册的地址表确认到底是多少。这里最容易出现我觉得是0x01和实际是0x04的错位。验证MDC/MDIO引脚上有没有波形。示波器抓MDC引脚正常应该能看到连续方波。MDIO在写操作时能看到数据跳变。如果MDC没有时钟检查GPIO配置或者HAL初始化。检查PHY有没有虚焊或者引脚短路。YT8512这种QFN封装手工焊接最容易出现相邻引脚锡连的问题。特别是MDIO和MDC挨得近的话短路就麻烦了。这类问题80%以上出在第3步和第1步。尤其注意PHY ID读出来全F优先怀疑PHY地址不对读出来全0优先怀疑复位没释放。5.2 Link状态一直为0症状MDIO通路正常PHY ID能读到但BMSR的bit2始终为0协商也一直不完成。排查链路确认对端设备是好的。把网线插到一台电脑或者路由器上看另一端的link指示灯是否亮。有时候是测试环境就没有对端设备PHY自然协商不起来。检查网线本身。百兆网线只用1/2和3/6这四根线如果线序不对或者接触不良link也会反复跳。换一根线排除。测量PHY的差分发送引脚波形。百兆PHY在协商阶段会不停发送脉冲用示波器量TXP/TXN差分对应该能看到信号。如果完全没有说明PHY内部可能没正常工作。检查网络变压器到RJ45的接线。变压器中心抽头接法对不对RJ45的1/2、3/6是否连通这些都是link起不来的常见物理原因。建议对照YT8512评估板的参考设计逐项核对。验证REF_CLK是否真的存在。示波器量PHY的REF_CLK引脚和MAC侧的RMII_REF_CLK引脚。如果PHY内部PLL方案这里应该有50MHz方波。没有的话查25MHz晶振是否起振。确认自动协商没有被人为关闭。读BMCR确认bit12是1。如果软件在出问题前往BMCR写了强制速率PHY可能停在需要手动匹配的模式。在链路状态排查上我个人的经验是先物理后逻辑。很多开发者link不上第一反应就是去翻寄存器配置结果调了半天发现是对端没接或者网线有问题。物理层的判断其实很快示波器上去看有没有信号就知道PHY状态了。5.3 Link up了但收发不通这个故障最让人头疼因为PHY层看起来是通的但应用层就是ping不通。排查链路要分几路第一路MAC侧配置是否与PHY一致。自动协商成功后PHY可能协商成100M全双工但MAC侧如果之前被配置成了10M半双工两边速率不匹配就会出现link灯亮但数据全丢的现象。确认MAC侧的速度和双工设置与协商结果一致。第二路信号线接反。RMII数据线只有2位TXD0/TXD1和RXD0/RXD1如果被原理图反接link能建立但不能传数据。用示波器在发送数据时看TXD引脚是否有跳变同时看对面PHY是否正确收到。这个要仔细对照原理图不能只看网络标签。第三路REF_CLK时序不对。有些板子用的是外部有源晶振给MAC和PHY同源时钟但走线一个长一个短相位差过大就会采样错数据。RMII数据在REF_CLK上升沿被采样如果时钟和数据之间的建立保持时间不满足收发会出现随机丢包或者完全不通。示波器看REF_CLK和TXD上升沿的相对位置如果数据变化和时钟沿太近就要检查走线等长和时钟源。第四路MAC侧没有使能收发。以STM32为例有些HAL版本在HAL_ETH_Init之后还需要调用HAL_ETH_Start才会真正启动MAC收发。如果只初始化没启动link状态正常但数据是进不了MAC收包路径的。检查程序的执行顺序。第五路软件协议栈问题。PHY和MAC都正常了还有可能是协议栈配置问题比如MAC地址全零、IP地址冲突、网关配错。这种情况用抓包工具看是否有ARP请求发出去能很快定位是物理层还是软件层。抓包软件看到有发送的ARP包但没响应那问题基本确定在对端或者链路物理层。5.4 排查顺序总结把上面的经验压缩成一张通用排查顺序表排查对象工具关键指标电源万用表3.3V稳定纹波小复位万用表/示波器RESET_N释放后波形干净MDC/MDIO示波器MDC有方波MDIO数据变化REF_CLK示波器50MHz方波频率稳定差分对示波器TXP/TXN有信号网线/对端换线/换设备link状态变化这张表我每次调PHY板子都会过一遍先物理后寄存器大部分问题在半小时内能定位。6. 几次做国产百兆PHY方案后的一些体会YT8512不是唯一的选择同类国产芯片还有不少像IP101GRI、RTL8201F这类都有各自的项目在用。用了几轮之后我说说实际感受。国产PHY在标准寄存器层面上和主流进口芯片兼容性做得相当好IEEE Clause 22定义的寄存器读写、自动协商流程基本上照着LAN8720A或者IP101G的代码逻辑就能跑通。真正要小心的埋在厂商扩展寄存器——不同芯片的能力配置、LED行为、时钟输出控制、链路诊断这些都不在标准寄存器里改板子换芯片时一定重新看数据手册。选型也好调板也好我建议早期把PHY地址、模式选择这些strap引脚全部通过0欧电阻引出甚至在设计阶段预留跳线。调试阶段可以不通电就改地址比反复焊电阻快得多。正式量产前再根据最终配置把电阻定死还能省下单板调试时来回拆焊的麻烦。上电时序上MCU初始化和PHY复位的先后顺序值得花心思设计。一次在RTOS环境里做产品系统启动后任务调度先于PHY复位完成结果每次冷启动PHY都读不到ID热重启正常。后来把复位延时从100ms加到200ms并且把PHY初始化放到协议栈任务之前问题就消失了。这种稳定性问题最难查因为现象是偶尔能通偶尔不通靠示波器看时序才定位到。如果产品对温度要求高或者走工业现场建议在出厂测试项里加入PHY ID读取和link状态检查。一次工装接触不良导致的虚焊如果测试程序不去读PHY ID报出来的故障可能是网口不通而不是PHY没工作对后端分析问题会多绕很多弯路。最后提醒一点RMII模式下的50MHzREF_CLK是整个链路的心脏。调试时如果所有寄存器配置都对但就是收发不正常先去量这个时钟的频率和波形。我见过最玄学的一次是一个贴片有源晶振的电源退耦电容位置放远了导致高低温切换时时钟抖动超标link能起来但吞吐率掉到几十Mbps。换一个靠近引脚的电容就恢复正常。这类问题靠逻辑推不出来必须靠示波器实测。
返回列表