1. MDIO协议概述:背景、应用场景归纳总结

为什么需要MDIO?

做嵌入式网络开发的朋友应该都接触过以太网PHY芯片。PHY芯片负责把MAC层传来的数字信号转换成线缆上的模拟信号,反过来也一样。但PHY本身不是傻子,它需要知道自己的工作模式——比如是千兆还是百兆,是全双工还是半双工,要不要开启自动协商。

这些配置信息存储在PHY内部的寄存器里。问题来了:MAC怎么去读写这些寄存器?

你想想看,总不能在PHY上拉几十根地址线吧?成本太高,也不现实。所以业界就想出了一个轻量级的管理总线——MDIO(Management Data Input/Output)。它只用两根线,就能完成对所有PHY寄存器的读写操作。

一点小历史
MDIO最初由IEEE 802.3u标准定义,后来在802.3-2008中被合并。说白了,它比I2C更简单,比SPI更省引脚,专为以太网管理场景定制。

MDIO的应用场景

我这些年做过不少带网口的项目,从家用路由器到工业交换机,基本都离不开MDIO。下面列几个典型的应用场景:

  1. PHY初始化配置
    板子上电后,MAC通过MDIO向PHY写入控制寄存器,指定速率、双工模式、LED灯控等。
  2. 链路状态监测
    实时读取PHY的状态寄存器,判断网线是否插好、链路是否建立、有没有错误帧。
  3. 自动协商控制
    触发或重新启动自动协商,读取对端能力字。
  4. 诊断与调试
    读取PHY内部统计计数器(如CRC错误数、碰撞数),用来排查物理层问题。
  5. 功耗管理
    通过MDIO写入电源管理寄存器,让PHY进入低功耗模式。

我记得有一次做一款工业交换机,上位机反馈偶尔丢包。折腾了好几天才想到直接通过MDIO读PHY的差错计数器,发现有大量的CRC错误——最后发现是变压器中心抽头接地出了问题。要是没有MDIO,这种问题排查起来无异于大海捞针。

MDIO协议的基本特点

特性说明
信号线2根:MDC(时钟)和MDIO(数据)
主从关系MAC(STA)作为主设备,PHY(MMD)作为从设备
最大速率MDC频率通常2.5MHz,但新一代标准允许更高
设备寻址5位PHY地址,最多支持32个PHY
寄存器寻址5位寄存器地址,共32个寄存器
数据宽度16位
帧格式固定结构:前导码+起始码+操作码+地址+数据+空闲
踩坑提醒
我曾见过有人将MDIO的片上拉电阻选得太大,导致信号上升沿过慢,在较高MDC频率下读写出错。结果查了三天,发现是硬件设计文档里的推荐电阻值没仔细看。嗯,这里要注意:MDIO是双向开漏或推挽,具体要看PHY手册的电气要求。

MDIO协议核心结构

下面这张图帮你把整个MDIO的知识脉络串起来。我个人习惯在学习一个新协议时先画这种全局图,避免“只见树木不见森林”。

MDIO协议知识体系结构图 MDIO协议知识体系 物理层 2线制:MDC + MDIO 主从结构 STA(MAC侧) MMD(PHY侧) 帧结构 前导码(32个1) 起始码(01) 操作码(读10/写01) 地址+数据+空闲 寄存器访问 5位PHY地址 5位寄存器地址 16位数据读写 基本寄存器0~15 应用场景 PHY初始化配置 链路状态监测 自动协商控制 诊断调试 / 功耗管理 扩展与演进 Clause 22(基本) Clause 45(扩展地址) MMD设备(0x1E等) SFP+/QSFP管理 MDIO协议是整个以太网管理生态的基石

帧格式拆解

MDIO的帧结构非常规整。我刚开始接触时觉得32位前导码好长,后来发现这是为了兼容老设备,让他们有足够时间同步。

  • 前导码(Preamble):32个连续的"1",表明开始传输。
  • 起始码(Start of Frame):01,紧跟前导码。
  • 操作码(Opcode):10表示读,01表示写。
  • PHY地址(PHYAD):5位,范围0~31。注意0通常留给CPU直连的PHY。
  • 寄存器地址(REGAD):5位,对应PHY内部寄存器编号。
  • 转向时间(Turnaround):2位,读操作用作总线周转,写操作固定为10。
  • 数据(Data):16位。
  • 空闲(Idle):MDIO变为高阻态,两周期释放总线。
关键点
读操作时,STA在转向周期将MDIO从输出切换为输入,PHY在此时接管数据发送。这个切换时机非常讲究——我曾经因为FPGA代码里时序没调好,导致读回的数据总是错位一位。后来用示波器一看,发现转向时间只给了一个周期,而标准要求两个周期。

一个简单的读写例子

假设我想读PHY地址1的寄存器0(基本控制寄存器)。帧序列如下(十六进制表示):

前导码: 0xFFFFFFFF
起始码: 0x01
操作码: 0x10 (读)
PHYAD:  0x01
REGAD:  0x00
转向:   0x2 (先输出高阻,PHY拉低MDIO准备)
数据:   0xXXXX (PHY返回的16位值)
空闲:   高阻

写操作类似,只是操作码为01,并且转向时间数据由STA主动发送。

实际项目中的注意点

  • MDC频率:大多PHY支持最高12.5MHz甚至25MHz,但很多MCU的MDC时钟是从系统时钟分频得到的,频率不精确。我建议先看PHY手册确认上限,再留50%余量。
  • 多PHY级联:MDIO本身是总线结构,所有PHY地址不能冲突。布线时注意MDIO信号线上拉电阻放置靠近主设备位置。
  • 时序毛刺:MDIO信号容易受到PCB噪声影响。我曾经在一条长走线上没加串联电阻,导致边沿振荡,读寄存器值时跳变。加上33Ω电阻后就稳了。
调试小技巧
如果你手头没有示波器,可以在软件里反复读取PHY的ID寄存器(通常是寄存器2和3)。如果每次读到的值都一样(比如0x2000xxx),说明MDIO基本通路没问题。如果值跳动或全为0xFFFF,先检查硬件连接。

好了,这一章我们聊了MDIO协议出现的背景——就是为了用最少引脚搞定PHY配置。它的应用场景从初始化到故障排查,贯穿整个网络设备生命周期。下一层我们会深入帧格式的每一位,以及如何用代码模拟MDIO时序。