1. 最终结论
跳转到“1. 最终结论”飞凌 OK8MP(i.MX8MP)已经能够通过 PCIe 访问达芬奇 Pro(XC7A200T)上的 XDMA,并经 AXI Memory Mapped 接口读写板载 DDR3。
以下项目均经过硬件实测,而不只是通过 Vivado 设计校验:
- i.MX8MP PCIe Root Complex 与 FPGA Endpoint 成功建立链路;
- Linux 枚举到 Xilinx 设备
10ee:7011; - 链路实际工作在 PCIe Gen1 x1;
- MSI 已启用,
xdma驱动自动绑定; /dev/xdma0_h2c_0和/dev/xdma0_c2h_0均已生成;- 4 KiB 和 1 MiB 的地址 0 双向传输及数据比较通过;
- DDR3 非零地址
0x00100000的 1 MiB H2C 写入、C2H 读回和逐字节比较通过; - 测试后没有新增 XDMA timeout 或 PCIe AER 错误。
当前成功的数据通路是:
flowchart LR SOC["i.MX8MP Linux<br/>PCIe Root Complex"] PCIE["PCIe Gen1 x1"] XDMA["XDMA Endpoint<br/>AXI-MM"] SMC["SmartConnect<br/>双时钟域"] MIG["MIG 7 Series"] DDR["板载 DDR3<br/>512 MiB"]
SOC <--> PCIE <--> XDMA <--> SMC <--> MIG <--> DDR当前只验证了 SoC、PCIe、XDMA 和 DDR3 基础数据通路。AD7768 采集逻辑、异步 FIFO、DDR 环形缓冲区和连续采集协议仍属于下一阶段,不能把本次结果表述成“AD7768 连续采集已经完成”。
2026-08-09 更新:AD7768-4 TDM 接收、异步 FIFO、AXI DMA S2MM、AXI-Lite 控制及新 bitstream 已完成仿真和 Vivado 实现验证,详见 AD7768-4 经 Artix-7、DDR3 和 PCIe 传输到 i.MX8MP。本页第 12 节保留为当时的历史设计计划;AD7768 真板采集仍需接线后验证。
2. 软硬件条件
跳转到“2. 软硬件条件”2.1 硬件
跳转到“2.1 硬件”| 项目 | 实际条件 |
|---|---|
| SoC 开发板 | 飞凌 OK8MP,处理器为 NXP i.MX8MP |
| FPGA 开发板 | 正点原子达芬奇 Pro,XC7A200T-FBG484-2 |
| FPGA 外部存储器 | 板载 DDR3,32 bit 数据宽度,总地址空间 512 MiB |
| PCIe 角色 | i.MX8MP 为 Root Complex,FPGA 为 Endpoint |
| 转接线 | PCIe x1 转机械 x16 延长线,实际只使用 Lane 0 |
| FPGA 调试 | Digilent JTAG,器件名 xc7a200t_0 |
| SoC 调试串口 | COM10,115200 8N1,无流控 |
| FPGA 板级时钟 | 50 MHz,连接到 FPGA R4 |
| PCIe 参考时钟 | 100 MHz 差分参考时钟,由 PCIe 接口提供 |
PCIe x1 转 x16 线只改变机械连接形式,不会把 x1 变成 x16,也不会自动提高速率。当前工程只使用一条收发 Lane,因此最终链路是 x1。
连接和上电时应注意:
- 断电状态下插拔 PCIe 转接线;
- i.MX8MP 与 FPGA 开发板按各自开发板要求供电,不依赖转接线为整块 FPGA 板供电;
- 保证两板公共地和 PCIe REFCLK、RX/TX、PERST# 连通;
- JTAG 只负责配置和调试 FPGA,不承担 PCIe 数据传输;
- FPGA 使用 JTAG 临时烧录时,断电会丢失 bitstream;正式启动应考虑将 bitstream 固化到配置 Flash。
2.2 软件
跳转到“2.2 软件”| 项目 | 版本或路径 |
|---|---|
| Vivado | AMD Vivado 2026.1,BASIC 许可证 |
| FPGA 最终工程 | C:\Users\mtxl\Desktop\project_analysis\adfpga |
| 官方对照工程 | C:\Users\mtxl\Desktop\project_analysis\6_pcie_xdma_ddr |
| 官方 PCIe 指南 | C:\Users\mtxl\Desktop\project_analysis\docs\FPGA\达芬奇Pro之PCIe开发指南(Linux系统版)-V2.0.pdf |
| OK8MP Linux SDK | Z:\fling\OK8MP-linux-sdk |
| Linux 内核 | 5.4.70-2.3.0 |
| XDMA 驱动仓库 | AMD/Xilinx dma_ip_drivers |
| XDMA 驱动版本日志 | Xilinx XDMA Reference Driver xdma v2025.2.0 |
| 最终 bitstream | adfpga\fpga_pcie.runs\impl_1\system_wrapper.bit |
| 最终 Vivado 脚本 | adfpga\connect_xdma_mig.tcl |
3. 设计原则
跳转到“3. 设计原则”本次先建立最小且可验证的 PCIe 存储器回环基线:
XDMA M_AXI -> SmartConnect -> MIG S_AXI -> DDR3这样设计的原因是:
- XDMA 的 H2C 操作把主机数据写入 FPGA AXI 地址空间;
- C2H 操作从同一 AXI 地址空间读回数据;
- MIG 把 AXI 请求转换成 DDR3 时序;
- DDR3 提供大容量缓存,BRAM 不适合作为持续高速采集的主存储;
- 先证明基础通路,再接入 AD7768,可以把 PCIe、DDR 和采集逻辑的问题分开定位。
本基线关闭了 XDMA AXI-Lite Master,所以不会生成 /dev/xdma0_user。这不是驱动异常,而是当前 Endpoint 的预期配置。当前可以使用 H2C/C2H DMA 通道访问 DDR3。
4. Vivado Block Design 配置
跳转到“4. Vivado Block Design 配置”4.1 XDMA
跳转到“4.1 XDMA”最终工程使用 DMA/Bridge Subsystem for PCI Express,关键参数如下:
| 参数 | 值 | 解释 |
|---|---|---|
| PCIe 功能 | DMA Endpoint | FPGA 是 Endpoint,i.MX8MP 是 Root Complex |
| DMA 接口 | AXI Memory Mapped | H2C/C2H 请求直接访问 AXI 地址空间 |
| Link Width | x1 | 只使用 Lane 0 |
| Maximum Link Speed | 2.5 GT/s | 对应 Gen1;这是当前已验证配置 |
| AXI Data Width | 64 bit | XDMA M_AXI 数据宽度 |
| AXI Clock | 62.5 MHz | 当前 Gen1 x1 配置生成的 axi_aclk |
| H2C Channels | 1 | 生成 /dev/xdma0_h2c_0 |
| C2H Channels | 1 | 生成 /dev/xdma0_c2h_0 |
| User Interrupts | 1 | 当前将请求输入固定为 0,尚未使用 |
| MSI | Enabled | Linux 实测 MSI: Enable+ |
| MSI-X | Disabled | 当前不使用 |
| AXI-Lite Master | Disabled | 因此没有 user BAR 设备节点 |
| Vendor ID | 10ee | Xilinx |
| Device ID | 7011 | Linux 实际枚举结果 |
| PLL | CPLL | 与官方成功工程一致 |
必须区分“转接线支持 PCIe 2.0”和“Endpoint 已配置为 Gen2”。当前 XDMA 参数明确是 2.5 GT/s,lspci 也显示 Speed 2.5GT/s,所以当前成功基线是 Gen1 x1。以后升级 Gen2 时,应单独修改 XDMA、重新实现并重新做完整回归,不能只改文档名称。
4.2 MIG 7 Series DDR3
跳转到“4.2 MIG 7 Series DDR3”达芬奇 Pro 板载存储器在 MIG 中使用官方工程的兼容器件配置。即使 Vivado 列表中没有板上 Nanya 器件的精确型号,也不要随意选择几何结构不同的器件。
最终 MIG 参数来自官方成功工程:
| 参数 | 值 |
|---|---|
| Memory Type | DDR3 SDRAM Components |
| Compatible Part | MT41J128M16XX-125 |
| 控制器数量 | 1 |
| DDR 数据宽度 | 32 bit |
| 容量 | 512 MiB |
| Row / Column / Bank | 14 / 10 / 3 |
| DDR 时钟周期 | 2500 ps,即 400 MHz |
| PHY:Controller | 4:1 |
| MIG 输入时钟 | 200 MHz |
| AXI 数据宽度 | 256 bit |
| AXI 地址宽度 | 29 bit |
| AXI ID 宽度 | 4 bit |
| ECC | Disabled |
| Data Mask | Enabled |
| Address Mapping | BANK_ROW_COLUMN |
| System Clock Type | No Buffer |
| Reference Clock Type | No Buffer |
MIG 的 DDR 引脚来自其内部 mig_a.prj。不要再在顶层 pins.xdc 重复约束 DDR3 全部引脚,否则容易与 MIG 的 scoped constraints 冲突。
4.3 Clock Wizard
跳转到“4.3 Clock Wizard”| 参数 | 值 |
|---|---|
| 输入 | 50 MHz |
| 输出 | 200 MHz |
| Primitive | MMCM |
| Reset | Active Low,端口名 resetn |
| Clock output buffer | BUFG |
50 MHz 板级时钟经 Clock Wizard 生成 200 MHz,同时连接 MIG 的 sys_clk_i 和 clk_ref_i。clk_wiz_0/locked 连接 MIG sys_rst;在当前 MIG 极性配置下,时钟稳定后高电平释放 MIG 系统复位。
4.4 SmartConnect
跳转到“4.4 SmartConnect”SmartConnect 负责连接 XDMA 和 MIG 的不同时钟域:
| 参数 | 值 |
|---|---|
| Slave Interfaces | 1 |
| Master Interfaces | 1 |
| Clock Inputs | 2 |
HAS_ARESETN | 1 |
HID_PARAM_26_1 | 1 |
| Advanced Property | legacy_low_area_mode 1 |
连接关系:
xdma_0/M_AXI -> axi_smc/S00_AXIaxi_smc/M00_AXI -> mig_7series_0/S_AXIxdma_0/axi_aclk -> axi_smc/aclkmig_7series_0/ui_clk -> axi_smc/aclk1xdma_0/axi_aresetn -> axi_smc/aresetnaclk 是 XDMA 一侧的时钟,aclk1 是 MIG UI 一侧的时钟。SmartConnect 在两侧之间完成必要的跨时钟处理。不要把 MIG ui_clk 和 XDMA axi_aclk 直接短接。
4.5 Processor System Reset
跳转到“4.5 Processor System Reset”MIG UI 域复位关系如下:
mig_7series_0/ui_clk -> proc_sys_reset_0/slowest_sync_clkmig_7series_0/ui_clk_sync_rst -> proc_sys_reset_0/ext_reset_inmig_7series_0/mmcm_locked -> proc_sys_reset_0/dcm_lockedproc_sys_reset_0/peripheral_aresetn -> mig_7series_0/aresetn两个 Constant 必须分开:
xlconstant_0 = 1'b0 -> proc_sys_reset_0/mb_debug_sys_rst -> xdma_0/usr_irq_req[0]
xlconstant_1 = 1'b1 -> proc_sys_reset_0/aux_reset_in这是本次调试最关键的修复。proc_sys_reset_0 的参数是:
C_AUX_RESET_HIGH = 0因此 aux_reset_in 是低有效输入:
- 接 0:永久断言辅助复位;
- 接 1:保持复位释放。
原工程错误地把 aux_reset_in 接到常数 0,导致 MIG AXI 接口一直处于复位状态。PCIe 可以枚举、XDMA 驱动也可以加载,但所有 H2C/C2H 描述符都无法完成,表现为:
completed_desc_count=0engine BUSYH2C/C2H timeout官方工程生成 HDL 的正确连接是:
.aux_reset_in(1'b1).mb_debug_sys_rst(1'b0)这证明故障不是 PCIe 物理层、Linux 驱动或 DDR 地址映射问题,而是复位极性错误。
4.6 地址映射
跳转到“4.6 地址映射”XDMA 的 AXI 主地址空间映射到 MIG:
Base address: 0x00000000Range: 512 MiB对应 Tcl:
assign_bd_address -offset 0x00000000 -range 512M \ -target_address_space [get_bd_addr_spaces xdma_0/M_AXI] \ [get_bd_addr_segs mig_7series_0/memmap/memaddr] -force因此对 /dev/xdma0_h2c_0 或 /dev/xdma0_c2h_0 执行 lseek(fd, offset, SEEK_SET) 后进行读写,offset 就是 FPGA DDR3 AXI 地址。
5. 引脚约束
跳转到“5. 引脚约束”顶层约束文件:
C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.srcs\constrs_1\new\pins.xdc已确认的关键引脚:
| 信号 | FPGA 引脚 | 电气标准或说明 |
|---|---|---|
sys_clk | R4 | 50 MHz,LVCMOS15 |
sys_rst_n | U7 | Active Low,LVCMOS15 |
pcie_ref_clk_p[0] | F6 | PCIe 100 MHz 差分参考时钟正端 |
pcie_mgt_rxp[0] | D9 | GTP Lane 0 接收正端 |
pcie_mgt_txp[0] | D7 | GTP Lane 0 发送正端 |
pcie_rst_n | N15 | PCIe PERST#,LVCMOS33 |
lnk_up_led | W7 | XDMA user_lnk_up 指示,LVCMOS15 |
差分对负端由 FPGA 专用差分资源和对应管脚关系确定,不应把普通单端 GPIO 任意配成负端。
时钟约束:
create_clock -period 20.000 -name sys_clk [get_ports sys_clk]
set_property CLOCK_DEDICATED_ROUTE BACKBONE \ [get_nets system_i/clk_wiz_0/inst/clk_in1_system_clk_wiz_0_0]这里使用 CLOCK_DEDICATED_ROUTE BACKBONE 是因为开发板把 50 MHz 时钟接在 R4,最终工程与官方工程保持一致。它不是可以忽略任意时钟布线错误的通用开关。
6. 使用最终 Tcl 重新配置工程
跳转到“6. 使用最终 Tcl 重新配置工程”最终脚本只有一个:
C:\Users\mtxl\Desktop\project_analysis\adfpga\connect_xdma_mig.tcl该脚本用于修复和重建现有 fpga_pcie.xpr 的 Block Design 连接。它要求工程中已经存在以下预配置 IP:
xdma_0util_ds_bufxlconstant_0mig_7series_0clk_wiz_0proc_sys_reset_0它会完成:
- 删除早期失败的 AXI Clock Converter、旧 SmartConnect、AXI GPIO 和超出 BASIC 许可证限制的 AXI ILA;
- 创建正确的双时钟 SmartConnect;
- 创建常数 1,并修复
aux_reset_in; - 重建 XDMA、SmartConnect、MIG 的 AXI、时钟和复位连接;
- 重新创建 512 MiB DDR 地址映射;
- 执行
validate_bd_design并保存 Block Design; - 可选执行完整 bitstream 构建或 JTAG 烧录。
6.1 Vivado GUI 中执行
跳转到“6.1 Vivado GUI 中执行”- 打开
adfpga\fpga_pcie.xpr; - 打开底部 Tcl Console;
- 执行:
source C:/Users/mtxl/Desktop/project_analysis/adfpga/connect_xdma_mig.tcl成功时应出现:
FINAL VALIDATION PASSEDPCIe REFCLK interface : pcie_refPCIe PERST# port : pcie_rst_nXDMA M_AXI DDR3 : 0x00000000 / 512M6.2 命令行完整构建
跳转到“6.2 命令行完整构建”确保 Vivado 2026.1 的 bin 已加入 PATH,然后执行:
cd C:\Users\mtxl\Desktop\project_analysis\adfpgavivado -mode batch -source connect_xdma_mig.tcl -tclargs build脚本依次重置综合、运行实现并生成 bitstream。最终文件应位于:
C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.runs\impl_1\system_wrapper.bit本次成功构建结果:
DRC Errors: 0Implementation Critical Warnings: 0Implementation Errors: 0WNS: +0.951 nsTNS: 0综合日志中的大量普通 warning 不能只看数量判断成败。必须重点确认 DRC、实现、时序和 bitstream 生成结果。
6.3 JTAG 烧录
跳转到“6.3 JTAG 烧录”命令行烧录:
cd C:\Users\mtxl\Desktop\project_analysis\adfpgavivado -mode batch -source connect_xdma_mig.tcl -tclargs program成功时应看到:
End of startup status: HIGHFPGA PROGRAMMED: ...system_wrapper.bitno supported soft debug core(s) 只表示当前 bitstream 没有 ILA/VIO 等调试核,不表示烧录失败。Vivado BASIC 对完整 AXI Monitor ILA 的探针数量有限制,因此最小可用基线中不放置完整 AXI ILA。
7. 上电和枚举顺序
跳转到“7. 上电和枚举顺序”PCIe Endpoint 必须在 i.MX8MP 枚举 PCIe 总线时已经配置完成。推荐顺序:
- 两板断电并确认 PCIe 线连接可靠;
- FPGA 上电并通过 JTAG 烧录正确 bitstream;
- 对 i.MX8MP 执行硬复位或重新上电;
- 等待 Linux 启动;
- 在
COM10以 root 登录并检查 PCIe。
如果先启动 i.MX8MP、后烧 FPGA,Root Complex 可能已经错过 Endpoint。烧录后应重启 i.MX8MP,不应仅反复 modprobe xdma。
在板端允许 SysRq 时,可通过串口触发硬重启:
echo 1 > /proc/sys/kernel/sysrqecho b > /proc/sysrq-triggerecho b 不会卸载文件系统或执行正常关机,只适合调试恢复,执行前应确保没有需要保存的数据。
8. i.MX8MP Linux 准备
跳转到“8. i.MX8MP Linux 准备”8.1 内核配置
跳转到“8.1 内核配置”进入内核源码:
cd ~/fling/OK8MP-linux-sdk/OK8MP-linux-kernelmake ARCH=arm64 OK8MP-C_defconfig确认 PCIe、MSI、AER 和模块支持:
grep -E '^CONFIG_PCI=|^CONFIG_PCIEPORTBUS=|^CONFIG_PCI_IMX6_HOST=' .configgrep -E '^CONFIG_PCI_MSI=|^# CONFIG_PCI_MSI' .configgrep -E '^CONFIG_PCIEAER=|^# CONFIG_PCIEAER' .configgrep -E '^CONFIG_MODULES=|^CONFIG_MODVERSIONS=' .config本次已确认:
CONFIG_PCI=yCONFIG_PCIEPORTBUS=yCONFIG_PCI_IMX6_HOST=yCONFIG_PCI_MSI=yCONFIG_PCIEAER=yCONFIG_MODULES=yCONFIG_MODVERSIONS=y确认内核发布版本和符号表:
make -s ARCH=arm64 kernelreleasecat include/config/kernel.releasels -lh Module.symverstest -s Module.symvers && echo "Module.symvers OK" || echo "Module.symvers missing"本次对应:
5.4.70-2.3.0Module.symvers OK.config、Module.symvers、内核源码和开发板正在运行的 Image 必须来自同一次内核构建。只要其中一个不匹配,启用 CONFIG_MODVERSIONS 后就可能出现 invalid module format 或符号版本错误。
8.2 编译 XDMA 驱动
跳转到“8.2 编译 XDMA 驱动”首先加载飞凌 SDK 交叉编译环境;具体脚本按 SDK 实际安装方式执行。本次编译器为:
aarch64-poky-linux-gcc确认环境:
echo "$CROSS_COMPILE"which aarch64-poky-linux-gcc本次结果:
CROSS_COMPILE=aarch64-poky-linux-/opt/forlinx-ok8mp/6.18-qt6.11/sysroots/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux-gcc设置路径:
export KERNEL_SRC=~/fling/OK8MP-linux-sdk/OK8MP-linux-kernelexport XDMA_SRC=~/fling/OK8MP-linux-sdk/dma_ip_drivers/XDMA/linux-kernelXDMA 的模块 Makefile 位于 linux-kernel/xdma/,不是 linux-kernel/ 根目录。编译命令:
make -C "$KERNEL_SRC" \ ARCH=arm64 \ CROSS_COMPILE="$CROSS_COMPILE" \ M="$XDMA_SRC/xdma" \ modules产物:
~/fling/OK8MP-linux-sdk/dma_ip_drivers/XDMA/linux-kernel/xdma/xdma.ko检查架构和 vermagic:
file "$XDMA_SRC/xdma/xdma.ko"modinfo "$XDMA_SRC/xdma/xdma.ko" | grep -E 'filename|name|vermagic'本次结果:
ELF 64-bit LSB relocatable, ARM aarch64name: xdmavermagic: 5.4.70-2.3.0 SMP preempt mod_unload modversions aarch648.3 把 xdma.ko 传入开发板
跳转到“8.3 把 xdma.ko 传入开发板”主机端文件:
Z:\fling\OK8MP-linux-sdk\dma_ip_drivers\XDMA\linux-kernel\xdma\xdma.ko有可用网络时优先使用 scp。只有串口可用时,推荐 ZMODEM:
cd /tmprz -y在串口软件中选择 xdma.ko,完成后必须校验:
ls -l /tmp/xdma.kosha256sum /tmp/xdma.ko本次实际使用串口 Base64 传输。传输二进制文件时必须关闭回显,并比较文件长度和 SHA-256;不能仅凭“命令结束”判断文件完整。
本次模块信息:
Size: 2144096 bytesSHA-256: 75e22b9b01aa67b0b18436668925b768ee0b1574b6a8f70e75f9e1b9cb6182c88.4 安装和自动加载
跳转到“8.4 安装和自动加载”mkdir -p /lib/modules/$(uname -r)/extracp /tmp/xdma.ko /lib/modules/$(uname -r)/extra/xdma.kodepmod -amodinfo xdma手动加载:
modprobe xdma确认 Endpoint 可以稳定枚举后,再配置开机自动加载:
printf '%s\n' xdma > /etc/modules-load.d/xdma.confsync本次重启后驱动已自动绑定,说明持久化安装和自动加载有效。
9. PCIe 和 XDMA 验证
跳转到“9. PCIe 和 XDMA 验证”9.1 检查枚举和链路
跳转到“9.1 检查枚举和链路”lspci -nn -s 01:00.0lspci -vv -s 01:00.0 | grep -E 'LnkCap:|LnkSta:|MSI:|Kernel driver'dmesg | grep -Ei 'imx6q-pcie|pcie|pci|link|xdma'关键实测输出:
01:00.0 Serial controller [0700]: Xilinx Corporation Device [10ee:7011]MSI: Enable+ Count=1/1 Maskable- 64bit+LnkCap: Speed 2.5GT/s, Width x1LnkSta: Speed 2.5GT/s (ok), Width x1 (ok)Kernel driver in use: xdmaimx6q-pcie 33800000.pcie: Link up, Gen1检查设备节点:
ls -l /dev/xdma*本次关键节点:
/dev/xdma0_control/dev/xdma0_h2c_0/dev/xdma0_c2h_0/dev/xdma0_events_0 ... /dev/xdma0_events_15没有 /dev/xdma0_user 是因为 AXI-Lite Master 被关闭,与当前设计一致。
9.2 地址 0 的基础回环
跳转到“9.2 地址 0 的基础回环”先生成测试数据:
dd if=/dev/urandom of=/tmp/tx.bin bs=4096 count=1写入 FPGA DDR:
dd if=/tmp/tx.bin of=/dev/xdma0_h2c_0 bs=4096 count=1读回:
dd if=/dev/xdma0_c2h_0 of=/tmp/rx.bin bs=4096 count=1cmp /tmp/tx.bin /tmp/rx.binecho "CMP_RC=$?"sha256sum /tmp/tx.bin /tmp/rx.bin4 KiB 实测结果:
H2C_RC=0 C2H_RC=0 CMP_RC=0SHA-256: 8a9894eff33f3f1f1912b84629ec677628031db6a80b7981c801e04b39115e51把 bs 改为 1M 再测试 1 MiB:
dd if=/dev/urandom of=/tmp/tx_1m.bin bs=1M count=1dd if=/tmp/tx_1m.bin of=/dev/xdma0_h2c_0 bs=1M count=1dd if=/dev/xdma0_c2h_0 of=/tmp/rx_1m.bin bs=1M count=1cmp /tmp/tx_1m.bin /tmp/rx_1m.binsha256sum /tmp/tx_1m.bin /tmp/rx_1m.bin实测结果:
TEST_1M_H2C=0TEST_1M_C2H=0TEST_1M_CMP=0SHA-256: 7da43bdc05449d60a2efd82e408ad7daac2f6b8612aee45bb945ab7546b1f3aa9.3 非零 DDR 地址验证
跳转到“9.3 非零 DDR 地址验证”BusyBox dd 对字符设备的 seek/skip 处理容易造成误判。XDMA 官方工具 dma_to_device 和 dma_from_device 未预装时,应使用 lseek 明确设置设备偏移。
板端虽然有 gcc,但没有安装 libc 开发头文件。下面的最小程序不依赖头文件,可直接编译,用于在 DDR 地址 0x00100000 写入和读回 1 MiB:
typedef unsigned long usize;typedef long ssize;typedef long off_t;extern int open(const char *, int, ...);extern off_t lseek(int, off_t, int);extern ssize write(int, const void *, usize);extern ssize read(int, void *, usize);extern int close(int);extern int printf(const char *, ...);
#define LEN (1024UL * 1024UL)static unsigned char tx[LEN] __attribute__((aligned(4096)));static unsigned char rx[LEN] __attribute__((aligned(4096)));
static int xfer(int fd, unsigned char *buf, usize len, int wr) { usize done = 0; while (done < len) { ssize n = wr ? write(fd, buf + done, len - done) : read(fd, buf + done, len - done); if (n <= 0) { printf("transfer failed at %lu rc=%ld\n", done, n); return -1; } done += (usize)n; } return 0;}
int main(void) { const off_t off = 0x00100000L; int h2c, c2h; usize i;
for (i = 0; i < LEN; ++i) { tx[i] = (unsigned char)((i * 131UL + (i >> 8) + 0x5aUL) & 0xffUL); rx[i] = 0; }
h2c = open("/dev/xdma0_h2c_0", 1); if (h2c < 0) return 2; if (lseek(h2c, off, 0) != off) return 3; if (xfer(h2c, tx, LEN, 1)) return 4; close(h2c);
c2h = open("/dev/xdma0_c2h_0", 0); if (c2h < 0) return 5; if (lseek(c2h, off, 0) != off) return 6; if (xfer(c2h, rx, LEN, 0)) return 7; close(c2h);
for (i = 0; i < LEN; ++i) { if (tx[i] != rx[i]) { printf("FAIL offset=0x%lx mismatch=0x%lx tx=%02x rx=%02x\n", off, i, tx[i], rx[i]); return 8; } }
printf("PASS offset=0x%lx length=%lu bytes\n", off, LEN); return 0;}保存为 /tmp/xdma_offset_test.c 后执行:
gcc -O2 /tmp/xdma_offset_test.c -o /tmp/xdma_offset_test/tmp/xdma_offset_testecho "TEST_RC=$?"实测结果:
PASS offset=0x100000 length=1048576 bytesTEST_RC=0这个结果证明 XDMA 不仅能访问地址 0,也能正确访问 MIG 的非零 DDR 地址。此前 dd seek/skip 比较失败是测试工具偏移语义问题,不是 FPGA 地址译码或 DDR 数据通路故障。
9.4 测试后检查错误
跳转到“9.4 测试后检查错误”dmesg | grep -Ei 'xdma.*timeout|aer.*error|completion timeout'本次所有成功测试后均未出现新的 XDMA timeout 或 AER 错误。
10. 故障现象和判断方法
跳转到“10. 故障现象和判断方法”10.1 lspci 没有 FPGA
跳转到“10.1 lspci 没有 FPGA”优先检查:
- FPGA 是否已经烧录包含 XDMA 的 bitstream;
- 烧录 FPGA 后是否重新硬复位 i.MX8MP;
- PCIe 100 MHz REFCLK 是否到达 FPGA;
- PERST# 是否正确连接 N15 并释放;
- RX/TX 差分对是否交叉方向正确;
- 两板电源和公共地是否稳定。
此时不要先怀疑 xdma.ko,因为驱动只有在 PCIe 枚举到设备后才可能绑定。
10.2 已枚举但没有 /dev/xdma*
跳转到“10.2 已枚举但没有 /dev/xdma*”检查:
lspci -nnk -s 01:00.0modprobe xdmadmesg | tail -n 100modinfo xdma重点确认 xdma.ko 的 aarch64 架构、vermagic、Module.symvers 和运行内核完全匹配。
10.3 驱动加载但 H2C/C2H 超时
跳转到“10.3 驱动加载但 H2C/C2H 超时”如果出现:
completed_desc_count=0engine BUSY说明 PCIe 配置访问可能正常,但 AXI 后端没有响应。检查顺序:
- MIG
init_calib_complete是否能完成; - MIG AXI
aresetn是否释放; - SmartConnect 两侧时钟是否都在运行;
- XDMA
axi_aresetn是否释放; proc_sys_reset输入极性是否正确;- AXI 地址是否映射到 MIG。
本次根因正是 aux_reset_in 被常数 0 永久拉入复位。
10.4 dd seek/skip 后比较失败
跳转到“10.4 dd seek/skip 后比较失败”不要立即判断 DDR 非零地址损坏。改用:
- AMD/Xilinx 的
dma_to_device、dma_from_device工具;或 lseek + read/write的 C 程序。
只有明确控制设备文件偏移后,才能验证 AXI 非零地址。
10.5 Vivado BASIC 的 ILA 许可证错误
跳转到“10.5 Vivado BASIC 的 ILA 许可证错误”完整 AXI Monitor ILA 会展开成超过 5 个探针,Vivado BASIC 可能报:
Detected an ILA instance ... with more than 5 probes enabled.Your current selected license is BASIC.最小基线先移除该 ILA。需要调试时可以:
- 使用不超过许可证限制的原生少探针 ILA;
- 分阶段观察少量复位、校准和握手信号;
- 或使用支持完整 AXI 调试核的许可证。
11. 下次直接复现的最短流程
跳转到“11. 下次直接复现的最短流程”FPGA 侧
跳转到“FPGA 侧”cd C:\Users\mtxl\Desktop\project_analysis\adfpgavivado -mode batch -source connect_xdma_mig.tcl -tclargs buildvivado -mode batch -source connect_xdma_mig.tcl -tclargs program确认 FPGA 编程完成后,硬复位 i.MX8MP。
i.MX8MP 侧
跳转到“i.MX8MP 侧”uname -rlspci -nn -s 01:00.0lspci -vv -s 01:00.0 | grep -E 'LnkCap:|LnkSta:|MSI:|Kernel driver'modprobe xdmals -l /dev/xdma*dmesg | grep -Ei 'pcie|xdma|aer|timeout' | tail -n 80基础数据测试:
dd if=/dev/urandom of=/tmp/tx.bin bs=1M count=1dd if=/tmp/tx.bin of=/dev/xdma0_h2c_0 bs=1M count=1dd if=/dev/xdma0_c2h_0 of=/tmp/rx.bin bs=1M count=1cmp /tmp/tx.bin /tmp/rx.binecho "CMP_RC=$?"sha256sum /tmp/tx.bin /tmp/rx.bin通过标准:
lspci: 10ee:7011LnkSta: 2.5GT/s x1Kernel driver: xdma/dev/xdma0_h2c_0: present/dev/xdma0_c2h_0: presentCMP_RC=0No new XDMA timeout or AER error12. 接入 AD7768 的下一阶段架构
跳转到“12. 接入 AD7768 的下一阶段架构”在不破坏当前成功基线的前提下,建议按以下结构扩展:
flowchart LR ADC["AD7768<br/>采样接口"] PACK["采样接收与帧打包"] FIFO["异步 FIFO<br/>采样时钟域 -> MIG UI 时钟域"] WRITER["AXI4 写主机<br/>或 AXI DataMover"] SMC["多入口 SmartConnect"] MIG["MIG DDR3"] XDMA["XDMA M_AXI"] SOC["i.MX8MP 应用程序"]
ADC --> PACK --> FIFO --> WRITER --> SMC --> MIG SOC <--> XDMA <--> SMC关键原则:
- 异步 FIFO 只负责跨时钟和短时突发吸收,不承担大容量存储;
- DDR3 用作大容量环形缓冲区;
- FPGA 采集写主机和 XDMA 都需要访问 MIG,SmartConnect 需要扩展为多个 Slave Interface;
- 明确定义写指针、读指针、缓冲区大小、帧序号、时间戳、溢出标志和数据有效长度;
- 通过 AXI-Lite 寄存器或独立控制通道传递状态;当前基线关闭 AXI-Lite,扩展时需要重新启用并验证 BAR;
- 可使用 XDMA user interrupt 通知 i.MX8MP “一块采集数据已完成”,当前
usr_irq_req固定为 0; - 先做 FPGA 内部测试数据发生器,再接 AD7768 真正数据,便于区分采集接口问题和 PCIe 问题;
- 每增加一个功能都保留当前 1 MiB DDR 回环测试作为回归项。
推荐开发顺序:
- 保留当前工程副本作为
pcie_ddr_baseline; - 增加可控测试数据发生器和异步 FIFO;
- 增加 AXI 写主机,将固定模式写入 DDR 指定区域;
- 由 i.MX8MP 使用 C2H 读回并验证模式;
- 增加环形缓冲区和控制寄存器;
- 增加中断和连续传输;
- 最后接入 AD7768,并进行丢帧、长时间稳定性和带宽测试;
- 基线稳定后再评估从 Gen1 x1 升级到 Gen2 x1。
13. 需要保留的工程资产
跳转到“13. 需要保留的工程资产”以下文件和目录是本次成功结果的主要依据,应纳入备份:
C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.xprC:\Users\mtxl\Desktop\project_analysis\adfpga\connect_xdma_mig.tclC:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.srcs\constrs_1\new\pins.xdcC:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.srcs\sources_1\bd\system\system.bdC:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.runs\impl_1\system_wrapper.bitZ:\fling\OK8MP-linux-sdk\dma_ip_drivers\XDMA\linux-kernel\xdma\xdma.ko建议同时记录 bitstream 和 xdma.ko 的 SHA-256。以后任何 Vivado IP 升级、MIG 重配、内核重编译或驱动更新,都应生成新的校验值并重新执行本笔记中的回归测试。