ARTICLE DETAIL

资讯详情

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

FPGA PCIE开发:XDMA IP核配置与AXI4接口实战指南

FPGA PCIE开发:XDMA IP核配置与AXI4接口实战指南 1. 为什么我劝你从XDMA入手而不是自己撸PCIE硬核搞FPGA高速接口的兄弟十个里有八个绕不开PCIE。但说实话Xilinx 7系列那套PCIE硬核直接怼寄存器手册能把你怼到怀疑人生。我最早做Kintex-7的PCIE通信光LTSSM状态机就啃了快两周最后发现——用XDMA IP核同样的功能两天就能跑通上位机读写DDR3。XDMA全称DMA Subsystem for PCI Express是Xilinx官方封装好的PCIE端点解决方案。它把物理层、数据链路层、事务层的脏活累活全包了对外只暴露AXI4接口。你不需要懂TLP包怎么组、流控信用怎么算只要会接AXI4就能让PCIE跑起来。这篇文章就是把我踩过的坑、调通的配置、以及AXI4接口那些容易翻车的细节一次性讲清楚。适合谁看如果你手上有7系列板子Artix-7/Kintex-7/Virtex-7都行想用PCIE跟主机通信又不想从零写PCIE逻辑那XDMA就是你的最优解。我会从IP配置、AXI4接口对接、地址映射、上位机联调几个维度展开每个参数为什么这么设我都会说清楚。2. XDMA IP核配置全流程拆解2.1 器件选型与IP核添加先确认你的器件支持PCIE硬核。7系列里Artix-7只有部分型号带GTP收发器能跑PCIE Gen1 x1Kintex-7和Virtex-7的GTX/GTH收发器支持Gen2甚至Gen3。我手头用的是XC7K325TGen2 x4带宽理论值20Gbps实际跑DMA读写能到1.6GB/s左右够大多数数据采集场景用了。在Vivado里新建工程后IP Catalog搜XDMA找到DMA/Bridge Subsystem for PCI Express。双击打开配置界面第一页是Basic配置PCIe Device / Port Type选PCI Express Endpoint device。除非你要做RCRoot Complex否则别选RC模式RC配置复杂得多而且7系列做RC的案例少踩坑没人帮你。PCIe Block Location自动选就行Vivado会根据你的约束分配GT位置。Lane Width根据板子实际走线选。x4是最常见的x8需要确认金手指和PCB走线都支持。Max Link Speed选5.0 GT/s对应Gen28.0 GT/s对应Gen3。注意Gen3需要额外的均衡配置新手建议先跑Gen2。注意Lane Width和Max Link Speed必须跟你的硬件设计匹配。我见过有人IP配了x8但板子只走了x4结果链路训练只能到x4白白浪费资源。2.2 PCIE ID与BAR配置的关键细节第二页是PCIe ID这里有个大坑Vendor ID和Device ID。默认是Xilinx的10EE和7024如果你只是自己调试用默认值完全没问题。但如果要交付给客户或者装到标准系统里最好改成你自己的ID否则驱动可能识别混乱。Class Code保持默认的Memory Controller或者改成Other都行不影响功能。Subsystem ID一般不用改。接下来是Base Address Registers (BAR)这是重中之重。XDMA支持BAR0和BAR1通常配置如下BAR用途大小建议类型BAR0AXI-Lite控制寄存器1MB32-bitBAR1可选用于DMA描述符或额外寄存器1MB32-bitBAR0映射的是XDMA内部的AXI-Lite从机接口上位机通过它读写用户逻辑的寄存器。大小给1MB足够因为XDMA内部寄存器只占前64KB剩下的空间可以映射你自己的AXI-Lite从机。实操心得BAR0的地址空间一定要在Address Editor里确认映射正确。我有次忘了分配地址结果上位机读出来全是0xFFFFFFFF查了半天以为是链路没训练成功其实是BAR没使能。2.3 DMA与中断配置的取舍第三页是DMA Configuration这里决定你用AXI4-MM还是AXI4-Stream接口AXI4 Memory Mapped勾选后会出现M_AXI接口用于读写DDR或BRAM。这是最常用的模式上位机通过DMA直接搬数据到FPGA的DDR3。AXI4 Stream勾选后出现M_AXIS接口适合高速数据流场景比如ADC采样直接推给PCIE。Number of DMA ChannelsH2CHost to Card和C2HCard to Host各选1个就够除非你做多通道并发。中断配置XDMA支持MSI和MSI-X中断。7系列只支持MSI勾选MSI Enable后中断会通过AXI-Lite接口的irq信号输出。如果你不需要中断可以不勾但DMA完成通知就得靠轮询状态寄存器效率低。踩坑记录MSI中断的Vector数量别乱填7系列最多支持32个Vector。我一开始填了64综合直接报错。2.4 时钟与复位配置第四页是Clock and ResetReference Clock Frequency100MHz是标准值如果你的板子给PCIE的参考时钟是其他频率这里要改。我见过有人板子给的是125MHzIP里没改结果链路死活训练不起来。AXI Clock Frequency这是用户逻辑的时钟通常设250MHz或125MHz。注意这个时钟是XDMA输出的你的AXI4从机必须用这个时钟。AXI-Lite Clock Frequency可以跟AXI Clock同频也可以独立。建议同频省得跨时钟域处理。复位方面XDMA会输出一个axi_aresetn信号低有效。你的用户逻辑复位必须同步到这个信号否则PCIE枚举时可能出问题。3. AXI4接口详解与对接实战3.1 AXI4-MM接口的信号组成XDMA的M_AXI接口是标准的AXI4 Memory Mapped协议包含五个通道读地址通道AR上位机发起读请求时XDMA通过这个通道把地址发给你。读数据通道R你把数据放上去XDMA打包成TLP发给主机。写地址通道AW上位机发起写请求。写数据通道W数据跟着地址过来。写响应通道B你写完数据后给XDMA一个响应。每个通道都有valid和ready握手信号这是AXI4的核心。valid不能等ready这是协议死规定。我见过新手写代码时先判断ready再拉valid结果仿真直接挂死。3.2 AXI4突发传输的地址对齐问题热搜里有人问axi4的fixed burst要求地址对齐吗这里统一回答Fixed burst要求地址必须对齐到传输大小的整数倍。比如你设AxSIZE38字节那地址必须是8的倍数。INCR burst没这个要求但首地址最好也对齐否则跨cache line会影响性能。XDMA的M_AXI接口通常配置为INCR burst因为DMA传输都是连续地址。但如果你自己写AXI4从机要注意AxLEN信号INCR模式下传输长度是AxLEN1。比如AxLEN15就是16次传输。实操技巧在AXI4从机里做地址解码时用AxADDR[31:12]做片选低12位做偏移。这样1MB空间正好对应一个从机简单不易错。3.3 写一个最简单的AXI4-Lite从机上位机通过BAR0读写寄存器走的是AXI-Lite协议。AXI-Lite是AXI4的简化版没有burst每次只传一个数据。下面是一个寄存器读写的Verilog模板module axi_lite_slave ( input wire s_axi_aclk, input wire s_axi_aresetn, // 写地址通道 input wire [31:0] s_axi_awaddr, input wire s_axi_awvalid, output wire s_axi_awready, // 写数据通道 input wire [31:0] s_axi_wdata, input wire [3:0] s_axi_wstrb, input wire s_axi_wvalid, output wire s_axi_wready, // 写响应通道 output wire [1:0] s_axi_bresp, output wire s_axi_bvalid, input wire s_axi_bready, // 读地址通道 input wire [31:0] s_axi_araddr, input wire s_axi_arvalid, output wire s_axi_arready, // 读数据通道 output wire [31:0] s_axi_rdata, output wire [1:0] s_axi_rresp, output wire s_axi_rvalid, input wire s_axi_rready ); reg [31:0] reg0, reg1; // 写逻辑 assign s_axi_awready s_axi_awvalid s_axi_wvalid; assign s_axi_wready s_axi_awvalid s_axi_wvalid; assign s_axi_bvalid s_axi_awvalid s_axi_wvalid; assign s_axi_bresp 2b00; always (posedge s_axi_aclk) begin if (s_axi_awvalid s_axi_wvalid) begin case (s_axi_awaddr[7:0]) 8h00: reg0 s_axi_wdata; 8h04: reg1 s_axi_wdata; endcase end end // 读逻辑 assign s_axi_arready s_axi_arvalid !s_axi_rvalid; assign s_axi_rvalid s_axi_arvalid; assign s_axi_rresp 2b00; reg [31:0] rdata_reg; always (posedge s_axi_aclk) begin if (s_axi_arvalid) begin case (s_axi_araddr[7:0]) 8h00: rdata_reg reg0; 8h04: rdata_reg reg1; default: rdata_reg 32hDEADBEEF; endcase end end assign s_axi_rdata rdata_reg; endmodule这个模板可以直接用注意awready和wready同时拉高是简化处理实际项目中最好分开握手避免死锁。3.4 AXI4-Stream接口的对接要点如果你用AXI4-Stream模式XDMA的M_AXIS接口没有地址只有数据流。关键信号是tvalid、tready、tlast。tlast标记一包数据的结束XDMA会根据它生成TLP的EOP。注意AXI4-Stream的tkeep信号决定有效字节。如果你传的是32位数据tkeep应该是4b1111。我见过有人忘了设tkeep结果上位机收到的数据全是0。4. 地址映射与上位机联调4.1 BAR地址空间的分配逻辑在Vivado的Address Editor里XDMA的BAR0会映射到一段PCIE地址空间。上位机枚举时BIOS或OS会给这段空间分配一个基地址。你的AXI-Lite从机地址必须落在这个范围内。举个例子BAR0大小1MB映射到AXI-Lite地址0x0000_0000到0x000F_FFFF。你的寄存器0在偏移0x00寄存器1在偏移0x04上位机访问基地址0x00就能读到寄存器0。实操心得在Linux下用lspci -vv查看BAR地址然后用devmem工具直接读写。Windows下可以用WinDriver或者自己写驱动。我一般先用Linux验证因为devmem太方便了。4.2 DMA传输的地址配置XDMA的DMA引擎需要知道数据在主机内存的地址和FPGA侧的地址。主机地址通过BAR0的DMA控制寄存器配置FPGA侧地址就是M_AXI的地址。以H2C传输为例上位机分配一段物理连续的内存拿到物理地址。把物理地址写入XDMA的H2C源地址寄存器。把FPGA侧目标地址比如DDR3的0x8000_0000写入H2C目标地址寄存器。写入传输长度启动DMA。XDMA通过M_AXI把数据写到DDR3。C2H反过来FPGA侧是源主机内存是目标。踩坑记录主机内存必须是物理连续的否则DMA会出错。Linux下用kmalloc或者dma_alloc_coherent分配Windows下用MmAllocateContiguousMemory。4.3 中断处理与轮询的取舍MSI中断配置好后DMA完成时XDMA会拉高irq信号。你的用户逻辑可以把这个信号接到中断控制器或者直接轮询XDMA的状态寄存器。轮询的优点是简单不需要中断控制器缺点是占CPU。我一般用中断因为DMA传输通常是大块数据中断开销可以忽略。注意MSI中断的清除方式跟传统INTx不同写1清除。具体看XDMA的寄存器手册别搞错了。5. 常见问题与排查技巧实录5.1 链路训练失败现象Vivado里看到LTSSM状态卡在Detect或者Polling。排查思路检查参考时钟频率是否跟IP配置一致。检查Lane Width是否跟硬件匹配。用IBERT工具扫描眼图确认信号质量。检查复位信号是否释放。我遇到过最坑的一次是参考时钟有但幅度不够IBERT眼图闭合换了个时钟源就好了。5.2 DMA传输卡死现象启动DMA后状态寄存器一直显示Busy。排查思路检查M_AXI的ready信号是否一直为低。如果从机没准备好DMA会一直等。检查地址是否越界。M_AXI地址超出从机范围从机可能不响应。检查时钟是否稳定。AXI Clock如果抖动握手会出错。实操技巧在AXI4从机里加一个超时计数器如果valid拉高超过1000个周期ready还没来就强制拉高ready并报错。这样至少不会卡死。5.3 上位机读出来全是0xFFFFFFFF现象devmem读BAR0返回0xFFFFFFFF。排查思路BAR没使能。检查IP配置里BAR0是否勾选。地址映射错误。检查Address Editor里的地址范围。链路没训练成功。如果PCIE链路没起来BAR访问会返回全F。我一开始以为是驱动问题后来发现是BAR0的Size设成了0Vivado默认不使能。5.4 常见问题速查表问题现象可能原因解决方法LTSSM卡在Detect参考时钟缺失或频率错误检查时钟源确认100MHzDMA一直BusyM_AXI从机未响应检查ready信号加超时逻辑BAR读回全FBAR未使能或链路未训练检查IP配置和LTSSM状态中断不触发MSI未使能或Vector配置错误检查中断配置确认Vector数量数据错位tkeep或wstrb未正确设置检查字节使能信号6. 一些让我少走弯路的经验XDMA这个IP核说难不难说简单也不简单。核心就三点链路训练要成功、AXI4握手要正确、地址映射要匹配。这三点搞定基本就能跑通。我建议新手先用Xilinx的官方Example Design跑一遍确认链路和DMA都能工作然后再改成自己的逻辑。Example Design里包含了完整的AXI4从机和DMA测试代码直接抄作业就行。另外Vivado的ILA集成逻辑分析仪是调试PCIE的神器。把M_AXI的信号抓出来看看握手时序比看波形图快多了。我一般会在M_AXI的valid和ready上各挂一个ILA探针一眼就能看出谁在等谁。最后说个细节XDMA的axi_aresetn信号必须同步到AXI Clock域。如果你用异步复位PCIE枚举时可能出问题。我一般用Xilinx的Processor System Reset IP核把复位同步做好省心。这个IP核后续还可以扩展到多通道DMA、AXI4-Stream直连ADC、甚至做PCIE Switch的上游端口。等你把基础跑通了这些扩展都是水到渠成的事。
返回列表