多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

MAC与PHY接口详解:MII/RMII/GMII/RGMII选型与调试

MAC与PHY接口详解:MII/RMII/GMII/RGMII选型与调试 前几天同事拿了一块STM32板子来找我说以太网怎么都ping不通。代码是从以前工程里拷过来的肯定没问题驱动初始化也没报错通过调试串口观察PHY的状态寄存器看起来一切正常。我拿了示波器去点PHY一侧的TXD引脚波形确实在跳说明MAC已经把数据通过接口送出来了。折腾了大半天最后一查问题出在接口上MAC配置成了MII模式而板子上PHY实际走的是RMII两边数据位宽和时钟都不一样等于一个讲普通话一个讲粤语看着都在发声实际谁也听不懂谁。这种问题在嵌入式以太网开发里太典型了。无论是画板子、移植驱动还是从头调试一个网络接口如果对MAC、PHY以及它们之间的MII/RMII/GMII/RGMII这几类接口没有一个整体认识你就很容易在“看起来正常”的地方浪费大量时间。这篇文章是“以太网详解”系列的第一篇先把最基本的概念讲清楚MAC和PHY各自承担什么职责MII家族这几类接口是怎么演变过来的它们的引脚、时钟、带宽有什么差异以及做硬件选型和调试时要注意哪些坑。对嵌入式工程师、FPGA开发者、刚接触以太网的在校学生这篇都适用。1. 先从一次ping不通开始MAC与PHY的分工与配合1.1 网络数据从CPU到网口的旅程以太网的数据通路从芯片内部看大致是这样CPU负责运行协议栈把要发送的数据交给MAC。MAC把数据封装成以太网帧加上前导码、帧起始定界符、源/目的MAC地址、长度类型字段以及尾部CRC校验。封装完之后MAC并不直接去驱动网线而是把帧数据一位一位地通过并行总线送到PHY。PHY再把数据做编码、串行化、电平转换和信号驱动最终通过网口变压器和RJ45发送到线缆上。接收方向刚好反过来。PHY从网线拿到很微弱的模拟信号先恢复出时钟和数据做解码、去抖动、串并转换然后把并行数据交给MAC。MAC负责检查帧的合法性——目的地址是否匹配、CRC是否正确、长度是否合法——过滤之后才把数据交给协议栈。这个流程里MAC是纯数字逻辑PHY则是数字加模拟的混合电路。很多人有个误解以为PHY只要“把信号放大”就行了实际完全不是这样。PHY内部有PLL做时钟恢复有编码器做物理层编码百兆的4B/5B、千兆的8B/10B有自适应均衡来处理长线缆带来的信号衰减还有自动协商逻辑去和对端设备交换速率与双工能力。打个比方MAC负责把信封装好、贴好地址、写好编号PHY是快递员负责把包裹变成适合在路上运输的形式并且确保能安全送达。两者缺一不可。1.2 集成网卡与外置PHY的两种常见组合既然MAC和PHY工作性质差异这么大实际芯片里就很少把它们硬凑在一起。数字逻辑和模拟电路在半导体工艺上的诉求截然不同——数字电路喜欢用更先进的制程来降低功耗和面积而PHY里的模拟前端需要在成本、稳定性、ESD防护之间做平衡反而愿意用稍微成熟一点的工艺。如果强行把两个模块做进同一颗die工艺选择上就得互相迁就成本不一定降得下来。所以你会看到绝大多数嵌入式方案都是“MAC集成在主机里PHY外挂”。常见组合有这么几类。第一类是MCU内置MAC外部接一颗PHY芯片典型代表就是STM32F407/F429/H743这类带以太网外设的型号外部PHY一般配LAN8720A、KSZ8081、IP101GR这些百兆芯片或者RTL8211F、KSZ9031等千兆芯片。第二类是FPGA里用逻辑实现MAC或调用厂商的软核MAC IPXilinx的TEMAC、Altera的TSE等外部再接PHY。第三类是SoC直接把MAC和PHY都集成进去比如一些USB网卡芯片但这种方案扩展性差真正做产品时很少这么干。顺带说一句这里说的MAC是Media Access Control介质访问控制子层和苹果的Mac电脑只是缩写撞车没有任何关系。你搜索“MAC PHY”相关内容时偶尔会混进来一堆苹果电脑的结果别被带偏就行。1.3 为什么说MII接口是MAC和PHY之间的“通信主干道”MAC和PHY之间的数据交换靠的是一组并行信号线这组信号线统称MII——Media Independent Interface。为什么叫“Media Independent”因为它把MAC和具体的物理介质隔离开了。PHY决定你用的是双绞线、光纤还是车载差分线MAC完全不需要关心这些它只按MII接口的协议把数据交给PHY。这样一来同一颗MAC可以接不同介质的PHY硬件上只需要换PHY和对应的变压器即可软件改动很小。MII接口的带宽由两个因素决定位宽和时钟频率。用工程上的类比位宽就是车道数时钟频率就是限速两者乘起来才是单位时间能通过的车流量。正因如此从100M到1000M的演进过程中先后出现了MII、RMII、GMII、RGMII四种接口本质都是在“带宽需求”和“引脚数量”这两个约束之间找平衡。下面把这四兄弟挨个讲透。2. MII、RMII、GMII、RGMII四种接口的带宽与引脚取舍2.1 MII100Mbps时代的经典标准IEEE 802.3u在定义100Base-TX的同时也把MII接口定了下来。这是最早被广泛使用的MAC与PHY之间的并行接口直到今天很多老款芯片上仍然能看到它。MII的信号大致分几组。发送方向TXD[3:0]是4位数据线TX_EN是发送使能TX_ER是发送错误指示TX_CLK是发送时钟由PHY提供。接收方向RXD[3:0]、RX_DV接收数据有效、RX_ER接收错误、RX_CLK同样是PHY提供时钟。另外还有CRS/COL用来指示载波监听和冲突再就是MDC/MDIO管理接口。整套信号加起来16根左右。MII的时钟分两种速率工作在100Mbps时TX_CLK和RX_CLK都是25MHz4位数据乘以25MHz正好是100Mbps工作在10Mbps时时钟降到2.5MHz。这个“4位加25MHz”的设计在当时很合理并行接口实现简单时序关系直来直去PCB等长要求也不苛刻。但MII的缺点同样明显16根信号线太占地方。MCU封装本来引脚就紧张接完以太网之后LCD、Flash、传感器都没地方接了。而且发送时钟TX_CLK是由PHY回送给MAC的两边时钟同步完全靠PHY输出如果PHY工作异常MAC这边连基本的时钟都拿不到排查起来比较被动。所以后来才催生了RMII。2.2 RMII用位宽减半换引脚数骤减RMII全称Reduced MII出现的原因很简单引脚不够用。RMII把数据位宽从4位缩到2位同时定了一个强制约束不管速率是100M还是10M参考时钟一律用50MHz。这样在100M速率下2位数据乘以50MHz正好等于100Mbps。10Mbps时时钟不变MAC和PHY通过拉长数据有效时间的周期来区分速率并不改变参考时钟频率。RMII的信号因此精简了很多TXD[1:0]、RXD[1:0]、TX_EN、CRS_DV、REF_CLK再加上MDC/MDIO总共10根左右比MII少了三分之一以上。在STM32这类MCU平台上RMII几乎是默认选择你会发现网上大量开发板原理图都是STM32加LAN8720A的RMII组合原因就是省引脚、布线简单。代价也有两个。第一REF_CLK必须来自同一个时钟源同时供给MAC和PHY不能像MII那样让PHY自己出时钟发送给MAC。如果两边各用各的时钟哪怕都是50MHz频率的微小偏差和相位漂移也会让采样点不稳定。第二CRS_DV信号把原来的CRS和RX_DV合并到了一根线上MAC要靠检测这根线上电平和时序来区分载波状态和接收有效状态协议上比MII复杂一点。这些问题在后面第3章还会展开讲。2.3 GMII千兆位宽接口的标准答案千兆以太网标准IEEE 802.3z以及后来的802.3ab推出时沿用了MII的设计思路把数据位宽从4位直接加到8位于是有了GMII。GMII的发送数据线TXD[7:0]和接收数据线RXD[7:0]各有8根1000M速率下GTX_CLK为125MHz8位乘以125MHz正好等于1000Mbps。兼容100M和10M时时钟分别回落到25MHz和2.5MHz。这里要注意GTX_CLK和TX_CLK的区别。千兆速率下GMII使用GTX_CLK作为发送时钟由MAC提供而在100M/10M速率下GMII转而使用TX_CLK作为发送时钟由PHY提供。不同速率下时钟方向还会变化这也是GMII在实际使用中一个容易忽略的点。GMII引脚全部算下来24根左右但好处是时序非常宽松对PCB设计要求不高。所以FPGA开发板、交换芯片、路由器主控这些引脚充裕、重视稳定性的场合GMII依然很常见。FPGA里的三速以太网MAC IP核很多默认就是GMII接口直接外接PHY芯片调试最省心。GMII的问题就是引脚太多。尤其在高速板卡上24根并行线要同时保证等长、抑制串扰这是一件很考验layout功底的事。而且数据线在125MHz下翻转过冲、振铃、串扰的问题都会冒出来。于是就有了RGMII。2.4 RGMIIDDR双边沿采样4根线跑千兆RGMII的思路和RMII类似把并行数据线减半但用更高的时钟效率弥补位宽损失。GMII的8位数据在RGMII里变成4位时钟仍然是125MHz但RGMII利用时钟的上升沿和下降沿各采一次数据等效于把125MHz用出了250MHz的效果。4位乘以125MHz乘以2刚好等于1000Mbps。带宽一点没少数据线却少了一半。RGMII的信号包括TXD[3:0]发送数据、TX_CTL发送控制是把原来的TX_EN和TX_ER打包在一根线上、TXC发送时钟由MAC提供、RXD[3:0]接收数据、RX_CTL、RXC接收时钟由PHY提供再加上MDC/MDIO总共有12根左右。在千兆场景下引脚数比GMII少了接近一半因此极受嵌入式MPU、交换芯片和FPGA设计欢迎。核心代价是时序。RGMII规定数据与时钟之间要有约2ns的偏置数据信号要相对时钟沿提前或滞后一个固定量接收端才能在采样窗口里稳定地同时采到数据和控制信号。这个2ns延迟可以在PHY内部实现可以在MAC内部实现也可以靠PCB走线绕出来。麻烦就麻烦在“到底谁来实现”没有统一标准不同PHY芯片的做法也不太一样有的用strap引脚配置有的用寄存器配置有的默认开启有的必须手动关掉。后面第3章我会专门讲这个坑。把四种接口放在一起对比差异一目了然接口数据位宽1000M时钟100M时钟10M时钟估算信号数典型应用场景MII4bit不支持25MHz2.5MHz约16百兆MCU、老产品兼容RMII2bit不支持50MHz参考50MHz参考约10STM32、引脚受限MCUGMII8bit125MHz25MHz2.5MHz约24FPGA、交换芯片RGMII4bit(DDR)125MHz25MHz2.5MHz约12千兆嵌入式、交换芯片3. 实际项目选型时怎么把这些接口用起来3.1 从引脚预算和PCB约束反推接口选择选接口第一件事是看主控的以太网MAC支持哪些接口。STM32F4/F7/H7系列内置MAC一般支持MII和RMIIi.MX、瑞萨RZ系列、全志、瑞芯微这些偏向Linux应用的SoCMAC通常支持RGMII和RMIIFPGA里的软核MAC则灵活很多GMII、RGMII、SGMII都能配。先看主控支持情况再谈其他。第二件事是看速率需求和可用引脚。只做百兆又没有引脚压力MII反而最稳妥时序宽松、兼容性好。如果引脚紧张直接选RMII这是STM32上的主流玩法。做千兆基本就是RGMII除非你的FPGA有充足引脚余量且追求更高可靠性才考虑GMII。交换芯片之间还有一种SGMII串行接口那是后面系列文章要讲的内容这里先不展开。第三件事是看PHY芯片的市场成熟度。百兆RMII方案我会优先考虑LAN8720A、KSZ8081、IP101GR这几个型号资料多、参考设计多出问题也好搜。千兆RGMII方案里RTL8211F、88E1512、KSZ9031这三颗用得最多寄存器映射各有差异但基本套路一样。这几年国产PHY也起来了百兆的裕太微YT8512、景略JL1101等型号做得挺成熟寄存器兼容性也不错在成本敏感的批量产品里很常见。不过国产PHY的数据手册有些细节写得不全选型时要多花点时间对着勘误表核对。3.2 RMII的50MHz参考时钟这里最容易翻车RMII看起来比MII简单但实际项目里翻车率最高的反而就是RMII十次有八次出在REF_CLK这个50MHz时钟上。RMII的REF_CLK必须保证MAC和PHY用的是同一个时钟源。原因前面已经提过RMII没有独立的RX_CLK/TX_CLKMAC只能靠自己的REF_CLK去采样PHY送来的RXD[1:0]和CRS_DV。如果MAC和PHY各自用不同的晶振或PLL就算频率都是50MHz相位差和频率漂移也会让采样点不稳定。轻则偶发丢包重则完全不通。具体实现上有三种常见做法。第一种外部有源晶振直接给MAC和PHY各送一个50MHz时钟前提是扇出足够、走线尽量等长。第二种PHY内部带时钟输出像LAN8720A的CLKOUT引脚可以直接输出50MHz给MAC用这样两边天然同源最省事。第三种MAC提供50MHz给PHY比如用STM32的MCO引脚输出50MHz但要注意MCO分频配置不能错很多人在这一步写错参数导致PHY根本没收到时钟。还有一个常见误区有人想用PHY的25MHz晶振再倍频到50MHz给两边的逻辑使用。实际不建议这么干。晶振加内部PLL的相位噪声和抖动控制不一定好而且MAC和PHY各自倍频出来的时钟相位关系完全不可控。老老实实用外部50MHz有源晶振或者用PHY的CLKOUT比什么都稳。调试的时候用示波器量一下REF_CLK引脚确认频率和波形幅度正常这一步能排除掉很多诡异问题。3.3 RGMII里的delay、等长和电平匹配RGMII的坑集中在那个2ns偏置上。按规范发送方向的数据和控制信号要相对TXC有约2ns的延迟接收端才能在一个稳定的窗口里采样。问题在于这个偏置到底由谁来做业界并没有统一规定。拿常见的几颗PHY举例。RTL8211F的TXDLY/RXDLY是strap引脚上电时电平决定内部是否加入延迟KSZ9031用寄存器配置上电默认值也可以改88E1512通过特定引脚组合设置延迟。而很多MAC侧比如FPGA的RGMII IP核默认输出的数据是对齐时钟沿的需要在外部逻辑里加延迟或者依赖PHY端加。所以设计阶段就要先查清楚MAC端是否已经加了延迟PHY端是否默认加了延迟。两边都加数据的有效窗口反而偏到外面去了两边都不加根本采不到正确数据。这个“双边都加等于不加”的陷阱我在实际项目中见过的次数不止一次。PCB层面RGMII的TXD[3:0]/TX_CTL与TXC之间RXD[3:0]/RX_CTL与RXC之间都要做等长控制。我一般要求长度偏差控制在几百密尔以内并且尽量走在同一层、少打过孔。还要注意的事等长不只是长度匹配走线拐角、过孔带来的延迟差异同样需要考虑。如果实在绕不出空间宁可信号走短一点也不要硬绕长线过长的走线反而引入更多串扰。还有一个容易被忽略的点是电平匹配。RGMII的电平标准有3.3V、2.5V、1.8V三种PHY的IO电源和MAC的IO电源必须一致。有的PHY支持1.8V VDDIO但主控MAC是3.3V这时就得加电平转换芯片而不是想当然地直接连。电压域不匹配的板子短时间测试可能没问题长时间跑或者温度一高随机不通、误码率升高的问题就会冒出来。画原理图时把这个核对清楚能省去后面一大半麻烦。4. 调试以太网链路先学会读这几个关键信号4.1 strap引脚一上电就决定了PHY的地址和接口模式PHY芯片和普通数字芯片不太一样很多关键配置不是在软件里写的而是上电瞬间靠strap引脚的电平“锁存”下来的。所谓strap引脚就是在芯片复位释放时被采样的引脚。常用到的有PHYAD[4:0]决定MDIO地址MODE或速率选择引脚决定接口模式RMII/MII/RGMIIANEG决定是否启用自动协商还有LED配置、延迟配置等。这个“上电即定”的特性要求硬件设计必须提前规划。比如LAN8720A如果PHYAD0引脚被拉低默认地址是0x00KSZ8081可能有多个地址选项RTL8211F默认地址0x00但如果板子上把它拉高了地址就会变成别的值。所以不要想当然地认为PHY地址一定是0x00一定要对着原理图去确认。如果你在软件里怎么都读不到PHY ID我建议先写一个MDIO扫描函数把0x00到0x1F这32个地址全部读一遍看看每个地址读回的值是什么。在MDIO总线上只有一颗PHY的情况下通常只有一个地址能读出有效的PHY ID其他地址读到的是0xFFFF或0x0000。扫描结果能同时告诉你两件事MDIO读写时序是否正常、PHY实际地址是多少。这是排查PHY初始化问题最有效的一招。strap引脚还有一个隐性影响它决定了PHY的工作模式。如果板子上把MODE引脚拉成了MII模式但MAC配置的是RMII数据宽度和时钟都不一样MAC可能完全收不到PHY送来的数据而PHY自己却觉得一切正常。这种“各自安好”的状态最难排查因为你读PHY的寄存器会发现link已经建立了就是数据不通。所以硬件上电之前一定要把strap配置和MAC配置逐项核对一遍。4.2 MDIO管理接口调试时最有用的那扇“后门”MDIO是PHY的管理通道两根线MDC管理时钟和MDIO数据线。规范里MDC最高频率是2.5MHz实际应用中很多MCU默认配置会超过这个值导致读写不稳定。如果你发现PHY寄存器读写一会儿正常一会儿超时第一步就是把MDC频率降下来再试。通过MDIO能读写的寄存器集中在基本寄存器组里。地址0x00是BMCR基本控制寄存器可以触发软复位、配置自协商、开启回环0x01是BMSR基本状态寄存器bit2是Link Status0x02和0x03是PHY ID寄存器出厂就固化0x04是自协商公告寄存器0x05是自协商对端能力寄存器。调试时我按这个顺序来先读PHY ID确认通信正常再读Link Status确认链路建立再读自协商结果确认速度和双工协商一致。这里有一个特别容易误导人的经验点很多PHY的Link Status位是带闩锁的。它只在链路状态发生变化时更新并把状态锁存住直到你读一次才清除旧值。所以第一次读BMSR时读到的是上一次变化后的状态第二次读才是当前实时状态。如果第一次读发现bit2是0别急着下“没link”的结论再读一次看看。这个细节很多参考代码里都没有体现但实际调试中非常关键。如果手头有逻辑分析仪可以把MDIO波形抓出来看。MDIO的帧格式是前导码加帧头加操作码加PHY地址加寄存器地址加数据用逻辑分析仪解码非常直观。抓一次波形你就能立刻确认代码到底有没有真的在往总线上发数据还是卡在某个等待循环里根本没动作。4.3 回环测试快速定位数据通路卡在哪一段回环测试是排查以太网物理层问题最实用的一招。所谓回环就是让数据不经过外部链路直接从发送通路绕回接收通路。以太网PHY普遍支持内部回环模式把BMCR寄存器里的Loopback位置1即可开启。开启之后从MAC发出的数据会被PHY直接收回来不经网线也不经对端设备。建议的排查顺序是这样的。第一步先开PHY内部回环从MAC侧发数据、看能否收到。如果能收到说明MAC到PHY的发送通路、PHY到MAC的接收通路、连同MII/RGMII接口的采样基本正常问题大概率出在网线、变压器、连接器或者自协商配置上。第二步如果PHY回环收不到再去配置MAC内部回环。STM32的ETH外设支持MAC回环FPGA的MAC IP也有对应选项。如果MAC回环能收到问题就收窄到PHY的初始化和接口时序。第三步拿示波器去量PHY的TXD引脚看数据线上有没有波形、时钟频率对不对。如果TXD有波形但PHY回环收不到基本就是PHY内部回路没有配好或者strap引脚把PHY弄到了错误模式。回环测试的价值在于把一条复杂链路逐级切开。很多开发者一遇到ping不通就想着去调协议栈、查ARP、检查IP地址其实协议栈出问题的概率极低。真正的问题九成都在PHY配置、接口模式或硬件链路上。先做回环测试再谈别的能省下大半天时间。我之前遇到过一个案例板子PHY回环一切正常连上交换机也能link但收发丢包严重。最后去看PHY的CRC错误计数和MAC侧的rx_error统计发现一直在涨这才确认是信号完整性问题根源是PCB上RGMII等长没做好。这类问题光看代码是永远看不出来的。写到这里MAC/PHY/MII/RMII/GMII/RGMII这几个概念就算讲完了一遍。我自己画过不少带以太网的板子最大的体会是以太网本身的协议栈并不难真正的坑全在硬件接口和PHY配置上。画原理图之前先把strap引脚、参考时钟、接口模式这三个问题定清楚能替你后面省掉一半的调试时间。尤其RMII的50MHz时钟来源和RGMII的延迟配置这两个点我几乎每次评审新板子都要重点看。这篇文章是系列的第一篇后面我打算继续写SGMII、车载以太网比如100BASE-T1和PHY寄存器级的配置实战这些内容在实际项目里一样避不开。如果你在调试过程中遇到过什么诡异的链路问题不妨对照着回环测试的思路自己过一遍大多数情况下都能快速定位到具体环节。
返回列表