news 2026/10/28 20:23:00

以太网PHY寄存器全解:从自协商、Auto MDIX到MDIO调试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
以太网PHY寄存器全解:从自协商、Auto MDIX到MDIO调试

简介:这份PDF是Realtek RTL8201F、RTL8201FL与RTL8201FN系列单芯片/单端口10/100M以太网PHY收发器的官方数据手册(Rev.1.4),面向从事嵌入式网络硬件设计、驱动移植与底层调试的软硬件工程师。文档围绕自动MDI/MDIX、10/100Mbps速率自适应、RMII接口与寄存器配置展开,涵盖电气特性、引脚定义、功耗、复位时序等细节,可用于网口初始化、链路状态监测与故障排查。资源包共1个文件,为PDF格式,约1.06MB,按修订记录、功能框图、寄存器表与电气规格分章组织,便于按模块检索查阅,已有1175人学习下载。其中寄存器定义、掉电与PHY复位流程、EEE能力及扩频时钟等章节可直接支撑驱动代码编写与原理图核对;修订历史还标明VB模型、中断指示与绝对最大额定值等改动,便于确认设计所依据的版本。

1. 一块 PHY 的寄存器表为什么值得逐行读完:网线插上就通的那两百毫秒里发生了什么

把网线插进设备,链路灯常亮,系统打印 100Mbps 全双工。多数人把这段归功于"自适应"三个字,好像 PHY 只是把数字信号翻译成差分电平的被动器件。真实的画面完全不是这样:两颗 PHY 在双绞线上用一串快速链路脉冲互相试探,交换各自支持的速率与双工能力,比较优先级,再各自翻转内部收发通道的交叉开关,最后才把状态位翻上去。整个过程没有 CPU 参与,全靠 PHY 内部状态机和寄存器在跑。

这也解释了为什么"插上不通、换根线就通"不是玄学:Auto MDIX 的交叉检测、自协商的能力位、复位期间被引脚锁存的配置,任何一环被上拉电阻或走线带偏,链路就起不来。这份标注为开发伙伴限定版的数据手册把三十多个寄存器、三张私有页和两套寄存器访问机制全部摊开,读懂它等于拿到这颗小控制器的内部地图。

2. 自协商与 Auto MDIX:为什么换根交叉线就通了,为什么又突然掉到半双工

链路建立这一步,几乎所有的现场问题都出在同一处:人们把"能 ping 通"当成"配置对了"。实际上自协商和 Auto MDIX 是两个耦合在一起的状态机,它们跑完之后留下的证据全在寄存器里,读一遍就能分辨是"协商成功"还是"并行检测兜底"。

2.1 自协商协商的到底是什么:16 位链路码字与优先级表

自协商并不交换速率数字,它交换的是一个 16 位的链路码字(base page)。发送侧把码字的每一位编码进快速链路脉冲的时序里:一串 33 个位置的脉冲中,奇数位置固定作为时钟,偶数位置有没有脉冲代表这一位是 1 还是 0。接收侧把这串脉冲解出来,就得到了对方的能力集合。

码字里几个位置是必须记住的:bit15 是 Next Page 标志,bit13 是 Remote Fault,bit12 到 bit5 是技术能力字段,bit4 到 bit0 是选择子字段,取 0b00001 表示遵循 IEEE 802.3。能力字段里 bit8 表示 100BASE-TX 全双工、bit7 表示 100BASE-TX 半双工、bit6 表示 10BASE-T 全双工、bit5 表示 10BASE-T 半双工。

软件侧对应的就是四个标准寄存器:Reg 4 自协商广告寄存器由本地写入自己的能力,Reg 5 自协商对端能力寄存器是只读的、反映对端发来的码字,Reg 6 自协商扩展寄存器记录过程状态,其中 bit4 是并行检测故障、bit1 是收到对端新页、bit0 是对端具备自协商能力。真正决定链路形态的是两个能力集合求交之后按优先级扫描的结果。

优先级顺序是固定的:100BASE-TX 全双工高于 100BASE-TX 半双工,高于 10BASE-T 全双工,高于 10BASE-T 半双工。这套规则的意义在于保证两端独立计算得到同一个结果,不需要任何一方主导。下面这段代码就是把这件事显式算出来,而不是靠"读一下链路状态位就完事"。

# 依据 IEEE 802.3 Clause 28 的优先级顺序,从两个能力集合求交后取最高 PRIORITY = [ (8, "100BASE-TX Full-Duplex"), (7, "100BASE-TX Half-Duplex"), (6, "10BASE-T Full-Duplex"), (5, "10BASE-T Half-Duplex"), ] def resolve(anar: int, anlpar: int): """anar: 本地 Reg4;anlpar: 对端 Reg5。返回实际生效的链路形态""" common = anar & anlpar # 取交集,只有双方都支持的才可能生效 for bit, name in PRIORITY: # 从高优先级往下扫,第一个命中的即为结果 if common & (1 << bit): return name return None # 交集为空:只能退到并行检测 # 常见取值:只开 100M 全双工与自协商 anar = (1 << 8) | 0b00001 # bit8 能力位 + selector=0x01 anlpar = (1 << 8) | (1 << 7) | 0b00001 print(resolve(anar, anlpar)) # -> 100BASE-TX Full-Duplex

这段逻辑的价值在于:当链路实际跑成 100M 半双工而预期是全双工时,你能立刻判断是本地没广告全双工能力,还是对端根本没发全双工位,而不是在一堆状态位里猜。参数上要注意anar必须把 selector 字段一起写进去,很多初始化代码只写能力位、把低 5 位留成 0,结果对端解析不出协议族,直接落到并行检测。

2.2 Auto MDIX 的检测机制:交叉开关什么时候翻转

10/100BASE-T 只用两对差分线,一对发、一对收。线序上有两种接法:MDI 是 1-2 发送、3-6 接收,MDIX 是把收发对调。直通线两端都是 MDI,交叉线一端 MDI 一端 MDIX。Auto MDIX 就是在芯片内部放一个交叉开关,让任意一种线缆都能配对成功。

检测过程和自协商共用同一套脉冲:芯片先在某个默认状态下发送链路脉冲,同时监听接收差分对上有没有能量进来。在一个几十到几百毫秒的窗口里如果什么都没收到,就翻转交叉开关再试一次。因此链路建立时间天然比固定接法长,链路断开重连时又要重跑一遍,指示灯会闪一下——这是正常现象,不是接触不良。

这里有个容易被忽略的耦合点:Auto MDIX 的探测脉冲本身就是自协商用的快速链路脉冲,两者是同一个状态机在推进。所以如果把自协商关掉(BMCR bit12 清零),Auto MDIX 的行为在某些实现里也会跟着变形,具体表现是交叉检测变慢或者干脆不切。手册里 Page 0 的 Reg 28 同时管光纤模式和回环,调试时务必确认回环位是关的,否则你会看到一条"自己能通、对端收不到"的假链路。

2.3 并行检测:老设备带来的半双工陷阱

对端如果不支持自协商——固定速率的老设备、某些直连的 MCU、部分工业交换机——它不会发快速链路脉冲。这时本地 PHY 退到并行检测:不听码字,只听物理层上有没有合法的链路活动,10BASE-T 看链路测试脉冲,100BASE-TX 看空闲码流。

问题就在这:并行检测能判断"对端在发什么速率",但判断不了双工。协议规定这种情况下一律按半双工处理。于是现场出现最经典的一类故障——一端自协商成 100M 全双工,另一端并行检测成 100M 半双工,链路是通的,ping 也通,但一跑吞吐就崩,FCS 错误和冲突计数飞涨,速度掉到几 Mbps。

正确的处理方式只有两条路。要么两端都开自协商;要么两端都强制,并且在强制的时候不要清掉自协商使能位,而是把广告寄存器改成只广告那一种能力,让对方在并行检测时也只能落到同一个结果上。只在一端强制、另一端自协商,是这段历史里最贵的一课。下面这段初始化代码体现的就是后一种写法。

/* 强制 100M 全双工的正确姿势:不清 AN enable,而是收窄广告集合 */ static void phy_force_100fd(int phy) { uint16_t bmcr = mdio_read(phy, 0x00); uint16_t anar = mdio_read(phy, 0x04); /* 只广告 100BASE-TX 全双工,其余能力位全部清掉 */ anar &= ~0x01E0; /* 清 bit8..bit5 技术能力字段 */ anar |= (1 << 8); /* 只置 100BASE-TX FD */ anar |= 0x0001; /* selector 必须保留 0b00001 */ mdio_write(phy, 0x04, anar); /* 重启自协商,让新广告集合生效;不要清 bit12 */ bmcr |= (1 << 9); mdio_write(phy, 0x00, bmcr); /* 随后轮询 BMSR bit5 直到置位,再读 BMSR bit2 确认链路 */ }

0x01E0这个掩码覆盖 bit8 到 bit5,正好是四个能力位。清掉再单独置 bit8,效果是对端只会看到"100M 全双工"这一项,求交结果唯一。重启自协商写的是 BMCR bit9,写完硬件会自动清零,轮询时不要指望它一直是 1。

3. MII、RMII 与 SMI:MAC 侧到底怎么"看见"这颗 PHY

PHY 有两张脸。一张朝着网线,跑的是模拟前端和编解码;另一张朝着 MAC,跑的是并行数据总线和一根两线制的管理接口。后者才是软件工程师日常打交道的地方,也是"寄存器读不出来"这类问题的源头。

3.1 MII 与 RMII 的取舍:引脚数、时钟与那点可怜的时序余量

MII 是 4 位并行接口,发送侧有 TXD[3:0]、TX_EN、TX_CLK,接收侧有 RXD[3:0]、RX_DV、RX_ER、RX_CLK,再加 CRS、COL 两根状态线,连同管理接口差不多十八根。100M 时 TX_CLK 和 RX_CLK 是 25MHz,10M 时是 2.5MHz,时钟由 PHY 提供,MAC 只需要在自己的采样窗口内把数据取走。

RMII 把数据宽度砍到 2 位,时钟统一成一路 50MHz 参考时钟,引脚数几乎减半,代价是时钟精度和走线匹配的要求上去了。50MHz 参考时钟通常要求 ±50ppm,而且它同时作为发送和接收的采样基准,走线延迟直接吃掉 setup/hold 余量。

维度MIIRMII
数据宽度4 位2 位
时钟TX_CLK / RX_CLK 各一路,由 PHY 输出单路 50MHz REF_CLK
典型引脚数约 18 根约 9 根
时序约束采样窗口相对宽松依赖 REF_CLK 走线延迟匹配
10M 模式时钟降到 2.5MHz50MHz 上做多次重复采样

手册里分别给出了 MII、RMII、MDC/MDIO 三组时序定义图,包括建立时间、保持时间和从时钟上升沿起的输出有效时间。这些数字不是给硬件工程师看的装饰,它们就是布线长度匹配的约束来源。RMII 模式下还有一件事必须做:接口模式不是自动识别的,要通过 Page 7 的 Reg 16 显式配置,默认值并不是 RMII。很多板子第一次上电跑不通,查到最后就是漏了这一次写。

3.2 SMI 的帧结构:MDC/MDIO 上那 32 个比特

管理接口只有两根线,一根时钟 MDC,一根双向数据 MDIO。帧结构是固定的:可选的前导码 32 个 1,然后是起始符 01,操作码读为 10、写为 01,5 位 PHY 地址,5 位寄存器地址,2 位翻转周期,最后 16 位数据。写操作翻转周期是 10;读操作的翻转周期是 Z0,也就是第一个比特由 PHY 释放总线,第二个比特由 PHY 驱动为 0。

MDIO 是双向开漏结构,必须加上拉电阻,典型取值在 1.5kΩ 到 10kΩ 之间,阻值选大了上升沿会变慢,在高速 MDC 下直接读错位。采样沿也要记牢:数据在 MDC 上升沿被采样,读回的数据在上升沿之后才有效,所以主机应当在下降沿切换输出、在上升沿读取输入。

/* Clause 22 读寄存器:bit-bang 版本,MDIO 为双向开漏 */ static int mdio_read(uint8_t phy, uint8_t reg) { uint16_t val = 0; int i; mdio_dir_out(); for (i = 0; i < 32; i++) mdio_write_bit(1); /* 前导码,部分 MAC 可省 */ mdio_write_bit(0); mdio_write_bit(1); /* ST = 01 */ mdio_write_bit(1); mdio_write_bit(0); /* OP = 10 读 */ for (i = 4; i >= 0; i--) mdio_write_bit((phy >> i) & 1); for (i = 4; i >= 0; i--) mdio_write_bit((reg >> i) & 1); mdio_dir_in(); /* 翻转周期:释放总线 */ mdio_read_bit(); /* 第一个比特 Z,丢弃 */ mdio_read_bit(); /* 第二个比特应为 0 */ for (i = 0; i < 16; i++) { /* 上升沿后采样 */ val = (val << 1) | mdio_read_bit(); } return val; }

每个mdio_write_bit内部都是"下降沿放数据、上升沿让从机采样"的节奏。mdio_dir_in()这一步不能省,忘记切换方向会导致总线上出现两个驱动源,读回的值恒为全 1。MDC 频率手册给了时序参数,实际工程里保守取 1MHz 到 2.5MHz,先跑通再提速,比一上来就冲高频然后怀疑芯片坏了要省时间。

3.3 分页与 MMD:32 个地址不够用之后的两套补丁

Clause 22 的寄存器地址只有 5 位,总共 32 个位置。前 8 个被标准占满,剩下的要放省电、中断、LED、扩频时钟、EEE 等一大堆私有功能,显然不够。芯片厂商用了两套办法来扩。

第一套是分页。Reg 31 是页选择寄存器,往里面写一个页号,接下来 0 到 31 号寄存器的含义就整体换成另一张表。手册里出现了 Page 0、Page 4、Page 7 三张页,Page 0 是标准寄存器加一部分私有寄存器,Page 4 放 EEE 能力,Page 7 放 RMII 模式、自定义 LED、中断与 WOL、MII 发送隔离、扩频时钟。

第二套是 MMD 间接访问。Page 0 的 Reg 13 是访问控制寄存器,写入设备地址和功能号;Reg 14 是地址数据寄存器,读写它等于读写目标 MMD 寄存器的内容。这套机制绕开了 5 位地址的限制,代价是每次访问要写两次、读一次,还得保证中间不被打断。

手册里 Device 3 是 PCS 层,0x00 是 PCS 控制、0x01 是 PCS 状态、0x14 是 EEE 能力、0x16 是 EEE 唤醒错误计数;Device 7 是自协商层,0x3c 是 EEE 广告、0x3d 是 EEE 对端能力。两套机制并存是历史包袱,也是翻车高发区。

def mmd_read(phy, dev, addr): """通过 Page0 Reg13/Reg14 间接读 MMD 寄存器""" mdio_write(phy, 0x0D, (dev << 8) | addr) # Reg13:设备地址 + 目标地址 mdio_write(phy, 0x0D, mdio_read(phy, 0x0D) | 0x4000) # 置功能位为读 return mdio_read(phy, 0x0E) # Reg14:数据在此

这三个参数里dev是 MMD 设备号,addr是设备内的寄存器偏移,phy是 5 位 PHY 地址。功能位的具体位置各厂商略有差异,写之前一定对着手册的位定义核对,凭经验套用别家的宏是最常见的错误来源。

4. 寄存器地图:从 BMCR 到 Page 7,一颗 PHY 的控制面是怎么摊开的

把寄存器按"谁在什么时候会写它"分类,比按地址顺序背要有效得多。驱动初始化阶段写的是标准寄存器,功能定制阶段写的是私有页,故障排查阶段读的是状态和计数。

4.1 前八个标准寄存器:初始化顺序比寄存器本身更重要

Reg 0 基本模式控制寄存器是唯一一个能改变芯片根本行为的寄存器。bit15 软复位,写 1 后硬件自清;bit14 回环;bit13 与 bit6 组合选择速率;bit12 自协商使能;bit11 掉电;bit10 隔离;bit9 重启自协商;bit8 双工选择。

位名称作用常见误用
15Reset软复位,自清写完立刻读,读到 1 就以为没复位
14Loopback内部回环调试后忘记关,链路假通
13/6Speed速率选择强制模式下与 bit8 不同步
12AN Enable自协商总开关强制速率时误清,触发并行检测
11Power Down掉电忘记清,整颗芯片不工作
9Restart AN重启协商轮询时不理解它会自清
8Duplex双工选择与对端不一致导致半双工塌陷

Reg 1 基本模式状态寄存器是只读的,bit5 表示自协商完成,bit2 表示链路状态,这一位是锁存低电平的,读一次会清零当前的低电平状态,连续读两次才拿到稳定值。bit4 是远端故障,bit1 是冲突检测。Reg 2 和 Reg 3 组成 32 位 PHY 标识,用来在总线上枚举设备、确认地址没配错。

初始化顺序上,稳妥的做法是:写 BMCR bit15 软复位,轮询直到该位自清;写 ANAR 配置广告能力;如果需要重启协商就写 bit9;轮询 BMSR bit5 等协商完成;再轮询 BMSR bit2 等链路建立;最后读回协商结果做一致性校验。中间任何一步用固定延时替代轮询,都会在慢速对端上翻车。

4.2 Page 0 的私有寄存器:省电、回环、中断与信噪比

Page 0 除了标准寄存器,还塞了几个私有功能。Reg 24 是省电模式寄存器,管几种低功耗状态的进入与退出;Reg 28 同时管光纤模式和回环,注意这两个功能挤在一个寄存器里,改动其中一半很容易误伤另一半;Reg 30 是中断指示与信噪比显示,链路质量差的时候这个寄存器里的信噪比数值比任何猜测都直观;Reg 31 是页选择。

这些私有寄存器的共同点是:它们不在任何 IEEE 标准里,换一颗 PHY 就全部失效。工程上值得把它们全部收进一个适配层,用phy_ops之类的结构体隔离,别让业务代码里散落着mdio_write(phy, 0x1F, 7)这种魔数。血泪经验是:一开始图快直接写在初始化函数里,后来换料或者做双供应商,改起来就是全文件搜索替换加逐行验证。

4.3 Page 4 与 Page 7:EEE、RMII 模式、LED 与扩频时钟

Page 4 只干一件事:EEE 能力的管理。Reg 16 是能力使能,Reg 21 是能力状态。EEE 也就是 802.3az 的低功耗空闲,链路空闲时收发双方约定进入静默,有数据再唤醒,唤醒延迟是它的代价。

Page 7 就杂得多。Reg 16 是 RMII 模式设定,用 RMII 接口就必须配;Reg 17 是自定义 LED 设置,决定每个 LED 引脚显示什么事件;Reg 18 是 EEE 指示灯使能;Reg 19 把中断使能、网络唤醒使能和 LED 功能挤在一起;Reg 20 是 MII 发送隔离;Reg 24 是扩频时钟寄存器。

页寄存器用途触发时机
0Reg 13 / 14MMD 访问控制与数据读写 Clause 45 寄存器
0Reg 24省电模式低功耗策略
0Reg 28光纤模式与回环介质切换、自测
0Reg 30中断指示与信噪比链路质量诊断
4Reg 16 / 21EEE 能力使能与状态开启低功耗空闲
7Reg 16RMII 模式设定板级接口选择
7Reg 17自定义 LED面板指示定制
7Reg 19中断、WOL、LED 功能唤醒与指示配置
7Reg 24扩频时钟EMC 整改

这张表本身就是一份调试路线图:链路类问题看 Page 0,接口类问题看 Page 7 Reg 16,功耗类问题看 Page 4 和 Page 0 Reg 24,面板指示灯不对就看 Page 7 Reg 17 和 Reg 18。

4.4 LED 引脚的两副面孔:复位期间是 PHY 地址,复位之后是灯

引脚紧张的时候,厂商会把配置信息在复位期间锁存到复用引脚上。这颗 PHY 就是这么做的:复位期间,几个 LED 引脚的电平被采样并锁存,作为 PHY 地址、接口模式等初始配置;复位释放之后,这些引脚变回 LED 驱动输出。

省了引脚,代价是上电瞬间的电平不由你说了算,而由 LED 的串联电阻和正向压降说了算。常见故障是这样:设计时按典型亮度选了 1kΩ 限流电阻,结果该引脚在复位期间被读成低电平,PHY 地址从预期的 1 变成 0,驱动按地址 1 去访问,读回来的全是 0xFFFF。

处理方式不复杂但必须做:先确认复位期间各复用引脚的目标电平,再反算 LED 支路的等效阻抗,必要时并联或串联电阻把电平拉到安全区。手册里 LED 与 PHY 地址那一节专门讲了这层关系,值得在画板子之前读一遍,而不是在打样回来之后。

4.5 省电、EEE 与扩频时钟:EMC 测试间里的取舍

省电模式、EEE、扩频时钟这三个功能的共同点是:单看指标都很美,叠加在一起就容易互相打架。

省电模式通过 Page 0 Reg 24 控制,进入后部分模拟电路关断,唤醒需要时间。EEE 通过 Page 4 和 MMD 里的几个寄存器协商,链路空闲时进入低功耗静默。扩频时钟通过 Page 7 Reg 24 把内部时钟频率做小幅周期性调制,把窄带的时钟能量摊开到一段频带上,降低辐射峰值。

扩频时钟的代价是时序抖动变大。在时序余量本来就紧张的 RMII 接口上开扩频,可能直接表现为偶发丢包;而对端如果不接受这种频率漂移,链路会周期性重协商。手册的修订记录里专门为这个寄存器加了一节说明,说明它不是默认开启的功能,属于"需要时再开、开完必须复测"的类型。

EEE 的排查路径更绕一些:先看 Page 4 Reg 16 和 Reg 21 确认本地能力打开,再通过 MMD Device 7 的 0x3c 和 0x3d 确认双方广告与能力匹配,然后看 Device 3 的 0x14 能力寄存器和 0x16 唤醒错误计数。唤醒错误计数持续增长,基本可以判定是链路伙伴的唤醒时序不满足,而不是本地配置写错了。

5. 常见问题排查:PHY 不链、链路闪烁与寄存器写不进去

这一节记录的都是"现象看着像硬件坏了,实际是软件或板级配置"的几类。每一条都按现象、原因、处理三步走,方便对着现场现象直接定位。

5.1 链路灯不亮,但自协商状态位显示已完成

现象:读取 BMSR,bit5 自协商完成已经置位,但 bit2 链路状态始终为 0,物理链路上没有任何活动。

原因通常有三类。一是 ANAR 里广告的能力集合为空或者 selector 字段写成了 0,对端解析不出协议族,协商虽然"走完流程"但没有任何共同能力,于是不建立链路。二是发送偏置回路上出了问题,变压器中心抽头的偏置电阻虚焊或者阻值错误,芯片发不出合法电平,链路伙伴根本检测不到能量。三是 Reg 28 里的回环位被误置,芯片把发送的数据绕回自己的接收端,自己觉得有活动,对端什么都收不到。

处理顺序建议从软件到硬件:先把 ANAR 读回来打印,确认低 5 位是 0b00001 且至少有一个能力位;再读 Reg 28 确认回环关闭;最后量变压器中心抽头的直流偏置电压和差分幅度。

5.2 寄存器写进去读回来不一致

现象:调用写函数之后立刻回读,得到的值和写入值不同,有时候读回 0x0000,有时候读回 0xFFFF。

原因分三层。最外层是 MDC 频率过高,MDIO 上拉电阻偏大导致上升沿不够陡,采样到错误的位,读回的值看起来像随机数。中间层是访问了只读寄存器,比如往 BMSR 或 ANLPAR 写数据,硬件直接丢弃,回读自然是旧值。最内层是页没切对——上一次操作切到了 Page 7,之后所有按标准地址读写的代码全都在读 Page 7 的内容。

处理办法是给寄存器访问加一层薄封装:每次访问私有页之前显式切页,访问完成后显式切回 Page 0,并且把页号作为参数传进读写函数而不是依赖全局状态。这个习惯能把这类问题从"偶发诡异"降级成"根本不会发生"。

5.3 LED 行为与手册描述完全不符

现象:配置了链路指示灯常亮、活动指示灯闪烁,实际观察到的是两颗灯同时闪,或者干脆全灭。

原因基本都在复位期间的引脚锁存上。LED 引脚在复位期间承担配置采样,如果外部电路让某个引脚电平偏离预期,锁存进去的配置就变了,复位释放后 LED 的功能映射也跟着变。另一种情况是自定义 LED 功能没有配置,芯片用的是默认映射表,跟你以为的映射不一样。

处理方式是先把 Page 7 Reg 17 读回来,逐位对照实际观察到的行为,确认映射是不是你写的那一份;再在复位期间用示波器抓各复用引脚的电平,看是否与设计预期一致。别在软件里给 LED 打补丁绕过去,那只是把配置错误藏起来。

5.4 RMII 模式下偶发丢包与 CRC 错误

现象:链路稳定,ping 大包时丢包率在千分之几,抓包能看到 FCS 错误,速率越低越不明显。

原因集中在时钟与接口配置。RMII 需要单路 50MHz 参考时钟,精度通常要求 ±50ppm,用普通晶振分频出来的时钟如果偏差过大,长时间运行会积累采样偏移。其次是 REF_CLK 到 MAC 和到 PHY 的走线长度不匹配,接收方向的有效窗口被压缩。第三是 Page 7 Reg 16 的 RMII 模式没配,芯片还在按 MII 时序工作,短包勉强能过、长包必错。

排查顺序:先确认 Reg 16 已正确配置,再用频率计核对 50MHz 的实际偏差,最后看时序余量。手册里 RMII 的建立时间、保持时间和输出延迟三张图就是用来算这个余量的,别跳过。

5.5 复位之后 PHY 地址变了

现象:同一块板子,冷启动时能正常通信,热复位之后寄存器全部读不到。

原因是复位类型不同,引脚锁存的时机也不同。冷启动时电源建立过程较慢,复用引脚上的电平有足够时间稳定到设计值;热复位时复位信号很窄,采样窗口落在电容还没放电完的时刻,锁存进去的地址就变了。手册里上电与复位时序那一节给了复位脉宽和稳定时间的要求,很多设计把这个时间压得太短。

处理方式是把复位脉宽按手册上限留足余量,并在复位释放之后加一段固定延时再发起第一次 MDIO 访问。另一个实用的做法是在驱动里做地址扫描:依次用 0 到 31 的地址读 Reg 2 和 Reg 3,能读出合法标识的那个就是当前地址,这比假设地址固定要稳得多。

6. 设计取舍:这颗 PHY 把复杂度放在了哪一侧

把寄存器地图读完,会发现一个有意思的分布:所有"跑起来就自动完成"的功能,复杂度都被推到了硬件状态机里;所有"需要人做决定"的功能,复杂度都被推到了软件侧的寄存器配置上。Auto MDIX 是前者的典型,你什么都不用做它就能识别线序;LED 映射、RMII 模式、EEE 协商、扩频时钟是后者的典型,不配就不工作,配错了现象还很隐蔽。

这个划分直接决定了两类工作的成本。硬件侧省下来的引脚,用复位期间的锁存换来,代价是上电瞬间的电平不再完全可控;软件侧省下来的寄存器地址,用分页和 MMD 间接访问换来,代价是访问顺序成了隐式依赖。两套扩展机制并存这件事本身就是历史包袱的化石:分页是早期在 32 个地址里挤空间的权宜之计,MMD 是后来标准给出的正解,但为了兼容已经出货的驱动,两套都得留着。

更值得琢磨的是功能取舍的边界。扩频时钟能过 EMC,但要牺牲时序余量;EEE 能省电,但要牺牲唤醒延迟和互操作性;省电模式能降功耗,但唤醒时间进了毫秒级。手册把这些开关全部交给软件,等于把"什么时候值得"这个判断也交给了软件。这也是为什么同一颗 PHY 在不同产品上表现差异巨大——不是芯片不同,是那几个私有寄存器的值不同。

验证上,我的习惯是把这套东西做成一个可复现的检查流程:上电后先扫 PHY 地址、读标识确认器件在位;再读 ANAR 和 ANLPAR 算出预期链路形态,与 BMSR 的实际状态比对;然后逐页读回所有被写过的私有寄存器,确认没有意外的页残留;最后跑一轮长包压力测试,看 FCS 错误计数是否稳定。这套流程不长,但能把九成以上的"玄学不链"挡在出货之前。

从那以后我每次碰新的 PHY,哪怕手册只有薄薄几十页,也强制先把寄存器页表抄一遍再写第一行驱动代码——因为翻车从来不是因为不会写 MDIO,而是因为不知道某个引脚在复位的那几微秒里已经被别人安排好了。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 20:22:21

ponytail:前端状态流可视化调试工具原理与实践

1. 项目概述&#xff1a;从“ponytail”热词切入&#xff0c;看清它到底是什么、能做什么、适合谁用最近刷技术社区、设计平台甚至短视频后台&#xff0c;总能看到“ponytail”这个词高频出现——不是发型&#xff0c;也不是动漫角色&#xff0c;而是突然冒出来的技术热词。搜索…

作者头像 李华
网站建设 2026/10/28 20:22:21

AI工具如何提升论文写作效率:从文献检索到格式规范

1. 论文写作痛点与AI工具的价值作为一名经历过毕业论文折磨的老学长&#xff0c;我深知专科生在论文写作中面临的三大困境&#xff1a;文献检索效率低、写作逻辑混乱、格式调整耗时。记得当年我写毕业论文时&#xff0c;光是调整目录页码就花了整整两天&#xff0c;参考文献格式…

作者头像 李华
网站建设 2026/10/28 20:21:08

cloudflare-os 实战:Workers 边缘 AI Agent 应用搭建与 pnpm 避坑指南

1. 从标题到落地&#xff1a;cloudflare-os 到底在解决什么问题第一次看到cloudflare-os这个标题&#xff0c;我下意识以为又是一个把 Linux 发行版塞进浏览器里的玩具项目。真正翻完仓库结构、跑通本地开发链路之后才发现&#xff0c;它跟“操作系统”这四个字的字面含义关系不…

作者头像 李华
网站建设 2026/10/28 20:20:50

Java工程中的AI Agent产品形态与实现技术详解

1. AI Agent产品形态全景解析在Java工程实践中&#xff0c;AI Agent已经演化出七种主流产品形态&#xff0c;每种形态都有其独特的应用场景和技术实现路径。作为在AI工程化领域深耕多年的实践者&#xff0c;我将结合具体案例和代码实现&#xff0c;带您深入理解这些形态的差异与…

作者头像 李华
网站建设 2026/10/28 20:20:40

Redis缓存一致性:缓存更新策略与延迟双删避坑指南

1. 从一个"数据明明改了却查不到"的现场说起先说一个我这些年反复遇到的场景&#xff1a;某次排查一个线上问题&#xff0c;用户反馈"修改完资料&#xff0c;刷新页面还是老样子"&#xff0c;但后台日志明明打印了更新成功的 SQL&#xff0c;数据库里查出来…

作者头像 李华