资讯详情

资讯详情

以太网MAC与PHY分工详解:从接口时序到调试实战

搞过以太网开发的人不管做单片机、FPGA、核心板还是交换机最后一定会碰到一组词MAC和PHY。尤其像STM32这类内置MAC、但没内置PHY的芯片外接一颗百兆或者千兆PHY芯片几乎是标配FPGA上做三速以太网也得在RGMII/SGMII接口上挂一颗PHY。很多新手一开始会被这两个名字搞晕MAC到底是做什么的PHY又管什么为什么不能一个芯片全搞定这一篇我就用实际做项目的视角把以太网里MAC和PHY的分工、接口、时序、寄存器和调试经验全部串一遍适合刚入手以太网开发或者在做STM32/FPGA以太网方案时被PHY配置折磨过的朋友直接参考。1. 先搞清楚分工MAC和PHY到底各自管什么1.1 从协议栈往下看数据是怎么一层层处理的理解MAC和PHY最稳的方式是从协议栈往下看。我们平时写网络应用接触的是Socket数据到了TCP/IP层之后会变成IP包这是软件层的事IP包要发出去还需要在数据链路层被封装成以太网帧这就是MAC层要干的事而帧最终变成网线上的电信号或光信号则是PHY层的事。你可以把这个过程类比成快递寄包裹。应用层和TCP/IP层好比是你填写的快递单和打包动作它决定了包裹里装的是什么MAC层负责给包裹贴上收件人地址、寄件人地址并且在包裹上写清楚长度还要贴防撕标签而PHY层就是那辆送货的货车它不关心包裹里是什么只负责把包裹从一个地方运到另一个地方并且保证运输过程中的信号不出错。在具体芯片设计里这种分工被拆成了两个相对独立的模块。MAC通常是一段数字逻辑可以集成在MCU里比如STM32的F407、H7系列也可以以IP核的形式存在FPGA里PHY则更像是模拟和数字混合电路需要处理线缆上的电平、时钟恢复、编码解码所以它通常是一颗独立的物理层芯片。你可能也听说过有些SoC会把MAC和PHY集成在一起比如很多单芯片交换机但对开发者来说把MAC和PHY分开理解永远是最安全的方式。1.2 MAC和PHY的职责对照我整理了一张对照表做项目时经常拿出来核对能避免很多“这到底是谁该干的事”的争论。对比项MAC层PHY层所在OSI层级数据链路层L2物理层L1处理的数据单位以太网帧Frame比特流Bit核心工作组帧、解帧、MAC地址过滤、FCS校验、流控、半双工退避编码/解码、并串转换、时钟恢复、电平/线缆驱动、自动协商典型芯片形态MCU内部、FPGA IP核、交换芯片内部独立PHY芯片、SFP模块内部常见输出接口MII/RMII/GMII/RGMII/SGMII双绞线、光纤、同轴电缆是否参与介质访问参与CSMA/CD、帧间隙控制不参与只看物理信号需要关注的错误CRC错误、超长帧、对齐错误Link down、信号衰减、误码表格里有个容易被忽略的点PHY层并不做CRC校验它把收到的比特流恢复好之后就会直接通过MII接口送给MAC由MAC来做帧的完整性和地址过滤。所以当你看到RX方向CRC错误暴增通常先查的是PHY侧信号质量和时钟而不是马上怀疑上层协议。1.3 为什么要分成两个芯片而不是全部集成既然MAC和PHY拆开会增加硬件设计复杂度为什么大多数方案还要外挂PHY原因很简单PHY涉及太多模拟电路和工艺差异。高速以太网的PHY要处理基带编码、均衡、阻抗匹配、时钟恢复这在芯片制造上更依赖模拟工艺而且不同传输介质铜缆、光纤、车载差分线对PHY的要求完全不同。MAC是纯数字逻辑跟着主芯片的制程走就行。如果硬要把两者集成在同一个SoC里要么PHY性能打折要么主芯片成本飙升对做产品的人来说完全不划算。明白了这一点你就会知道选择一颗以太网PHY本质上是在选择“MAC以什么接口方式跟这颗PHY对话”。这也直接把话题引到了整个方案最核心的决策点MAC和PHY之间走什么接口。2. MAC与PHY之间的接口选型直接决定硬件方案2.1 从MII到RGMII接口是怎么一步步变快的以太网MAC和PHY之间有标准接口做了几十年从最早的AUI一路演化到今天。对普通开发者来说真正需要熟练掌握的是四种MII、RMII、GMII、RGMII。另外还有SGMII这种串行总线现在也特别常见。MII是最经典的并行接口在10M/100M时代是绝对主流。它用4根数据线TX4根数据线RX再加上TX_CLK、RX_CLK、TX_EN、RX_DV、TX_ER、RX_ER这些控制脚一共大概16根线。MII的时钟在100M以太网时是25MHz10M以太网时是2.5MHz每个时钟周期送4位数据。RMII是精简版专门为了减少引脚数量设计。它在100M下只用一个50MHz时钟数据线TX和RX各改为2根收发都在这2根线上完成另外用CRS_DV一根信号把载波监听和接收数据有效合成在一起。RMII优点就是引脚少很多单片机比如STM32F407的ETH、NXP i.MX系列都是用这种接口接PHY缺点是FPGA里时序约束比MII更严格。到了千兆MII/RMII就不够用了。GMII把数据线扩展到8根时钟提高到125MHz纯GMII引脚数更多在PCB上很占面积。于是业内又搞出了RGMII保留8根数据线但采用双沿DDR采样数据线和时钟线在上升沿和下降沿都传输数据时钟还是125MHz但实际带宽翻倍到千兆。RGMII几乎成了千兆PHY和MAC之间最主流的物理接口。接口支持速率数据位宽时钟频率是否双沿采样大概引脚数MII10/100MTX 4bit RX 4bit2.5/25MHz否16根左右RMII10/100MTX 2bit RX 2bit50MHz否9根左右GMII10/100/1000MTX 8bit RX 8bit2.5/25/125MHz否24根左右RGMII10/100/1000MTX 4bit RX 4bit2.5/25/125MHz是12根左右SGMII10/100/1000M串行1bit1.25Gbps串行4根差分线2.2 以RGMII为例把引脚和时序看明白RGMII最容易被新手搞混的一点是它虽然“看起来”每位只有4根数据线但因为上升沿和下降沿都在传所以一个方向实际等效8个数据位。具体来说RGMII的TXD[3:0]在时钟上升沿发送低4位下降沿发送高4位RXD[3:0]同样处理。TX_CTL和RX_CTL也是一样上升沿分别发送TX_EN和RX_DV下降沿分别发送TX_ER和RX_ER。画原理图的时候RGMII接口大致就是这些信号GTX_CLK、TXD[3:0]、TX_CTL、RXD[3:0]、RX_CTL、RX_CLK。在千兆模式下GTX_CLK由MAC提供125MHz时钟给PHY在100M或者10M模式下这个时钟会变成25MHz或者2.5MHz具体由MAC侧根据当前协商速率调整。如果你使用FPGA做三速以太网这里就必须设计一个动态时钟切换逻辑不能只给PHY一个固定125MHz。实际调试中有一个非常常见的坑RGMII的RX_CLK在千兆模式下是PHY输出的125MHz时钟但在10M/100M模式下有些PHY输出的RX_CLK是连续时钟有些则是跟数据相关的突发时钟。如果你在FPGA里用固定的时序约束做两级寄存采样很容易在低速模式下读到不稳定数据。我的习惯是把RX_CLK当成普通时钟管理单元输入先经过PLL或者BUFG再结合IDELAY调整采样相位不要想当然地认为PHY给出的时钟一定干净。2.3 SGMII串行接口以及“MAC模式”这个坑SGMII是千兆以太网里另一种非常常见的MAC与PHY接口但它不是并行8根线而是用一对差分发送、一对差分接收速率固定为1.25Gbps。也就是说不管是跑10M、100M还是1000MSGMII链路上的物理速率都是1.25Gbps然后通过在链路里插入空闲码和内嵌状态信息来实现各种速率适配。正因为SGMII是串行点对点通信它自己也有主从关系需要明确哪一端是MAC哪一端是PHY。这里就碰到一个很现实的配置问题很多FPGA里的SGMII IP核或者SoC里的千兆MAC控制器允许你配置成MAC模式或者PHY模式。当你的SGMII IP核是接在一个外部PHY芯片前面负责跟PHY芯片对接时IP核必须配置成MAC模式反过来如果你的SGMII IP核要模拟成一个PHY去接交换芯片的MAC那就要配置成PHY模式。这个配置一旦搞错最典型的现象就是链路一点反应都没有。因为SGMII的初始协商帧内容和角色定义完全反了两边都无法正确识别对方。遇到这种情况不要先去怀疑硬件焊接先翻IP配置界面确认角色是MAC mode同时确认是否启用了SGMII自动协商很多IP核如果关闭了自动协商还要额外给出速率参数否则PHY侧无法获得正确速率。从整体选型来看并行RGMII的优势是资源占用低、调试直观串行SGMII的优势是引脚少、适合高速背板和高密度交换机。但对大多数嵌入式设计来说RGMII仍然是最高性价比选择。3. 时钟、帧格式和收发通路这些细节决定数据能不能跑稳3.1 以太网的时钟体系是怎么确定的以太网所有速率都和时钟频率绑定得很死。10BASE-T的码元速率是10Mbps对应MII接口2.5MHz100BASE-TX是100Mbps对应MII接口25MHz1000BASE-T是1000Mbps对应GMII接口125MHz。而RMII因为芯片内部做了2比特并行处理所以100M时稳定用50MHz参考时钟而不是用25MHz。很多朋友第一次接触RGMII时会被“千兆GMII是125MHz为什么RGMII也是125MHz”这个问题卡住。原因就是RGMII用了双沿采样8位数据被拆成两组4位分别在时钟的上升沿和下降沿传输所以原始位宽虽然只有4根线等效带宽还是跟8位并行一样时钟仍然是125MHz。在实际电路里时钟的来源有两类。一类是PHY提供参考时钟给MAC常见于RMII模式比如STM32外加一颗RMII PHYPHY的50MHz时钟可以直接输出给MAC用作参考时钟另一类是MAC提供发送时钟给PHY常见于RGMII千兆模式MAC给出GTX_CLK。还有一个容易让人绕晕的点很多PHY芯片上有REF_CLK引脚它和MAC接口上的TX_CLK、RX_CLK并不是同一个东西REF_CLK是PHY内部PLL的参考源可以由外部有源晶振提供也可以由MAC侧直接输入。具体怎么接必须查PHY手册的时钟树章节不能想当然。3.2 一帧以太网数据到底由哪些字段组成MAC层核心工作就是处理和生成以太网帧所以帧结构必须刻在脑子里。经典的DIX以太网帧格式如下字节偏移字段长度作用0前导码 Preamble7字节同步时钟内容为0x557SFD1字节帧起始定界符0xD58目的MAC地址6字节接收方地址14源MAC地址6字节发送方地址20类型/长度2字节0x0800表示IPv40x0806表示ARPIEEE 802.3里该字段表示长度22载荷数据46-1500字节上层IP包不足46字节要填充最后FCS4字节CRC32校验和覆盖从目的MAC到载荷的全部内容有个容易忽略的细节PHY并不会把前导码和SFD完整传给MAC。通常PHY恢复时钟并检测到SFD之后会把RX_DV拉高从目的MAC地址开始往外送数据。所以你在FPGA或单片机上看到的接收数据流往往已经去掉了前导码和SFD的前缀只剩下目的MAC、源MAC、类型、载荷、FCS。如果你设计MAC接收逻辑第一个进入的字节就是目的MAC地址的第一个字节不要期望还能收到0x55这些同步前导。FCS是MAC层计算并附加的CRC32它的计算范围是目的MAC、源MAC、类型和载荷不包括前导码和SFD本身。发送时MAC必须自己算好FCS再一并交给PHY接收时MAC也必须自己验证FCS。如果FCS错误正常工作的MAC会直接丢弃该帧上层协议完全看不见。所以你在Wireshark里看到的丢包可能根本就没到达网卡驱动而在MAC层就被扔了。3.3 TX/RX通路上的状态切换、帧间隙和流控MAC与PHY交换数据并不是简单地“有数据就传”还需要管理帧间隙IFG。以太网标准规定两个合法帧之间至少要有96比特时间的间隙。这是为了保证接收端有足够时间处理上一帧、释放FIFO。很多初学者在做FPGA时序时为了追求吞吐把帧间隙压得太短结果就是PC端网卡持续报CRC错误或者丢帧因为对端MAC没来得及处理完上一帧又来了新帧。碰到这种吞吐上不去的问题先量一下两帧之间的间隔是不是真的够96比特。流控方面100M/1000M的半双工退避机制现在已经不太常用但全双工下的PAUSE流控仍值得了解。当接收端FIFO快满时MAC可以发出一个PAUSE帧告诉对端暂停发送。这个PAUSE帧在MAC层生成PHY只是透明传输。如果你外接PHY芯片发现网络吞吐异常先查一下是不是哪边把PAUSE能力或者对端的能力配置错了导致不停发PAUSE帧把链路卡死。TX方向还有一个常见的错误处理信号TX_ER。当MAC在发送过程中发现错误可以把TX_ER拉高PHY收到后用编码层定义的错码符号把这个错误帧显式标记出去。在标准以太网收发器里PHY不会主动丢弃这个帧而是让对端PHY收到错误标记后再送给对端MAC去判断。所以调试时如果对端CRC错误飙升不只是接收路径问题发送路径的异常信号也可能被PHY“原样标记出去”了。4. 硬件实操PHY电路设计、MDIO管理接口与调试流程4.1 一个最小PHY系统该怎么搭外接一颗PHY芯片最小系统其实就几块电源、时钟、接口、MDIO管理、网络隔离变压器。但恰恰是这几个基础部分最容易在画板时埋雷。首先要关注PHY的内核电压和IO电压。老一代百兆PHY常用3.3V千兆PHY内核可能是1.0V、1.2V而IO口要根据MAC侧的电平选择常见有2.5V、3.3V。如果MAC接口是3.3V的RGMII却把PHY的IO电源配成2.5V电平不匹配会导致信号质量极差甚至完全不通。时钟部分很多PHY支持无源晶振也支持直接输入参考时钟。直接输入参考时钟的方式更常见因为可以用MAC侧或者主控侧统一生成50MHz或25MHz。但要注意有些PHY的REF_CLK输入引脚和MII接口的TX/RX时钟是复用关系手册里有启动配置位或者strap引脚决定必须按照目标工作模式设置。还要注意PHY的复位和strap引脚。PHY在上电或复位释放时会通过若干引脚的电平确定PHY地址、时钟模式、接口模式。比如PHYAD[0]、PHYAD[1]设置MDIO访问地址MODEO[2:0]设置接口是MII、RMII还是RGMII。很多人上电后读不到PHY ID或者PHY工作模式不对多半是strap引脚被悬空或者上下拉电阻配错了。这些strap引脚通常不能直接悬空要按数据手册焊死到上拉或下拉否则复位瞬间电平不稳定PHY可能随机进入错误模式这种故障时好时坏特别难排查。近两年国产百兆PHY芯片在工控和车载项目里用得越来越多它们的MDIO基础寄存器族基本和传统PHY保持一致0号寄存器是控制、1号寄存器是状态、2/3号寄存器是厂家ID遇到不熟悉的芯片先读这4个寄存器基本能识别身份。如果驱动适配不上再去翻厂商提供的驱动和勘误表不要一上来就改大逻辑。4.2 MDIO管理接口用一根数据线操纵PHY的全部状态PHY芯片除了数据通路还有一个独立的管理通路叫MDIO/MDC。MDIO是双向串行数据线MDC是管理时钟。规范规定MDC最高约2.5MHz但很多芯片支持更高的频率实际调试时可以先用较低频率保证可靠。MDIO读写协议很像SPI一个完整帧32位。前导码是32个1然后起始码是01操作码两位读是10写是01。后面跟着5位PHY地址、5位寄存器地址接着是2位切换状态最后是16位数据。下面是一个读寄存器的典型序列共64比特逻辑写方向 1...1(32bit) 01 10 PHYAD(5bit) REGAD(5bit) TA(2bit: Z0) 之后切换为读方向PHY返回 16bit data写寄存器时MAC发起完整32位帧写方向 1...1(32bit) 01 01 PHYAD(5bit) REGAD(5bit) TA(2bit: 10) 16bit data如果你在FPGA里自己写MDIO控制器一定要让读操作里的TA第一位输出高阻第二位拉到0然后再释放总线读取16位数据。很多第一次写MDIO控制器的人在这里栽跟头把TA也当普通数据输出了导致读到全0或者时序错位。在单片机平台上最简单的做法是先用软件的GPIO翻转出MDC然后按位操作MDIO虽然慢但原理最清晰调试也方便。4.3 经常要读写的PHY寄存器速查不同厂商PHY寄存器会有差异但基础寄存器是IEEE标准可以直接拿来排查问题。寄存器地址常用名称关键位调试作用0x0控制寄存器bit15软复位bit13bit6速率选择bit8全双工bit12自动协商使能bit14回环使能配置速率、开启回环0x1状态寄存器bit15自动协商完成bit2链路建立bit5自动协商能力判断链路是否up、协商是否完成0x2PHY ID高16位厂商和型号信息识别PHY型号0x3PHY ID低16位厂商和型号信息识别PHY型号0x4自动协商广告广播自己支持的速率和双工模式确认本地能力0x5链路伙伴能力对端PHY支持的速率和双工模式确认对端能力0x10千兆控制部分PHY1000M全双工/半双工能力千兆协商调试时最常用的流程是先读0x1看bit2链路是否建立再读bit15看协商是否完成如果链路没建立去查链路伙伴能力0x5和本地广告0x4看看两边协商的公共交集是不是空集。比如本地只广告百兆对端只支持千兆那么协商完双方会直接降级或者彻底失败此时0x1的bit2会是0。4.4 PHY回环测试是板级调试的第一武器以太网调试时回环测试永远比抓线缆信号来得快。PHY芯片内部通常都有数字回环和模拟回环开启方式就是在0x0寄存器bit14写1。使能后MAC发出的数据经过PHY的发送通路后直接回到接收通路再送给MAC。这样就能验证MAC侧的逻辑、RGMII接口、时序约束、数据通路是否有问题而不依赖网线和对端设备。回环方式很多从近到远分别是MAC内部回环不进PHY、PHY数字回环、PHY模拟回环、远端回环对端设备把数据环回。我在实际项目里建议按顺序测先把MAC内部回环打开确认MAC发送和接收逻辑正确再开PHY回环确认RGMII/MII接口时序没问题然后把网线插到一个已知正常的交换机或者用网线直连测试确认PHY的模拟收发通路和网络变压器正常。这样逐步收缩范围能省掉大量瞎猜的时间。5. 常见问题与排查技巧实录5.1 网线插上之后Link就是起不来怎么办这是以太网调试里遇到最多的问题。出现link down先不要急着怀疑代码按照从上到下的顺序排查。第一步用命令读PHY的状态寄存器在Linux下可以用ethtool eth0看Speed和Link detected也可以直接在驱动调试接口里读0x1寄存器看bit2是不是0。如果是0说明PHY物理层都没有建立链路问题大概率在硬件。硬件方面重点看几个点PHY供电电压是否到位、参考时钟有没有起振、PHY复位释放时间够不够、strap引脚是否配置正确、网络变压器到RJ45之间走线是否正常。有一个特别隐蔽的问题PHY的复位引脚被CPU的GPIO控制但CPU端GPIO默认方向不对或者上电顺序不对导致PHY一直处于复位状态。这种问题难查就在于你示波器看复位引脚可能已经拉高了但复位释放的那一刻PHY的电源还没完全稳定PHY就锁死在了未知状态。稳妥做法是软件里给PHY做一个不低于10ms的复位延时之后再初始化MDIO。5.2 从PC端ping不通板子但PHY明明是link up这种情况也很典型PHY协商成功Link up但ping不通。原因通常集中在三层一是MAC层的MAC地址没有配好比如全是0二是IP地址配置不在同一网段三是MAC没有真正把数据送进PHY。遇到这种先不要直接看TCP/IP先在板子上用抓包或者计数的方式确认有没有收到ARP请求。如果收到了ARP请求但没有回包说明MAC接收正常但发送异常重点查发送FIFO、TX_EN、TX_CTL时序以及RGMII接口的时钟相位。RGMII要求发送时钟与数据满足大约1ns左右的建立保持时间如果PCB走线不等长或者FPGA里没有加输出延迟就可能出现每几帧丢一帧、对端CRC错一堆的现象。此时可以用Wireshark在PC侧看收到帧的源MAC和CRC情况Wireshark虽然抓不到物理层CRC错误但能通过Dropped帧数和异常帧长透露出很多线索。另外不要忘了一个最基本的排查如果PHY的MDIO读出来链路是up但PHY的速率寄存器显示的是100M交叉网线或者直通网线的场景下可能出现速率协商不匹配导致虽然link up但无法正常传输。强制把速率和双工改成一致比如两端都改成100M全双工再验证。5.3 RGMII接口采样不稳定、丢帧多应该怎么调RGMII是最考验时序的接口之一。在FPGA里做RGMII接收一定要用IDELAY调节RX_CLK相对于RXD[3:0]和RX_CTL的相位不能只靠简单的时序约束。我调试的经验是先用一个滑动窗口去扫描IDELAY的延时值同时让板子反复发已知数据帧统计CRC错误数画出“误码率-延时步进”的曲线选择误码率最低的一个稳定平台而不是选曲线边缘。在STM32平台上RGMII用得相对少多数是RMII但时隙问题同样存在RMII的CRS_DV信号和RXD[3:0]是同步的如果PCB上这三根线长度差太多或者PHY芯片的REF_CLK相位抖动比较大也会出现收帧不完整。我的习惯是原理图阶段就把RMII/RGMII数据线做等长并且在PHY芯片附近预留几颗RC滤波或者串联匹配电阻位置方便硬件改版前先用调试手段补偿。5.4 车载以太网100BASE-T1和普通百兆以太网别混为一谈现在车载以太网非常热很多STM32和嵌入式工程师也开始接触。但车载以太网里的100BASE-T1和你日常用的100BASE-TX虽然都叫百兆物理层完全不是一回事。100BASE-T1只用一对差分线就能实现全双工通信数据收发在同一对线上通过回波抵消技术分离而100BASE-TX需要两对差分线一发一收。这意味着你不能把普通RJ45 PHY的变压器方案直接套到车载以太网上也不能用普通网线去连T1接口的PHY否则物理层根本起不来。另外100BASE-T1的自动协商机制也特殊它需要配置成Master/Slave角色这类似传统以太网在千兆下的Master/Slave同步机制。在SGMII IP核接车载PHY芯片时同样要确认IP核工作在MAC模式否则SGMII管理帧对不上链路也起不来。如果你现在是做车载以太网测试用例很大一部分工作就是测PHY的Master/Slave状态、误码率、线束开路短路场景下的表现。这些用例都依赖对PHY寄存器层的控制能力所以MDIO读写熟练度依然是基本功。5.5 Linux下网络不通时我常用的排查命令在Linux板卡上调试以太网除了看硬件常用命令也得顺手。快速查看MAC地址、链路状态、驱动名称用ethtool。如果需要隔离MAC层问题可以用ethtool开启PHY回环或者MAC回环测试比如常见的有ethtool eth0 # 查看链路、速率、双工 ethtool -P eth0 # 查看网卡永久MAC地址 ethtool -S eth0 # 查看网卡统计重点是rx_crc_errors、tx_dropped ethtool --test eth0 offline # 网卡自测部分驱动支持MAC/PHY环回 ip link set eth0 up ip addr add 192.168.1.10/24 dev eth0还要提醒一句查“MAC地址怎么查”的时候很多人会直接去看主板贴纸但在Linux下真正影响通信的是设备驱动加载的MAC地址。如果驱动读到的MAC全是0有些网卡会自动生成一个随机MAC有些则直接不工作。用ethtool -P显示的是硬件永久MAC和当前生效MAC可能不一样排查路由问题时以ip link输出的MAC为准。最开始我调以太网也经常一头雾水后来养成了一个固定的“三板斧”习惯先读PHY基础状态寄存器确认物理链路再开PHY回环验证MAC到PHY通路最后才用抓包工具分析协议层问题。这套思路帮我省了大量时间也避免了无数次改板到底是不是硬件问题的争论。如果你也在被MAC和PHY的问题折磨不妨先把这套流程跑一遍大概率能快速定位问题所在。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →