寄存器基本概念:地址、数据位定义、读写操作

做 PHY 调试这些年,我见过不少工程师拿着 Datasheet 翻半天,愣是不知道从哪里下手改配置。说白了,寄存器就是你跟 PHY 芯片沟通的“对讲机”。你对着它喊一声,它回你一句。但这台对讲机有固定的频道、约定的暗号、以及特定的用法。弄不懂这些基础,后面的调试全是瞎猫撞死耗子。

寄存器地址:找到那扇正确的门

每个寄存器在芯片内部都有一扇唯一的门,这门牌号就是它的地址。PHY 芯片的地址空间通常由 MDIO(Management Data Input/Output)接口来访问。MDIO 的帧结构里会携带两个关键地址:PHY 设备地址和寄存器地址。

  • PHY 设备地址:一般由芯片的管脚(比如 AD0、AD1、AD2)决定。我调试一块 8 口交换机时,发现 PHY 地址全是 0x1C,一查才发现硬件工程师把这几个管脚全接地了。嗯,这算是常见坑。
  • 寄存器地址:芯片内部每个功能模块对应的编号。比如 802.3 标准里,寄存器地址 0x00 是控制寄存器,0x01 是状态寄存器。地址范围一般是 0x00 ~ 0x1F,但很多 PHY 芯片通过扩展地址或页面选择机制,能访问到更深的区域。

你可以把这件事想象成去一栋楼找人:楼号是 PHY 设备地址,房间号是寄存器地址。两个数字对不上,你就敲错门了。

// 一个典型的 MDIO 写操作帧格式(简化)
Preamble | Start | OP Code | PHY Addr | Reg Addr | Turnaround | Data
   32'b1   | 01    | 01      | 5-bit    | 5-bit    | 10         | 16-bit

我个人习惯在调试初期,先用一个简单的读取脚本,把 0x00 ~ 0x1F 所有寄存器的默认值 dump 出来。这能帮你快速确认 MDIO 通信是否正常、PHY 是否响应。如果读出来全是 0xFFFF 或 0x0000,大概率是地址或时序出了问题。

数据位定义:每个比特的战场

寄存器的数据宽度通常是 16 位,但每个位或某些位组合,代表不同的含义。举个例子,控制寄存器 0x00 的第 15 位是软件复位,第 13 位是速度选择,第 12 位是自动协商使能……你想想看,如果一不小心写错了一个位,整个链路可能就挂了。

我在项目中遇到过一个问题:某款 PHY 在千兆模式下总是掉线,抓包也看不出所以然。后来我逐位检查寄存器 0x00,发现第 6 位(强制全双工)莫名其妙被置成了 0。明明读出来是正常的,写进去就变了。最后定位到是软件里另一个线程在抢写,冲突了。这种问题,不看寄存器位定义根本找不出来。

位[15:0] 名称 描述 类型
15 Reset 软件复位,写 1 复位,自清 0 RW/SC
13:12 Speed[1:0] 00=10M, 01=100M, 10=1000M, 11=Reserved RW
11:8 Reserved 保留位,写 0 RO
7 Collision test 碰撞测试使能,不建议普通场景使用 RW
6 Duplex 双工模式:1=全双工,0=半双工 RW
5:0 Others 其他控制位,具体见 Datasheet RW/RO

曾经有个新手工程师把速度选择位写成了 11b,结果芯片进入保留模式,端口直接 down 了。一定要严格按照 Datasheet 的定义来,保留位必须写指定的值(一般是 0),否则芯片行为不可预期。

读写操作:开口之前想清楚

寄存器的访问类型分为几种:只读(RO)、只写(WO)、读写(RW)、写1清零(W1C)、自清零(SC)。每种类型对应不同的行为和坑。

  • RO 寄存器:写是无效的,如果你尝试写,通常会被芯片忽略,或者引发意外行为。我曾经在调试某款 PHY 时,没仔细看描述,对着状态寄存器一顿写,结果干扰了内部状态机。
  • W1C 寄存器:这是中断处理常用的。往某一位写 1,会清零该位对应的中断标志。注意:写 0 没任何作用。如果你按 RW 的习惯去操作,中断永远清不掉。
  • SC 位:比如软复位位,你写完 1 之后,芯片会在完成复位的同时自动把该位清 0。如果轮询这个位等它变 0,就能确认复位完成了。
// 正确读取然后修改(Read-Modify-Write)的操作示例
uint16_t reg_val = phy_read(phy_addr, reg_addr);   // 先读
reg_val |= (1 << 6);                                // 置位第6位
phy_write(phy_addr, reg_addr, reg_val);             // 再写

我这里想强调一点:很多 PHY 寄存器是共享的。你读到的值可能不是你想要的,尤其是中断状态寄存器。它可能在读操作的瞬间就被自动清零了。这就是所谓的“读取即清除”行为。必须设计好读取顺序。

好了,我们来总结一下这一章的核心逻辑。下面这张图可以帮你快速建立寄存器基本概念的完整结构。

寄存器基本概念体系视图 寄存器地址 数据位定义 读写操作类型 PHY设备地址 寄存器偏移地址 保留位 功能位域 RW / RO / WO W1C / SC 核心流程: 先读 → 修改目标位 → 再写回 ⚠️ 常见陷阱:读取即清零、保留位写非零值、地址不匹配、多线程抢写

最后说一句,寄存器调试本质上就是一场“猜谜”游戏。你只有清楚它在哪里、它存什么、以及怎么操作它,才能让 PHY 芯片按照你的想法工作。