MDIO标准规范:Clause 22与Clause 45深解
说到MDIO,绕不开的就是IEEE 802.3里的两个标准——Clause 22和Clause 45。我刚入行那会儿,以为这东西统一着用就行,结果第一次调试10G光模块时就吃了大亏。说白了,这两个标准就像老式电话和智能手机,虽然都能打电话(读写寄存器),但能力和用法完全不一样。
这章咱们就来拆开看看,它们到底差在哪,你又该在什么场合选哪个。
Clause 22:经典但有限制
Clause 22是MDIO协议的初代标准。1998年左右提出,最早用在百兆以太网的PHY芯片上。它的设计很简洁,固定访问5位地址,总共能管理32个设备。
核心指标:
- 帧长固定:64位(前导码+起始+操作码+PRTAD+TA+数据+空闲)
- PRTAD(端口地址):5位,范围0-31
- 寄存器地址:5位,每个设备最多32个寄存器
- 数据位宽:16位
- 波特率:最高2.5MHz(实际常用1.25MHz)
我在项目中遇到过一种情况:一个板子上挂了4颗PHY,地址分别是1、2、3、4。按说没冲突,可调试时怎么都读不到地址4的数据。后来用示波器抓波形才发现,地址4的应答时序有问题。嗯,这里要注意:Clause 22的32个设备地址虽然是可用,但很多PHY芯片默认只预留了几种硬件配置地址,像0x00、0x01、0x02这类。你硬要设一个芯片不支持的地址,它根本就不理你。
Clause 45:为复杂芯片而生
2002年左右,随着万兆以太网和复杂光模块的出现,Clause 22那32个寄存器实在不够用了。于是Clause 45诞生。它引入了一个叫“设备类型(DEVAD)”的概念,地址空间一下扩展到32×32 = 1024个寄存器。
个人习惯:我调试10G/25G光模块时,一律用Clause 45。因为Clause 45可以直接访问光模块内部的诊断寄存器(比如温度、电压、偏置电流),而Clause 22根本办不到。
Clause 45的帧格式变了,操作码(Opcode)的含义也不一样。你看,Clause 22的操作码是01(写)和10(读);Clause 45的操作码改成了00(地址写入)、01(写数据)、10(读后自增地址)、11(读数据)。这个细节我曾经踩过坑——用Clause 45驱动去读一个只支持Clause 22的PHY,结果永远返回0xFFFF。
关键差异对比
你想想看,这两个标准在收发器侧能不能混用?答案是:不能直接混用。很多新芯片支持双模式(Dual Mode),但默认只开Clause 22。你需要手动切到Clause 45。
| 对比项 | Clause 22 | Clause 45 |
|---|---|---|
| 帧长度 | 64位固定 | 64位固定(但含义不同) |
| PRTAD(端口地址) | 5位 | 5位 |
| DEVAD(设备地址) | 无 | 5位(共32种设备类型) |
| 寄存器空间 | 32个寄存器/设备 | 32×32 = 1024个寄存器/端口 |
| 数据位宽 | 16位 | 16位 |
| 操作码含义 | 01写 / 10读 | 00地址 / 01写 / 10读自增 / 11读 |
| 典型场景 | 百兆/千兆PHY | 万兆PHY、光模块、MACsec控制器 |
注意:Clause 45的读取操作有两种模式——带地址自增和不带自增。带自增时,每次读完寄存器地址会自动+1,方便批量读。但如果你连续读相同地址(比如轮询状态位),一定要用不带自增的模式(Opcode=11),否则地址会跳走。
帧格式实操解析
我建议你记住这两种帧的构成,因为调试时你需要用示波器抓波形,然后手动解析每一bit。
Clause 22读操作帧(32位数据阶段之外的部分):
前导码: 32个1
起始码: 01
操作码: 10 (读)
PRTAD: 5位 (要访问的设备地址)
寄存器: 5位 (目标寄存器)
TA: 2位 (Z0用于读, 10表示应答)
数据: 16位 (从设备返回)
空闲: 若干Idle bit
Clause 45读操作帧(不带自增):
前导码: 32个1
起始码: 00
操作码: 11 (读数据,不带地址自增)
PRTAD: 5位 (端口地址)
DEVAD: 5位 (设备类型)
TA: 2位
数据: 16位
空闲: 若干Idle bit
你看,两个帧在起始码和操作码的位置就开始不同了。示波器上看波形,Clause 22的起始码是“01”,Clause 45的起始码是“00”。有一次我调试一款光模块,示波器抓到起始码是“00”,但软件里配成了Clause 22模式,结果读回来的数据全是0xFFFF——这就是典型的协议不匹配。
如何选择与切换
实际项目中,你需要根据PHY芯片的数据手册来决定用哪个标准。新出的芯片往往支持双模式,但切换方式各不相同:
- 有的靠硬件引脚拉高/拉低
- 有的靠写某个特殊寄存器(比如MMD中的0x0000寄存器)
- 有的靠上电时序(比如MDC时钟个数)
我个人习惯是先读Clause 22的寄存器0x01(状态寄存器),如果能读到有效的link状态,说明芯片当前工作在Clause 22模式。然后尝试写一个Clause 45特有的寄存器(比如设备类型0x1E的0x0000),如果写入后能读回来,说明它已经切换到Clause 45了。
你想想看,如果你读不到任何有效数据,那不是协议选错了,就是时序有问题。这个时候千万别怀疑芯片坏了——先抓MDC/MDIO波形看一眼。
SVG:Clause 22 vs Clause 45 帧流程对比
避坑指南:我踩过的三个坑
坑一:地址0的陷阱。 很多PHY芯片的PRTAD=0是广播地址。Clause 22的标准里,地址0用于广播写操作,但读操作会失效。我曾经向全板广播写一个配置,结果地址0的PHY也收到了数据,但读回来时所有PHY都拉低了MDIO,造成总线冲突。
坑二:Clause 45的地址自增模式。 有一回我批量读光模块的诊断数据,用了Opcode=10(带自增)。读到第5个寄存器时,地址自动跳到了0x0005,但我期望的是读0x0000到0x0004后再手动设地址。结果数据全错位了。从此我只在连续地址遍历时用自增,单次读永不启用。
坑三:时序余量。 Clause 22和45都在规范里定义了MDC的频率上限。但实际布板时,如果MDIO走线过长,或者有寄生电容,2.5MHz的边沿可能会变缓。我的经验是:新板子调试时先降到1MHz,波形确认无误后再提频。