ARTICLE DETAIL

资讯详情

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

FPGA驱动ZYNQ 7020实现UDP通信:从RGMII到AXI DMA链路搭建

FPGA驱动ZYNQ 7020实现UDP通信:从RGMII到AXI DMA链路搭建 简介ZYNQ 7020以太网UDP通信资源包面向FPGA开发者和嵌入式网络工程师聚焦ZYNQ SoC上UDP通信的FPGA驱动与软硬件协同设计系统梳理了从以太网帧收发包、UDP数据报封装解析到ARM侧协议栈处理的完整链路。压缩包共610个文件、约49.5MB涵盖Verilog/VHDL逻辑源码、XDC管脚约束、DCP综合网表、Tcl/Shell/DO仿真脚本、ARM侧C驱动、示例应用及配置文档其中HDL文件负责UDP引擎与MAC接口逻辑XDC定义时序约束脚本用于工程编译和仿真C驱动处理中断与DMATXT/RST文档说明协议原理目录按IP核、仿真、约束和驱动分层组织。已有996人学习下载。资源对UDP校验和计算、GMII/RGMII接口适配、DMA环形缓冲管理、中断触发以及ARP/IP/UDP协议栈协作等关键技术均提供了可综合的HDL实现和C驱动代码并带有比特流文件与一键编译脚本可结合Vivado工程直接运行直观验证ZYNQ平台上的高速以太网通信也可作为二次开发的底层驱动参考。1. 用FPGA驱动ZYNQ 7020的UDP先搞清楚哪条链路才叫驱动在Zynq 7020上进UDP通信新手最容易掉进坑里配好Linux IP、socket一开、数据发出去了就以为UDP通了。其实这条路全部在PS自带的千兆以太网MACGEM和Linux协议栈里走PL侧的FPGA逻辑根本没参与。标题里说的“FPGA驱动”是指由PL侧的MAC接PHY芯片把以太帧通过AXI DMA搬到DDR再由设备驱动交给系统——网络接口从FPGA里长出来CPU只在控制面干预。这个方案解决两类典型问题PS网口被业务占满时开第二路UDP或者FPGA内部信号直接封装成UDP帧绕开CPU逐层拷贝。高速数据采集、FPGA把ADC数据打包上传的场景尤为常用。适合的读者是调过RGMII时序、能看懂DMA描述符的嵌入式工程师以及准备让自定义总线上送以太网的算法工程师。2. 从RGMII到AXI Stream搭建ZYNQ 7020的UDP物理链路2.1 为什么选RGMII引脚、电平和PHY选型如果从头在PL侧开千兆以太网第一选择就是RGMII。原因很朴素GMII接口的TX/RX各8位数据线加上时钟、控制、MDIO整体超过30根信号Zynq 7020的PL Bank引脚本来就不富裕还要给DDR、LVDS图像接口留位置。RGMII把收发各压到4根数据线时钟和数据都走DDR双沿12根引脚就能完成一个千兆口。SGMII更省引脚但需要走PL的SerDes通道。7020上MGT Bank常常被PCIe、SATA或其它高速串口占用为一个辅助网口让出SerDes资源并不划算。下表是三种PL侧千兆接口的常规对比接口数据线宽度时钟方式引脚消耗7020 PL侧使用场景GMII8位并行125MHz SDR约30根较少Bank资源宽裕且PCB允许大量走线时RGMII4位DDR125MHz DDR约12根AXI Ethernet IP常规选项第二网口首选SGMII串行1.25Gbps SerDes4根MGT Bank空闲时可用但常被PCIe抢走PHY选型跟着接口走88E1512、88E1518、RTL8211系列都支持RGMII到铜缆的转换。选型重点有三个RGMII电平是否匹配PL Bank的VCCOZynq 7020的HR Bank常用2.5V供电MDIO地址引脚是否有硬件拉拔关系到设备树里PHY地址是0x0还是0x10以及PHY的125MHz时钟输出是否要反送回FPGA当作GTX参考时钟这会直接改变XDC里时钟约束的写法。上电后第一步用MDIO读PHY的标识寄存器寄存器2和3确认MDIO连接和PHY地址正确再进时序调试。这一步能省下好几个小时的“网口死活不link”排查时间。2.2 RGMII时序约束与RXC相移用Vivado的AXI Ethernet IP时RGMII引脚约束看着简单把端口名对上就行真正影响收包率的是时钟与数据的相位关系。RGMII 2.0规范中PHY送出的RXC与RXD之间存在最大1纳秒左右的Skew到MAC侧时数据沿已经不在时钟采样窗口中心。常见做法是让FPGA内部对RXC经过IDELAY后再进IDDR采样同时用XDC里的set_input_delay约束数据相对时钟的窗口set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS25} [get_ports rgmii_rxd[0]] create_clock -period 8.000 -name rgmii_rxc_i [get_ports rgmii_rxc] set_input_delay -clock rgmii_rxc_i -max 1.000 [get_ports rgmii_rxd[*]]逻辑说明第一行把引脚绑定到具体封装位置并声明IO电平第二行创建125MHz输入时钟对象8ns周期对应千兆DDR第三行声明RXD相对RXC的最大到达延迟为1ns。实际调试中大多数PHY要求RXD比RXC晚0.5到1ns到达但PCB走线长度会改变这个窗口因此XDC里的具体数值要以PHY数据手册和实际误包率为准。调这个延时时最有效的验证方式是发固定长度帧同时观察MAC侧CRC错误计数。需要注意CRC错误计数上涨不一定表现为丢包而是表现为接收帧被MAC丢弃从用户侧看就是“偶尔少几个UDP包”。PCB布局把同组RGMII信号等长控制在50mil以内能显著降低这类调试成本。2.3 AXI Stream与以太网帧格式的映射AXI Ethernet接收侧的AXI Stream输出是完整以太网帧前导码和SFD已被MAC剥离数据从目的MAC地址开始到TLAST拉高表示帧结束。CRC在默认配置下也被MAC移除不会出现在Stream里。搞清这一点很重要很多从裸PL逻辑接手的人会在DMA缓冲区里看到帧尾多出4字节那不是错误而是TX_INCLUDE_FCS配置被打开了。以太网帧格式对UDP解析的影响体现在三个固定偏移帧头第12、13字节是EtherType0x0800代表IPv40x0806代表ARPIPv4头从偏移14开始标准长度20字节UDP头在IP头之后源端口与目的端口的偏移由此计算。FPGA驱动层面的数据通路本质上就是把RGMII上串行到达的字节按这个布局写入AXI Stream再由DMA搬到内存。如果你在调试中看到PC端能抓到板子发出的ARP却收不到UDP数据回头查这一层的EtherType和IP头长度字段往往比抓协议栈更有价值。3. 在Vivado里搭建AXI Ethernet加AXI DMA的UDP收发链路3.1 带PS还是纯PL先定数据处理归属做UDP通信前需要先回答一个问题要不要把协议栈放进FPGA逻辑。纯PL方案的思路是在PL里用RTL实现MAC、ARP、IP、UDP校验和所有包处理都在硬件里完成带PS方案则让PL只做MAC和数据搬运IP/UDP协议栈交给ARM上的Linux。一线工程里带PS方式更常见因为Zynq的CPU本来就有富余算力Linux协议栈的稳定性远超自研RTL网络栈而且调试工具丰富。纯PL适合极低延迟或要求零CPU介入的数据采集前端但ARP、ICMP、分片重组都要自己写调试周期往往按周计算。从“FPGA驱动”这个标题看两条路都说得通。下面以带PS方案为主线展开因为AXI Ethernet、AXI DMA、设备树、Linux驱动这一整套组合是Zynq平台最成熟可靠的UDP落地方案踩坑最少。3.2 块设计最小组合IP选型与关键配置在Vivado Block Design里一个最小可跑通UDP的工程包含以下IPAXI Ethernet选择1000Mbps、RGMII、使能MDIOAXI DMAS2MM和MM2S两个通道都打开用于收发两个方向AXI Interconnect把DMA的存储映射接口连到PS的HP口Processing System 7启用HP0、GP0、PL中断AXI BRAM Controller可选只在不用DDR做DMA缓冲时使用创建AXI Ethernet并设置参数的TCL脚本示例如下create_bd_cell -type ip -vlnv xilinx.com:ip:axi_ethernet:7.2 axi_eth_0 set_property -dict [list \ CONFIG.PHY_TYPE {RGMII} \ CONFIG.RX_INCLUDE_FCS {false} \ CONFIG.TX_INCLUDE_FCS {false} \ CONFIG.ENABLE_MDIO {true}] [get_bd_cells axi_eth_0]参数说明PHY_TYPE选RGMII对应外部PHY芯片接口RX_INCLUDE_FCS和TX_INCLUDE_FCS都设为false让MAC自动剥离和追加CRC避免DMA缓冲区里出现多余字节ENABLE_MDIO开启管理通道驱动才能通过MDIO读取PHY状态和协商结果。连线层面AXI Ethernet的s_axi配置口接GP口或HP口均可中断接PS的PL中断AXI DMA的S2MM从以太网接收AXI StreamMM2S向以太网发送流DMA的m_axi接AXI Interconnect后挂到HP0。有一个容易忽略的点是DMA中断和Ethernet中断要在Block Design里同时引出Linux驱动通常同时依赖这两个中断源设备树里也要对应配两个中断号。3.3 DMA描述符与缓冲区对齐的硬约束AXI DMA在PS侧看来就是一组描述符加数据缓冲区。描述符由驱动维护数据缓冲区要求物理地址连续且基地址和长度都满足对齐要求。在裸机裸金属程序中Xil_DCacheFlush()必须在CPU写完数据后调用否则DMA读到的可能是Cache里的旧数据Linux下用dma_alloc_coherent()分配缓冲区才能保证设备地址和CPU虚拟地址在同一个映射视图里。UDP包进入DMA缓冲后描述符的环回顺序决定接收连续性。如果环缓冲区只配置一个描述符上一帧还没被用户程序取走下一帧就会覆盖同一块内存表现为“UDP数据时而新时而旧”。常规设计至少配置4个独立描述符并在驱动里维护一个“生产者-消费者”索引。调试时如果发现高流量下丢帧先看描述符数量而不是先去调RGMII延时这往往是缓冲区深度不足造成的。4. Linux侧驱动与UDP应用让FPGA网卡出现在eth14.1 设备树与驱动匹配AXI Ethernet在Linux内核里有现成驱动设备树要做的是把硬件资源告诉驱动。一个典型节点如下etherneta4010000 { compatible xlnx,axi-ethernet-1.00.a; reg 0x0 0xa4010000 0x0 0x40000; interrupts 0 57 4; local-mac-address [00 0a 35 00 01 00]; phy-handle phy0; mdio { #address-cells 1; #size-cells 0; phy0: ethernet-phy0 { reg 0; }; }; };字段说明compatible决定内核用哪个驱动匹配reg必须是Vivado地址向导分配给该IP的基地址要和Block Design里的地址一致interrupts里的57是PL中断经GIC映射后的SPI编号具体值以Vivado向导打印为准phy-handle指向MDIO子节点而子节点中的reg填写PHY芯片的MDIO地址。最常踩的坑是PHY实际地址与reg不一致驱动初始化时找不到PHY直接导致link状态永远为down。修改设备树后重新编译启动ifconfig -a能看到新网卡接口通常命名为eth1。如果设备树没生效先检查/proc/device-tree里对应节点是否存在再确认内核里AXI Ethernet驱动是否编译进内核。4.2 用户态UDP应用的两条通道网卡注册成功后最直接的方式是把它当普通网卡用绑定IP后通过socket收发UDP。这种方式的优点是完全复用Linux协议栈代码和PC端没有区别。另一种方式是用户态直接读取DMA缓冲区适合PL侧硬件已经完成了IP/UDP解析、只想拿净荷的场景典型实现是用UIO框架int fd open(/dev/uio0, O_RDWR); void *buf mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); uint16_t ethertype (buf[12] 8) | buf[13]; if (ethertype 0x0800 buf[23] 17) { uint16_t dport (buf[36] 8) | buf[37]; printf(UDP dport%u\n, dport); }代码里的偏移量对应标准以太网帧buf[12]和buf[13]是EtherType0x0800表示IPv4buf[23]是IP头中的协议字段17表示UDPbuf[36]和buf[37]是UDP目的端口。这个片段用于验证PL侧DMA搬运过来的数据排列是否符合预期特别是网络字节序与主机字节序的差异调RGMII时也经常用它快速确认链路。需要说明的是UIO方式要求驱动把DMA缓冲区通过mmap暴露给用户态并保证中断到达后用户态能感知。相比socket方式UIO省去了两次数据拷贝但把协议解析工作推给了应用。如果FPGA里有UDP卸载引擎选UIO如果PL只做MAC直接用socket更省事。4.3 没有ARP就没有UDP排查还是要从协议栈看起Linux协议栈发送IP包前会先发ARP请求只有拿到目的IP对应的MAC地址UDP数据帧才会真正发出。因此“网线插着、ifconfig正常、socket却没数据”时第一步查ARP而不是查UDP代码本身。PC端用Wireshark抓包判断依据如下表现象问题所在PC抓不到板子发出的ARP请求RGMII TX方向、PHY link、MAC使能状态ARP能看到但没有回应DMA接收描述符、中断配置、设备树phy-handleARP通了但UDP收发失败应用层端口绑定、防火墙、网络调试助手设置第三条在Linux里很常见绑定端口时不指定IP或错误指定IPUDP包发到了别的接口上或者PC防火墙拦截了来自FPGA网卡的包。把防火墙关掉再测通常能立刻区分是驱动问题还是应用问题。5. 用MDIO环回和Wireshark确认FPGA侧包处理正确5.1 MDIO数字环回是最快的问题分割手段UDP发不出去时第一步不是换网线而是让PHY进入数字环回模式。在这种模式下PHY在芯片内部把发送端的RGMII数据直接送回接收端不经过网线物理链路。FPGA发出一个UDP包如果接收方向能看到同样的帧就说明FPGA侧的TX/RX数据通路、AXI DMA和驱动逻辑都成立问题被隔离到PHY与线缆侧反之环回不通则说明问题在FPGA内部链路。88E1518等PHY的数字环回控制通常位于寄存器0的bit14通过MDIO写入即可开启mdio-tool eth1 phy_write 0x0 0x14 0x4000参数说明第一条0x0是MDIO地址第二条0x14是寄存器地址0x4000对应bit14置1。不同PHY芯片寄存器定义不同这里只是常用示例。开启环回后要关闭自适应并固定1000Mbps全双工否则PHY在环回条件下无法完成正常协商现象反而更奇怪。5.2 Wireshark对拍时看帧格式不只是看UDP载荷PC端抓包时过滤条件直接锁定FPGA的MAC和UDP端口eth.addr00:0a:35:00:01:00 udp.port5000抓到的包要检查三处EtherType是否为0x0800确认IPv4帧被正确递交IPv4头校验和是否错误错误说明FPGA侧做了IP层处理但实现有缺陷UDP校验和是否为0。不少自研PL协议栈为省逻辑把UDP校验和写成0IPv4允许这个做法但部分硬交换芯片会直接丢弃零校验和UDP帧。因此商用验证时最好让PL把UDP校验和计算出来别省这个逻辑。5.3 收尾技巧用两个计数定位丢包点网络基本跑通后再做一轮压测同时盯两个数值FPGA内部AXI Stream的TLAST脉冲计数以及PC端Wireshark收到的帧计数。两个数字应接近1:1。如果TLAST很多但Wireshark收得少问题在RGMII发送侧或PHY调IDELAY和发送时序如果Wireshark收得多但板子侧面TLAST少问题在接收方向。Zynq 7020的UDP链路每一层都有清晰的特征顺着这个两计数法能比盲改代码更快收窄问题。下一回遇到UDP丢包先跑一次PHY环回确认内部基线再动RGMII延时省下的是按天计算的调试时间。本文还有配套的精品资源点击获取
返回列表