ARTICLE DETAIL

资讯详情

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

AXI转PCIe工程实战:从IP配置到上板调试与性能优化

AXI转PCIe工程实战:从IP配置到上板调试与性能优化 搞PCIe这种东西最怕的就是“看着教程每一步都点了结果上板一跑全是问题”。我当年第一次在Vivado里配AXI转PCIe的IP核时光是一个DMA通道模式和AXI接口位宽的选择就来回折腾了一周最后发现根本原因是初始配置里把中断类型选错了。这篇文章我把整套流程重新梳理了一遍从IP选型、参数配置到AXI握手和背压处理再到上板调试和性能优化顺序全部串好尽量减少重复踩坑的时间。不管你是刚开始接触FPGA PCIe还是已经能点亮链路但吞吐率上不去的开发者这篇都应该能帮上忙。1. 项目需求拆解与方案选型思路1.1 为什么要把AXI总线转成PCIe先把场景理清楚。FPGA内部所有IP核之间通信基本都跑在AXI总线上这是一种片上总线协议CPU核、DMA控制器、外设控制器都挂在这条总线上。但FPGA要把数据送给电脑主机走的却是PCIe总线这是板级高速串行接口。两者之间必须有一个IP核做桥接把内部AXI事务转换成外部PCIe事务这就是标题里“AXI转PCIe”的核心含义。实际项目里最常见的应用场景有三类高速数据采集卡ADC采完数据进FPGA经过预处理后通过PCIe DMA搬运到主机内存主机上的采集软件直接拿到波形数据做分析。硬件加速器主机把任务描述符和输入数据写到FPGA侧DDRFPGA上部署的AI或信号处理算法跑完后把结果经PCIe回传给主机。测试测量设备逻辑分析仪、误码仪、任意波形发生器等都需要一个稳定的高带宽数据通路和上位机交互。不管哪类场景核心需求其实就一句话在主机CPU和FPGA逻辑之间提供一条高带宽、低延时的双向数据通道。这个通道好不好用很大程度上取决于桥接IP核选得对不对、配得好不好。1.2 方案选型XDMA、7系列集成块还是自研软核这里必须先做一道选择题很多人买完开发板就直接在IP Catalog里搜“PCIe”结果出来一堆选项不知道选哪个。我按实际工程经验帮大家分个类。第一类是Xilinx DMA/Bridge Subsystem for PCIe也就是大家常说的XDMA IP核。这是目前最主流的方案它在硬核PCIe控制器之上帮我们封装好了DMA引擎主机侧有配套驱动用户逻辑侧直接暴露AXI接口。我们不需要自己写DMA描述符管理逻辑只需要在FPGA内部做好AXI从端和主端的逻辑绝大多数项目用这个就能搞定省心。第二类是7 Series Integrated Block for PCIe不包含DMA引擎只提供物理层、数据链路层和事务层的基本功能。对开发者来说相当于只给你一个PCIe控制器上面的DMA搬运、中断控制、描述符解析全部要自己用逻辑实现。好处是灵活坏处是工作量非常大适合要做非标准协议、深度定制DMA的团队。第三类是用PCIe硬核加上MicroBlaze软核用软件去操作BAR空间实现一个“伪DMA”。这种做法在功能验证阶段可以用但性能和稳定性都不够生产级项目不建议碰。我的建议很直接新项目一律选XDMA除非有特殊需求。理由有三点第一XDMA自带的DMA引擎经过大量项目验证稳定性比自研要高出一个量级第二它支持Legacy Interrupt、MSI和MSI-X三种中断方式MSI-X对多队列高性能IO是刚需自己实现非常痛苦第三配套驱动源码完善Windows和Linux都有成熟方案。1.3 开发环境准备正式开始配置IP之前先把Vivado环境弄利索。这里提几个容易被忽略的点几乎每个新手都会卡在这里。安装Vivado时默认会提示是否安装器件支持包如果你只需要7系列或UltraScale系列建议不要全选否则安装包占用空间会非常夸张C盘直接爆破。我一般是只勾当前项目要用的器件系列省下几十GB空间。许可证问题也很常见。不少人装完Vivado打开工程提示“2035”错误这个错误码指的是FlexLM许可证校验失败原因通常是许可证路径没配好或者环境变量LM_LICENSE_FILE写错了。解决办法是把许可证文件路径加进Vivado License Manager的配置里并确认服务器地址或本地文件路径没有拼写错误。另外如果你用的是Windows系统驱动安装这一步非常容易出问题。很多人插上JTAG下载器或PCIe板卡后系统提示“驱动无法识别板子”其实十有八九是驱动文件没有用管理员权限安装或者被杀毒软件拦截了。建议把Vivado安装目录下的XilinxUSB Cable驱动通过设备管理器手动更新选择“从计算机中浏览查找驱动程序”路径指到Vivado安装目录下的data\xip\cable_drivers\nt64。Vivado还存在一个小毛病就是在某些语言环境下打开老工程会出现中文注释乱码这个一般是文件编码不统一造成的建议所有HDL源文件统一使用UTF-8编码并且在Vivado的Text Editor设置里把默认编码也改成UTF-8能减少很多无谓的烦恼。2. IP核创建与关键参数配置全流程2.1 创建XDMA IP核并完成基础配置打开Vivado工程后在IP Catalog里搜索“DMA for PCIe”找到DMA/Bridge Subsystem for PCIe双击创建。进入配置界面后第一页是Basic选项卡这里重点看四个参数Mode选择Advanced还是Basic。Advanced会暴露出更多PCIe配置选项比如设备ID、厂商ID、Class Code等Debug阶段建议直接用Basic它会自动填好一套默认值省事。Lane Width链路宽度4 Lane还是8 Lane视板卡实际走线和金手指定义而定。务必保证FPGA物理引脚和PCIe金手指实际连接的数量一致否则链路只能协商到实际物理链路的宽度。Link Speed链路速率2.5GT/s对应Gen15.0GT/s对应Gen28.0GT/s对应Gen3。新项目通常选Gen3但要注意板卡PCB的走线质量和连接器规格是否支持。PCIe ID和Class CodeBasic模式下会使用默认值如果要安装自签名驱动或有多个相同FPGA板卡需要区分建议在Advanced模式下修改Device ID为自定义值。这里有个容易踩的坑就是Type选项。XDMA支持Endpoint和Root Port两种角色。绝大多数场合FPGA做的是Endpoint也就是被主机枚举的设备。如果你选成了Root Port主机根本识别不到它作为普通PCIe设备整条链路行为完全不一样新手极容易在这里选错。2.2 DMA与AXI接口配置详解XDMA配置界面里有一个非常重要的页面专门配置DMA引擎和AXI接口参数这里直接决定了后续用户逻辑怎么挂上去。在DMA选项卡里你会看到“Number of DMA Read/Write Channels”之类的选项。XDMA默认提供H2C和C2H两个独立DMA通道H2C是Host to Card即主机写数据到FPGAC2H是Card to Host即FPGA把数据读回主机。每个通道又可以配置一个或多个队列。多队列是配合MSI-X中断用的可以实现类似多核并行处理的效果。如果只是单线程搬运大块数据一个队列就够多队列反而增加中断处理的复杂度。AXI接口配置是整个配置流程的重头戏。XDMA内部会暴露出多个AXI接口典型的包括AXI MM Master接口用于C2H方向也就是FPGA主动发起读操作把数据从DDR或逻辑FIFO读到主机内存。AXI MM Slave接口用于H2C方向主机下发数据时XDMA作为AXI主设备写到FPGA侧这时需要FPGA内部提供一个AXI Slave来接收。AXI4-Stream接口用于High Speed Data。如果不想在FPGA内部处理复杂的地址映射可以把XDMA配置为Stream模式数据流直接从主机搬运到FPGA的用户逻辑FIFO里。很多人在配置时纠结选MM还是Stream。我的经验是控制类低速数据用AXI4-Lite即可块数据搬运优先考虑AXI4-Stream因为在Stream模式下不需要产生大量读写地址天然适合连续流的场景。但Stream模式对用户逻辑的FIFO深度和反压处理要求更高这个后面第三节会细讲。接口位宽和数据时钟频率也需要认真选。选择“128-bit 250MHz”和“256-bit 250MHz”带来的吞吐能力差别很大但位宽增加会让内部逻辑的布线压力变大时序收敛变难。通常情况下Gen3 x4链路选128位250MHz就够了Gen3 x8或者想榨干带宽的可以上256位。2.3 自定义AXI外设IP封装光有XDMA还不够大多数情况下我们还需要一个用户逻辑模块挂在AXI总线上。比如做一个数据采集卡FPGA内部需要有一个寄存器控制模块用来启动采集、配置采样率、读取状态这个模块就可以封装成AXI4-Lite从设备。在Vivado里通过Tools菜单下的Create and Package IP可以自动生成一个AXI4-Lite外设模板。这里有几个关键步骤值得记录。首先在Create and Package IP向导里选择Create AXI4 Peripheral软件会自动生成一个带有S_AXI接口的Verilog或VHDL模板其中包含了寄存器读写逻辑的标准实现。这个模板的读写逻辑是可以直接用的但我的建议是不要大改它的时序结构AXI Slave最忌讳的就是在握手信号上画蛇添足。模板默认生成4个寄存器分别是slv_reg0到slv_reg3。举个例子你可以把slv_reg0的第0位定义为“软件触发标志”用户逻辑检测到这个标志后开始采集采集完毕后通过slv_reg1返回状态。这种方式非常简单代码量极少但功能上完全够用。如果不走自定义AXI封装Vivado也内置了很多现成的AXI外设可以直接使用。比如AXI Quad SPI用于挂FlashAXI UART16550用于串口调试AXI GPIO用于面板按键和LED。尤其AXI UART16550平时大家只是拿它做打印日志但如果项目里需要高速串口传输可以把UART接入DMA走DMA通道来搬运数据避免CPU中断频繁。这个思路在很多工控板卡的FPGA设计里都有应用属于典型的“小成本解决大问题”。2.4 时钟与复位电路约束AXI转PCIe这个工程的时钟架构是另一个重点。XDMA IP核的参考时钟来自PCIe的REFCLK引脚一般是100MHz差分为输入。进入IP核后内部会生成用户时钟User Clock这个时钟就是AXI接口的工作时钟。在配置页面里你可以选择用户时钟频率。注意这个用户时钟频率会影响AXI接口能够承载的理论带宽。举个例子XDMA配置为128位AXI数据位宽用户时钟250MHz理论最高带宽是128×250MHz也就是4GB/s接近Gen3 x4链路的物理极限。如果用户时钟只有125MHz理论带宽直接折半再算上协议开销实际带宽会明显不足。如果可以让我有一个建议用户时钟不要低于IP核允许的最大值尤其是要做DMA大数据搬运的项目。时钟频率低虽然时序容易收敛但带宽瓶颈会在后期性能测试阶段爆发出来那时候再改时钟架构牵一发而动全身。复位电路也需要注意。AXI接口的复位信号必须是低电平有效这与很多新手习惯使用的高电平复位不太一样。如果复位极性接反仿真时数据可能看起来正常一上板就死机这是非常经典的低级错误。另外复位释放要和时钟稳定保持足够的时间间隔通常需要几十个时钟周期。时钟结构和复位极性都确定后记得在XDC约束文件里把PCIe的参考时钟引脚、复位引脚都约束好。这里特别提示PCIe复位信号PERST#通常连接到FPGA的全局复位引脚但在开发板上它往往和PCIe硬核的复位逻辑绑定不需要额外用普通GPIO控制。3. AXI协议细节与背压机制3.1 valid/ready握手规则与stall背压逻辑AXI总线上的每一次数据传输都是通过valid和ready这一对信号来完成的。发送方拉高valid表示当前数据有效接收方拉高ready表示当前可以接收数据只有当两个信号同时为高时数据才算真正完成传输。这就和两个人面对面递东西一样一个说“我递了”一个说“我接着”同时发生才算交接完成。这套握手里有一个非常重要的协议规则一旦发送方拉高valid就必须保持valid直到本次握手完成中间不能反悔把valid拉低。这相当于你递东西递到一半不能把手缩回去。但ready信号没有这个限制接收方如果暂时接不了可以在任何时刻把ready拉低这就是背压机制产生的根本原因。在实际工程里背压非常常见。比如XDMA的AXI Stream接口往用户FIFO写数据用户的后续处理模块一堵FIFO满了这时FIFO向AXI接口反馈一个反压信号AXI接口把ready拉低数据就停滞在总线上。整个链条就像一个水管系统下游堵住了上游水流自然就慢下来严重的会造成数据溢出。在写AXI从机逻辑时一个经典误区是为了“防止背压”把ready信号跟数据一起等。我见过有同事写代码非要把数据FIFO里读到数据后才去拉ready结果等了很久valid和ready一直不满足同时为高的条件吞吐率惨不忍睹。正确处理办法是所有可以接收的Slot都要提前把ready置为高只有在FIFO满或内部总线冲突的时候才拉低。也就是说默认是“能接就接”而不是“来了再看”。再看XDMA这一侧它内部的DMA在读主机内存时也是通过AXI读通道的ready来调节节奏的。如果FPGA侧处理不过来读请求会被block住DMA带宽自然下降。所以系统级的性能问题往往可以从AXI握手的活跃程度一眼看出来。3.2 利用FIFO缓冲吸收瞬时反压既然背压无法完全避免我们的目标就是把它对性能的影响降到最小。最直接的手段是在两端之间插入一定深度的FIFO比如AXI4-Stream FIFO IP核。当你把一个数据源和一个数据宿直接相连时只要宿端一阻塞源端就会立刻被反压导致上游链路整体停摆。中间加了FIFO之后相当于加了个蓄水池宿端阻塞时源端的数据可以暂时涌入FIFO给宿端一点喘息时间。这个做法对PCIe链路尤其重要因为PCIe的DMA传输是突发性的主机侧描述符处理逻辑经常会有微小的延迟微小的暂停如果直接传导到FPGA内部逻辑会导致整个发送节奏被打乱。FIFO深度的选择是一个折中。深度太小缓冲能力不够一个大突发就把FIFO塞满。深度太大资源占用多而且数据延迟会增加。我的经验是如果数据率是128位250MHz突发大小在几KB量级FIFO深度选512×128bit到1024×128bit比较合适。纯逻辑FIFO吃资源不算多但如果你用Block RAM实现要关注这个FIFO消耗的BRAM数量是否在预算内。使用FIFO时还要注意一个细节FIFO的读侧计数信号比如rd_data_count是异步时钟域下比较麻烦的信号。如果FIFO两端时钟不同数据计数信号会有不确定性必须谨慎使用或者尽量用同步FIFO只跨一次时钟域。3.3 AXI仲裁器在多主多从场景下的应用当系统里出现两个AXI主设备都想访问同一个从设备时就需要仲裁器了。最简单的例子是XDMA的H2C写通道要把数据写入DDR同时MicroBlaze软核也要访问DDR读写日志这个时候如果DDR控制器只暴露一个AXI Slave端口就必须有一个仲裁器来分配访问权这就是AXI仲裁器的用途。Vivado里自带AXI Interconnect IP核它内部集成了仲裁逻辑可以处理多对多的AXI互联。配置时你可以选择仲裁策略常见的有循环仲裁和优先级仲裁。循环仲裁对多个主机相对公平适合数据流量均匀的场景。优先级仲裁适合有一个主设备必须优先服务的场景比如实时性要求高的数据采集通道但高风险是低优先级主机可能被饿死长时间拿不到总线。仲裁器的位宽和时钟转换功能是另一个作用有时会被忽略。如果你有一个64位AXI主设备和128位AXI从设备AXI Interconnect可以自动完成位宽转换。如果你的主设备时钟是100MHz从设备时钟是250MHz它也能帮忙做跨时钟域处理。这个IP核非常实用但我提醒一句AXI Interconnect在逻辑构面上比较大尤其多主多从全连接时资源消耗很大建议只在必要的地方使用不要什么地方都挂一层Interconnect。3.4 外设接入AXI总线的经典案例理解了AXI总线机制之后再回来看各种AXI外设IP核就通透了。比如AXI Quad SPI它把SPI控制器封装成AXI8-Lite从接口FPGA里的MicroBlaze或软核CPU可以通过AXI总线读写SPI Flash。AXI UART16550同样如此不过如果只做低速日志输出CPU轮询寄存器也能跑不一定非要DMA。但遇到大批量数据要过串口发送时采用DMA传输的效果会明显好很多CPU完全解放出来只负责配置描述符和响应中断。这类外设的存在说明了AXI总线设计的一个重要思想一切皆可以通过总线上挂接IP核来扩展。你不需要为每种外设单独写控制逻辑统一通过AXI地址映射来读写寄存器即可。这种设计在大型FPGA工程里维护性和可迁移性都很好。4. 上板调试与PCIe链路验证4.1 用ILA IP核实时抓取内部信号AXI和PCIe链路调不通的时候仿真只能解决一部分问题。很多问题尤其是和主机驱动、链路协商、实际时序相关的bug必须上板抓信号。此时ILA IP核是最顺手的工具。ILA的使用思路非常简单在需要观察的信号上插入探针把信号连到ILA的输入端口触发条件满足时ILA会把一段时间内的波形存到Block RAM里然后通过JTAG上传到Vivado的硬件管理器显示。实际项目中我一般会抓三类信号XDMA的user_clock和复位信号确认时钟复位是否正常AXI接口的valid、ready、last信号确认数据是否真正在传DMA描述符的状态信号确认主机侧搬运是否启动。配置ILA时有几个参数会影响调试效率。采样深度可以选4096或819230多个信号的情况下8192样本会占不少BRAM但能抓到更长的数据段。触发条件建议设在关键数据包的起始位置比如设一个AXI通道上valid拉高且last为低的组合触发这样能精确抓到一次完整的DMA搬运过程。ILA最容易翻车的地方是触发位置找不到。别急我教你个技巧先把触发条件设成复位信号的下沿先抓一轮确认数据通路是否在跑然后逐步缩小触发条件范围。先确认“链路活没活”再去抓“特定包长什么样”效率会高很多。4.2 PCIe枚举过程与驱动绑定PCIe设备上电后并不是直接就能用。主机的BIOS或操作系统内核要先对PCIe总线进行枚举给设备分配BDF总线号、设备号、功能号读取设备的配置空间分配BAR地址空间和中断资源。整个过程对FPGA开发者来说就像一个黑盒但它直接影响驱动能否找到设备。在Linux系统下枚举完成后可以通过lspci命令查看设备是否出现在PCIe设备列表里。如果你能看到类似“1a:00.0 Memory controller: Xilinx Corporation Device 9038”的输出说明设备枚举成功。此时FPGA端配置空间里的Vendor ID和Device ID就会显示出来这就是你配置XDMA时填的那些ID。如果lspci里什么都看不到先按这个顺序排查板卡是否被系统识别到看主板BIOS的PCIe设备列表。链路是否协商成功在BIOS里或者通过带外管理查看链路状态。FPGA的PCIe参考时钟是否稳定REFCLK没有输入或幅值不够链路不可能up。XDMA配置里的链路宽度和速率是否和主板插槽匹配比如主板槽是x4而IP核配置成x8即使FPGA物理通道都拉出来了系统也只能协商到x4。枚举成功之后还要绑定驱动。XDMA官方驱动的装法在Xilinx文档里有详细说明这里只提一个坑Linux下mknod设备节点时设备号必须和内核注册的major/minor一致否则执行DMA打开操作会一直报No such device。4.3 硬件布局关键点PCIe耦合电容与走线软件和逻辑层面的问题几乎都能通过调试解决但PCIe物理层的问题就难排查了需要返工重画PCB。所以在这里提几个原理图设计和PCB布局的关键点。PCIe高速差分信号线上必须放置AC耦合电容这个电容一般都要求是0.1uF或0.22uF的0402封装。放置位置上需要特别留意业界惯例是要求放在信号的接收端也就是靠近接收器一侧。为什么不能随意靠近发送端这是为了确保发送端看到的直流偏置不受电容影响。实际项目里开发板上电容位置在产品手册里通常会标出来自己做板子时最好严格参照PCIe规范差分走线两侧都要等长阻抗控制按85Ω差分来设计。还有一个经常被忽略的点是REFCLK参考时钟的走线。它必须走专用时钟走线层阻抗要求较高不能和普通数据线一样布线。REFCLK通常也是差分对且AC耦合电容一般要求靠近接收端另外要做包地处理减少对相邻信号的干扰。layout阶段如果发现REFCLK质量差会导致链路训练失败或者误码率升高这种问题查起来极其痛苦。电源质量也不能忽视。PCIe接口有可能需要额外的3.3V和12V电源引脚12V供电质量差会直接导致板卡枚举不稳定。典型的症状是同一块板卡在A机器上能识别插到B机器上就不行。这种问题大概率是电源纹波或者金手指接触不良造成的可以先检查金手指附近是否加了足够的去耦电容。4.4 PCIe带宽测试方法与实测分析链路验证通过后下一步要测试带宽。很多开发者的第一反应是“直接用大块数据搬运测就行”但如果不考虑协议开销和驱动行为测出来的数字往往会让人一头雾水。先看理论极限。PCIe Gen3单通道速率是8GT/sx4链路总速率32GT/s采用128b/130b编码有效数据率是32乘128除以130约等于3.94GB/s。这还不包括事务层包头的开销。如果按64B的Memory Read payload来算每个TLP要额外付20字节左右的包头和CRC开销带宽利用率要再打折扣。所以Gen3 x4链路实际能跑到3.5GB/s到3.7GB/s就已经很优秀了。测试方法上我建议用两层验证。先用官方驱动自带的DMA测试工具做一次双向连续DMA搬运打印出每秒传输的字节数。这个数字代表的是驱动到DMA引擎整条软件链路能达到的带宽。之后在FPGA内部用ILA抓AXI接口的计数看valid和ready均为高的周期占比这个比例直接反映了FPGA侧是否已经满负荷工作。如果AXI接口利用率已经超过90%但总带宽仍然偏低那问题出在PCIe协议层比如payload size设置过小、开启了一些不必要的特性。针对数据块大小建议测试时分别用4KB和1MB两种大小的DMA描述符跑一轮。小的描述符用来测试延迟和中断处理能力大的描述符用来测持续带宽。如果你发现小描述符场景吞吐异常低大概率是中断处理次数太频繁可以考虑用MSI-X和中断合并机制来改善。4.5 算法IP核接入数据通路的示例AXI转PCIe的工程里数据通路中间往往还会插入一些算法IP核。以CORDIC IP核为例它可以用来做三角函数、开方等数学运算。假设你要从ADC采集I/Q两路数据然后实时计算幅度和相位这个场景就非常适合在AXI数据流中间插入CORDIC。具体做法是ADC数据经过简单的格式转换后通过AXI4-Stream接入CORDIC IP核的输入CORDIC配置成Vector Translate模式输入X和Y通道的数据输出幅度和相位结果再通过AXI4-Stream送往XDMA的C2H接口上传给主机。整个链路都是流式的没有CPU参与数据一路从天线到上位机效果非常好。使用CORDIC这类IP核时要注意输入输出的数据格式。大多数版本默认使用带符号定点数需要自己处理好整数位和小数位的对齐。如果数据位宽不匹配可以在CORDIC前后加AXI宽度转换模块。这里强烈建议在插入算法IP之前先在CORDIC后面加一个AXI Stream FIFO把两个模块之间的握手节奏解耦否则某一拍算法模块输出延迟变化就会把整条流水线卡住。5. 性能优化技巧与常见问题排查5.1 提升DMA吞吐率的关键参数调整性能优化是最有意思也最考验功力的阶段。我总结了几个立竿见影的优化方向。第一增大DMA描述符的命令环深度。XDMA驱动在初始化时会给每个DMA通道分配描述符环环深太浅时主机侧必须频繁写Doorbell寄存器来通知DMA引擎取新的描述符产生大量PCIe配置写操作严重消耗带宽。把描述符数量从32增加到256或1024效果非常明显。但这个值的增加会占用主机内存要在驱动代码里找到对应的宏或参数修改。第二启用中断合并。默认情况下DMA每搬运完一个描述符就触发一次中断高吞吐率时每秒中断数可以到几十万次CPU忙于处理中断吞吐反而下降。通过XDMA的Interrupt Moderation机制把中断合并到每N个描述符或每T微秒触发一次CPU占用率下降吞吐率往往能提升10%到20%。第三优化AXI数据位宽和地址对齐。DMA搬运时如果源地址或目标地址不是64B对齐PCIe的TLP会被拆分一个请求被拆成多个效率骤降。因此建议在主机侧分配内存时使用对齐到页大小甚至更大粒度的内存块FPGA内部涉及DDR读写的地址也尽量做到大块连续。第四调整DMA读写请求的有效载荷大小。PCIe设备配置空间的Max Payload Size字段控制着单个TLP能携带的最大数据字节数。如果FPGA侧的EP配置允许可以尝试用驱动把MPS设置到512B或更大这样大块连续搬运时每个TLP包含的有效数据更多带宽利用率会更好。5.2 吞吐率上不去时的排查顺序如果上面这些参数都调过以后吞吐率还是卡在一个不合理的值上我建议按下面的顺序重新排查一遍。先看链路协商状态用lspci -vv确认LinkCap、LinkStatus里的速率和宽度是否真为8GT/s和x4。如果协商到了Gen1 x1那吞吐率不可能高这根物理链路配置或PCB走线有关。再看驱动侧DMA传输是否真正在并行执行。有些驱动在实现时把H2C和C2H两个方向串行化了导致双向传输时总带宽减半。这种问题的解决方式要看驱动代码尽量确保两个方向可以独立发起多个DMA传输。然后看FPGA内部的数据通路是否存在瓶颈。可以用ILA同时抓XDMAAXI接口和用户逻辑FIFO的读写计数。如果XDMA的读valid一直高但用户逻辑FIFO的数据输出一直有间隙说明瓶颈在用户逻辑自身比如算法IP核处理速度不够。这种情况需要优化的是用户逻辑的时间安排而不是PCIe本身的配置。最后别忘了主机侧内存带宽和CPU频率。曾经遇到过一个案例开发板在服务器上跑满带宽在台式机上只能跑一半最后发现是台式机DDR内存频率太低双通道没插对。5.3 常见问题速查表把工程实践中遇到的典型问题整理成表格方便大家直接对号入座。现象可能原因排查/解决办法Vivado报许可证2035错误许可证路径配置错误或环境变量丢失检查License Manager路径和LM_LICENSE_FILE变量下载器驱动无法识别板子驱动安装权限不足或被安全软件拦截手动更新驱动路径指向安装目录下cable_drivers生成比特流失败时序不收敛用户时钟频率过高或XDC约束缺失降低时钟频率检查虚拟时钟约束优先收敛复位路径中文注释乱码源文件编码不统一统一使用UTF-8编码并修改Vivado编辑器设置lspci看不到设备链路协商失败或REFCLK异常检查金手指供电、参考时钟和XDMA链路配置DMA搬运数据出错地址未对齐或描述符长度错误检查主机内存对齐FPGA侧地址递进逻辑吞吐率只有理论值的一半MPS过小、中断太频繁或地址非连续增大MPS启用中断合并使用大块连续内存板卡在部分主机无法识别12V电源纹波大或金手指接触不良增加电源去耦电容用橡皮清洁金手指并重新插拔时钟设置中找不到800MHz选项该FPGA系列PLL输出范围不够改用MMCM级联或选择支持的输出频率不要硬设5.4 我的实战体会最后分享几点个人感觉最有价值的心得。第一PCIe和AXI的调试一定要分层。先确保物理层链路能up再谈AXI通不通最后才去优化性能。我见过太多人链路还没协商好就开始调DMA描述符纯属浪费时间。第二仿真阶段的AXI验证不可跳过。就算上板条件很紧张也至少要跑一轮带XDMA模型的数据通路的仿真把地址对齐、突发边界、FIFO满空这些边界情况都点亮一遍。很多在板上很难复现的偶发数据错乱其实在仿真阶段就能暴露出来。第三给自己留个调试后门。设计时就要想到后期调试需要观察哪些内部信号提前把ILA调试核心固定在顶层或预留调试端口避免后期改版重新综合布线。上板调试时间往往比设计时间更紧这一步能救急。第四注意接口电平与时序约束。XDMA的AXI接口在综合时属于跨时钟域接口务必使用同步约束比如set_clock_groups把相关时钟设为不同组。不做约束时序分析可能掩盖跨时钟域问题导致上板后偶发数据错误很难定位。这个工程做完之后你会发现AXI转PCIe的整个体系其实并不神秘。核心就是把PCIe物理层的链路拉通把AXI总线的握手节奏控制好把数据通路的瓶颈一个个排除掉。真正花时间的不是配置IP核而是把整个链路从软件到硬件全链路的细节打通。希望这篇文章能帮你少走点弯路尽早看到自己的数据在PCIe上跑起来。
返回列表