3. MDIO/MDC 接口协议与寄存器访问原理

讲到PHY寄存器配置,绕不开的就是MDIO/MDC接口。很多工程师一开始觉得这玩意儿就是个简单的两线协议,不就是读写一下寄存器吗?嗯,实际项目里栽跟头的人可不少。我见过有人因为时序不满足,整个链路协商都上不去。今天就好好聊聊这个接口。

3.1 两线接口,藏着不少门道

MDIO(Management Data Input/Output)和MDC(Management Data Clock)是IEEE 802.3标准定义的管理接口。说白了,就是用两根线去读写PHY芯片内部的寄存器。

  • MDC:时钟线,由MAC或控制器提供。最高频率一般为2.5 MHz或12.5 MHz(取决于标准)。
  • MDIO:数据线,双向传输。既可以写指令,也可以读数据。

注意,MDC是推挽输出,MDIO是双向开漏,需要外部上拉电阻。我在项目中遇到过,因为上拉电阻选得太大,导致信号上升沿太慢,通信直接失败。你想想看,一个简单的电阻选型,就能让整个系统翻车。

我的建议:上拉电阻一般取1.5kΩ~4.7kΩ,具体看走线长度和负载电容。板子小、走线短,可以选大一点;反之就选小一点。别图省事随便贴个10kΩ。

3.2 MDIO帧结构:读写流程解析

每次通信都是一个帧。帧结构由几个固定字段组成,我用表格梳理一下,方便你对照调试。

字段 位数 说明
PREAMBLE 32 起始前导码,32个连续的“1”。用于同步。
ST(Start of Frame) 2 帧起始标志。固定为“01”。
OP(Operation Code) 2 操作码。“01”=写,“10”=读。
PHY ADDR 5 目标PHY地址。最多支持32个PHY。
REG ADDR 5 目标寄存器地址。最多32个寄存器。
TA(Turnaround) 2 切换周期。写操作:MDIO输出“10”;读操作:第一个周期MDIO为高阻,第二个周期PHY驱动数据。
DATA 16 读/写的数据。
IDLE 1+ 空闲状态,MDIO为高阻。

你可能会问:为什么读操作TA是两个周期?第一个周期,控制器释放总线;第二个周期,PHY开始驱动数据。这个切换设计是为了避免总线冲突。我见过一个开发板,TA时序没做对,读回来的数据全是0x0000,排查了半天才发现是GPIO输出使能切换慢了。

3.3 MDC时钟与数据采样

MDC是源同步时钟,MDIO在MDC的上升沿被采样。控制器在MDC上升沿之前把数据准备好,PHY在上升沿读取。反过来,PHY输出数据时,也是在MDC上升沿之前把数据驱动到MDIO上。

关键参数:

  • MDC周期:至少160 ns(2.5 MHz模式),或者40 ns(12.5 MHz模式)。
  • MDIO数据建立时间(tsetup):最小10 ns。
  • MDIO数据保持时间(thold):最小10 ns。
  • MDIO输出有效时间(tvalid):最大30 ns。

我记得有一次调试一个光纤模块,MDC走线绕了大半块板子,导致时钟歪斜太大,数据总是错位。后来在FPGA里加了一级延迟矫正,才稳住。所以啊,时序裕量一定要留够。

3.4 读操作 vs 写操作:核心差异

读和写的主要区别在于TA字段和数据驱动方向。我直接列个对比表:

操作OP CodeTA(2位)数据源
写操作0110(直接驱动)控制器
读操作10Z0(先高阻,再PHY驱动)PHY

写操作比较简单,控制器从头到尾控制MDIO。读操作就需要总线切换技术。我曾经在一个项目中,控制器是MCU的GPIO模拟MDIO,结果读操作时GPIO方向切换延迟太大,导致TA阶段被PHY和控制器同时驱动,直接干烧了PHY的驱动管脚。嗯,教训深刻。

3.5 多PHY共线:地址冲突与避免

一条MDIO总线最多可以挂32个PHY。每个PHY有唯一的5位地址(通常通过硬件管脚或strap配置)。如果两个PHY地址一样,总线就会冲突。这种情况在板级设计时很容易被忽略。

避坑指南:
  • 确认每个PHY的地址配置管脚是否被正确拉高或拉低。
  • 如果PHY支持地址修改(通过寄存器或strap),确保上电后的默认地址不冲突。
  • 曾经我遇到一个项目,两个PHY的地址都设成了0x01,结果读写总是一个成功一个失败,最后用示波器抓MDIO才发现的。

3.6 MDIO/MDC时序波形的核心逻辑

下面我画一张流程图,把MDIO/MDC的完整读写过程串起来。这张图我每次调试时都会在脑子过一遍,很重要。

MDIO/MDC 读写流程核心状态机 MDIO/MDC 读写流程核心状态机 IDLE(空闲) 写/读开始 PREAMBLE(32个1) ST(01) OP + PHY ADDR + REG ADDR TA(10):写操作 TA(Z0):读操作 写数据(16位) 读数据(16位) 返回 IDLE 写路径 读路径

看图就清楚了:写操作走左边,读操作走右边。读操作多了一个总线切换的步骤(TA阶段PHY接管MDIO),这也是最容易出问题的地方。

3.7 实际项目中的经验检查表

我来分享一个我个人很常用的调试检查清单。每次排查MDIO通信问题时,我会从头到尾过一遍:

  1. 硬件层面: MDC波形是否干净?边沿有没有过冲或振铃?上拉电阻对吗?
  2. 前导码: 是不是完整的32个“1”?有些PHY不检查前导码,但大部分还是需要的。
  3. 地址匹配: PHY ADDR对不对?有没有多个PHY共线冲突?
  4. TA时序: 读操作的第一个TA周期,控制器是否确实释放了MDIO?输出使能有没有及时切?
  5. 数据窗口: 在MDC上升沿采样时,数据是否稳定?特别是走线较长时,要考虑传输延迟。
  6. 回读验证: 先写一个已知值,再读回来;如果对不上,问题大概率就在上面几点。
我曾经经历的一个典型案例: 一个项目使用MCU的GPIO模拟MDIO,结果不管怎么配,读回的寄存器永远是0x0000。查了两天才发现,MCU读操作时,GPIO方向从输出切换到输入有超过100 ns的延迟,而PHY在TA第二个周期就开始驱动数据,导致总线冲突。最后靠外部三态缓冲器解决。

好了,这一章的内容就到这里。MDIO/MDC看起来简单,但是细节决定成败。只要把帧结构、TA切换、时序参数这几个关键点吃透,调试起来就会顺手很多。