第2章 MDIO/MDC协议详解与读写时序
咱们做PHY调试,天天和寄存器打交道。要读写这些寄存器,就得通过MDIO/MDC接口。这玩意儿说白了就是两条线:一条时钟线(MDC),一条数据线(MDIO)。PHY芯片靠它们跟MAC层或者CPU通信。我第一次接触这个接口时,以为挺简单,结果被时序坑了好几次。今天我把这块说透了,你以后遇到寄存器读出来全是0xFF或0x00,大概率是MDIO没玩对。
2.1 协议基础:信号定义与帧结构
MDIO(Management Data Input/Output)是双向数据线,MDC(Management Data Clock)由主控产生。标准速率下MDC最高25MHz,但有些老PHY只能到12.5MHz。我建议你读手册时先看这个参数,否则时序超了,PHY根本不搭理你。
完整的MDIO帧长64个MDC周期,包含几个固定段。下面这个表列出每个字段,你对照着看就知道了。
| 字段 | 位宽 | 说明 |
|---|---|---|
| Preamble | 32 | 连续32个1(高电平),用于同步 |
| Start of Frame | 2 | 固定为01,标识帧开始 |
| Opcode | 2 | 读为10,写为01 |
| PHY Address | 5 | 目标PHY芯片地址(0~31) |
| Register Address | 5 | 寄存器地址(0~31) |
| Turnaround | 2 | 读操作时:Z0(高阻→0);写操作时:10 |
| Data | 16 | 读写的数据内容 |
你看,光是个帧结构就有这么多讲究。我实战时经常犯的错误是:Preamble少了几个时钟,或者PHY地址写错了。有一次我拿示波器抓MDIO波形,发现Preamble只有30个1,结果PHY根本没响应。后来我习惯在代码里把Preamble多发送几个时钟,反正没坏处。
2.2 读写时序详解
其实读和写的主要区别就在Opcode和Turnaround这两个地方。咱们分开说。
读操作:主控发完前导码后,Opcode为10(二进制),接着发PHY地址和寄存器地址。之后Turnaround是Z0——主控先释放MDIO(高阻),等一个时钟,让PHY接管数据线,这段时间是PHY把寄存器值放到MDIO上。注意!Z0那个时钟周期里,MDIO是高阻态,外部需要上拉电阻把它拉高,否则数据会飘。
写操作:Opcode为01,Turnaround直接用10。主控在Turnaround阶段输出1和0,然后紧接着输出16位要写的数据。写操作全程由主控驱动MDIO,PHY只管接收。
说得再直白一点:读操作需要交换数据线控制权,所以多了一个高阻过渡。写操作则全程主控当家。
下面这张SVG图把读和写操作的关键差异画出来了,你一看就明白。
2.3 实战中的常见坑与经验
纸上谈兵容易,真上手就发现有各种坑。我总结几个你大概率会碰到的。
时钟频率:MDC不是越快越好。我见过有人把MDC设到50MHz,结果PHY不理人。实际上标准规定最高25MHz,但有些老PHY降到12.5MHz甚至更低。我的习惯是:先2.5MHz跑起来,确认通信正常后再往上提。
上电时序:PHY复位后需要一段时间才能响应MDIO。我踩过坑:软件在PHY复位后立即发MDIO帧,结果读回的数据全乱。至少要等1ms,安全起见我一般等10ms。有些PHY手动复位引脚拉低后还要等更久,看手册最准。
- PHY地址冲突:多颗PHY共一条MDIO总线时,地址不能重复。我遇到过硬件上两个PHY都设为0x1F,结果全挂。解决办法:每颗PHY单独用硬件管脚设置地址,程序里逐个扫。
- 上拉电阻:MDIO线必须接上拉电阻到1.8V或3.3V,通常2.2kΩ~4.7kΩ。没有上拉电阻,读操作时高阻状态会让信号悬空,数据全乱。
- 寄存器的影子拷贝:有些PHY在读取某些寄存器(如状态寄存器)后会自动清除某些位。你连续读两次,第二次可能看到不同的值。我自己的经验是:读一次后立刻保存,不要再读第二次。
嗯,还有一点很多人忽略:MDC在空闲时必须保持低电平。如果时钟线一直高或一直低,PHY可能误判帧边界。
接着说说我自己的一个小技巧。我用逻辑分析仪抓MDIO波形时,先抓一个已知的写操作,看帧头是不是对的。比如写控制寄存器0x00为0x1140,然后读回来验证。如果读回不对,先看PHY地址是否正确,再看TA的Z0部分主控是否释放了总线。有一次我发现是主控在TA阶段没释放,导致数据线一直冲突,读到的数据全是0xFF。
快速定位异常值的思路:当你发现读到的寄存器值出乎意料时,按这个顺序排查——①MDC频率是否超标;②PHY地址是否匹配硬件;③上拉电阻是否安装;④复位后的等待时间够不够;⑤是否是读清型寄存器;⑥用示波器看MDIO波形,确认帧结构完整。
好了,MDIO/MDC这块其实不复杂,但每个细节都可能让你卡半天。记住:读看Z0,写看Opcode。搞定这两点,大部分问题都能解。