ARTICLE DETAIL

资讯详情

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

基于FPGA TSE IP核的以太网UDP通信实战指南

基于FPGA TSE IP核的以太网UDP通信实战指南 FPGA里做网络通信最常见也最稳的方案之一就是Altera现在叫Intel FPGA的Triple-Speed Ethernet IP核搞过以太网的工程师习惯直接叫它TSE。这个IP核支持10/100/1000M三速以太网MAC功能内部集成了MAC、FIFO还能根据你选的接口类型把MII/GMII/RGMII/SGMII这些物理层时序一并解决。在很多图像采集、高速数据记录、工业控制项目里用FPGA通过TSE把数据打包成UDP报文发到PCPC端再用网络调试助手收包是特别典型的应用套路。这篇文章我打算完全按实战来写从TSE IP核该怎么理解、Quartus里参数怎么配、Avalon-ST接口怎么对接到UDP收发通路怎么用状态机实现、ARP怎么应答、网络调试助手怎么联调最后把USB-Blaster的代码39、PHY链路起不来、校验和不对这些坑都过一遍。内容主要针对Altera Cyclone系列和Arria系列用的软件是Quartus Prime/Quartus II 13.0以上版本适合刚接触TSE IP核但已经有点FPGA基础的人也适合做网络通信项目的老手拿来当配置清单查。1. TSE IP核的整体认知与选型思路1.1 三个速率模式带来的设计红利TSE这个名字里的“Triple-Speed”指的是它支持10Mbps、100Mbps、1000Mbps三挡以太网速率。对于很多工业现场和数据采集设备来说这个范围几乎覆盖了所有常规以太网应用场景低速传感器数据采集可以跑10M或100M图像视频这类高带宽数据直接上千兆。从内部结构看TSE IP核把以太网MAC层功能全做了包括帧的封装与解析、CRC32生成与校验、帧间间隔IFG、冲突检测用于半双工、全双工/半双工自适应等。用户侧不需要关心MAC层怎么把UDP包塞进以太网帧里只需要面向Avalon-ST接口读写数据即可。这和“自己用Verilog写一个GMII接口的MAC”完全是两个工作量级后者光是要处理时序收敛、CRC计算、错误帧丢弃这几个点就够折腾一两个星期而且很容易在边界条件上翻车。TSE的另一个隐含红利是用户逻辑看到的接口速率不会因为MAC速率的变化而改变。也就是说不管底层是10M、100M还是千兆Avalon-ST用户接口都是同一个时钟域、同一套握手时序。这意味着应用逻辑可以完全不用关心物理速率切换只要配置好对应寄存器或者让TSE自动协商用户侧设计基本不用改动。这个抽象对项目迭代来说非常友好。1.2 你该选哪种物理接口TSE IP核本身只是MAC层可选配PCS要和网口通信必须外接PHY芯片。PHY与TSE之间的接口有几种选择我直接用一张表说明接口类型引脚数工作模式适用场景MII约16根10/100M老方案、低成本低速板卡GMII约24根10/100/1000M传统千兆方案引脚占用大RGMII约12根10/100/1000M当前最常见的FPGA-PHY连接方式SGMII差分2对10/100/1000M高速串行、引脚少、板级走线简单简单说一下选型逻辑。如果PCB面积紧张、器件密度高RGMII是主流选择4位数据线双沿采样125MHz的DDR速率就能跑千兆对走线要求比GMII低很多。如果对EMI更敏感或者要跨背板连接SGMII更合适本质是串行差分信号只需要一对发送、一对接收板级实现非常干净。不过要注意RGMII和GMII只是并行的数据接口而SGMII内部需要PCS/PMA层做8B/10B编解码TSE IP核在配置界面里会有一个选项决定是否内置SGMII PCS。如果你的设计选择了SGMII接口TSE会自动生成PCS逻辑不需要再单独例化一个GXB Transceiver IP。如果你选的是RGMII或者GMIITSE就只提供MAC侧的信号外部PHY芯片直接对接即可。1.3 SGMII对接PHY时的模式配置这里必须专门讲讲热搜词里反复出现的那个问题“sgmii ip核与phy芯片一起使用时应配置成mac模式”。这个描述不准确但确实踩过的人太多了。SGMII链路的两端一端是MAC也就是TSE的SGMII接口另一端是PHY芯片的SGMII接口。正常情况下TSE的SGMII这一端就是MAC角色PHY芯片那一端是PHY角色两者通过SGMII自协商机制完成速率匹配。这里的关键在于有些PHY芯片的SGMII口支持配置成MAC模式这个模式是为了“PHY级联”或者“CPU直连交换芯片”这种特殊场景准备的。如果外部PHY被配置成了MAC模式再接TSE的SGMII口两侧角色就会冲突表现为链路协商失败、link up不了或者数据错误。所以正确的理解是TSE的SGMII口始终按MAC端使用外部PHY芯片应保持默认的PHY模式。自动协商时TSE会把自己的速度能力广播给PHYPHY再根据对端网口速度来确定最终速率。很多PHY芯片有专门的寄存器控制SGMII侧的autoneg需要确保这个功能处于开启状态否则协商结果可能锁定在1000M导致10/100M设备接入后异常。从配置层面看TSE IP核里如果选择“SGMII with PCS”内部会自动生成一个SGMII PCS实例并在顶层对应引脚引出串行差分对txp/txn/rxp/rxn和125MHz参考时钟。外部PHY看到的就是一个标准的SGMII MAC接口。如果选了RGMII就完全不用关心PCS这些内部细节直接把RGMII引脚引到PHY即可。2. Quartus工程与TSE IP核配置实操2.1 建工程前先理清时钟树和复位顺序TSE配置看起来简单但时钟和复位处理不当后面调试非常痛苦。先说时钟。一个典型的千兆以太网设计时钟至少涉及这几路用户侧Avalon-ST接口时钟通常用125MHz对应千兆速率下TSE用户时钟MAC/PHY接口时钟RGMII模式下需要一个125MHz的参考时钟给PHY芯片或由FPGA输出或由PHY提供反馈SGMII模式需要125MHz参考时钟给TSE内部的PCS如果外接PHY芯片还需要PHY的工作时钟这个一般由晶振或FPGA提供。在Quartus工程里这些时钟需要建立正确的时钟约束否则时序分析报告会大量报错。实际操作中我习惯把所有时钟都约束成同一个source比如用一个125MHz差分晶振到FPGA由PLL分出用户时钟和接口时钟尽量减少异步域。TSE内部的Avalon-ST收发FIFO本身就是异步FIFO可以处理跨时钟域的缓冲问题但前提是IP配置里把“Use internal FIFO”打开并且把两边的时钟都正确连线。复位方面TSE IP核有独立的复位输入。需要注意复位释放后用户逻辑不能立刻开始收发数据建议等待一段时间尤其是外部PHY芯片MDIO配置完成后、Link Up信号拉高后再开始业务数据发送。否则数据会丢在MAC的FIFO里收端什么都等不到。最简单的做法是FPGA上电复位 → 等待PLL锁定 → 释放TSE复位 → 配置MDIO寄存器 → 等待PHY link up → 开始业务。2.2 TSE IP核配置清单详解在Quartus IP Catalog里搜索“Triple-Speed Ethernet”双击打开配置界面。不同版本参数名略有差异但关键项基本一致。下表是我在Cyclone V和Cyclone 10 GX上验证过的配置建议配置项推荐值说明Device family按实际器件选择同一IP在不同系列上有细微差异Speed grade按实际器件选择影响时序收敛难度Interface根据PHY选MII/GMII/RGMII/SGMIIRGMII最常用SGMII适合高速和少引脚MAC mode10/100/1000 Mbps可选单速、双速、三速建议三速Half/Full duplexFull duplex only或支持自协商绝大多数场景用全双工PCS/PMA仅SGMII/千兆光口需要RGMII接口不要选Avalon-ST packet transfer打勾用户侧按包传输不用管FIFO细节Use internal FIFO打勾极大简化设计推荐开启MDIO interface打勾用来配置和管理外部PHYShare MDIO可选项多PHY时共用MDIO需要地址分配Suppress wakeup packet默认省电场景才需要Enable ECC视可靠性要求航空/高可靠场景建议开启重点关注“Use internal FIFO”这个选项。开了之后TSE会在MAC核与用户逻辑之间自动插入收发FIFO用户侧的Avalon-ST接口就不需要精细到每个cycle的时序只需要在FIFO ready时写入、在FIFO valid时读出。对于第一版调试来说这个选项能帮你屏蔽掉一半以上的接口时序问题。等整个UDP通路调通了再考虑去掉FIFO做极致流水线的方案。另外要强调一个容易忽略的地方IP核配置界面里有一个“Enable legacy SGDMA interface”之类的选项如果你不是要用DMA描述符方式不要勾选。很多新手在配置时看到DMA字眼觉得可以“加速”结果生成的接口变成Avalon-MM memory mapped跟网上的例程对不上整个设计推倒重来。第一版老老实实用Avalon-ST FIFO模式数据通路最简单。2.3 Avalon-ST接口的信号与时序理解用户侧与TSE交互的信号主要有这几个clk用户时钟reset_n复位tx_readyTSE侧发送FIFO可以接收数据tx_valid用户侧发数据有效tx_data数据总线tx_sop包的起始beattx_eop包的结束beattx_empty最后一个beat中的无效字节数当数据总线比实际数据宽时需要tx_error用户侧主动上报错误包接收方向对应的就是rx_valid、rx_data、rx_sop、rx_eop、rx_empty、rx_error。整个握手逻辑和Avalon总线一致发送侧拉高valid接收侧拉高ready当valid和ready同时为高时当前一拍的数据被成功交接。在UDP传输这种包式通信中sop和eop是最关键的控制信号。帧起始时sop拉高一个周期帧结束对应对teop拉高并且eop所在beat的数据在总线上的有效字节数通过empty信号表示。以32位数据总线为例如果一包UDP数据长度不是4的倍数最后一拍数据只有1~3个字节有效empty就会标识剩余无效字节数。写这个逻辑的时候很容易把empty的值算错导致接收端拼接出的数据错位这是我在联调里见过最多的问题之一。有一个新手很容易踩的坑发送时valid不能有毛刺否则TSE会解析出一个错误的包边界。实战中最好把要发送的一整包数据先在用户侧RAM或FIFO里缓存好再统一按顺序推给TSE确保sop/eop之间的数据是连续无气泡的避免在中间出现valid拉低又拉高的过程造成接收端丢包。3. 自研一个最小UDP协议栈3.1 MAC帧、IP头、UDP头的字段对照UDP over Ethernet的本质就是在以太网帧里依次封装IP报文和UDP报文。FPGA这一端要做的就是在发送时把各层头部按顺序填好接收时按顺序解析校验。我把每一层的字段和偏移整理成下面这组表开发时直接对照抄就行。以太网帧头14字节偏移长度字段内容06目的MAC对端物理地址66源MAC本端物理地址122以太网类型0x0800表示IP0x0806表示ARPIP头20字节偏移长度字段示例值01版本首部长度0x45IPv420字节头11服务类型0x0022IP总长度IP头UDP头数据42标识每次发送自增62标志片偏移0x0000不分片81TTL6491协议17UDP102首部校验和对IP头计算124源IP如192.168.1.10164目的IP如192.168.1.100UDP头8字节偏移长度字段内容02源端口自定义如500022目的端口自定义如600042UDP长度UDP头数据62校验和可选但建议计算以太网帧结构的最后一个部分是FCSCRC32这个完全由TSE的MAC硬件负责生成和校验用户逻辑不用写。但正因为FCS由硬件算如果你在用户侧把帧长弄错了比如短于64字节MAC可能会自动填充导致PC端收到的报文长度和你期望不一致。做协议解析时要把这些考虑在内。3.2 发送通路状态机FPGA端发送UDP包整体流程可以分成四段先把应用数据写入发送缓存然后计算IP头和UDP头接着按“以太网头 IP头 UDP头 数据”的顺序拼包最后通过Avalon-ST发送给TSE。状态机可以参考下面的跳转IDLE等待用户启动发送命令命令中携带目标IP、目标端口、数据长度、数据在RAM中的起始地址。MAC_HDR发送14字节以太网头。目的MAC可以是固定值先通过ARP学到也可以是ARP表里查到的值。IP_HDR发送20字节IP头。总长度字段 20 8 data_len校验和需要预先算好。UDP_HDR发送8字节UDP头。长度字段 8 data_len。DATA从RAM按4字节或数据总线位宽切片逐拍发送。WAIT_END拉高eop结束本包。开发时建议先把“伪校验和”的概念搞清楚。UDP校验和的计算范围不仅包含UDP头和数据还包含一个12字节的伪首部源IP、目的IP、保留0、协议17、UDP长度。伪首部本身不发送只参与校验和计算。算法是把所有16bit字累加进位回卷最后取反。如果数据长度不是2的倍数末尾补一个0字节参与计算。这个计算可以在发送数据的同时做可以先算出结果再发起发送。一个实用的技巧如果调试初期不想算UDP校验和可以把UDP校验和字段填成0x0000。RFC规定发送方为0表示不校验接收方可以忽略。对PC上的网络调试助手和Wireshark来说UDP校验和为0会有一个提示但基本不影响收包。这样可以把状态机调通后再补上校验和逻辑分步推进少踩很多坑。3.3 接收通路状态机接收方向TSE检测到有效以太网帧后通过Avalon-ST把整个帧从目的MAC开始一直到数据末尾送给用户逻辑。用户逻辑需要做的第一件事就是缓存整包或者至少缓存头部以便解析用途。接收状态机的典型流程等SOP接收帧头前14字节判断以太网类型是否0x0800不是IP帧直接丢弃或者送到其他处理分支。解析IP头继续接收20字节检查版本号校验首部校验和确认协议是17UDP记录源IP、目的IP。解析UDP头继续接收8字节检查目的端口是不是FPGA业务端口不是则丢弃。接收数据按数据帧长度把有效载荷写入接收RAM生成接收完成中断或标志。这里有一个容易忽略的点TSE接收FIFO输出的rx_error信号会在MAC层检测到CRC错误、短帧、长度错误时拉高并且会对应当前包的某个位置。用户逻辑必须在eop之后检查rx_error如果这个包出错直接丢弃不要写入RAM。即使UDP头都解析正确了只要CRC不过整个包都不可信。我个人建议在接收通路里做一个简单的FIFO缓存至少保留一个完整包的数据等解析通过后再把整包交给上层逻辑处理。这样能避免边收边处理导致的半包状态也方便添加过滤规则。3.4 ARP应答和Ping如果没有ARP上面这套UDP收发只能工作在“目标MAC已经预先填好”的情况下。一旦PC端IP和FPGA IP在不同网段或者PC的ARP表里没有FPGA的MACPC发UDP就会报“无法访问目标主机”。所以一个实用的UDP通信方案必须实现ARP应答。FPGA端收到ARP请求后解析出源MAC和源IP如果目的IP是本机IP就把源MAC换成自己的MAC填入应答报文发送给请求方。ARP请求是以太网广播帧目的MAC是FF:FF:FF:FF:FF:FF类型0x0806操作码1。应答帧是单播帧目的MAC就是请求方的MAC操作码2。Ping功能的ICMP回显请求处理逻辑类似收到ICMP类型8的请求把类型改成0回显应答重新计算ICMP校验和然后原路发回。虽然不是UDP通信的必需功能但强烈建议实现。联调的时候如果FPGA能ping通PC说明链路、MAC、PHY、ARP这些底层都没问题再把问题聚焦到UDP协议上层如果ping都不通就不用浪费时间去抓应用层问题了。4. 网络调试助手联调与验证4.1 先营造一个干净的网络环境在把FPGA接入复杂网络前建议先用一根网线直连FPGA板和PC不要经过交换机、路由器。直连可以排除交换机端口协商、VLAN、防火墙等干扰因素。PC端需要做几个固定步骤给有线网卡设置一个静态IP比如192.168.1.100子网掩码255.255.255.0关闭防火墙或者至少允许UDP端口通过确认网卡没有启用“随机硬件地址”这类影响MAC地址的选项在命令行里用ipconfig确认网卡的IP确实生效。FPGA端建议使用与PC同网段的IP比如192.168.1.10。这样ARP和UDP都在二层和三层直接可达不需要网关参与。如果条件允许可以先不用FPGA直接用两台PC通过网线直连在网络调试助手里做一次UDP收发测试。这个步骤看起来多余但实测下来非常有价值它能确认网线OK、PC网卡OK、调试助手配置OK把环境里的变量全部洗干净剩下的问题就只可能出在FPGA这一侧。4.2 网络调试助手的基本操作网络调试助手的版本很多基本是同一个操作套路。以常见的NetAssist为例协议类型选择UDP本地IP选择PC网卡的IP192.168.1.100本地端口填入一个空闲端口比如9000远程IP填入FPGA的IP192.168.1.10远程端口填入FPGA业务监听的端口比如6000。配置完成后打开连接在发送区输入数据点发送。如果FPGA端接收正确并返回了数据接收区就会显示回来的报文。要注意网络调试助手的“接收区”通常只显示文本或HEX如果你发的是一串字符串它不会自动识别UDP包的边界不会显示以太网头这些信息。要精细地看包结构还是需要Wireshark。联调时建议先在发送区发一条固定内容比如“55 AA 00 FF”这种特征明显的HEX然后在FPGA的Signal Tap或逻辑分析仪里观察对应的数据是否到达。逐级确认一步一步缩小问题范围。4.3 抓包辅助定位问题Wireshark在FPGA联调中扮演的角色相当于“以太网协议分析仪”。把PC网卡设置为混杂模式过滤条件打上udp or arp就能看到PC和FPGA之间的所有报文。抓包能快速回答几个问题ARP请求发出去没有FPGA有没有回ARP应答FPGA发的UDP包格式对不对IP头、UDP头偏移是否正确校验和字段是否正确如果Wireshark标记“checksum incorrect”说明FPGA算的校验和有问题或者PC网卡硬件卸载计算导致的假阳性。数据载荷是否符合预期可以在载荷区看到FPGA发送的原始数据。我有个习惯联调阶段PC端始终开着Wireshark抓包。不是说每帧都要看而是遇到问题时有第一手现场数据不用猜。“猜”是调试以太网最大敌人抓包能让你从“猜”切换到“查”模式。5. 常见问题与排障速查5.1 USB-Blaster驱动代码39这个热搜关键词出现得非常多说明很多人卡在了下载器这一关。现象是USB-Blaster插入电脑后设备管理器显示黄色感叹号属性里报“Windows无法加载这个设备的驱动程序错误代码39”。代码39的常见原因包括驱动签名问题、USB控制器供电不足、第三方USB-Blaster兼容性问题。处理顺序建议是换一个USB端口优先插主机背板直出的USB口不要插前置面板或HUB在设备管理器里卸载这个设备勾选“删除驱动程序软件”然后重新扫描硬件以管理员身份运行Quartus安装目录下的驱动安装工具重新安装驱动如果系统是Win10/Win11尝试禁用驱动程序强制签名后重装驱动换一根USB线。是的USB线也可能出问题有些劣质线只支持充电不支持数据最后要考虑是不是兼容版USB-Blaster的问题。虽然兼容版性价比高但驱动和抗干扰能力确实不如原厂长时间调试时可以先检查这个环节。这里提醒一下USB-Blaster驱动问题往往是环境问题不是FPGA工程问题。不要在一个环境问题上耗太久如果以上方法都不行换一台电脑装Quartus再试很多场景下立刻就好转了。5.2 PHY链路起不来怎么办PC网卡显示“网络电缆被拔出”说明物理层没有link up。检查思路从底层开始测量PHY芯片电源、时钟、复位确认硬件正常用MDIO读取PHY的寄存器比如88E1512的0x01寄存器状态、0x11寄存器速度指示看PHY本身是否检测到对端确认MDIO通信正常。如果读出来全是0xFFFF说明MDIO时序有问题或PHY地址不对SGMII模式下确认TSE的PCS是否完成自协商可通过IP核提供的status信号观察RGMII模式下重点检查TSE和PHY之间的时钟极性。RGMII标准规定数据在时钟的上升沿和下降沿都采样部分PHY支持通过寄存器调整时钟相位偏移。联调前我通常会在FPGA里写一个简单的MDIO读写模块把PHY的ID寄存器读出来。能读到正确的PHY ID说明管理通道通物理链路才有继续调的基础读不到后面所有调试点都无从谈起。5.3 能收到包但校验和错误这个现象在PC收FPGA发来的UDP包时比较常见。Wireshark提示IP校验和或UDP校验和错误但网络调试助手依然能收到数据很容易让人误判为“没问题”。实际上很多网卡驱动对UDP校验和并不做严格校验错误包也会往上送但某些应用层或者交换机可能会丢弃这种包。校验和错误一般来自两个地方IP首部校验和计算错误。注意IP头的计算范围只覆盖IP头本身不包含UDP头和数据UDP校验和计算错误。要检查伪首部和补零逻辑数据长度是奇数时末尾补0参与计算。我踩过最多次的坑是IP总长度字段和UDP长度字段没同步更新。比如数据长度改了但IP头里的总长度还是旧值IP校验和也按旧值算Wireshark就会同时报IP长度异常和校验和错误。写代码时建议把长度计算集中到一个功能函数里所有头部字段都从这个函数的结果来生成避免多处修改导致不一致。5.4 数据错位、乱序、丢数据数据链路已经通了但PC端收到的数据内容对不上。这类问题大概率出在Avalon-ST的sop/eop和empty处理上。先说错位。如果接收端按字节拼接数据时没有正确使用empty信号最后一拍会把无效字节也拼进来导致后续数据整体偏移。这种情况通常表现为第一包数据末尾多出几个字节第二包开始所有字段都错位。再说乱序。TSE内部有收发FIFO如果发送端在FIFO还没ready时强行写入或者接收端没有及时读取导致FIFO溢出都可能丢包或乱序。解决办法是先确认每拍数据都是在valid和ready同时有效时写入的不要漏掉握手的“同时”条件。丢数据还有一个常见原因是发送端没有等上一个包的eop发完就启动下一包。Avalon-ST要求一个完整包必须连续发送包与包之间可以间隔但同一个包内不能有非法的“断流”。如果业务逻辑是不断流水的建议在发送状态机里增加“发送完成后返回IDLE再检查是否有新包”的严格流程。5.5 在线调试的Signal Tap触发设置Signal Tap在较新版本中叫In-System Debugger是定位FPGA内部问题的利器。但很多初学者抓不到有效波形原因是触发条件设置不对。对于TSE调试建议这样设置把tx_ready、tx_valid、tx_sop、tx_eop、tx_data加入采集列表触发条件设为tx_valid 1 tx_sop 1这样可以从一个包的起始位置开始抓采样深度根据包长的需求设置通常4K~16K样本足够如果逻辑里没有输出sop这些信号到观察点可以在TSE输出端把它们引到顶层测试引脚或者直接在内部逻辑里加ILAIntel在较新工具里也支持类似调试IP。Signal Tap里我最常查的信号是ready和valid是不是都拉高以及sop和eop之间的数据节拍数是不是和预期帧长一致。很多时候问题一眼就能看出来sop之后数据断了一个cycle或者包长多了一拍马上就能定位到状态机问题。5.6 善用IP核自带的Example DesignTSE IP核在生成时Quartus会附带一个example design工程里面包含了完整的PHY配置、时钟管理、复位逻辑和测试发送模块。很多问题其实不用自己从头折腾参考example design能省下大量时间。具体操作路径在TSE IP核生成界面点击“Generate Example Design”Quartus会生成一个独立的工程。可以先用这个工程在目标板上跑起来配合Signal Tap看TSE的输出是否符合预期。如果example design能跑通再逐步把example里的PHY配置和复位逻辑迁移到自己的设计里。我见过不少工程师遇到问题不查example自己硬写MDIO配置结果PHY模式配置错了半天都定位不出来。最后从我个人经验出发再补一条TSE调通UDP通路最怕“一次集成到位”。正确节奏是先把example design跑起来再实现ARP应答让PC能ping通FPGA最后才加入UDP收发和业务数据。每走一步都确认一步的返回结果。调UDP通信这种事底层链路不干净上层协议怎么调都白搭。按照这个顺序来绝大多数板卡都能在一天内把UDP通路跑起来剩下的时间都花在优化业务逻辑上而不是跟IP核死磕。
返回列表