跳转到内容
新建笔记

i.MX8MP 与 Artix-7 通过 PCIe XDMA 访问 DDR3

飞凌 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 真板采集仍需接线后验证。

项目实际条件
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。

连接和上电时应注意:

  1. 断电状态下插拔 PCIe 转接线;
  2. i.MX8MP 与 FPGA 开发板按各自开发板要求供电,不依赖转接线为整块 FPGA 板供电;
  3. 保证两板公共地和 PCIe REFCLK、RX/TX、PERST# 连通;
  4. JTAG 只负责配置和调试 FPGA,不承担 PCIe 数据传输;
  5. FPGA 使用 JTAG 临时烧录时,断电会丢失 bitstream;正式启动应考虑将 bitstream 固化到配置 Flash。
项目版本或路径
VivadoAMD 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 SDKZ:\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
最终 bitstreamadfpga\fpga_pcie.runs\impl_1\system_wrapper.bit
最终 Vivado 脚本adfpga\connect_xdma_mig.tcl

本次先建立最小且可验证的 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。

最终工程使用 DMA/Bridge Subsystem for PCI Express,关键参数如下:

参数值解释
PCIe 功能DMA EndpointFPGA 是 Endpoint,i.MX8MP 是 Root Complex
DMA 接口AXI Memory MappedH2C/C2H 请求直接访问 AXI 地址空间
Link Widthx1只使用 Lane 0
Maximum Link Speed2.5 GT/s对应 Gen1;这是当前已验证配置
AXI Data Width64 bitXDMA M_AXI 数据宽度
AXI Clock62.5 MHz当前 Gen1 x1 配置生成的 axi_aclk
H2C Channels1生成 /dev/xdma0_h2c_0
C2H Channels1生成 /dev/xdma0_c2h_0
User Interrupts1当前将请求输入固定为 0,尚未使用
MSIEnabledLinux 实测 MSI: Enable+
MSI-XDisabled当前不使用
AXI-Lite MasterDisabled因此没有 user BAR 设备节点
Vendor ID10eeXilinx
Device ID7011Linux 实际枚举结果
PLLCPLL与官方成功工程一致

必须区分“转接线支持 PCIe 2.0”和“Endpoint 已配置为 Gen2”。当前 XDMA 参数明确是 2.5 GT/s,lspci 也显示 Speed 2.5GT/s,所以当前成功基线是 Gen1 x1。以后升级 Gen2 时,应单独修改 XDMA、重新实现并重新做完整回归,不能只改文档名称。

达芬奇 Pro 板载存储器在 MIG 中使用官方工程的兼容器件配置。即使 Vivado 列表中没有板上 Nanya 器件的精确型号,也不要随意选择几何结构不同的器件。

最终 MIG 参数来自官方成功工程:

参数值
Memory TypeDDR3 SDRAM Components
Compatible PartMT41J128M16XX-125
控制器数量1
DDR 数据宽度32 bit
容量512 MiB
Row / Column / Bank14 / 10 / 3
DDR 时钟周期2500 ps,即 400 MHz
PHY:Controller4:1
MIG 输入时钟200 MHz
AXI 数据宽度256 bit
AXI 地址宽度29 bit
AXI ID 宽度4 bit
ECCDisabled
Data MaskEnabled
Address MappingBANK_ROW_COLUMN
System Clock TypeNo Buffer
Reference Clock TypeNo Buffer

MIG 的 DDR 引脚来自其内部 mig_a.prj。不要再在顶层 pins.xdc 重复约束 DDR3 全部引脚,否则容易与 MIG 的 scoped constraints 冲突。

参数值
输入50 MHz
输出200 MHz
PrimitiveMMCM
ResetActive Low,端口名 resetn
Clock output bufferBUFG

50 MHz 板级时钟经 Clock Wizard 生成 200 MHz,同时连接 MIG 的 sys_clk_i 和 clk_ref_i。clk_wiz_0/locked 连接 MIG sys_rst;在当前 MIG 极性配置下,时钟稳定后高电平释放 MIG 系统复位。

SmartConnect 负责连接 XDMA 和 MIG 的不同时钟域:

参数值
Slave Interfaces1
Master Interfaces1
Clock Inputs2
HAS_ARESETN1
HID_PARAM_26_11
Advanced Propertylegacy_low_area_mode 1

连接关系:

xdma_0/M_AXI -> axi_smc/S00_AXI
axi_smc/M00_AXI -> mig_7series_0/S_AXI
xdma_0/axi_aclk -> axi_smc/aclk
mig_7series_0/ui_clk -> axi_smc/aclk1
xdma_0/axi_aresetn -> axi_smc/aresetn

aclk 是 XDMA 一侧的时钟,aclk1 是 MIG UI 一侧的时钟。SmartConnect 在两侧之间完成必要的跨时钟处理。不要把 MIG ui_clk 和 XDMA axi_aclk 直接短接。

MIG UI 域复位关系如下:

mig_7series_0/ui_clk -> proc_sys_reset_0/slowest_sync_clk
mig_7series_0/ui_clk_sync_rst -> proc_sys_reset_0/ext_reset_in
mig_7series_0/mmcm_locked -> proc_sys_reset_0/dcm_locked
proc_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=0
engine BUSY
H2C/C2H timeout

官方工程生成 HDL 的正确连接是:

.aux_reset_in(1'b1)
.mb_debug_sys_rst(1'b0)

这证明故障不是 PCIe 物理层、Linux 驱动或 DDR 地址映射问题,而是复位极性错误。

XDMA 的 AXI 主地址空间映射到 MIG:

Base address: 0x00000000
Range: 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 地址。

顶层约束文件:

C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.srcs\constrs_1\new\pins.xdc

已确认的关键引脚:

信号FPGA 引脚电气标准或说明
sys_clkR450 MHz,LVCMOS15
sys_rst_nU7Active Low,LVCMOS15
pcie_ref_clk_p[0]F6PCIe 100 MHz 差分参考时钟正端
pcie_mgt_rxp[0]D9GTP Lane 0 接收正端
pcie_mgt_txp[0]D7GTP Lane 0 发送正端
pcie_rst_nN15PCIe PERST#,LVCMOS33
lnk_up_ledW7XDMA 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_0
util_ds_buf
xlconstant_0
mig_7series_0
clk_wiz_0
proc_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 烧录。
  1. 打开 adfpga\fpga_pcie.xpr;
  2. 打开底部 Tcl Console;
  3. 执行:
source C:/Users/mtxl/Desktop/project_analysis/adfpga/connect_xdma_mig.tcl

成功时应出现:

FINAL VALIDATION PASSED
PCIe REFCLK interface : pcie_ref
PCIe PERST# port : pcie_rst_n
XDMA M_AXI DDR3 : 0x00000000 / 512M

确保 Vivado 2026.1 的 bin 已加入 PATH,然后执行:

终端窗口
cd C:\Users\mtxl\Desktop\project_analysis\adfpga
vivado -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: 0
Implementation Critical Warnings: 0
Implementation Errors: 0
WNS: +0.951 ns
TNS: 0

综合日志中的大量普通 warning 不能只看数量判断成败。必须重点确认 DRC、实现、时序和 bitstream 生成结果。

命令行烧录:

终端窗口
cd C:\Users\mtxl\Desktop\project_analysis\adfpga
vivado -mode batch -source connect_xdma_mig.tcl -tclargs program

成功时应看到:

End of startup status: HIGH
FPGA PROGRAMMED: ...system_wrapper.bit

no supported soft debug core(s) 只表示当前 bitstream 没有 ILA/VIO 等调试核,不表示烧录失败。Vivado BASIC 对完整 AXI Monitor ILA 的探针数量有限制,因此最小可用基线中不放置完整 AXI ILA。

PCIe Endpoint 必须在 i.MX8MP 枚举 PCIe 总线时已经配置完成。推荐顺序:

  1. 两板断电并确认 PCIe 线连接可靠;
  2. FPGA 上电并通过 JTAG 烧录正确 bitstream;
  3. 对 i.MX8MP 执行硬复位或重新上电;
  4. 等待 Linux 启动;
  5. 在 COM10 以 root 登录并检查 PCIe。

如果先启动 i.MX8MP、后烧 FPGA,Root Complex 可能已经错过 Endpoint。烧录后应重启 i.MX8MP,不应仅反复 modprobe xdma。

在板端允许 SysRq 时,可通过串口触发硬重启:

终端窗口
echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger

echo b 不会卸载文件系统或执行正常关机,只适合调试恢复,执行前应确保没有需要保存的数据。

进入内核源码:

终端窗口
cd ~/fling/OK8MP-linux-sdk/OK8MP-linux-kernel
make ARCH=arm64 OK8MP-C_defconfig

确认 PCIe、MSI、AER 和模块支持:

终端窗口
grep -E '^CONFIG_PCI=|^CONFIG_PCIEPORTBUS=|^CONFIG_PCI_IMX6_HOST=' .config
grep -E '^CONFIG_PCI_MSI=|^# CONFIG_PCI_MSI' .config
grep -E '^CONFIG_PCIEAER=|^# CONFIG_PCIEAER' .config
grep -E '^CONFIG_MODULES=|^CONFIG_MODVERSIONS=' .config

本次已确认:

CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_IMX6_HOST=y
CONFIG_PCI_MSI=y
CONFIG_PCIEAER=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y

确认内核发布版本和符号表:

终端窗口
make -s ARCH=arm64 kernelrelease
cat include/config/kernel.release
ls -lh Module.symvers
test -s Module.symvers && echo "Module.symvers OK" || echo "Module.symvers missing"

本次对应:

5.4.70-2.3.0
Module.symvers OK

.config、Module.symvers、内核源码和开发板正在运行的 Image 必须来自同一次内核构建。只要其中一个不匹配,启用 CONFIG_MODVERSIONS 后就可能出现 invalid module format 或符号版本错误。

首先加载飞凌 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-kernel
export XDMA_SRC=~/fling/OK8MP-linux-sdk/dma_ip_drivers/XDMA/linux-kernel

XDMA 的模块 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 aarch64
name: xdma
vermagic: 5.4.70-2.3.0 SMP preempt mod_unload modversions aarch64

8.3 把 xdma.ko 传入开发板

跳转到“8.3 把 xdma.ko 传入开发板”

主机端文件:

Z:\fling\OK8MP-linux-sdk\dma_ip_drivers\XDMA\linux-kernel\xdma\xdma.ko

有可用网络时优先使用 scp。只有串口可用时,推荐 ZMODEM:

终端窗口
cd /tmp
rz -y

在串口软件中选择 xdma.ko,完成后必须校验:

终端窗口
ls -l /tmp/xdma.ko
sha256sum /tmp/xdma.ko

本次实际使用串口 Base64 传输。传输二进制文件时必须关闭回显,并比较文件长度和 SHA-256;不能仅凭“命令结束”判断文件完整。

本次模块信息:

Size: 2144096 bytes
SHA-256: 75e22b9b01aa67b0b18436668925b768ee0b1574b6a8f70e75f9e1b9cb6182c8
终端窗口
mkdir -p /lib/modules/$(uname -r)/extra
cp /tmp/xdma.ko /lib/modules/$(uname -r)/extra/xdma.ko
depmod -a
modinfo xdma

手动加载:

终端窗口
modprobe xdma

确认 Endpoint 可以稳定枚举后,再配置开机自动加载:

终端窗口
printf '%s\n' xdma > /etc/modules-load.d/xdma.conf
sync

本次重启后驱动已自动绑定,说明持久化安装和自动加载有效。

终端窗口
lspci -nn -s 01:00.0
lspci -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 x1
LnkSta: Speed 2.5GT/s (ok), Width x1 (ok)
Kernel driver in use: xdma
imx6q-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 被关闭,与当前设计一致。

先生成测试数据:

终端窗口
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=1
cmp /tmp/tx.bin /tmp/rx.bin
echo "CMP_RC=$?"
sha256sum /tmp/tx.bin /tmp/rx.bin

4 KiB 实测结果:

H2C_RC=0 C2H_RC=0 CMP_RC=0
SHA-256: 8a9894eff33f3f1f1912b84629ec677628031db6a80b7981c801e04b39115e51

把 bs 改为 1M 再测试 1 MiB:

终端窗口
dd if=/dev/urandom of=/tmp/tx_1m.bin bs=1M count=1
dd if=/tmp/tx_1m.bin of=/dev/xdma0_h2c_0 bs=1M count=1
dd if=/dev/xdma0_c2h_0 of=/tmp/rx_1m.bin bs=1M count=1
cmp /tmp/tx_1m.bin /tmp/rx_1m.bin
sha256sum /tmp/tx_1m.bin /tmp/rx_1m.bin

实测结果:

TEST_1M_H2C=0
TEST_1M_C2H=0
TEST_1M_CMP=0
SHA-256: 7da43bdc05449d60a2efd82e408ad7daac2f6b8612aee45bb945ab7546b1f3aa

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_test
echo "TEST_RC=$?"

实测结果:

PASS offset=0x100000 length=1048576 bytes
TEST_RC=0

这个结果证明 XDMA 不仅能访问地址 0,也能正确访问 MIG 的非零 DDR 地址。此前 dd seek/skip 比较失败是测试工具偏移语义问题,不是 FPGA 地址译码或 DDR 数据通路故障。

终端窗口
dmesg | grep -Ei 'xdma.*timeout|aer.*error|completion timeout'

本次所有成功测试后均未出现新的 XDMA timeout 或 AER 错误。

10. 故障现象和判断方法

跳转到“10. 故障现象和判断方法”

优先检查:

  • 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.0
modprobe xdma
dmesg | tail -n 100
modinfo xdma

重点确认 xdma.ko 的 aarch64 架构、vermagic、Module.symvers 和运行内核完全匹配。

10.3 驱动加载但 H2C/C2H 超时

跳转到“10.3 驱动加载但 H2C/C2H 超时”

如果出现:

completed_desc_count=0
engine BUSY

说明 PCIe 配置访问可能正常,但 AXI 后端没有响应。检查顺序:

  1. MIG init_calib_complete 是否能完成;
  2. MIG AXI aresetn 是否释放;
  3. SmartConnect 两侧时钟是否都在运行;
  4. XDMA axi_aresetn 是否释放;
  5. proc_sys_reset 输入极性是否正确;
  6. 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. 下次直接复现的最短流程”
终端窗口
cd C:\Users\mtxl\Desktop\project_analysis\adfpga
vivado -mode batch -source connect_xdma_mig.tcl -tclargs build
vivado -mode batch -source connect_xdma_mig.tcl -tclargs program

确认 FPGA 编程完成后,硬复位 i.MX8MP。

终端窗口
uname -r
lspci -nn -s 01:00.0
lspci -vv -s 01:00.0 | grep -E 'LnkCap:|LnkSta:|MSI:|Kernel driver'
modprobe xdma
ls -l /dev/xdma*
dmesg | grep -Ei 'pcie|xdma|aer|timeout' | tail -n 80

基础数据测试:

终端窗口
dd if=/dev/urandom of=/tmp/tx.bin bs=1M count=1
dd if=/tmp/tx.bin of=/dev/xdma0_h2c_0 bs=1M count=1
dd if=/dev/xdma0_c2h_0 of=/tmp/rx.bin bs=1M count=1
cmp /tmp/tx.bin /tmp/rx.bin
echo "CMP_RC=$?"
sha256sum /tmp/tx.bin /tmp/rx.bin

通过标准:

lspci: 10ee:7011
LnkSta: 2.5GT/s x1
Kernel driver: xdma
/dev/xdma0_h2c_0: present
/dev/xdma0_c2h_0: present
CMP_RC=0
No new XDMA timeout or AER error

12. 接入 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 回环测试作为回归项。

推荐开发顺序:

  1. 保留当前工程副本作为 pcie_ddr_baseline;
  2. 增加可控测试数据发生器和异步 FIFO;
  3. 增加 AXI 写主机,将固定模式写入 DDR 指定区域;
  4. 由 i.MX8MP 使用 C2H 读回并验证模式;
  5. 增加环形缓冲区和控制寄存器;
  6. 增加中断和连续传输;
  7. 最后接入 AD7768,并进行丢帧、长时间稳定性和带宽测试;
  8. 基线稳定后再评估从 Gen1 x1 升级到 Gen2 x1。

13. 需要保留的工程资产

跳转到“13. 需要保留的工程资产”

以下文件和目录是本次成功结果的主要依据,应纳入备份:

C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.xpr
C:\Users\mtxl\Desktop\project_analysis\adfpga\connect_xdma_mig.tcl
C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.srcs\constrs_1\new\pins.xdc
C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.srcs\sources_1\bd\system\system.bd
C:\Users\mtxl\Desktop\project_analysis\adfpga\fpga_pcie.runs\impl_1\system_wrapper.bit
Z:\fling\OK8MP-linux-sdk\dma_ip_drivers\XDMA\linux-kernel\xdma\xdma.ko

建议同时记录 bitstream 和 xdma.ko 的 SHA-256。以后任何 Vivado IP 升级、MIG 重配、内核重编译或驱动更新,都应生成新的校验值并重新执行本笔记中的回归测试。