4. 标准MII寄存器详解(下):ANLPAR、ANE 与扩展状态寄存器

上一节我们聊了基本控制寄存器和状态寄存器,那些是芯片能跑起来的基础。但真正让两个 PHY 对上话、协商出最佳传输模式的,是自动协商那一套组合拳。今天要讲的三个寄存器,就是自动协商的关键信息载体。

我个人做项目时,常常在联调阶段卡在自动协商上——明明两边都支持千兆,怎么就是协商不上?这时候,抓这几个寄存器的值比看示波器管用多了。

4.1 ANLPAR 寄存器(寄存器 0x05)——读懂对方的“底牌”

ANLPAR 的全称是 Auto-Negotiation Link Partner Ability Register。翻译过来就是:自动协商链路伙伴能力寄存器。它存放的是对端 PHY 通过快速链路脉冲(FLP)发过来的能力宣告。

实际用法:你只管读这个寄存器,就能知道对端是什么水平。比如它支不支持 100BASE-TX,支不支持全双工。你这边想协商成什么模式,也得看对方接不接得住。

这个寄存器的位定义和咱们自己的 ANAR(寄存器 0x04)几乎一模一样,只不过这里面的数据是对方发过来的。我简单列一下重点位:

位名称含义
15Next Page对端是否还有下一页需要交换
14Ack确认位,对方已经收到了你的能力宣告
13Remote Fault对端检测到远端故障
12-9Technology Ability技术能力,定义支持的速率与双工组合
8-5Selector Field选择字段,通常为 00001 表示 IEEE 802.3
4-0Base Page基本页,低位表示 10BASE-T、100BASE-TX 等

有一点很关键:Ack 位(bit 14)在协商过程中会翻转为 1,表示对方已经成功收到你的能力宣告。我曾经遇到过一条网线接触不良,Ack 位死活不置 1,排查了半天才发现是线序有问题。

注意:ANLPAR 寄存器只有在自动协商完成(即 BMSR 寄存器 bit 5 为 1)之后读到的值才真正反映对方能力。协商过程中读到的可能是中间状态,不要拿来做决策。

4.2 ANE 寄存器(寄存器 0x06)——自动协商的“扩展控制面板”

ANE(Auto-Negotiation Expansion)寄存器,名字叫“扩展”,实际上更像是一个状态指示寄存器。它的各位告诉你自动协商内部的细粒度状态。很多 PHY 芯片厂商会在它基础上增加一些私有位,但标准位就那么几个。

位名称说明
4Parallel Detection Fault并行检测故障,表示链路伙伴不支持自动协商
3Link Partner Next Page Able对端支持下一页交换
2Next Page Able本端支持下一页交换
1Page Received已收到一个新的能力页
0Link Partner Auto-Negotiation Able对端支持自动协商

这里面我比较看重的是 bit 0 和 bit 4。Bit 0 告诉你对方是有自动协商能力的正常 PHY,还是老旧设备。Bit 4 如果变成 1,那就麻烦了——说明并行检测失效,常见于对端PHY根本没有发出 FLP 脉冲的情况。

实战经验:有一次客户反馈说他们的板子接上我们交换芯片后,协商总是失败。我让他读 ANE 寄存器的 bit 4,果然置 1 了。进一步排查发现是客户 PCB 上的差分走线过长,导致信号衰减严重,对方 PHY 无法检测到 FLP。缩短走线长度后问题解决。

顺便一提,ANE 寄存器通常不需要我们改写,它只读就好。但有个别 PHY 芯片会用它来触发软复位,具体得看数据手册。

4.3 扩展状态寄存器(寄存器 0x0F)——多了一双眼睛

标准 MII 规范里,扩展状态寄存器的地址是 0x0F。它最早被 1000BASE-T 引入,用来报告一些基本状态寄存器里放不下的信息。它的位定义各家厂商会有差异,但核心的几位是通用的:

位名称含义
151000BASE-T Full Duplex如果为 1,表示本端支持千兆全双工
141000BASE-T Half Duplex千兆半双工支持
131000BASE-X Full Duplex光纤千兆全双工支持
121000BASE-X Half Duplex光纤千兆半双工支持
11-0Reserved / Vendor Specific保留或芯片私有定义

这个寄存器有用在哪?举个例子:基本状态寄存器(BMSR)的 bit 7 只能告诉你是否支持千兆,但具体是千兆全双工还是半双工,你要到扩展状态寄存器里看。我在调试百兆升千兆的兼容性问题时,习惯先读 BMSR 确认能力,再读这个寄存器确认具体模式。

避坑提醒:并不是所有 PHY 芯片都实现了寄存器 0x0F,特别是那些老款的 10/100M PHY。你在读之前,最好先检查 PHY 的器件 ID 或者参考手册。记得有一次我直接按照标准去读 0x0F,结果返回的全是 0,白折腾了半天。

4.4 这三个寄存器在自动协商中的“角色分工”

下面这张图帮你理清思路:自动协商过程中,ANLPAR 负责接收对方的“底牌”,ANE 告诉你协商过程中的各种状态,扩展状态寄存器则给千兆能力的细节补充信息。

自动协商中的寄存器角色图 本端 PHY 对端 PHY FLP 脉冲交换 ANLPAR(读对方能力) ANE(协商状态指示) 扩展状态(千兆细节) 说明: 1. ANLPAR 存的是对方发来的能力页 2. ANE 记录协商中的故障/下一页能力 3. 扩展状态寄存器补充千兆双工能力 4. 这三个寄存器一般在 BMSR bit5 为 1 后读取 读取形成最终链接配置

嗯,这张图把流程串起来了。你想想看:本端PHY和对端PHY通过FLP脉冲交换能力,ANLPAR 负责接收对方的“底牌”,ANE 告诉你交换过程是否顺利(比如并行检测失败),而扩展状态寄存器则在你需要确认千兆模式的时候提供精准答案。读完这三个,你基本就知道链路怎么协商的了。

4.5 实操:怎么用代码读取这些寄存器

下面给出一段简单的伪代码,演示通过 MDIO 接口读取这三个寄存器。注意,实际地址偏移需要根据 PHY 和 MDIO 框架做调整。

// 假设 mdio_read 函数已经实现,参数为 phy_addr, reg_addr
// 先检查自动协商完成
uint16_t bmsr = mdio_read(phy_addr, 0x01);
if (!(bmsr & (1 << 5))) {
    // 自动协商还没完成,等一会儿再读
    delay(100);
    bmsr = mdio_read(phy_addr, 0x01);
}

// 读 ANLPAR(寄存器 0x05)
uint16_t anlpar = mdio_read(phy_addr, 0x05);
printf("ANLPAR = 0x%04X\n", anlpar);
// 判断对方是否支持 100BASE-TX 全双工
if (anlpar & (1 << 8)) {
    printf("Link partner supports 100BASE-TX full duplex\n");
}

// 读 ANE(寄存器 0x06)
uint16_t ane = mdio_read(phy_addr, 0x06);
if (ane & (1 << 4)) {
    printf("WARNING: Parallel detection fault detected!\n");
}

// 读扩展状态(寄存器 0x0F)
uint16_t ext_status = mdio_read(phy_addr, 0x0F);
if (ext_status & (1 << 15)) {
    printf("This PHY supports 1000BASE-T full duplex\n");
}
Tips:我在项目中习惯把这三个寄存器的读取封装成一个函数,返回一个结构体,方便上层协议栈直接使用。这样调试时一条 log 就能看到所有协商细节。

4.6 常见问题与我的排查套路

  1. ANLPAR 读出来全是 0 —— 大概率是自动协商还没完成,或者对端根本没发 FLP。先确认链路是否有信号,再检查对端是否启动了自动协商。
  2. ANE bit 4 为 1 —— 并行检测失败。通常是链路质量太差,或者对端是老旧 10BASE-T 设备。我遇到过一次是因为降压芯片的噪声耦合到网口,导致 FLP 报文被淹没。
  3. 扩展状态寄存器读到 0 —— 这款 PHY 可能不支持千兆,或者扩展状态寄存器被厂商挪作他用。查数据手册最稳妥。

我自己调试时,经常在 PHY 初始化代码后面加一段“诊断模式”,把这三个寄存器的值全部打印出来。连上对端设备,观察数值变化,基本一眼就能看出问题出在哪边。

好了,这一节的内容就到这里。自动协商的核心寄存器已经讲完了,下次如果调试中再遇到协商失败,你知道该从哪里下刀了。