ARTICLE DETAIL

资讯详情

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

Zynq EMIO转RGMII接PHY:从GMII信号引出的完整调试指南

Zynq EMIO转RGMII接PHY:从GMII信号引出的完整调试指南 做Zynq-7000板卡的人估计都遇到过这种情况PS自带千兆以太网MAC功能很强但要把网口真正点亮总绕不开接口电平、引脚分配、PHY芯片选型这一堆事情。MIO引脚虽然是现成的RGMII通道但它固定在PS侧、电平受BANK供电限制一旦被SD卡、QSPI、调试串口占满就只能另想办法。这篇文章记录的是我最近一次用PS端EMIO把GMII信号引到PL侧再转换成RGMII去接外部PHY的完整调试过程包含了Vivado 2023.1的配置步骤、时序约束写法和几处容易掉进去的坑。如果你正在做网络通信板卡、图像采集系统或者工控主板而且遇到了MIO引脚不够、PHY电平不匹配、或者想更自由地在PL侧走线的情况这篇笔记可以直接按步骤抄。1. 为什么选EMIO接RGMIIZynq网络方案的思路对比1.1 Zynq PS以太网的三条通路Zynq-7000的PS端内置了两个GEMGigabit Ethernet MAC控制器MAC层已经在硅片上做好了不需要自己用PL逻辑去拼一个MAC核。但MAC只是数据链路层它对外输出什么接口、通过哪些引脚出来是需要配置的。粗略分一下常用的做法有三种MIO直连RGMII把GEM的RGMII接口直接映射到PS的MIO引脚上外部PHY直接挂到MIO Bank。这个方案配置最简单但有两个硬性条件MIO Bank的供电必须做在1.8V而且MIO引脚的位置是芯片手册固定的PCB布局没有什么发挥空间。MIO直连MII同样是走MIO但把接口模式改成MII数据线变成8位并行加控制信号引脚变化不大。问题是现在MII接口的PHY芯片已经很不好找了大部分千兆PHY都是RGMII/SGMII所以这个方案在成熟项目里用得越来越少。EMIO引出GMII再转RGMII把GEM的数据接口配置成GMII通过EMIO把信号送到PL端再由PL侧的IO按RGMII的物理规则发出去。这是本文要详细展开的方案。要注意的是在Zynq-7000上GEM的MDIO管理接口通常仍然分配在MIO引脚上真正通过EMIO走到PL端的是GMII数据总线、发送时钟和接收时钟这一组信号。所以就算数据路径选了EMIOMIO也不会完全空闲规划引脚时别把MDIO也算进可自由挪用的范围内具体引脚编号以芯片手册为准。1.2 什么场景下绕不过EMIO我用EMIO根本原因是板子上的PHY芯片工作在3.3V电平而MIO网络接口需要1.8V的BANK电压。强行给MIO Bank供1.8V当然可以但那个BANK上还挂了别的3.3V外设电平冲突就无解了。这种时候把数据路径转移到PL侧用PL的Bank去匹配PHY的电平是最顺理成章的思路。除了电平不匹配下面几种情况也大概率要走EMIOMIO资源被其他高速外设占满了。QSPI Flash、SD卡、CAN、UART、USB的外设引脚经常把MIO挤得只剩零头MAC又不想放弃网口那就只能牺牲一部分PL IO来换网络功能。PHY位置的PCB布线需求。MIO引脚位置固定如果PHY和RJ45必须放在PCB的某个位置MIO走线绕得太长信号质量和时序都会受影响。EMIO方案里PL引脚是可以自己指定的绕线可控得多。想做接口电平转换或者加信号调理。PL侧的IO标准、驱动强度、上下拉都可配置调试期改起来比改MIO Bank方便。现在市面上大量Zynq开发板和工控主板网口部分用的其实就是这个套路PS的GEM配成GMII/EMIOPL侧例化gmii_to_rgmii再接一颗RTL8211或KSZ9031之类的PHY。这个方案能被这么多厂商采用说明它的稳定性和可复制性已经被反复验证过了。1.3 整条链路里各环节的分工明确一下这次项目的完整数据链路PS GEM通过EMIO输出GMII信号信号到达PL侧后由GMII-to-RGMII转换逻辑把8位并行GMII变成4位DDR RGMIIRGMII信号再经过PL引脚送到外部PHY芯片PHY完成物理层编码和线路驱动最后通过网络变压器接到RJ45。在这个链路里GEM负责MAC层的数据收发GMII信号通过EMIO桥接到PL侧的普通IO上。PL侧的转换逻辑负责处理ODDR、IDDR、发送时钟生成和接收延迟调整这一步通常直接使用Xilinx官方的gmii_to_rgmii IP。PHY负责物理层编码、串并转换和线路驱动常见选择有Realtek RTL8211系列、Microchip KSZ9031系列、Marvell 88E1512等。弄清楚这条链路后后面的所有配置和调试就有了主线PS端配置要让GEM输出GMIIPL端要让gmii_to_rgmii转换核正常工作引脚约束要保证RGMII信号落在正确的PL引脚上时序约束要保证转换核和PHY之间的数据窗口足够宽。文章后面章节的每一步都是围绕这条主线展开的。2. RGMII接口的时序本质先弄懂窗口再动手2.1 DDR双沿复用一个时钟传两位RGMII为什么叫Reduced GMII因为它把GMII的8位数据线砍成了4位靠125MHz时钟的上升沿和下降沿各采一次等效回8位并行带宽还是1Gbps。除了数据线控制信号TX_CTL/RX_CTL也做了同样的DDR处理上升沿传TX_EN下降沿传TX_ER。来算一笔账RGMII时钟125MHz周期8nsDDR模式下每根数据线的有效数据率是250Mbps。4根数据线加起来就是1000Mbps正好是千兆以太网的真实单向吞吐双向加起来是2Gbps。也就是说一帧数据要从MAC到PHY必须在一个8ns时钟周期内完成两拍数据切换。这个速率放今天看算不上极限但因为数据是双沿采样的每个沿只有4ns窗口扣除各种skew之后实际能用的稳定窗口会更窄。对比一下常见接口就明白了接口时钟频率数据位宽单向带宽数据-时钟关系MII25MHz4bit100Mbps源同步单沿采样GMII125MHz8bit1000Mbps源同步单沿采样RGMII125MHz4bit1000Mbps源同步DDR双沿采样DDR双沿采样意味着同样是125MHz的时钟RGMII对setup/hold窗口的敏感程度比GMII高一倍。这也是为什么RGMII接口即使只跑到1Gbps布线约束和时序约束仍然要认真对待。2.2 RGMII 1.0与2.0延迟到底谁来做RGMII接口规范有1.0和2.0两个主要版本它们对数据与时钟相对延迟的要求不同这也是很多调试问题产生的根源。RGMII 1.0发送端输出的数据边沿和时钟边沿是对齐的接收端需要自己把数据延后大约1.5~2ns让数据落在时钟沿附近完成稳定采样。也就是说时序补偿的压力在接收端。RGMII 2.0发送端直接输出中心对齐的数据数据跳变沿和时钟跳变沿错开约2ns接收端不需要做额外延迟或者只需要很小范围的调整。这套规范放在FPGA和PHY之间会出现两种组合。如果PHY是1.0规范的收发两个方向都需要做延迟补偿FPGA接收方向用IDELAY把输入数据延迟约2nsFPGA发送方向用ODDR或内部逻辑把输出数据相对时钟移动约2ns。如果PHY是2.0规范的链路初始化后PHY内部已经完成了发送方向的延迟调整FPGA这边通常只需要在接收方向做较小的IDELAY校准。实际项目里不能完全相信PHY数据手册上写的是哪个版本因为很多PHY的RGMII模式通过strap引脚选择不同延迟模式甚至同一颗PHY在不同配置下表现完全不同。调试的时候第一步永远是确认PHY是不是工作在2.0延迟模式再决定FPGA侧要不要做额外的延迟调整。我试过不少板子最后都是通过MDIO寄存器把PHY内部delay打开后FPGA这边的IDELAY只需要微调就能跑通。2.3 为什么差一点就通不了RGMII的采样窗口往宽了算也就4ns左右。这个窗口里要容纳时钟skew、PCB走线skew、IO Buffer的传输延迟、温度电压漂移如果PL侧的IDELAY或者PHY的internal delay没设置对实际有效窗口可能连1ns都不剩。用一个不太严谨但很好理解的类比你每天8点15分要赶上地铁但你的表快了2分钟、路上有两个红绿灯、进站口排队还要1分钟任何一个环节稍微波动你就卡在闸机外面。RGMII也是一样125MHz时钟、双沿采样所有延迟误差都会叠加到那个4ns窗口上。时序收敛的本质就是把所有误差的来源逐一控制住让数据稳定落在时钟沿附近。这也是为什么RGMII调试时Vivado的时序报告里动不动出现几百ps的slack不足告警。不是你的逻辑写错了而是边界约束没有把实际延迟关系描述清楚或者IDELAY值偏离了最佳采样点。3. Vivado 2023.1实操PS配置到gmii_to_rgmii核连接3.1 Block Design的最小连接拓扑我这边用的版本是Vivado 2023.1器件是XC7Z020CLG400-1速度等级-1。步骤从新建工程开始工程类型选RTL Project其他保持默认。第一步在IP Catalog里找到ZYNQ7 Processing System添加到Block Design。双击打开配置界面在Peripheral Configuration - I/O Peripherals - Ethernet 0下面勾选Enable接口模式选择GMII。这里不同版本的界面文字略有差异有些版本显示GMII有些直接显示EMIO本质上是同一件事把GEM的GMII数据信号通过EMIO桥接到PL侧。配置完成后Block Design里会自动出现一个ps_ethernet_0接口里面包含txd[7:0]、tx_en、tx_er、tx_clk、rxd[7:0]、rx_dv、rx_er、rx_clk这一组GMII信号。如果MDIO接口没有出现在PL侧说明它仍然绑定在MIO上这是正常现象不必额外处理。第二步添加GMII-to-RGMII转换IP。在IP Catalog里搜索gmii_to_rgmii这个IP是Xilinx官方提供的PL侧接口转换IP。它的左边是GMII接口右边是RGMII接口内部集成了ODDR、IDDR、IDELAYCTRL等原语还提供了可选的AXI4-Lite寄存器接口用于动态调整接收延迟。把两个IP放进Block Design后将PS的GMII接口和gmii_to_rgmii的GMII侧连接起来连线时注意信号名一一对应。第三步处理时钟。gmii_to_rgmii IP需要125MHz时钟输入我习惯把PS的FCLK_CLK0在Zynq配置里设成125MHz同时把这个时钟接到gmii_to_rgmii IP的时钟端口上省去额外管理时钟域的问题。另外PS的GEM本身需要参考时钟输入这个参考时钟的来源也要在PS配置里确认。没有这个参考时钟GEM不会正常工作而你在Block Design里看不到任何报错只有上板以后发现PHY的MDIO寄存器完全读不到才知道是这里出了问题。3.2 引脚约束与电平标准gmii_to_rgmii IP的RGMII侧信号要引出到顶层所以Block Design里的这个IP需要Make External每个RGMII端口会变成顶层端口。之后在XDC约束文件里给它们分配物理引脚。示例约束写法如下set_property PACKAGE_PIN T22 [get_ports {rgmii_txd[0]}] set_property PACKAGE_PIN T21 [get_ports {rgmii_txd[1]}] set_property PACKAGE_PIN U22 [get_ports {rgmii_txd[2]}] set_property PACKAGE_PIN U21 [get_ports {rgmii_txd[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {rgmii_txd[*]}]上面只是示例实际引脚编号要以板卡原理图为准。注意IOSTANDARD不是固定用LVCMOS33要看这个引脚所在的BANK电压。如果引脚落在HR Bank且BANK供电3.3V就用LVCMOS33如果是1.8V的HP Bank就用LVCMOS18。电平不匹配的后果是PHY端信号摆幅不够表现为Link能建立但误码率极高或者干脆收不到数据。RGMII的两个时钟也需要给引脚约束rgmii_txc是FPGA输出给PHY的发送时钟rgmii_rxc是PHY输出给FPGA的接收时钟。这两个时钟在后续时序约束里要区别对待一个是真实输入时钟一个是输出时钟加虚拟时钟的约束方式。3.3 第一次跑综合和实现别被一堆warning吓住连好Block Design、生成HDL Wrapper、把RGMII端口约束到物理引脚之后就可以跑综合和实现了。第一次跑通常不会直接失败但会看到大量warning主要集中在以下几类未约束的IO端口。Vivado会提示某些输入或输出端口没有时序约束这正是RGMII没加IO delay约束的表现。未连接的MDIO。如果你的PHY的MDIO走的是MIOPL侧没有对应端口。时钟组交叉警告。gmii_to_rgmii IP内部有多个时钟域跨时钟路径在没有约束时会被工具标记。如果你用的是gmii_to_rgmii IP综合后打开Schematic能看到IP内部已经把ODDR、IDDR、IDELAYCTRL实例化好了RGMII输出侧的那一排寄存器和延迟单元就是时序收敛的关键所在。第一次实现的时序报告里大概率会有RGMII路径的违例这在预期之内下一步就是写约束、调延迟。4. 时序收敛实战约束写法、IDELAY校准与DRC排雷4.1 输入输出延迟约束的具体写法RGMII是源同步接口Vivado不会自动知道这个端口的时钟和数据关系必须通过XDC约束告知工具。约束的关键有两个为PHY输出过来的rx时钟创建真实时钟约束为FPGA输出给PHY的tx时钟创建虚拟时钟约束。接收方向PHY到FPGArgmii_rxc是实际存在的输入时钟create_clock -period 8.000 -name rgmii_rxc [get_ports rgmii_rxc] set_input_delay -clock rgmii_rxc -max 0.5 [get_ports {rgmii_rxd[*] rgmii_rx_ctl}] set_input_delay -clock rgmii_rxc -min -0.5 [get_ports {rgmii_rxd[*] rgmii_rx_ctl}] set_input_delay -clock rgmii_rxc -max 0.5 -clock_fall [get_ports {rgmii_rxd[*] rgmii_rx_ctl}] set_input_delay -clock rgmii_rxc -min -0.5 -clock_fall [get_ports {rgmii_rxd[*] rgmii_rx_ctl}]这里的0.5ns只是起步值。如果PHY的数据和时钟完全对齐那么数据相对时钟的输入延迟大约是0加上板级skew正负0.5ns是个安全的初始范围。工程跑起来以后再按实际抓到的波形往中间收敛。发送方向FPGA到PHYrgmii_txc是FPGA用ODDR生成的输出时钟工具里没有一个现成的时钟对象所以要创建一个虚拟时钟create_clock -period 8.000 -name rgmii_txc_virt set_output_delay -clock rgmii_txc_virt -max 2.0 [get_ports {rgmii_txd[*] rgmii_tx_ctl}] set_output_delay -clock rgmii_txc_virt -min 0.5 [get_ports {rgmii_txd[*] rgmii_tx_ctl}]发送方向的输出延迟来源于RGMII规范里要求的“数据相对时钟移动约2ns”。如果PHY是2.0模式的这个值可以适当缩小具体看PHY手册里的internal delay设置。写约束时记住一个原则数值代表的含义是“PHY收到的数据相对于PHY收到的时钟提前或滞后多少纳秒到达”。不要生搬硬套每一颗PHY都有细微差别。还有一点很重要这些约束要写在顶层XDC文件里而不是放在Block Design的约束里。Vivado对IO约束的位置有管理逻辑顶层XDC是最稳妥的位置。4.2 IDELAY是怎么参与进来的很多人第一次看到gmii_to_rgmii IP里有一堆IDELAYE2原语不知道这些延迟单元到底在干什么。简单说IDELAY就是PL IO里面的可编程延迟线每个tap大约78ps参考时钟200MHz时范围从几十到几千皮秒。接收方向的数据从引脚进来以后可以先经过IDELAY延迟一小段再进入IDDR采样。为什么需要这个延迟因为RGMII 1.0的PHY发出来的数据和时钟是对齐的上升沿和下降沿正好落在数据跳变的边界上直接采样会采到不稳定的电平。用IDELAY把数据往后推2ns左右让数据跳变离开时钟沿采样点就能落到数据的稳定区间。gmii_to_rgmii IP提供了一个可选的AXI4-Lite寄存器接口用来动态读改IDELAY的tap值。调试时最常用的操作是从0开始往上加每加一个tap跑一次ping或持续打流同时看RX数据是否正确找到能稳定工作的tap范围。这个范围通常有十几个tap的余量取中间值就是最佳工作点。如果没有AXI接口也可以直接在IP配置界面里把tap值设为常数省事但后期温度电压变化时余量可能不够。发送方向的延迟同理ODDR输出的数据和ODDR生成的时钟要保证在PHY端呈现所需的相位关系。很多设计在发送方向把数据与时钟打在同一拍再依靠PHY的2.0模式延迟去满足采样要求。这也是为什么我前面反复强调先弄清楚PHY的延迟模式因为发送方向的调整手段比接收方向少得多。4.3 时序报告与DRC排查违例的标准顺序Vivado Implementation跑完后如果出现时序违例先不要急着改代码按顺序做下面几步打开Implemented Design运行Report Timing Summary看最差的slack出现在哪条路径上。如果违例路径是RGMII的输入输出路径检查set_input_delay/set_output_delay的数值是否合理。最常见的错误是只写了一个方向的延迟没有写-clock_fall导致DDR另一沿完全没有约束。如果违例路径出现在gmii_to_rgmii IP内部多半是IDELAYCTRL的参考时钟没约束好。检查IDELAYCTRL的REFCLK是不是真的存在频率是不是200MHz附近。生成比特流之前跑Report DRC如果看到类似RTSTAT-2这类和时序路径检查相关的DRC报错基本可以断定是IO约束不完整工具无法评估那条路径的真实时序。这时候返回第2步补齐约束DRC通常就消失了。所谓“实现以后变红”在Vivado里大多数是Implementation策略里的Timing结果不达标或者DRC报告有error把run的log翻到最下面找到第一个error或者critical warning原因一目了然。千万别一上来就改implementation strategy或者关掉某个优化选项那样只会掩盖问题不会解决问题。现象常见根因处理方向时序报告RGMII IO路径slack爆炸缺少input/output delay约束或数值不合理补set_input_delay/set_output_delayDRC RTSTAT类报错接口时钟/边界路径约束不完整创建rgmii_rxc真实时钟和rgmii_txc虚拟时钟RX方向长时间不通PHY延迟模式与IDELAY不匹配先确认PHY strap/MDIO延迟模式再调tapTX方向PHY采样不稳定输出数据与TXC没有中心对齐调ODDR相位或gmii_to_rgmii发送延迟参数5. 上板调试中的常见掉坑点与验证心得5.1 PHY配置脚与复位时序时序收敛再准也没用PL侧转换核调得再好如果PHY没工作对一切都是白搭。PHY芯片本身是靠复位引脚和一组配置脚strap pin来设定工作模式的板子上电时PHY把这些配置脚采样进去决定RGMII模式、时钟延迟模式、PHY地址等。这里面最容易踩的坑是PHY复位时序。很多PHY要求复位信号保持有效电平多数PHY是低有效一段时间至少几十毫秒释放后还需要等待时钟稳定PHY内部才开始采样配置脚。如果复位时间太短或者复位信号和125MHz参考时钟一起上电PHY很可能采到错误的配置表现为Link状态反复、速率协商成100M甚至10M。我的习惯是让PS端GPIO控制PHY复位在FSBL或裸机代码里延时几百毫秒再释放复位确认时钟稳定后再启动驱动。PHY地址也是一个经常被忽略的坑。RTL8211默认PHY地址是0x00或0x04取决于strap引脚的设置。如果在MDIO上读不到PHY寄存器先检查PHY地址对不对别急着怀疑FPGA逻辑。5.2 MDIO回读先确认PHY状态再谈以太网协议上板后第一步不是直接跑lwIP而是用MDIO去读PHY的寄存器确认PHY自己觉得状态正常。常见的几个关键寄存器寄存器0BMCR控制寄存器可以在这里把PHY设为1000M全双工、打开auto-negotiation、设置回环模式。寄存器1BMSR状态寄存器bit5表示链路建立bit6表示auto-negotiation完成。寄存器2PHY ID High、寄存器3PHY ID Low用于确认MDIO总线上挂的确实是目标PHY。从PS的GEM驱动里直接调用读MDIO的接口读不到PHY ID的话先查复位再查PHY地址再查参考时钟。MDIO读通了至少说明MAC、PHY之间的管理通道正常接下来才是数据通道的验证。我还遇到过一种情况MDIO能读到PHY IDBMSR里也显示Link up但ping就是不通。这时候用PHY的寄存器把PHY设置为回环模式在FPGA侧从GMII接口发包看数据能不能从PHY再绕回来。如果回环正常说明PL侧的gmii_to_rgmii和PHY之间的物理层没问题问题出在上层MAC配置或者时钟频率上如果回环也不通问题大概率在RGMII的时序或者PHY配置上。5.3 回环、ping、持续打流一步步缩小范围调试链路时我的顺序永远是从小到大、从底层到上层。第一步做PHY回环通过MDIO把PHY设为内部回环在GMII侧用ILA抓数据确认gmii_to_rgmii IP的接收路径能把回环数据解出来。第二步做PS与PHY之间的联调关掉PHY回环让PS的GEM直接发包给PHYPHY正常发到网线。此时可以在电脑端用Wireshark看有没有报文出来哪怕校验错都行有报文就说明物理通路通了。第三步启用Vitis里的lwIP库配置网卡为千兆模式ping通以后做持续打流测试长时间观察有没有丢包。第四步做温度电压波动测试这一步很多人跳过但工业场合必须做RGMII时序的余量在常温下看起来很充足一到高低温或者电压波动下就露馅。关于ILA抓信号RGMII的RX数据是DDR抓起来有点别扭。比较省事的做法是在gmii_to_rgmii IP的GMII侧抓也就是已经转成单沿的rxd[7:0]和rx_dv这样波形看起来和GMII时序一致定位问题直观得多。直接用ILA去抓RGMII引脚上的DDR信号也可以但要注意ILA时钟用rgmii_rxc还是125MHz抓出来的数据只有半个字节在同一时刻容易看晕。5.4 调试中反复出现的小问题复位同步与时钟质量最后说几个零碎但很影响成败的点。PS端或者PL端的复位信号如果来自按键或者电源监控芯片最好在FPGA里做一次异步复位同步释放处理。这个道理大家都懂但很多人忘了PHY的复位也应该走同样的处理。否则PHY复位释放的瞬间恰好落在125MHz时钟沿附近PHY内部逻辑出现亚稳态表现出来就是偶尔一次上电网口不通多复位几次又好了。时钟质量方面125MHz给gmii_to_rgmii的时钟必须干净不能直接从PS的FCLK_CLK0拉出来就完事FCLK_CLK0往往带一点抖动建议用MMCM或PLL重新生成一个125MHz时钟。信号完整性上RGMII的数据线和时钟线在PCB上要走等长误差尽量控制在500mil以内时钟线优先打孔少、参考层连续。Vivado能把时序调到收敛但PCB上的设计规则上限就那么高两者要配合好。另外建议把IO约束、时钟约束、物理约束分文件放置保持约束文件的模块化。RGMII的约束只是整个工程的一小部分一旦工程复杂度上来模块化约束文件对排查问题会有很大帮助。我个人在反复调了几块板子之后最大的体会是RGMII调试九成的问题不在代码而在接口的“边界条件”——PHY的延迟模式、IDELAY的最佳tap、IO delay约束的准确性。把这三件事固定下来剩下的就是按部就班的验证。每当你觉得某个方向怎么看都没问题时回去检查一下边界条件通常一抓一个准。
返回列表