尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FPGA PCIe XDMA开发:AXI MM与AXI Stream选型及调试全攻略

FPGA PCIe XDMA开发:AXI MM与AXI Stream选型及调试全攻略 做 PCIe 相关的 FPGA 开发Xilinx 的 XDMA IP 基本是绕不开的。我见过不少团队一上来就在 AXI Memory Mapped 和 AXI Stream 之间犯选择困难症接口选错之后硬件、驱动、应用全得返工甚至有人把 MM 当 Stream 用把 Stream 当 MM 用最后 DMA 传输各种灵异现象。这篇文章就把 XDMA 的选型逻辑、Vivado 配置流程和上板调试方法完整摊开结合我实际踩过的坑尽量让你一次走对。不管是刚接手 FPGA PCIe 项目的入门者还是已经被 DMA 传输卡了几周的工程师这篇文章都适合。我会先讲清楚 XDMA 内部是怎么工作的再对比 AXI Memory Mapped 与 AXI Stream 在软件模型、性能、资源上的差别接着给出我在 Vivado 里的完整配置过程最后整理一套 PCIe 调试排查顺序。内容偏实战有些细节可能文档里没写全但都是我会在真实项目里验证过的东西。1. XDMA 选型前先搞懂这几个底层概念1.1 真正要理解的是描述符搬运机制很多工程师把 XDMA 简单理解成一个“PCIe 转 AXI 的桥”这个理解只对了一半。XDMA 本质上是三部分组合PCIe 物理层和事务层、DMA 引擎、AXI 接口。其中 DMA 引擎是灵魂它通过读取主机内存里的描述符来决定数据从哪来、往哪去、传多少。描述符是 XDMA 最重要的概念类似一个“快递面单”。主机驱动会在 RAM 里维护一个描述符环形缓冲区每个描述符包含源地址、目标地址、传输长度、控制标志以及完成状态。XDMA 引擎会通过 PCIe 读请求把这些描述符搬回 FPGA 侧解析之后产生对应的 AXI 读和写事务数据传完后再把完成状态写回主机内存。这个机制决定了你选 AXI Memory Mapped 还是 AXI Stream 会有完全不同的用户体验。选 MM 接口时描述符直接映射到 AXI 总线上的具体地址数据在主机内存和 FPGA 侧指定地址之间有来有回。选 Stream 接口时描述符就变成了单纯的数据搬运任务数据像水龙头一样从 AXI Stream 口灌进来或者流出去没有地址概念。1.2 三种 AXI 接口出口到底差在哪XDMA 的 IP 配置界面里会有三个可选的 AXI 接口AXI Memory Mapped通常叫 AXI MM、AXI Stream AXI MM 主接口有时也叫 AXI MM、以及 AXI Lite。很多人看到这几个选项就晕我换个方式讲。AXI MM 就像小区里的快递柜每个柜门都有编号你告诉快递柜“放 3 号柜”数据就往 3 号柜去。而 AXI Stream 是一条传送带数据挨个从传送带流过没有柜门编号只要传送带不堵数据就一直往前走。AXI Lite 则是用来读写小容量控制寄存器的低速接口功能简单地址空间小一般只用来做控制状态寄存器。XDMA 默认会给你分配至少一个 AXI Lite 接口用于 FPGA 侧寄存器访问。真正的数据传输通道是你要在 IP 配置里选的 AXI MM 或 AXI Stream。注意新版 XDMA 还支持同时把 MM 和 Stream 都开出来但实际项目中我通常不建议一开始就全开接口越多跨时钟域和调试的复杂度就越大。1.3 PCIe 事务是在和地址打交道还有一个容易被忽略的背景知识PCIe 协议本身是带地址语义的。事务层协议里的 Memory Read/Write TLP 都带有地址、长度、标签等信息完成报文还要带 Completer ID。换句话说即使 XDMA 面向 FGPA 侧输出的是 AXI Stream 接口它在 PCIe 链路上仍然要通过带地址的 TLP 和主机内存交互。这个背景解释了为什么 Stream 模式也会要求你配置主机侧 DMA 缓冲区地址并且要维护描述符。很多新手以为选 Stream 就等于不需要地址了其实不需要地址的只是 FPGA 这一侧主机侧仍然要告诉 XDMA 数据放在内存的哪个位置。搞清楚这一点后面选型和调试都不会慌。2. AXI Memory Mapped vs AXI Stream选型决策指南2.1 软件模型差异决定了 80% 的选型方向选型最优先看的不是带宽而是你的软件模型。所谓软件模型就是主机 CPU 希望以什么方式访问 FPGA 上的资源。如果主机软件需要随机访问 FPGA 侧某个地址上的数据比如读取采集卡里某个缓冲区的内容或者往某个寄存器写参数那就应该用 AXI Memory Mapped。这种模式下XDMA 会把 PCIe 的带地址 TLP 直接转成 AXI 总线上的地址读写CPU 发起一个 read/write数据就能落到指定地址来回通透。如果你的数据是连续不断的流水比如 ADC 采样、网络报文、视频流、信号发生器波形主机不需要知道数据具体存在 FPGA 哪个地址只需要搬进搬出那应该用 AXI Stream。这种模式对软件来说就是一个持续运行的数据通道驱动一般会维护一个环形缓冲区数据到达后自动写入这个缓冲区或者从缓冲区送出到 FPGA。2.2 带宽、时延与资源占用的真实差别性能上AXI Stream 通常更容易跑出高带宽。因为 Stream 接口没有地址翻转的成本只要 source 和 sink 握手正常数据就能持续流动。AXI Memory Mapped 在顺序读写大块数据时也能跑到接近峰值带宽但一旦涉及随机访问效率会下降明显。原因是 PCIe TLP 的带宽利用率取决于有效数据载荷占总开销的比例随机小数据块会放大 TLP 头部的开销。资源占用方面AXI MM 接口如果不做地址重映射或者跨时钟域处理通常资源消耗和 Stream 差不多。但如果启用 512 位数据总线、或者加多通道描述符、多通道 DMA资源占用会上升。Stream 模式如果需要做多通道tkeep和tlast解析也会额外占用一些逻辑资源但通常比 MM 内部的地址仲裁逻辑少。延迟方面AXI MM 因为要处理地址和响应通道读延迟会明显高于 Stream。Stream 模式在读回数据时本质上是一个连续的读事务流对 PCIe 完成报文的处理更加流水化端到端时延也更低。对时延敏感的高性能计算和数据处理场景这是很关键的一个参考点。2.3 一张选型决策清单照着走就行我把实际项目里的选型判断整理成一张清单虽然做不到 100% 覆盖所有场景但能覆盖绝大多数情况。如果你的项目有这些特征优先考虑 AXI Memory Mapped主机需要随机访问 FPGA 内多个地址空间比如管理多个 DMA 缓冲区。FPGA 侧连接的是 DDR、BRAM、寄存器文件这类可寻址存储。调试阶段希望直接用读写工具查看某个内存地址的数据。数据传输是块状任务而不是永久流水。如果你的项目有这些特征优先考虑 AXI Stream数据是连续流比如高速 ADC、视频流、自定义帧协议。主机侧不需要知道每个数据包在 FPGA 里放哪个地址。数据要经过 FPGA 内的数据通路处理比如加解密、滤波、协议解析。追求极致的带宽和时延不希望地址映射带来额外开销。我用一个实际项目举例之前做一台高速数据采集设备FPGA 侧接 ADC 采样数据量很大主机只需要持续把采到的数据存盘。当时直接选了 AXI Stream主机驱动维护两个环形缓冲区采满一块切另一块几乎可以把 PCIe Gen3 x4 的带宽用到九成以上。如果当时选 MM虽然也能跑但软件要频繁管理描述符和中断随机地址回写的时延会造成采样断流。2.4 对比表格别靠直觉拿数据说话对比维度AXI Memory MappedAXI Stream地址语义有地址可随机访问无地址连续流典型应用寄存器读写、DDR 存储、块传输数据采集、视频流、网络包处理主机交互习惯CPU 读写下发地址和长度DMA 连续搬移驱动维护环形缓冲时延读延迟较高受地址总线和完成报文影响流水式处理端到端时延较低随机访问效率较好但小块随机传输效率低不适合随机访问只适合连续流资源占用中高地址仲裁和响应通道复杂中低数据通路相对简单调试难度地址和描述符出错较容易排查背压和流控问题要仔细看握手信号带宽潜力顺序大块传输接近峰值随机访问下降明显容易达到峰值带宽只要握手不堵3. Vivado 里 XDMA IP 的完整配置实操3.1 基本配置页先定链路和接口类型打开 Vivado在 IP Catalog 里搜索 XDMA双击打开配置界面。左侧有几个标签页第一步是 Basic 页。这里要确认三个东西PCIe 链路宽度、链路速率、AXI 接口类型。链路宽度按你的板卡设计来常见的是 x4 或 x8。速率如果是 PCIe Gen3那吞吐目标就是 Gen3 x4 或者 Gen3 x8。这里提示一下Vivado 里 IP 生成后链路速率很难在 FPGA 内部改所以硬件板卡设计时就要想清楚。AXI Interfaces 这里就是选型关键。如果你选 AXI Memory Mapped会看到以 MASTER AXI Memory Mapped 形式提供一个或多个接口。如果你选 AXI Stream Enabled会看到 H2C 和 C2H 两组 AXI Stream 接口。我习惯在配置界面里先只勾选一个口把链路调通之后再回来扩展这样 IP 生成时的信号更少综合时序压力也更小。3.2 AXI Memory Mapped 模式的配置细节选 MM 模式之后有几个参数容易踩坑。第一个是 AXI Address Width。这个宽度决定了 FPGA 侧能访问的地址范围一般设 32 位就够除非你要挂超大地址空间再设 64 位。地址宽度越大内部跨时钟域和地址译码逻辑越多建议按实际需求来。第二个是 AXI Data Width。常见可选 32、64、128、256、512 位。数据位宽变化会直接影响 AXI 时钟频率和 PCIe TLP 包长。比如 Gen3 x4 的带宽大约 3.9 GB/s如果 AXI 总线的数据宽度是 64 位AXI 时钟至少要跑到 250 MHz 才能匹配上限。如果 AXI 数据宽度选 128 位AXI 时钟可以降到 125 MHz。实际选择时一定要保证 AXI 总线的理论吞吐大于 PCIe 物理层有效带宽否则 DMA 会变成瓶颈。第三个是 BAR 配置。XDMA 至少需要一个 BAR 给 AXI Lite 寄存器访问通常还会分配一个 BAR 给 MM 数据传输。我一般做一个 64 位非预取 BAR 给数据面一个 32 位 BAR 给控制面。BAR 的类型和大小在驱动枚举时会影响 Linux 或 Windows 的映射方式别乱设按 PCIe 规范来。3.3 AXI Stream 模式的配置细节切到 Stream 模式后重点看三个地方数据宽度、TLAST/TKEEP、以及描述符完成标志。Stream 数据宽度一般选 64 或 128 位。选 64 位时一个周期搬 8 字节TLAST 信号指示一个包和结束。TLAST 很重要XDMA 会靠它判断一次 DMA 传输任务是否结束。有些新手只接tdata和tvalid/tready把 TLAST 悬空结果 DMA 传输永远不结束或者最后一个包卡住非常典型。TKEEP 表示哪些字节有效。在做非整数倍数据宽度的包时最后一拍必须把 TKEEP 置成正确掩码。比如 64 位数据宽度下最后一个有效数据只有 3 字节那 TKEEP 应该是 8h07TLAST 拉高。这个细节如果处理错数据长度对不上驱动层会经常报错。描述符完成标志这里有个选项完成时产生中断、每 N 个描述符完成中断、整个 DMA 描述符队列完成中断。实际项目中我推荐用“描述符完成时中断”配合驱动侧的完成队列不要每拍都在中断否则高吞吐时 CPU 会被中断淹没。3.4 Block Design 里的连接方式XDMA IP 在 Block Design 里使用时连接方式并不复杂但要注意时钟和复位。AXI MM 模式下我会把 XDMA 的 M_AXI 口接到 DDR 控制器、BRAM Controller 或者 AXI Interconnect然后再接用户逻辑。用户逻辑通过 AXI 接口去访问这些存储资源。这个场景下XDMA 相当于一个高性能 DMA 代理把主机访问转化成 FPGA 侧的存储访问。AXI Stream 模式下通常把 H2C 的 AXIS 口接到用户逻辑的输入把 C2H 的 AXIS 口接到用户逻辑的输出。用户逻辑里要准备好和 AXI Stream 握手tvalid、tready、tdata、tlast。数据有效时拉 tvalid接收方就绪时拉 tready两者同时为高的一拍传输有效。如果接收方忙拉低 tready背压数据流XDMA 会根据背压暂停数据发送。Block Design 里还要把中断信号接好。XDMA 的中断输出一般是多个 irq 通道我习惯用一个 Concat IP 把 H2C、C2H 各通道中断并成一个再接到 MicroBlaze 或 PS 的中断控制器。如果不上 PS也要把中断引到引脚方便驱动注册中断处理函数。没有正确的中断连接DMA 完成事件就无法通知主机软件会一直等待。4. PCIe 调试技巧从点不亮到跑满带宽4.1 设备枚举不到先按这个顺序查PCIe 调试最让人崩溃的就是插上板卡后操作系统完全找不到设备。这时候别急着怀疑 XDMA IP 配置先按下面的顺序一层层查第一步检查供电和复位。FPGA 的 PCIe 端口的供电要足够尤其是多 lane 高速度时电源跌落会导致链路训练反复失败。检查 PERST 信号是否正常释放主机端会给板卡发复位信号如果 FPGA 复位逻辑把它屏蔽了链路永远起不来。第二步查参考时钟。PCIe 参考时钟一般是 100 MHz精度要求通常在 ±300 ppm 以内。用示波器看波形不一定能发现频偏最好用频谱仪或者用 FPGA 内部监测。参考时钟不稳的最常见后果就是链路反复训练设备时而出现时而消失。第三步查链路训练状态。用 Vivado 的 Hardware Manager 挂上 ILA把 XDMA 的user_lnk_up信号拉出来观察。如果这个信号始终为低说明链路没有训练成功。常见情况是卡在 Polling 或 Configuration 状态。卡在 Polling基本是参考时钟或收发器问题卡在 Configuration多半是链路宽度协商不一致或者复位问题。第四步查系统里的设备节点。Linux 下用lspci -vWindows 下打开设备管理器。如果能看到 Xilinx VID 为 10ee 的设备但驱动有感叹号说明枚举阶段已经过去问题在驱动或 BAR 配置。4.2 LTSSM 状态机是 PCIe 调试的“心电监护仪”PCIe 链路训练的底层是 LTSSM 状态机调试 PCIe 问题熟悉 LTSSM 状态转换相当于掌握了心电监护仪。状态机主要经历 Detect、Polling、Configuration、L0 等状态L0 才是正常工作状态。我在实际调试时最常用的方法是用 ILA 抓 XDMA 暴露出的链路状态寄存器或者直接抓 LTSSM 编码信号。卡在 Polling.Active 状态多半是发送端和接收端的速率协商失败比如一端支持 Gen3另一端只能 Gen1两边没握手成功。卡在 Configuration.Idle 状态常见原因是 lane 宽度协商不一致比如主板只支持 x1FPGA 配置了 x4又没有开启 lane 反转或极性反转处理。还有一种很隐蔽的情况PCIe 收发器的极性接反了。PCB 布线时 P/N 反接链路训练会间歇性失败。检查原理图和 PCB 走线确认每一 lane 的 P/N 和收发器要求匹配。极性反转选项在有些 Xilinx 系列里可以自动处理但并不是所有板卡都默认开启。4.3 驱动与 BAR 空间问题设备枚举成功但驱动加载失败最常见的是 BAR 空间没正确分配。Linux 下用lspci -v看 BAR 是否被分配了地址如果显示[size1M]但前面没有实际基地址说明固件没分配成功。可以在 BIOS 里调整 PCIe 资源分配策略或者检查 XDMA BAR 配置是否过大超过系统分配上限。Windows 下驱动问题更直接经常出现“无法加载设备驱动”或者感叹号错误 10/43。这种情况我一般先确认驱动是否签了名Windows x64 强制驱动签名没签名或者签名过期的驱动会被拒载。另一个常见原因是 BAR 类型不匹配。比如 XDMA 配置里 BAR 是可预取的驱动却按非预取访问反过来也一样。额外提一句如果你是用 Xilinx Platform Cable USB 下载器调试板卡Windows 偶尔也会报无法加载设备驱动这通常是下载器驱动没装好不是 FPGA 的问题。重新装一下 Cable Drivers或换个 USB 口很多时候就解决了。4.4 跨时钟域与弹性缓冲链路掉线的隐形杀手PCIe 的发送端和接收端各自使用独立的时钟域两侧频率不可能完全一致。为了吸收频率偏差接收端会用一个弹性缓冲配合数据流里的 SKP 有序集合来对齐时钟。这对工程师来说是个重要认知链路稳定性很大程度上依赖时钟质量而不是单纯靠 IP 配置。调试时如果出现链路能枚举但运行一段时间后 suddenly 掉线先怀疑参考时钟和恢复时钟。用示波器看 100 MHz 参考时钟波形再看 FPGA 内部收发器的时钟抖动指标。时钟源尽量选低抖动晶振或时钟芯片不要随便用一个普通晶振凑合。另一个容易忽略的是 AXI 时钟和 PCIe 用户时钟的关系。XDMA 内部会把 PCIe 用户时钟域的数据搬到 AXI 时钟域如果 AXI 时钟和 PCIe 时钟毫无关联且频率差太大跨时钟 FIFO 可能溢出或空读。尽量让 XDMA 的 AXI 时钟来自同一个参考时钟源分频或倍频能减少很多诡异问题。4.5 DMA 传输异常描述符、中断、流控逐个查DMA 传输卡死是 XDMA 调试里最高频的问题。我先说排查顺序描述符、中断、背压。描述符环节先确认主机驱动往描述符环里写的数据是否正确。常见错误是描述符地址没有按 64 字节对齐或者长度字段和实际缓冲区长度不一致。XDMA 对描述符对齐有严格要求地址对齐不对DMA 引擎会一直读描述符失败表现为 DMA 状态寄存器永远停在某个状态。这种问题用逻辑分析仪抓取其实很费劲最直接的方式是看驱动返回的错误码和 XDMA 状态寄存器的错误位。中断环节很影响调试效率。如果中断没配好驱动等不到完成事件整条 DMA 链路就像“发货后没人通知收货”。先确认 XDMA 的中断引脚连接到了处理器再确认中断服务程序能读到正确的中断状态寄存器并在处理完后清中断。MSI 中断模式下还要确认 MSI 地址和数据写入正确否则中断到了主机但无法响应。流控环节主要针对 Stream 模式。AXI Stream 的握手如果没拉对数据流会卡在 FPGA 内部。比如接收方 tready 一直为低数据就会在 XDMA 内部 FIFO 里越堆越满最后溢出错。用 ILA 观察tvalid/tready的波形看看是源头没有数据还是接收方没有就绪。还有一个是我反复强调过的TLAST 位置不对。Stream DMA 传输要靠 TLAST 判断包结束TLAST 永远不拉高传输就一直挂着软件会以为还在等数据。4.6 带宽测试从“能通”到“跑满”设备能枚举、DMA 能传离“能上线”还差一步就是带宽测试。最简单的办法是用 Xilinx 官方提供的 dma 测试程序或者自写驱动发起大块连续读/写。测试时先把缓存行对齐。主机内存缓冲区如果非对齐XDMA 会做多次搬运造成性能下降。推荐用 page-locked 内存或 DMA 一致性内存确保物理地址连续。第二步测试分别用不同传输长度跑从 4KB 到 1MB 往上加记录吞吐。你通常会发现 64KB 之后吞吐趋于平稳。如果吞吐远低于理论值先看链路速率是否正确协商到了 Gen3再查 BAR 和驱动是否限制了 Max Payload Size。Stream 模式下带宽上不去还有一个隐蔽因素用户逻辑端的 TREADY 拉低太频繁。接收端每拉低一次就会在数据流中打一个气泡PCIe 有效载荷利用率就下降一点。要让接收端尽量保持高 TREADY只在 FIFO 半满或关键节流点拉低不要每个周期都抖动。5. 常见问题速查表照着这张表去排错现象可能原因处理方式设备没有被操作系统枚举链路训练失败、参考时钟不稳、供电复位异常查 LTSSM 状态、测 100 MHz 参考时钟、确认 PERST设备枚举了但驱动报错误 10/43驱动未签名、BAR 分配异常、IRQ 冲突重装签名驱动、调整 BAR 配置、检查系统资源DMA 传输一直卡住不完成描述符对齐错误、长度字段错误、TLAST 未拉高核对描述符地址对齐与长度、观察 AXIS 握手信号数据内容错位或偏移TKEEP 掩码错误、数据宽度不匹配、地址偏移检查最后一拍 TKEEP、确认 AXIS 数据宽度一致吞吐远低于预期速率协商失败、Max Payload 限制、TREADY 频繁拉低查看链路速率、调整 BIOS 的 Max Payload、优化用户逻辑背压链路运行一段时间后掉线时钟源抖动大、弹性缓冲溢出、电源纹波大换低抖动时钟、检查电源纹波、抓 PCIe 错误状态中断风暴或中断丢失MSI 配置错误、中断清除逻辑缺失确认 MSI 地址和数据写入、在 ISR 里正确清状态这张表覆盖了我这几年接触到的多数 XDMA 问题。需要注意的是PCIe 问题往往是多因素叠加不是单一原因。所以我建议调试时保持一个原则一次只改一个变量改完重新测试别同时调驱动、改硬件、换时钟否则出了问题你都不知道是哪个改动引起的。写在最后的一点经验XDMA 的 MM 和 Stream 选型本质上不是性能竞赛而是软件模型匹配竞赛。我选型时先问自己一个问题主机 CPU 希望怎么看待这个设备是把它当成一块可寻址内存还是当成一个数据管道答案清晰了接口选型基本就锁定了。不要看着别人用 Stream 跑得爽就无脑跟风你的应用如果是随机访问MM 才是更省事的选择。调试 PCIe 时还有个习惯分享尽量在硬件上留一个 JTAG 调试口和一个板载 ILA 触发引脚。硬件调不通时JTAG 口能帮你看 FPGA 内部状态链路异常时用 ILA 抓 LTSSM 和握手信号比盲猜高效太多。另外保持 XDMA 驱动、Vivado 版本、IP 版本三者尽量匹配跨版本组合偶尔会出现莫名兼容问题换版本最浪费时间。
返回列表