2. PHY芯片核心寄存器详解:基本寄存器(BCR/BSR)、状态寄存器、协商寄存器、厂商特定寄存器
好,咱们直接进入正题。PHY芯片的寄存器,说白了就是它的“大脑”和“神经”。你通过MDIO总线读写这些寄存器,就能控制PHY怎么工作,也能知道它现在状态好不好。我个人习惯把寄存器分成四类:基本控制状态、协商相关、扩展状态,还有厂商自己加的那些“私货”。
2.1 基本控制寄存器(BCR)—— 地址0x00
BCR,全称Basic Control Register。这是PHY芯片的“总开关”。你想想看,一个设备要工作,总得先知道怎么启动、怎么复位吧?BCR就是干这个的。
| 位 | 名称 | 描述 |
|---|---|---|
| 15 | Reset | 软件复位,写1复位,复位后自动清零 |
| 14 | Loopback | 回环模式,1使能,用于自测 |
| 13 | Speed Selection (LSB) | 与位6配合选择速率 |
| 12 | Auto-Negotiation Enable | 自协商使能,1开启 |
| 11 | Power Down | 省电模式,1进入低功耗 |
| 10 | Isolate | 隔离模式,断开PHY与MAC的连接 |
| 9 | Restart Auto-Negotiation | 重启自协商,写1触发 |
| 8 | Duplex Mode | 双工模式,1全双工,0半双工 |
| 6 | Speed Selection (MSB) | 与位13配合:00=10M, 01=100M, 10=1000M |
重点提醒:复位操作(位15)写1后,硬件会立即开始复位流程。但你不能马上接着写其他寄存器!我建议你写复位后,轮询等待位15自动变回0,通常需要等几十毫秒。我曾经在项目里吃过这个亏,复位后立刻配置,结果配置没写进去,排查了半天。
我的小技巧:调试时,我习惯先读BCR的默认值。如果读出来全是0xFFFF或者全是0x0000,那基本可以断定MDIO通信有问题,别急着查PHY配置,先查硬件连接。
2.2 基本状态寄存器(BSR)—— 地址0x01
BSR,Basic Status Register。这个寄存器告诉你PHY现在“活得好不好”。它是个只读寄存器,你只能读,不能写。
| 位 | 名称 | 描述 |
|---|---|---|
| 15 | 100BASE-T4 | 是否支持T4模式 |
| 14 | 100BASE-TX Full Duplex | 是否支持100M全双工 |
| 13 | 100BASE-TX Half Duplex | 是否支持100M半双工 |
| 12 | 10BASE-T Full Duplex | 是否支持10M全双工 |
| 11 | 10BASE-T Half Duplex | 是否支持10M半双工 |
| 10-7 | Reserved | 保留位,通常读为0 |
| 6 | MF Preamble Suppression | 是否支持前导码抑制 |
| 5 | Auto-Negotiation Complete | 自协商是否完成,1表示完成 |
| 4 | Remote Fault | 远端错误指示 |
| 3 | Auto-Negotiation Ability | 是否支持自协商 |
| 2 | Link Status | 链路状态,1表示链路已建立 |
| 1 | Jabber Detect | 是否检测到Jabber异常 |
| 0 | Extended Capability | 是否支持扩展寄存器 |
嗯,这里要注意位2(Link Status)。这个位很关键,它直接告诉你网线插没插好、对端设备有没有开机。但有个坑——这个位是“锁存”的。什么意思?就是链路断了之后,它不会立刻变0,而是保持1。你必须读一次BSR,它才会更新成真实状态。我刚开始做驱动时,就因为这个特性,死活读不到链路断开的事件,后来翻手册才明白。
避坑指南:我曾经在一个项目中,发现PHY的Link Status一直为1,但网络就是不通。排查了半天,发现是PHY芯片的硬件复位引脚没拉高,导致PHY根本没工作。所以,读BSR之前,先确认硬件复位和时钟都正常。
2.3 自协商寄存器组
自协商,说白了就是让两端的PHY自己商量:“咱俩用啥速度?全双工还是半双工?” 这个过程涉及三个核心寄存器。
2.3.1 自协商通告能力寄存器(ANAR)—— 地址0x04
这个寄存器告诉对端:“我能支持这些模式,你看着办。” 你写这个寄存器,就是告诉PHY你愿意协商哪些能力。
// 示例:配置ANAR,通告100M全双工和10M全双工能力
// 假设PHY地址为0x01
unsigned short anar_value = 0x01E0; // 位15:5为协议特定,位4:0为选择器字段
// 实际项目中,需要根据PHY手册设置正确的值
phy_write(0x01, 0x04, anar_value);
2.3.2 自协商链路伙伴能力寄存器(ANLPAR)—— 地址0x05
这个寄存器是只读的,它告诉你对端PHY支持什么能力。自协商完成后,你可以读这个寄存器,看看对端到底支持哪些模式。
2.3.3 自协商扩展状态寄存器(ANER)—— 地址0x06
这个寄存器提供自协商过程的详细信息。比如,协商是否完成、有没有发生错误、对端是否支持某种技术等。
我的经验:调试自协商问题时,我习惯先读ANAR确认自己通告的能力对不对,再读ANLPAR看对端回了什么。如果ANLPAR全是0,那说明对端可能没开启自协商,或者网线有问题。这时候别急着改软件,先拿个测线仪试试。
2.4 状态寄存器与扩展状态寄存器
除了BSR,IEEE 802.3还定义了一些扩展状态寄存器,地址从0x0A到0x0F。这些寄存器提供更详细的状态信息,比如具体的协商结果、Master-Slave配置等。
以1000BASE-T状态寄存器(地址0x0A)为例,它包含:
- Master-Slave配置状态
- 1000BASE-T全双工/半双工能力
- 协商结果
我个人觉得,这些扩展寄存器在调试千兆网络时特别有用。比如,你可以通过读0x0A寄存器,确认两端是否协商成了Master-Slave模式,如果两端都是Master,那链路肯定起不来。
2.5 厂商特定寄存器
这部分就“百花齐放”了。每个PHY厂商都会根据自己的芯片特性,增加一些私有寄存器。比如:
- LED控制寄存器:控制PHY芯片上的LED指示灯怎么亮、什么颜色、什么闪烁模式。
- 中断控制寄存器:配置哪些事件可以触发中断,比如链路断开、自协商完成等。
- EEE(节能以太网)寄存器:控制低功耗模式的进入和退出。
- MDI/MDIX控制寄存器:控制网口是直连还是交叉,有些PHY支持自动翻转。
重要提醒:厂商特定寄存器没有统一标准!你换一个PHY型号,这些寄存器的地址和位定义可能完全不同。我见过有人把A厂商的寄存器配置直接套到B厂商的PHY上,结果PHY直接不工作。所以,一定要仔细看对应PHY的数据手册(Datasheet)。
2.6 实战:如何读取PHY芯片的ID
说了这么多理论,咱们来点实际的。怎么确认你读到的PHY是正确的?读它的ID寄存器!
PHY芯片的ID通常分布在两个寄存器里:
- PHY ID Register 1(地址0x02):包含OUI(组织唯一标识符)的高16位
- PHY ID Register 2(地址0x03):包含OUI的低6位和厂商型号、版本信息
// 读取PHY ID的示例代码
unsigned int phy_id1, phy_id2;
unsigned int phy_id;
phy_id1 = phy_read(phy_addr, 0x02);
phy_id2 = phy_read(phy_addr, 0x03);
// 组合成32位的PHY ID
phy_id = (phy_id1 << 16) | phy_id2;
printf("PHY ID: 0x%08X\n", phy_id);
// 常见的PHY ID示例:
// 0x2000A240 - 某款常见千兆PHY
// 0x0141B8C0 - 另一款常见百兆PHY
嗯,这里要注意。有些PHY的ID寄存器在复位后可能不是立即有效的,需要等一小段时间。我建议你在读取ID之前,先做个延时,比如等待10毫秒。
2.7 小结
好了,这一章的内容就这些。总结一下:
- BCR(0x00):控制PHY的复位、速率、双工、自协商等基本功能。
- BSR(0x01):读取PHY的状态,包括链路状态、自协商是否完成等。
- 自协商寄存器(0x04-0x06):配置和读取自协商过程。
- 厂商特定寄存器:每个PHY的“私货”,必须看手册。
- PHY ID寄存器(0x02-0x03):确认你读到的PHY对不对。
下一章,咱们会深入讲讲MDIO总线的读写时序,以及怎么用代码实现一个健壮的PHY驱动。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。