ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

嵌入式以太网核心:MAC、PHY与MII家族接口全解析

嵌入式以太网核心:MAC、PHY与MII家族接口全解析 做嵌入式开发只要碰过以太网功能十有八九会遇到这么一种情况板子焊好了PHY芯片装上了RJ45也压好了结果Linux起来网口就是起不来或者Link灯一亮一灭终于稳定Link了一跑吞吐量又疯狂掉包。很多人第一反应就是查驱动、查DMA描述符、查内核配置折腾半天还不知道问题出在硬件还是软件。我自己的体会是与其在代码里大海捞针不如先把以太网这条数据通路上MAC、PHY、MII这几个角色的分工彻底吃透。硬件上谁负责组帧、谁负责编码数据走过哪些引脚软件能看到哪一层、看不到哪一层把这些串起来之后绝大多数问题都能很快定位到具体模块。这篇内容适合三类人一是刚开始碰嵌入式以太网的开发者想弄明白STM32或FPGA外接PHY芯片时那个MII/RMII接口到底在干什么二是做硬件或驱动的人想知道为什么有的板子引MII、有的引RGMII接口选择跟速率、引脚、PCB成本到底有什么关系三是对以太网帧结构有好奇心想搞清楚Wireshark里看到的MAC地址、长度字段是在哪一层被处理的。今天这一篇先把MAC、PHY和MII家族接口这条主干道讲明白属于整个以太网系列的第一篇。1. 一条以太网链路里到底有几个角色在干活先厘清MAC与PHY的边界1.1 从OSI分层到实际芯片MAC是逻辑PHY是物理大多数人谈网络协议都从OSI七层模型开始但落到实际硬件上我们真正关心的其实就是二层和一层。数据链路层的下半部分叫MAC子层物理层则由PHY芯片实现。平时大家说的“网卡”其实是一个很笼统的概念在一些板卡上它可能只是一个PCIe接口的独立控制器内部同时集成了MAC和PHY但在单片机、FPGA这类嵌入式系统里MAC往往以内置IP核或外设形式存在于主控芯片内部PHY则是外面一颗独立的小芯片。这两颗芯片各管一段中间的连接接口就是MII家族。MAC负责的是逻辑层面的事把上层IP包封装成以太网帧填好目的MAC、源MAC、类型字段算好FCS校验码再通过发送FIFO交给PHY。PHY负责的是物理层面的事把MAC送来的并行数据变成能在网线上传输的电平信号同时从网线接收到的模拟信号中恢复出时钟和数据再交还给MAC。如果一定要打个比方MAC像快递公司里负责贴面单、分拣包裹的人PHY则像驾驶员负责把包裹从仓库送到另一个城市MII接口就是仓库门口那条装货通道。搞清这个边界对调试非常关键。很多驱动问题被误判为“PHY不工作”实际上MAC侧DMA配置根本就没配对也有很多硬件问题被误判为“驱动bug”实际上PHY的参考时钟根本没起来。把分层边界画出来你才知道该拿示波器量哪里、该拿工具读哪里。1.2 数据帧的接力赛从DMA到RJ45每一棒都在忙什么我自己排查问题时习惯把一条完整的发送链路拆成几棒每一棒都单独验证。以最典型的MCU外置PHY为例一个帧从CPU到网线的实际路径是这样的CPU把要发送的数据放在内存DMA描述符告诉MAC控制器“数据在哪、多长”。MAC从内存取出数据计算CRC32插入前导码、SFD、源MAC、EtherType等字段按MAC层的规则组装成完整帧放进发送FIFO。MAC通过MII/RMII/GMII/RGMII这些并行接口把帧数据按位宽和时钟节拍送给PHY。PHY收到并行数据后先做物理层编码10M的曼彻斯特、100M的4B/5B、千兆的PAM5之类再做电平/线缆驱动最终从差分对送出。信号经过隔离变压器、RJ45、网线到达对端设备的PHY然后反向走一遍解码、去掉前导码、恢复并行数据、按接口协议交给对端MAC。接收路径正好反过来。这里有一个重要概念驱动能看到的只有MAC这一侧比如DMA描述符里的状态、MAC接收错误计数、中断标志而PHY内部的链路状态、自协商结果、信号质量需要通过MDIO/MDC管理接口去读寄存器。所以“软件能管到哪一层”决定了你的排查手段。1.3 “媒介无关接口”这个名字本身就是答案MII的全称是Media Independent Interface直译就是“媒介无关接口”。这个词不是随便起的它道出了MAC和PHY分离设计的核心动机MAC只需要跟PHY通过一个标准接口打交道至于PHY后面接的是双绞线、光纤、还是车载的单对线MAC根本不需要关心。同样一个MAC IP核今天配百兆铜口PHY明天配千兆光模块PHY只要接口符合约定义务MAC侧不用大改。这也是为什么车载以太网、工业以太网、普通以太网在MAC层几乎可以复用同一套软件栈差异都集中在PHY一侧。“媒介无关”是整套设计的灵魂理解了它你就理解了为什么MII家族会演化出那么多版本接口标准越统一产业链解耦越彻底做SoC的和做PHY芯片的厂商才能各自发挥。2. MAC层到底在忙什么帧结构、地址过滤与差错检测的交接逻辑2.1 以太网帧的完整构造抓包工具不会显示的字段以太网帧格式很多人背过但真到调试时往往发现和抓包软件看到的对不上原因在于抓包软件通常不会把前导码和帧间隙显示出来。一个标准的802.3以太网帧从介质上看其实长这样字段长度作用前导码Preamble7字节用于接收端时钟同步每个字节固定0x55SFD帧起始定界符1字节标记帧内容正式开始目的MAC地址6字节接收方地址广播就是全FF源MAC地址6字节发送方地址EtherType/Length2字节大于或等于0x0600时是类型字段如0x0800表示IPv4Payload数据46-1500字节上层协议数据不足需补零FCS帧校验4字节对目的MAC到Payload做CRC32的结果之所以有46字节的最小数据限制是为了保证整个帧从目的MAC到FCS至少有64字节。在经典半双工以太网里这个最小帧长度和碰撞检测窗口直接相关发送端必须在发出64字节之前就能判断是否发生了碰撞否则一个短帧发完了都不知道自己有没有和别的设备撞车。千兆以太网在半双工模式下为了维持这个机制还额外引入了载波扩展和帧突发把发送窗口拉长。2.2 单播、广播、组播与混杂模式MAC怎么决定“这包是不是我的”MAC地址一共48位前24位是厂商OUI组织唯一标识符后24位由厂商分配。第一个字节的最低位是I/G位0表示单播地址1表示组播或多播地址第二个低位是U/L位0表示全球唯一1表示本地管理地址。这也是为什么组播MAC地址通常以01开头而广播地址FF:FF:FF:FF:FF:FF其实就是“所有位全1”的特殊组播。接收方向MAC控制器会做一层很硬的过滤逻辑单播帧必须和本机MAC地址完全一致才接收广播帧无条件接收组播帧则看有没有使能对应组播组很多硬件用哈希表实现不一定精确匹配如果驱动把网卡设成混杂模式那么所有帧都收下来Wireshark抓包就是靠这个实现的。日常有人问“MAC地址怎么查”Windows用ipconfig /allLinux用ip link show或ethtool -P eth0但在批量产品上更该注意的其实是不要每台设备都用默认随机MAC最好在bootloader阶段把唯一MAC烧进Flash再写入MAC控制器的地址寄存器否则同一局域网里两台设备就可能互相打架。2.3 CRC32与CSMA/CD今天仍需理解的老机制FCS字段用的CRC32多项式是0x04C11DB7接收端重新算一遍结果不匹配就把整个帧丢掉驱动里表现成rx_crc_errors一类的统计计数在涨。这个计数是我排查“能通但丢包”时必看的指标如果它涨得厉害要么线上干扰要么PHY和MAC之间的数据线采样有问题要么晶体频率偏差太大。CSMA/CD是另一个绕不开的历史包袱。半双工模式下发送前要监听信道发送中要检测碰撞碰撞后按退避算法重传。现在的主干网络基本都是交换机和全双工每个端口一个冲突域CSMA/CD已经没有实际作用对应的MII接口信号CRS、COL在全双工下也基本闲置。但你仍要理解这套机制因为工业现场、老旧设备、某些串口服务器还会用半双工而且自协商出错时设备可能会从全双工掉到半双工出现“能通但速度极慢”的怪现象。3. PHY层不只是收发器编码、自协商与MDIO寄存器3.1 从曼彻斯特到PAM5以太网编码到底在解决什么问题很多人觉得PHY就是“把数字信号转成模拟信号发出去”实际上PHY内部特别忙编码就是它最核心的活之一。为什么要编码因为接收端要从数据流里恢复时钟不能允许长时间出现连续的0或1同时信号经过变压器和长线缆时还要考虑直流平衡、EMI和抗干扰能力。不同的以太网速率用了完全不同的编码方式速率/标准编码/线路码备注10BASE-T曼彻斯特编码每个bit中间必然有跳变时钟恢复简单带宽开销大100BASE-TX4B/5B MLT-34bit扩成5bit再用三电平调制成形降低高频分量1000BASE-TPAM54对线同时双向传输每对250Mbps五电平编码1000BASE-X / SGMII8B/10B8bit扩成10bit用于光口和串行PHY接口我见过不少新工程师误以为所有千兆PHY都用8B/10B实际上1000BASE-T铜口走的是PAM58B/10B更多出现在光模块和SGMII这类串行链路上。编码这件事决定了同样一段网线在100M和1000M下对噪声的敏感程度不同也决定了你在PCB布线、变压器选型时的要求不同。3.2 自协商网线两端是怎么“谈判”的PHY上电之后并不会一上来就按最高速率跑而是先和链路对端“谈判”一轮。10BASE-T时代PHY会定期发Normal Link Pulse表示自己在线100BASE-TX升级成FLP快速链路脉冲里面携带了本端支持的能力信息速率、全/半双工、流控等。两端PHY交换能力后按优先顺序选一个双方都支持的最高组合通常优先级是千兆全双工 千兆半双工 百兆全双工 百兆半双工 10M全双工 10M半双工。这里有个非常经典的坑现场为了“稳定”把交换机某个口强制成100M全双工但设备端没有关闭自协商。结果对端发来的FLP里没有可协商的“100M全双工”对应项时本端可能会落到100M半双工。链路看起来是通的Ping也通但只要流量一上来半双工侧的碰撞和冲突会直接让吞吐量崩掉。所以检查“能通但慢”的故障时一定先确认两端的速率和双工模式是不是一致不要想当然。3.3 用MDIO“体检”PHY寄存器1的bit2为什么最重要PHY的管理接口就是MDC管理时钟和MDIO管理数据两根线。MAC通过MDIO读写PHY内部的寄存器标准寄存器有32个前6个有统一规范寄存器0是控制寄存器bit0是软复位bit12是自协商使能bit13和bit8分别控制速度和双工寄存器1是状态寄存器bit2是Link Statusbit5是自协商完成标志。这个bit2基本是排错第一站链路通不通读它就知道了。在带Linux系统的主板上可以这样快速看ethtool eth0 mii-tool -v eth0如果系统还没起来在U-Boot里也能操作MDIOmdio list mdio read eth 1 1这里的“1”是PHY地址后面“1”是寄存器号。PHY地址不是软件分配的而是由芯片外面的PHYAD引脚在复位时被上下拉决定的常见默认地址有0x00、0x01、0x04等。遇到“设备树里配置了但找不到PHY”第一件事不是改代码而是拿万用表量PHYAD引脚看strap到底拉成了几。4. MII家族接口逐个拆解MII、RMII、GMII、RGMII与SGMII4.1 接口演进主线从四车道到双车道从并行到串行MII家族的名字看着多其实演进逻辑非常清楚。第一个标准MII是IEEE 802.3为10/100M以太网定义的并行接口数据线4位发送、4位接收跑25MHz时钟刚好100Mbps。到了千兆直接把位宽翻倍变成8位发送、8位接收时钟升到125MHz这就是GMII。但GMII引脚太多SoC和PHY芯片都很占地方于是出现了RMII和RGMII这类“缩线”版本。RMII把发送和接收各砍成2位参考时钟固定50MHz用“速率换位宽”的思路在百兆下刚好满足100Mbps。RGMII则把千兆的8位数据拆成4位用125MHz时钟双沿采样在上升沿和下降沿各送4bit等效8bit这样既保住了千兆吞吐又把管脚从二十几根压到十几根。越往后走接口越窄、时钟越快、时序越苛刻这就是整个MII家族的主线。4.2 一张表看全MII家族位宽、时钟、线速与管脚我把常见接口的要素整理成一张表方便对照接口数据位宽参考时钟最高线速管脚数量适用速率MIITXD/RXD各4bit25MHz(100M) / 2.5MHz(10M)100Mbps约16根10/100MRMIITXD/RXD各2bitREF_CLK固定50MHz100Mbps约10根10/100MGMIITXD/RXD各8bitGTX_CLK 125MHz1000Mbps约24根10/100/1000MRGMIITXD/RXD各4bitTXC 125MHz DDR1000Mbps约12根10/100/1000MSGMII差分串行TX/RX各一对1.25Gbps SerDes1000Mbps不到10根10/100/1000M以RMII为例100Mbps 2bit × 50MHz正好而到了10M模式REF_CLK仍然是50MHz但数据不是每个周期都有效而是大约每10个周期里传2位有效数据所以等价速率降到10Mbps。再看RGMII千兆模式 4bit × 2(双沿) × 125MHz同样算得刚刚好。每次看接口先算一遍“位宽×有效边沿×时钟频率”心里就有底了。4.3 时钟方向与“同源”问题这些坑最隐蔽接口位宽搞对了时钟方向是最容易翻车的地方。标准MII里TX_CLK和RX_CLK都由PHY给MAC因为PHY知道当前介质上的线速是多少。GMII比较特殊千兆模式下GTX_CLK由MAC提供给PHY因为发送时钟必须跟MAC的125MHz一致但10/100M模式下又退回MII式的PHY送时钟。RGMII在千兆模式下通常也是MAC侧输出TXC而且很多PHY要求TXC和TXD之间有约2ns的延迟关系有的要开PHY内部delay有的要开FPGA内部的IODELAY搞反的结果就是“能Link但数据全是错帧”。RMII还有一个著名的“同源”问题REF_CLK必须是同一个时钟源送到MAC和PHY不能你用一个晶振、我用一个晶振否则时钟频率偏差会在长帧传输时把采样点完全拉开表现出来的就是偶发掉包。很多STM32板卡上RMII参考时钟会通过PHY的REF_CLK引脚回送给MCU或者由MCU的MCO输出50MHz给PHY两种方案都能用但一定要保证源头唯一、电平摆幅够。示波器量一下频率和幅值往往比读半天手册更直接。4.4 SGMII与“MAC模式/PHY模式”的配置选择SGMII是串行接口里的代表一对差分发送、一对差分接收线速1.25Gbps因为内部编码是8B/10B有效数据速率正好1Gbps。它最大的好处是把并行接口从几十根线压到几根而且SerDes天生适合跨板传输、抗干扰能力强所以在交换芯片、FPGA网卡、车载以太网主控上非常常见。但SGMII有一个特别容易被忽略的配置项当FPGA的SGMII IP核和外部PHY芯片一起使用时IP核必须配置成MAC模式而不是PHY模式。这个“应配置成MAC模式”的细节网上相关的问题一搜一大把。原因是SGMII在链路建立时也会跑一套自己的自协商和带内状态字IP核得知道对面是PHY还是另一个MAC对面是PHY时IP核要当MAC对面是MAC时IP核才当PHY。选错模式经常表现为接口层Link正常但对端始终收不到有效报文。换一个PHY型号或者改一种背靠背互联方式第一件事就是把SGMII的角色方向确认清楚。5. 接口在真实项目里的落点STM32、FPGA三速以太网与车载以太网5.1 STM32内置MAC外接PHY为什么RMII方案居多STM32F4/F7/H7系列芯片内部继承了以太网MAC外设但PHY需要外挂。这类MCU引脚本来就紧张所以资源受限的板子绝大多数走RMII只用两组2位数据线和一根50MHz参考时钟只有引脚富余或者要求扫描兼容MII特性时才会选标准MII。典型接法就是PHY芯片承担介质接口RMII的REF_CLK由外部50MHz晶振或者主控MCO提供MDIO/MDC用来配置PHY。我之前调过一块STM32F407的板子现象是偶尔能获取到IP但ping包时通时不通。最后量波形发现RMII REF_CLK上升沿过缓幅值只有2V多MCU和PHY对时钟边沿判断不一致导致采样错位。把晶振的负载电容重新匹配之后问题立刻消失。这类情况软件怎么查都查不出来因为你看到的是驱动层表现“丢包”根因却在时钟信号质量。5.2 FPGA三速以太网IPGMII、RGMII、SGMII怎么选FPGA里做以太网常见的路线是用三速以太网MAC IP10/100/1000自适应。这种IP对外通常会出GMII、RGMII、SGMII三种类型的引脚看实际需求选。资源充足、速率要求高、时序约束好做可以考虑GMII板级走线紧张、要减少输出引脚就用RGMII若FPGA内部有硬核SerDes、PHY距离远就上SGMII。RGMII在FPGA项目里特别考验时序约束。千兆125MHz DDR模式下数据在时钟上升沿和下降沿各采样一次PCB走线长度、FPGA IODELAY、PHY内部delay三者必须协调好。我碰到过一个例子同一块FPGA板卡换了一个牌子的PHY之后原来能正常工作的RGMII接口开始偶发CRC错误后来查下来发现新PHY默认不使能内部TXC delayFPGA侧又没有补这个延迟需要在PHY寄存器里把发射延迟打开才解决。所以FPGA调RGMII不能只改代码还要把PHY的delay相关寄存器一个一个对照手册确认。5.3 车载以太网与国产PHY一样的MAC不一样的介质车载以太网这两年讨论很多热搜里也一直有“车载以太网测试”“100BASE-T1”这类词。车载以太网和传统以太网最大的差异在物理层100BASE-T1用一对非屏蔽双绞线编码方式也变成PAM3链路线缆更少、EMC要求更苛刻。但MAC层和MII/RMII/SGMII这类接口概念完全没变所以你的协议栈、上层服务、网络安全机制都可以无缝复用到车上这就是“媒介无关”在工程上的巨大优势。国产PHY芯片这些年也越来越多。百兆PHY、千兆PHY甚至车载PHY都有国产厂商在做对项目来说可选项变多了供货和成本压力会小很多。但换国产PHY时不要以为驱动可以原样照搬虽然IEEE标准寄存器一样但不少厂商的扩展寄存器用于延时配置、LED控制、低功耗模式各不相同初始化序列经常需要重新适配。6. 调试链路时我的排错顺序从Link灯到PHY寄存器6.1 先看Link状态再谈驱动问题我自己的习惯是拿到一块网卡不工作的板子第一件事不是翻驱动而是读PHY寄存器1的bit2。这一步只需要一条命令或者一片几百微秒的MDIO访问但能直接把问题分成两半——Link都不通问题在物理链路、PHY配置、变压器、RJ45这一侧Link通但收发异常问题才可能在MAC、DMA、驱动协议栈。很多工程师一上来就查驱动把链路层的问题绕了一个大圈。如果Link不通按这个顺序查先看PHY的供电、晶体、复位时序再看PHYAD strap到底配了几号地址设备树和驱动里写的和实际是否一致然后用网线测试仪确认线序特别是交叉线和直连线在带自适应功能的PHY上一般能自动翻转但老设备不一定支持。这些基础都排除后再用示波器量MDIO有没有波形如果MAC根本没去访问PHY那问题可能又回到了MAC侧初始化。6.2 能Link但收发异常时优先怀疑接口时钟与采样时序Link灯亮了只能说明物理层“握手”成功不代表MAC和PHY之间的数据接口没问题。遇到能Link但收不到、或者疯狂CRC错误的情况先看RTOS或Linux里的统计计数ifconfig eth0 ethtool -S eth0 | grep -i crc如果rx_crc_errors、rx_errors在涨重点查三个方向一是MII/RMII/RGMII的数据线、时钟线布线是不是等长、有没有跨分割二是时钟方向是否和PHY手册一致尤其是RGMII的TXC delay和RMII的REF_CLK同源三是PHY的工作模式有没有被配置成百兆、千兆不一致的状态。很多时候这比反复改软件参数有效得多。这里有个很实用的隔离手段先用PHY的数字环回Digital Loopback让MAC发出的数据在PHY芯片内部直接绕回MAC。如果环回模式下收发正常说明MAC和接口没问题故障点在PHY的模拟收发链路或网线上如果环回模式本身都不通那就要回到MAC侧和接口时序去找。6.3 速率/双工不匹配导致的“能通但慢”怎么定位有一种极常见的故障表现网络能通Ping能通但传文件、跑带宽测速时吞吐量掉到正常值的几分之一。这大概率不是CPU算力问题而是对端或PHY的速率/双工协商结果不一致。用ethtool一眼就能看到ethtool eth0重点关注Speed和Duplex两行。如果本端显示100Mbps全双工对端交换机口却显示100Mbps半双工链路就已经处于双工不匹配状态。半双工端会产生大量冲突表现就是高延迟、高重传、吞吐暴跌。这种问题通常是有人手动把交换机端口强制成了半双工或者设备端关闭了自协商而交换机还开着自协商两边协商到了不同的能力。解决办法就是两端统一策略要么全部自协商要么全部强制到同一组速率/双工参数。我个人的习惯是拿到新板子之后第一件事不是急着跑网络demo而是先用MDIO把PHY的寄存器0、1、4、5全部读一遍把复位状态、能力、协商结果、Link状态记录下来。很多疑难杂症其实在环境一致、记录完整的条件下都会自己浮出水面。这篇先把MAC、PHY和MII家族接口的基本盘理清了下一篇我打算把MDIO寄存器逐位过一遍再单独聊RGMII的时序约束和PHY芯片的调试手法那个更贴近实战遇到问题了可以直接拿来对照。
返回列表