1. 结论先行
跳转到“1. 结论先行”本阶段已经完成一条面向手持式振动分析仪的、不依赖 FPGA 外部 DDR3 的 PCIe 采集基线:
flowchart LR SRC["确定性四通道测试源<br/>未来替换为 AD7768 接收器"] FIFO["128 bit × 2048 帧<br/>XPM 异步 FIFO"] PKT["固定 64 KiB 分包器<br/>64-bit AXI4-Stream"] XDMA["XDMA C2H Stream<br/>PCIe Gen1 x1"] RAM["i.MX8MP 内存<br/>软件环形缓冲区"]
SRC --> FIFO --> PKT --> XDMA --> RAM控制通路为:
flowchart LR APP["i.MX8MP 应用"] USER["/dev/xdma0_user"] LITE["XDMA M_AXI_LITE<br/>1 MiB aperture"] CSR["自定义 AXI-Lite CSR<br/>启动、停止、计数、溢出状态"]
APP --> USER --> LITE --> CSR设计目标器件是 XC7A35T-FGG484-2。当前 35T 已完成综合、布局、布线、时序、DRC 和资源门限验证,说明该数据链路可以放入 35T;但产品 PCB 管脚仍未签核,所以脚本故意禁止生成 35T bitstream。
真板验证使用现有的正点原子达芬奇 Pro XC7A200T-FBG484-2。同一套 RTL 和 XDMA 配置已在 A200T 与飞凌 i.MX8MP 间通过完整回归,包括连续传输、启停、清零竞争、反压、强制溢出、恢复和 10,000 包耐久测试。
1.1 必须准确区分的状态
跳转到“1.1 必须准确区分的状态”| 范围 | 当前状态 |
|---|---|
| RTL 行为仿真 | 已通过 |
| A35T 综合、布局布线、DRC、时序和资源门限 | 已通过 |
| A35T 产品管脚、精确订货型号和 bitstream | 未签核,禁止烧录 |
| A200T bitstream | 已生成并通过真板回归 |
| XDMA AXI-Stream C2H 与 AXI-Lite CSR | 已在 A200T + i.MX8MP 真板验证 |
| FPGA 外部 DDR3、MIG、SmartConnect、AXI DMA | 当前方案不使用 |
| AD7768 数据接收和 SPI 控制 | 尚未接入 |
| 光电键相/转速输入 | 尚未接入 |
| i.MX8MP 产品级环形缓冲和振动算法 | 不属于本阶段 FPGA 范围 |
因此,本页证明的是:35T 资源和时序可行,A200T 上的等价 PCIe 流式链路已通过硬件测试。它还不能证明 AD7768 真板采样或 35T 产品板已经完成。
2. 为什么从 DDR3 方案切换到直通方案
跳转到“2. 为什么从 DDR3 方案切换到直通方案”早期基线采用 XDMA AXI-MM -> SmartConnect -> MIG -> FPGA DDR3,用于证明 PCIe、XDMA 和板载 DDR3 可读写。之后也实现过 AD7768 -> AXI DMA S2MM -> DDR3 -> XDMA 的 A200T 方案。两者仍然是有价值的历史回归基线,但不再是 35T 手持产品的主线。
2.1 带宽并不是主要矛盾
跳转到“2.1 带宽并不是主要矛盾”按四通道、每通道 32 bit、每秒约 256 k 帧计算:
256000 frame/s × 4 channel × 4 byte = 4.096 MB/s当前测试时钟的精确值为:
frame rate = 62.5 MHz / 244 = 256147.541 frame/spayload = 256147.541 × 16 = 4.098361 MB/sapplication stream = payload + 64-byte packet headers ≈ 4.102367 MB/s4.102367 MB/s 是包含自定义 64-byte 包头的 AXI/C2H 应用层数据率,不包含 PCIe TLP、DLLP 和 8b/10b 编码开销,不能称为 PCIe 物理线速。
这远低于 PCIe Gen1 x1 的有效吞吐能力。只要 i.MX8MP 采集进程持续提交 C2H 请求,没必要为了约 4.1 MB/s 的数据流,在 35T 产品上再增加 MIG、外部 DDR、AXI DMA 和多主设备互连。
2.2 “i.MX8MP 始终在线”的工程含义
跳转到“2.2 “i.MX8MP 始终在线”的工程含义”这里不是说处理器永远不会掉电,而是说在一次有效采集会话中:
- i.MX8MP 已启动 Linux 和采集服务;
- PCIe 链路保持建立;
- 用户态或内核态缓冲持续提交 C2H 读取;
- 大容量缓存放在 i.MX8MP DRAM 中;
- FPGA 只吸收短时 PCIe/软件抖动,不承担离线记录。
如果产品要求 SoC 睡眠时 FPGA 仍持续采集、PCIe 长时间不可用仍不得丢样,或者断电前必须保存大段波形,那么无 DDR 直通方案的前提就不成立,需要重新评估 FPGA 外部内存或独立存储。
2.3 35T 方案的收益与代价
跳转到“2.3 35T 方案的收益与代价”收益:
- 去掉 MIG、AXI DMA、DDR 数据互连和 FPGA 外部 DDR;
- 降低器件资源、PCB 复杂度、功耗、启动校准和故障定位成本;
- 数据只经过一次 FIFO 和分包,不需要 DDR 写入后再读出;
- 大容量环形缓冲、文件写入和算法均由 i.MX8MP 统一管理。
代价:
- FPGA 的 32 KiB FIFO 只能吸收约 8 ms 的反压;
- 软件必须连续挂起 C2H 请求;
- 当前协议没有“中止半包”命令;
- 发生长时间 PCIe 停顿时会明确计数丢帧,而不是继续无限缓存。
3. 设计总览
跳转到“3. 设计总览”3.1 数据、控制和验证三条路径
跳转到“3.1 数据、控制和验证三条路径”flowchart TB subgraph DATA["数据路径"] S["capture_test_source<br/>4 × 32-bit"] --> F["capture_async_fifo<br/>128-bit × 2048"] F --> P["capture_packetizer<br/>64 KiB / packet"] P --> C["XDMA S_AXIS_C2H_0<br/>64-bit"] end
subgraph CONTROL["控制路径"] U["XDMA M_AXI_LITE"] --> R["capture_axil_csr"] R -->|"start / rate / safe clear"| S F -->|"level / full / overflow"| R P -->|"frames / packets"| R end
subgraph HOST["i.MX8MP"] DEVU["/dev/xdma0_user"] DEVC["/dev/xdma0_c2h_0"] TEST["capture_hw_test.c"] TEST --> DEVU TEST --> DEVC end
U --- DEVU C --- DEVC3.2 当前时钟关系
跳转到“3.2 当前时钟关系”XDMA 在 Gen1 x1、64-bit AXI4-Stream 配置下输出 axi_aclk = 62.5 MHz。当前测试源和 AXI4-Stream 读侧都暂时使用该时钟,但 FIFO 仍然使用真正的 xpm_fifo_async,因为未来 AD7768 接入后:
- 写时钟会变成 ADC 数据时钟域;
- 读时钟仍是 XDMA
axi_aclk; - 128-bit 帧数据只能通过双时钟 FIFO 跨域;
- 计数器通过 Gray 码同步,单 bit 状态通过两级触发器同步。
这使测试基线与未来真实采样的跨时钟结构一致,避免接入 ADC 时重写整条数据通路。
4. 工程资产和开发方式
跳转到“4. 工程资产和开发方式”4.1 下载源码
跳转到“4.1 下载源码”源码包 SHA-256 在第 17 节给出。包内不含 Vivado 缓存、运行目录、报告和 bitstream;这些输出必须由脚本重新生成。
4.2 目录结构
跳转到“4.2 目录结构”adfpga/├── README.md├── adfpga.xpr├── constraints/│ ├── a200t/davinci_pro.xdc│ └── a35t/provisional_pcie.xdc├── ip/│ └── capture_xdma/capture_xdma.xci├── rtl/│ ├── capture_top.sv│ ├── capture_datapath.sv│ ├── capture_test_source.sv│ ├── capture_async_fifo.sv│ ├── capture_gray_sync.sv│ ├── capture_packetizer.sv│ └── capture_axil_csr.sv├── sim/│ ├── tb_capture_datapath.sv│ ├── tb_capture_axil_csr.sv│ └── tb_capture_block_size.sv├── scripts/│ ├── create_project.tcl│ ├── run_sim.ps1│ ├── program_a200t.tcl│ └── check_project.tcl└── tools/ └── capture_hw_test.c4.3 VS Code 与 Vivado 的分工
跳转到“4.3 VS Code 与 Vivado 的分工”推荐工作方式是:
- VS Code 编辑
rtl/、sim/、constraints/、scripts/和 C 测试工具; - Vivado 2026.1 负责 XDMA IP、仿真、综合、实现、时序、DRC 和下载;
scripts/create_project.tcl是器件、IP 参数和构建门限的权威来源;adfpga.xpr便于图形界面打开同一组源文件,但不应成为唯一配置来源。
使用 VS Code 不影响 Vivado 打开工程。修改源文件后,Vivado 会读取同一文件;若增删源文件或修改 XDMA 参数,应同步更新 Tcl 脚本,并用脚本重建工程。
Vivado 版本固定为 2026.1。脚本会检查版本并拒绝其他版本,以避免 IP 升级或生成结果无声变化。
5. XDMA 配置
跳转到“5. XDMA 配置”脚本创建 DMA/Bridge Subsystem for PCI Express 4.2,关键参数如下:
| 参数 | 值 | 作用 |
|---|---|---|
| Mode | Basic / DMA | PCIe DMA Endpoint |
| AXI interface | AXI Stream | 直接传输采集流,不走 AXI-MM DDR |
| PCIe link | Gen1 x1 | 2.5 GT/s、Lane 0 |
| AXI stream width | 64 bit | 对应当前 XDMA 接口 |
| AXI clock | 62.5 MHz | XDMA 产生 axi_aclk |
| C2H channels | 1 | FPGA 到 i.MX8MP 数据流 |
| H2C channels | 1 | XDMA 要求保留,设计中接收后丢弃 |
| AXI-Lite master | Enabled | 暴露自定义 CSR |
| AXI-Lite aperture | 1 MiB | /dev/xdma0_user 访问范围 |
| Device ID | 10ee:7011 | Linux 枚举标识 |
| MSI | 1 vector | XDMA DMA 完成中断 |
| MSI-X | Disabled | 当前不使用 |
| User interrupt | tied low | 当前没有独立 usr_irq_req |
| PLL | CPLL | 与板级 PCIe 基线一致 |
对应的 Tcl 配置核心如下:
set_property -dict [list \ CONFIG.mode_selection {Basic} \ CONFIG.xdma_axi_intf_mm {AXI_Stream} \ CONFIG.axi_data_width {64_bit} \ CONFIG.pl_link_cap_max_link_width {X1} \ CONFIG.pl_link_cap_max_link_speed {2.5_GT/s} \ CONFIG.axisten_freq {62.5} \ CONFIG.xdma_pcie_64bit_en {true} \ CONFIG.plltype {CPLL} \ CONFIG.xdma_wnum_chnl {1} \ CONFIG.xdma_rnum_chnl {1} \ CONFIG.axilite_master_en {true} \ CONFIG.axilite_master_size {1} \ CONFIG.axilite_master_scale {Megabytes} \ CONFIG.pf0_device_id {7011} \ CONFIG.pf0_msi_enabled {true} \ CONFIG.pf0_msi_cap_multimsgcap {1_vector} \ CONFIG.pf0_msix_enabled {false} \] $xdma_ip虽然 H2C 不是采集所需方向,XDMA 仍会生成 M_AXIS_H2C_0。顶层把 m_axis_h2c_tready_0 固定为 1,持续接收并丢弃数据,避免未使用的 H2C 通道反向阻塞 IP。
6. RTL 设计细节
跳转到“6. RTL 设计细节”6.1 顶层 capture_top.sv
跳转到“6.1 顶层 capture_top.sv”顶层完成以下工作:
- 用
IBUFDS_GTE2接收 PCIe 100 MHz 差分参考时钟; - 实例化 XDMA;
- 将 XDMA C2H AXI4-Stream 接到采集数据通路;
- 将 XDMA AXI-Lite Master 直连 CSR;
- 用四级复位流水线产生采集逻辑本地同步复位;
- 将
user_lnk_up输出到板载链路指示灯; - 将独立用户中断固定为 0。
复位释放代码:
(* ASYNC_REG = "TRUE" *) reg [3:0] capture_resetn_pipe = 4'b0000;
always @(posedge axi_aclk) begin if (!axi_aresetn) capture_resetn_pipe <= 4'b0000; else capture_resetn_pipe <= {capture_resetn_pipe[2:0], 1'b1};end
wire capture_aresetn = capture_resetn_pipe[3];6.2 确定性测试源 capture_test_source.sv
跳转到“6.2 确定性测试源 capture_test_source.sv”测试源每帧产生四个 32-bit 字:
channel0 = {8'hA0, source_sequence[23:0]};channel1 = {8'hA1, source_sequence[23:0]};channel2 = {8'hA2, source_sequence[23:0]};channel3 = {8'hA3, source_sequence[23:0]};frame = {channel3, channel2, channel1, channel0};四通道使用相同的 24-bit 源序号,因此软件可以同时检查:
- 通道顺序是否正确;
- 128 bit 拆成两个 64-bit beat 后是否错位;
- AXI4-Stream 反压期间数据是否保持;
- FIFO 溢出时,硬件丢帧计数是否与 payload 序号缺口一致;
- 24-bit 序号回绕是否正确处理。
RATE_DIVIDER 在启动时锁存。寄存器为 0 时使用默认值 244;应在停止状态下修改,再启动新会话。
为了使每次安全停止都落在完整包边界,测试源收到停止请求后会完成当前 4092 帧块,不会在半包位置突然停下。
安全清理采用计数 baseline 实现会话统计归零,不会复位 payload 中的 24-bit 源序号。该序号跨会话连续,约 65.498 秒回绕一次;cycles 和 race 测试正是按模 2^24 检查跨会话连续性。
6.3 异步 FIFO capture_async_fifo.sv
跳转到“6.3 异步 FIFO capture_async_fifo.sv”关键参数:
| 参数 | 值 |
|---|---|
| Primitive | xpm_fifo_async |
| 写/读宽度 | 128 bit |
| 深度 | 2048 帧 |
| 容量 | 32 KiB |
| 存储资源 | Block RAM |
| 读模式 | FWFT |
| CDC stages | 2 |
prog_full | 深度减 16 |
| ECC | Disabled |
核心实例:
xpm_fifo_async #( .CDC_SYNC_STAGES(2), .FIFO_MEMORY_TYPE("block"), .FIFO_READ_LATENCY(0), .FIFO_WRITE_DEPTH(2048), .PROG_FULL_THRESH(2032), .READ_DATA_WIDTH(128), .READ_MODE("fwft"), .RELATED_CLOCKS(0), .SIM_ASSERT_CHK(1), .WRITE_DATA_WIDTH(128)) fifo_i (...);2048 帧在默认测试速率下只能覆盖:
2048 / 256147.541 ≈ 7.995 ms所以它用于时钟域隔离和短时反压,不是大容量波形缓存。
6.4 Gray 码计数同步 capture_gray_sync.sv
跳转到“6.4 Gray 码计数同步 capture_gray_sync.sv”源域先把二进制计数转换为 Gray 码并寄存,再通过带 ASYNC_REG 属性的两级触发器进入目标域,最后转换回二进制。这样避免二进制计数器多个 bit 同时翻转造成撕裂。
这些计数用于运行状态和诊断,不替代未来的采样时间戳。接入 AD7768 后,如果要求精确定位丢失样点,数据帧本身仍应包含硬件采样序号或时间戳。
6.5 64 KiB 分包器 capture_packetizer.sv
跳转到“6.5 64 KiB 分包器 capture_packetizer.sv”分包器状态机:
stateDiagram-v2 [*] --> IDLE IDLE --> HEADER: FIFO 出现第一个帧 HEADER --> PAYLOAD_LOW: 8 个 header beat 已发送 PAYLOAD_LOW --> PAYLOAD_HIGH: 取出一个 128-bit 帧 PAYLOAD_HIGH --> PAYLOAD_LOW: 未到第 4092 帧 PAYLOAD_HIGH --> IDLE: 最后一帧高 64 bit + TLASTAXI4-Stream 的任何状态变化都以 TVALID && TREADY 为准。TREADY=0 时,TDATA、TKEEP、TLAST 和状态机保持不变。
分包器不会等 FIFO 预存完整 4092 帧才发送 header;只要第一个帧到达就开始一包,后续帧不足时在 payload 阶段等待。运行中的测试源会补齐完整块,安全停止也会先补齐当前块,因此正常会话最终仍以完整包结束。
每个输入帧是 128 bit,而 XDMA 是 64 bit,所以:
PAYLOAD_LOW输出 CH0、CH1;PAYLOAD_HIGH输出 CH2、CH3;- 只有高 64-bit beat 被接受后,该帧才计入 transmitted;
- 最后一帧的高 64-bit beat 同时置
TLAST=1。
TKEEP 始终为 8'hFF。
6.6 AXI-Lite CSR capture_axil_csr.sv
跳转到“6.6 AXI-Lite CSR capture_axil_csr.sv”AXI-Lite 的 AW 和 W 通道没有规定必须同周期到达。CSR 分别锁存地址和数据,只有两者都收到后才执行一次写操作;B/R 响应在对端未 ready 时保持稳定。仿真覆盖 AW 先到、W 先到、同时到达、写 strobe 和响应反压。
版本 1.1 还修复了 clear/start 竞争:清理进行中时,新的 start 命令被拒绝,防止旧会话尚未排空就开始新会话。
核心门控逻辑:
if (wdata_hold[1]) begin test_enable <= 1'b0; if (!datapath_status[6]) clear_stats <= 1'b1;end else if (!wdata_hold[0] || !datapath_status[6]) begin test_enable <= wdata_hold[0];end7. CSR 寄存器定义
跳转到“7. CSR 寄存器定义”所有寄存器通过 /dev/xdma0_user 访问,均为 32-bit little-endian。
| 偏移 | 属性 | 名称 | 含义 |
|---|---|---|---|
0x00 | RO | MAGIC | 0x31424956,字节序显示为 VIB1 |
0x04 | RO | VERSION | 0x00010001 |
0x08 | RO | BUILD_ID | 0x20260816 |
0x0C | RW/命令 | CONTROL | bit 0 启动;bit 1 停止并请求安全清理 |
0x10 | RW | RATE_DIVIDER | 测试源分频;0 等价于 244 |
0x14 | RO | STATUS | 链路、运行、清理、FIFO 和溢出状态 |
0x18 | RO | SOURCE_FRAMES | 已产生帧数,含未写入 FIFO 的帧 |
0x1C | RO | ACCEPTED_FRAMES | 成功写入 FIFO 的帧数 |
0x20 | RO | DROPPED_FRAMES | FIFO 满导致的丢帧数 |
0x24 | RO | TRANSMITTED_FRAMES | 已被 XDMA AXI-Stream 接受的完整帧数 |
0x28 | RO | PACKET_COUNT | TLAST 已被 XDMA 接受的 64 KiB 包数 |
0x2C | RO | FIFO_LEVEL | 当前 FIFO 帧数 |
0x30 | RO | FIFO_HIGH_WATERMARK | 本会话 FIFO 最高水位 |
CONTROL.bit1 是写命令而不是可保持配置位;读回 CONTROL 只反映 bit 0 的当前启动状态。
TRANSMITTED_FRAMES 和 PACKET_COUNT 在 TVALID && TREADY 时递增,只证明 XDMA 已接受数据,不单独证明 PCIe TLP 已发送或数据已经写入 i.MX8MP 用户缓冲。端到端完成必须以主机 65,536-byte read 返回并通过 payload 校验为准。
STATUS 位定义:
| bit | 含义 |
|---|---|
| 31 | PCIe user_lnk_up |
| 6 | stop/clear 事务待完成 |
| 5 | 数据源正在运行或补齐当前块 |
| 4 | FIFO 读侧处于 reset busy |
| 3 | FIFO 写侧处于 reset busy |
| 2 | FIFO 溢出/丢帧粘滞标志 |
| 1 | FIFO prog_full |
| 0 | FIFO 中存在数据 |
7.1 安全停止和清理协议
跳转到“7.1 安全停止和清理协议”sequenceDiagram participant H as i.MX8MP 软件 participant C as CSR participant S as 测试源 participant P as FIFO/分包器
H->>C: CONTROL = 0,停止继续产生新块 S->>S: 补齐当前 4092 帧块 H->>P: 保持 65536-byte C2H 读取 P-->>H: 排空最后一个完整包 H->>C: CONTROL = 2,请求清理 C->>P: 等待 source quiet、FIFO empty、packetizer idle P-->>C: pipeline idle C->>S: 跨域 clear toggle S-->>C: clear acknowledge C-->>H: STATUS.bit6 = 0,所有会话计数为 0注意:清理可能在两次软件轮询之间迅速完成,软件不应要求先观察到 STATUS.bit6=1。正确做法是写入 clear 后轮询到 bit 6 为 0,并再次确认所有会话计数为 0。
8. 64 KiB C2H 数据协议
跳转到“8. 64 KiB C2H 数据协议”8.1 包长度
跳转到“8.1 包长度”64-byte header + 4092 frame × 16 byte/frame = 65536 byte每包正好 8192 个 64-bit AXI4-Stream beat,便于 XDMA 和 Linux 应用固定长度读取。
8.2 头部格式
跳转到“8.2 头部格式”头部由 8 个 little-endian 64-bit beat 组成:
| Beat | bits 31:0 | bits 63:32 |
|---|---|---|
| 0 | magic 0x31424956 | version/header 0x00010040 |
| 1 | session ID 1 | packet sequence |
| 2 | first output-frame index | reserved 0 |
| 3 | frames 4092 | payload bytes 65472 |
| 4 | source frames snapshot | accepted frames snapshot |
| 5 | dropped frames snapshot | FIFO high watermark |
| 6 | status snapshot | build ID 0x20260816 |
| 7 | first output-frame index mirror | packet sequence mirror |
其中 first output-frame index 是已发送数据流中的帧偏移,不是 ADC 的绝对采样时间戳。
8.3 Payload 格式
跳转到“8.3 Payload 格式”每帧 16 字节:
| 帧内字节偏移 | 内容 |
|---|---|
+0x00 | CH0:{8'hA0, source_sequence[23:0]} |
+0x04 | CH1:{8'hA1, source_sequence[23:0]} |
+0x08 | CH2:{8'hA2, source_sequence[23:0]} |
+0x0C | CH3:{8'hA3, source_sequence[23:0]} |
Linux 解析时按 little-endian 32-bit 字读取。序号按模 2^24 递增,默认速率下约 65.498 秒回绕一次,测试程序已覆盖回绕。
XDMA 自身的 C2H DMA 完成机制负责唤醒阻塞读取;当前 usr_irq_req 固定为 0,未使用独立 user interrupt,也不以 /dev/xdma0_events_0 作为本协议的完成条件。
8.4 长时间无缝波形的计数边界
跳转到“8.4 长时间无缝波形的计数边界”当前 CSR 计数、包序号和 first output-frame index 均为 32 bit。在默认帧率下,帧计数约在以下时间回绕:
2^32 / 256147.541 ≈ 16767.5 s ≈ 4.658 h测试载荷内的 24-bit 源序号更早在约 65.498 秒回绕。测试程序能按模数校验这些回绕,但单次 stream 命令会拒绝总帧数超过 0xffffffff 的请求。当前 159.754 秒耐久测试不能推出产品已具备数小时或数天的无缝长波形能力。
产品协议至少应升级为 64-bit 采样序号和 64-bit 时间戳,并做跨 32-bit 边界、跨小时、文件分段、应用重启和环形缓冲覆盖测试。
9. 行为仿真
跳转到“9. 行为仿真”9.1 环境检查
跳转到“9.1 环境检查”打开 Vivado 2026.1 命令行环境,确认以下命令可执行:
vivado -versionxvlog -helpxelab -helpxsim -help9.2 一键运行
跳转到“9.2 一键运行”先检查根工程没有残留旧 Block Design、器件和 XDMA 模式正确:
vivado -mode batch -source scripts\check_project.tcl必须出现:
CAPTURE_ROOT_PROJECT_PASS该检查确认根工程为 xc7a200tfbg484-2、顶层为 capture_top、Block Design 数量为 0、XDMA 使用 AXI-Stream,且 AXI-Lite Master 已启用。
然后运行三项行为仿真:
进入源码包根目录执行:
powershell -ExecutionPolicy Bypass -File scripts\run_sim.ps1脚本依次运行三个测试:
| 测试平台 | 覆盖内容 |
|---|---|
tb_capture_datapath.sv | 测试源、异步 FIFO、跨域计数、反压、分包、停止与清理 |
tb_capture_axil_csr.sv | AXI-Lite AW/W 独立握手、R/B 反压、WSTRB、clear/start 竞争 |
tb_capture_block_size.sv | 生产配置 65536 字节、4092 帧、8192 beat、TLAST 位置 |
通过标志必须完整出现:
CAPTURE_DATAPATH_TEST_PASSCAPTURE_AXIL_CSR_TEST_PASSCAPTURE_BLOCK_SIZE_TEST_PASS bytes=65536 frames=4092CAPTURE_ALL_SIMULATIONS_PASS只看到仿真进程退出不算通过;必须检查全部四个标志。
10. 生成工程、实现和 bitstream
跳转到“10. 生成工程、实现和 bitstream”10.1 Tcl 动作定义
跳转到“10.1 Tcl 动作定义”create_project.tcl 接受两个目标和四种动作:
target: a35t | a200taction: create | synth | impl | buildcreate:只创建工程和 XDMA IP;synth:运行综合并生成利用率报告;impl:运行到 route,不生成 bitstream;build:A200T 运行到 bitstream;A35T 因临时管脚仍只运行到 route。
脚本会删除自己管理的生成目录。运行前应关闭 Vivado GUI,避免工程锁或 GUI 中未保存的修改被丢失。
10.2 创建 A200T 图形工程
跳转到“10.2 创建 A200T 图形工程”vivado -mode batch -source scripts\create_project.tcl -tclargs a200t create随后可用 Vivado 2026.1 打开根目录的 adfpga.xpr。顶层是 capture_top,本设计没有 Block Design、MIG 或 AXI DMA,可在 RTL Analysis -> Open Elaborated Design 查看原理图。
10.3 验证 A35T 可实现性
跳转到“10.3 验证 A35T 可实现性”vivado -mode batch -source scripts\create_project.tcl -tclargs a35t impl预期末尾包含:
CAPTURE_A35T_NOTICE=route-only; product pinout is still provisionalCAPTURE_IMPLEMENTATION_PASS target=a35t脚本对 A35T 设置工程门限:
- LUT 不超过 17,680,即器件的 85%;
- BRAM 不超过 40 tiles,即器件的 80%;
- WNS 和 WHS 不得为负;
- DRC Error 和 Critical Warning 必须为 0;
no_clock和unconstrained_internal_endpoints必须为 0。
10.4 构建 A200T bitstream
跳转到“10.4 构建 A200T bitstream”vivado -mode batch -source scripts\create_project.tcl -tclargs a200t build生成文件:
artifacts/a200t/capture_top.bit每次重新构建都会改变“已验证产物”的身份。只有重新完成第 12 节全部真板回归后,才能把新哈希标记为硬件验证通过。
11. A200T 下载与 PCIe 重新枚举
跳转到“11. A200T 下载与 PCIe 重新枚举”11.1 A200T 实际管脚约束
跳转到“11.1 A200T 实际管脚约束”| 信号 | 管脚/约束 | 说明 |
|---|---|---|
pcie_ref_clk_p[0] | F6 | PCIe 100 MHz 差分参考时钟正端 |
pcie_mgt_rxp[0] | D9 | GTP Lane 0 RX 正端 |
pcie_mgt_txp[0] | D7 | GTP Lane 0 TX 正端 |
pcie_rst_n | N15, LVCMOS33 | PCIe PERST# |
lnk_up_led | W7, LVCMOS15 | user_lnk_up 指示 |
时钟及例外约束:
create_clock -period 10.000 -name pcie_ref_clk \ [get_ports {pcie_ref_clk_p[0]}]set_false_path -from [get_ports pcie_rst_n]set_false_path -to [get_ports lnk_up_led]差分负端由对应的专用差分资源确定,不能把普通 GPIO 任意指定为负端。
11.2 下载 bitstream
跳转到“11.2 下载 bitstream”先确认 JTAG 链上只有一个 xc7a200t,再执行:
vivado -mode batch -source scripts\program_a200t.tcl下载脚本会检查器件数量;发现 0 个或多个候选器件时会停止,不会模糊选择。
11.3 上电与枚举顺序
跳转到“11.3 上电与枚举顺序”- 断电连接 PCIe,确认两板供电和公共地;
- 给 FPGA 上电并通过 JTAG 下载新 bitstream;
- 硬复位或重启 i.MX8MP;
- 等待 Linux 重新枚举 Endpoint;
- 检查链路和设备节点;
- 再运行采集测试。
修改 XDMA 的 BAR、AXI-Stream 引擎或 IP 配置后,只执行 modprobe -r xdma; modprobe xdma 不足以让 Root Complex 重新分配资源。
11.4 Linux 侧检查
跳转到“11.4 Linux 侧检查”lspci -nnlspci -vv -s 01:00.0 | grep -E 'LnkCap:|LnkSta:|MSI:|Kernel driver'modprobe xdmals -l /dev/xdma*dmesg | grep -Ei 'pcie|pci|xdma|aer|timeout|link' | tail -n 120当前测试至少需要:
/dev/xdma0_user/dev/xdma0_c2h_0预期设备为 10ee:7011、链路为 2.5GT/s x1、MSI 启用、驱动为 xdma。
12. i.MX8MP 真板回归
跳转到“12. i.MX8MP 真板回归”12.1 编译测试工具
跳转到“12.1 编译测试工具”源码包中的 tools/capture_hw_test.c 是完整的独立回归程序。目标根文件系统有 gcc 但没有 libc 开发头文件,因此程序在源码中声明了所需的最小 ABI,不依赖目标头文件。
本次记录环境为 Linux 5.4.70-2.3.0、XDMA 驱动日志版本 v2025.2.0。换内核或驱动后必须重新执行本节,不能直接继承 user BAR 文件语义和板测结论。
有网络时从源码包根目录传入板端:
scp tools/capture_hw_test.c root@<board-ip>:/tmp/capture_hw_test.c只有串口时可在已登录的板端 shell 中使用 ZMODEM:
cd /tmprz -y无论采用哪种方式,都在板端校验:
sha256sum /tmp/capture_hw_test.c预期 SHA-256:
ae049dcde68fea89e03ebc7044eeb61516888ab6883e1333470621531d03a03b把文件放到板端 /tmp/capture_hw_test.c 后执行:
gcc -O2 -Wall -Wextra /tmp/capture_hw_test.c -o /tmp/capture_hw_test编译必须无 error。warning 也应逐项检查,不要直接忽略。
12.2 当前 /dev/xdma0_user 的特殊行为
跳转到“12.2 当前 /dev/xdma0_user 的特殊行为”当前实测 XDMA 驱动的 user 字符设备:
- 拒绝
lseek; - 每次
read只前进一个 32-bit BAR word; - 测试工具每次重新
open,从偏移 0 逐字读到目标寄存器; - 写目标寄存器前也先顺序读到对应位置。
因此不能照搬旧 DDR 教程中的 lseek + read/write 方法,也不要用 dd skip/seek 猜寄存器偏移。若替换驱动版本,应先重新验证 user BAR 的文件操作语义。
12.3 身份和清洁状态
跳转到“12.3 身份和清洁状态”开始回归前保存内核日志基线:
dmesg > /tmp/dmesg.before.txt/tmp/capture_hw_test info必须出现:
IDENTITY_PASS magic=31424956 version=00010001 build=20260816 ...并确认:
STATUS.bit31=1;- CONTROL 为 0;
- FIFO 为空;
- source、accepted、dropped、transmitted、packet 计数均为 0。
如果版本不是 0x00010001,停止测试,先确认 bitstream 和重新枚举过程。
12.4 100 次启停、排空和清理
跳转到“12.4 100 次启停、排空和清理”/tmp/capture_hw_test cycles 100该测试每次运行两个完整包,验证启动、停止、补齐当前块、C2H 排空和清零。通过标志:
CYCLES_PASS cycles=100 packets=200 frames=818400HW_TEST_RC=012.5 100 次 clear/start 竞争
跳转到“12.5 100 次 clear/start 竞争”/tmp/capture_hw_test race 100测试在第二个包待处理时发出 clear,紧接着尝试 start。版本 1.1 必须拒绝清理期间的 start。通过标志:
CLEAR_START_RACE_PASS cycles=100 packets=200 frames=818400HW_TEST_RC=012.6 1000 包连续流
跳转到“12.6 1000 包连续流”/tmp/capture_hw_test stream 1000通过条件:
- 每包恰好 65,536 字节;
- 包序号连续;
- 每帧 A0/A1/A2/A3 标签正确;
- 24-bit 源序号连续;
- dropped 为 0;
- 停止后 accepted 等于 transmitted;
- 安全清理后所有计数归零;
- 最终
HW_TEST_RC=0。
12.7 4 ms 短时反压
跳转到“12.7 4 ms 短时反压”/tmp/capture_hw_test pause 4000测试先启动数据源,再故意让 C2H 读取暂停 4000 微秒。预期:
BACKPRESSURE_PASS pause_us=4000 dropped=0 hwm=<诊断值>HW_TEST_RC=0硬判据是 dropped 为 0;高水位用于记录裕量,不要求固定数值。本次实测为 1204/2048。它验证 32 KiB FIFO 能覆盖设计目标内的短时主机抖动。
12.8 50 ms 强制溢出与恢复
跳转到“12.8 50 ms 强制溢出与恢复”/tmp/capture_hw_test overflow 5000050 ms 明显超过 FIFO 覆盖时间,测试故意制造溢出。这里“发生丢帧”是预期行为,真正的验收点是:
STATUS.bit2=1;DROPPED_FRAMES > 0;- FIFO 高水位不低于
prog_full门限 2032; - payload 中统计的源序号缺口等于硬件 dropped 计数;
- 安全清理后可以重新启动并正确接收;
- 输出
OVERFLOW_RECOVERY_PASS和HW_TEST_RC=0。
12.9 10000 包耐久测试
跳转到“12.9 10000 包耐久测试”前述测试全部通过后执行:
/tmp/capture_hw_test stream 10000该测试传输 655,360,000 字节、40,920,000 帧,并跨越多次 24-bit 源序号回绕。
12.10 测试后的内核日志
跳转到“12.10 测试后的内核日志”dmesg > /tmp/dmesg.after.txtdiff -u /tmp/dmesg.before.txt /tmp/dmesg.after.txt \ | grep '^+' | grep -v '^+++' \ | grep -Ei 'xdma.*timeout|aer.*error|completion timeout|link.*down'命令无输出才表示本轮相对基线没有新增匹配项。本轮测试期间不得新增 XDMA timeout、PCIe AER、completion timeout 或 link-down。若系统没有 diff,至少记录开始前的 dmesg 行数,并只检查此后新增行,不能用一次全量 grep 区分历史错误和新错误。
13. C2H 操作中最重要的顺序
跳转到“13. C2H 操作中最重要的顺序”第一次 C2H 读取必须遵循:
sequenceDiagram participant APP as capture_hw_test participant XDMA as /dev/xdma0_c2h_0 participant CSR as /dev/xdma0_user participant FPGA as FPGA 数据源
APP->>XDMA: 先提交 65536-byte 阻塞 read APP->>CSR: CONTROL = 1 CSR->>FPGA: 启动测试源 FPGA-->>XDMA: 64 KiB AXI4-Stream + TLAST XDMA-->>APP: read 返回 65536 APP->>APP: 校验 header、标签、序号和计数不要先启动数据源再慢慢准备 DMA。FIFO 只有约 8 ms 缓冲,错误顺序会把软件启动延迟误判成硬件吞吐问题。
如果进程在收到半个 C2H 包后退出,当前 FPGA 没有 force-abort 命令。恢复方法只有:
- 继续完成该包读取;或
- 重新配置/复位 Endpoint,并让 i.MX8MP 重新枚举。
14. 已记录的真板结果
跳转到“14. 已记录的真板结果”以下结果来自 2026-08-16 工程回归记录。原始串口 transcript 未作为独立附件发布,因此这些数据应理解为工程记录摘要,而不是第三方可重复审计的原始日志。
| 测试 | 结果 |
|---|---|
| Identity | MAGIC=31424956、VERSION=00010001、BUILD_ID=20260816 |
| 100 次 cycles | 200 包、818,400 帧,通过 |
| 100 次 clear/start race | 200 包、818,400 帧,全部拒绝过早 start |
| 1000 包连续流 | 65,536,000 字节、4,092,000 帧、15.976 s、4.102 MB/s、0 丢帧 |
| 4 ms 反压 | 0 丢帧,FIFO 高水位 1204/2048 |
| 50 ms 强制溢出 | dropped 10,922,payload gaps 10,922,高水位 2048,恢复通过 |
| 10000 包耐久 | 655,360,000 字节、40,920,000 帧、159.754 s、0 丢帧 |
| 内核日志 | 无新增 XDMA timeout、AER、completion timeout、link-down |
最终清理后的 CSR 状态为空,证明停止、排空、清理和重启形成闭环。
15. 实现结果与 35T 产品迁移
跳转到“15. 实现结果与 35T 产品迁移”15.1 资源和时序
跳转到“15.1 资源和时序”Vivado 2026.1 记录结果:
| 目标 | LUT | FF | BRAM | DSP | WNS | WHS | 状态 |
|---|---|---|---|---|---|---|---|
XC7A35T-FGG484-2 | 10,519 / 20,800 | 12,670 / 41,600 | 25 / 50 | 0 / 90 | +4.108 ns | +0.030 ns | route-only |
XC7A200T-FBG484-2 | 10,514 / 134,600 | 12,670 / 269,200 | 25 / 365 | 0 / 740 | +2.253 ns | +0.036 ns | bitstream + 真板通过 |
两个目标均记录为:
- DRC Error = 0;
- DRC Critical Warning = 0;
- 无未加时钟寄存器;
- 无未约束内部 endpoint;
- 自定义采集逻辑无未解释 CDC;
- 剩余警告位于生成的 XDMA IP 内部。
A35T 的时序和 DRC 数字只适用于当前临时管脚 XDC。最终 PCB pinout 会改变布局和路由,必须重新实现;当前正时序不能作为正式管脚的时序签核。
35T 已使用约 50.6% LUT、50% BRAM,仍可接入 AD7768 接收、SPI、键相捕获、时间戳和少量预处理,但后续每次扩展都必须重新检查资源、路由拥塞和时序。不要只看“还有 LUT”,BRAM、时钟资源、GTP、IO bank 和 PCB 管脚同样可能先成为限制。
从层级利用率看,XDMA 本身约占 9,674 LUT、11,169 FF 和 17.5 BRAM;采集 datapath 约占 825 LUT、1,385 FF 和 7.5 BRAM。35T 的主要固定成本是 PCIe/XDMA,而不是测试源或分包器。按当前工程门限还剩 7,161 LUT 和 15 BRAM 的余量,适合增加采样接收、键相边沿捕获、时间戳和控制逻辑,但不应据此承诺把角度重采样、FFT 和完整动平衡算法全部放入 FPGA。
15.2 为什么目前不生成 35T bitstream
跳转到“15.2 为什么目前不生成 35T bitstream”constraints/a35t/provisional_pcie.xdc 中的管脚只是用于 place/route 可行性分析,不能代表产品板。脚本设置 allow_bitstream=0,即使使用 a35t build 也只运行到 route。
产品化前必须确认:
- 精确订货型号是
XC7A35T还是车规XA7A35T; - 封装是否确实为
FGG484; - 速度级和温度等级;
- PCIe Lane 0 的 GTP RX/TX 管脚;
- 100 MHz REFCLK 差分输入及其专用资源;
- PERST# 电平标准和上电时序;
- 配置 Flash、JTAG、模式脚和电源配置;
- AD7768 DCLK 是否进入合适的时钟能力管脚;
- AD7768、SPI、键相输入的 IO bank 电压;
- 根据 ADC 手册和 PCB 走线补齐输入延迟约束。
只有这些项目签核后,才能替换临时 XDC、允许 35T 写 bitstream。还必须新增只接受精确产品器件的下载脚本,例如 program_a35t_product.tcl;现有 program_a200t.tcl 会严格拒绝 35T,不能复用。完成正式 XDC、产品构建脚本和 35T 下载脚本后,再在真实产品板上重复仿真、工程检查、实现、下载、枚举和第 12 节板端回归。
15.3 后续接入 AD7768
跳转到“15.3 后续接入 AD7768”接入真实 ADC 时保留 packetizer、CSR 和 XDMA,替换测试源前端:
flowchart LR ADC["AD7768-4<br/>DCLK / DRDY / DOUT"] RX["TDM 接收与帧对齐<br/>4 × 32 bit"] META["采样序号 / 时间戳 / 状态"] FIFO["128-bit async FIFO"] PKT["64 KiB packetizer"] XDMA["XDMA C2H"]
ADC --> RX --> META --> FIFO --> PKT --> XDMA四个 32-bit ADC 字已经占满当前 128-bit FIFO 帧,因此不能在“仍保持 16-byte 帧”时直接再塞入序号和时间戳。产品协议必须先明确以下方案之一:
- 扩宽内部帧,例如 256 bit,携带四通道数据、64-bit 序号和 64-bit 时间戳;固定 64 KiB 包将相应改为
64-byte header + 2046 × 32-byte frame,并升级协议版本; - 保持 16-byte 数据帧,只在块头记录 64-bit 首样序号、首样时间戳和丢帧增量,同时把溢出策略改成整块丢弃,才能明确定位缺口边界;
- 使用独立元数据流,但必须定义它与数据包的原子对应、复位和丢失恢复规则。
在真实 AD7768 接入前应选定一种并完成带宽、BRAM、异常恢复和软件解析评审。不能同时承诺当前 128-bit 帧、当前每包 4092 帧和新增的逐帧 128-bit 元数据都保持不变。
建议分步验证:
- 保留测试源回归,确认 PCIe 基线未破坏;
- 只接入 AD7768 SPI,完成芯片 ID/复位值读回;
- 用仿真模型替换测试源,验证 DRDY、DCLK、MSB first 和四通道顺序;
- 用 ILA/示波器确认真板采样边沿;
- 在每帧加入硬件采样序号,验证丢样定位;
- 再加入键相边沿时间戳;
- 最后由 i.MX8MP 做角度重采样、阶次谱和动平衡矢量计算。
FPGA 不需要在 35T 内完成完整阶次谱或动平衡算法。它更适合保证确定性采样、键相时间戳、分包、丢帧可检测和 PCIe 传输;复杂浮点计算及用户界面放在 i.MX8MP。
16. 常见故障定位
跳转到“16. 常见故障定位”16.1 lspci 看不到 FPGA
跳转到“16.1 lspci 看不到 FPGA”检查:
- FPGA 是否已下载包含 XDMA 的正确 bitstream;
- 下载后是否硬复位/重启 i.MX8MP;
- 100 MHz REFCLK、PERST#、RX/TX 方向和公共地;
- 两板电源是否稳定。
此时不要先调 xdma.ko,因为 PCIe 枚举发生在驱动绑定之前。
16.2 有 PCIe 设备但没有 /dev/xdma0_user
跳转到“16.2 有 PCIe 设备但没有 /dev/xdma0_user”检查:
- 是否加载了当前 AXI-Stream bitstream,而不是旧 AXI-MM DDR bitstream;
- XDMA AXI-Lite Master 是否启用;
- Root Complex 是否在下载后重新枚举;
- xdma.ko 的架构、vermagic 和运行内核是否匹配。
16.3 info 的版本不对
跳转到“16.3 info 的版本不对”VERSION=0x00010001 才包含 clear/start 竞争修复。版本不符时不要继续压力测试;先检查 bitstream SHA-256、JTAG 下载结果和 PCIe 重新枚举。
16.4 第一包超时
跳转到“16.4 第一包超时”检查顺序:
- 是否先提交 65536-byte C2H read;
- 再写 CONTROL=1;
STATUS.bit31是否为 1;STATUS.bit5是否变为 1;- source/accepted 是否增长;
- FIFO level 是否增长;
- XDMA C2H engine 是否存在 timeout。
16.5 能收到数据但长度不是 65536
跳转到“16.5 能收到数据但长度不是 65536”重点检查:
- header 是否为 64 字节;
- 每包是否恰好 4092 帧;
TLAST是否只在最后一帧高 64-bit beat;TKEEP是否始终0xFF;- 主机 read 长度是否正好 65536。
16.6 4 ms 反压就丢帧
跳转到“16.6 4 ms 反压就丢帧”检查:
- FIFO 是否实际综合成 2048 × 128 bit BRAM;
- C2H read 是否提前挂起;
- 测试速率是否被改高;
TREADY恢复后 packetizer 是否继续握手;- FIFO reset busy 是否意外出现。
16.7 overflow 的 dropped 与 payload gap 不一致
跳转到“16.7 overflow 的 dropped 与 payload gap 不一致”这意味着统计或数据路径有不一致,不能把它当成“溢出本来就会丢数据”而忽略。检查源序号、FIFO 写使能、Gray 计数同步、payload 解析和 24-bit 回绕处理。
16.8 clear 后无法重新启动
跳转到“16.8 clear 后无法重新启动”检查:
- 软件是否继续读取并排空最后一个完整包;
STATUS.bit6是否回到 0;- FIFO 是否为空;
- accepted 是否等于 transmitted;
- 所有会话计数是否归零;
- 是否遗弃了半个 C2H 包。
16.9 不要混用旧 DDR 测试
跳转到“16.9 不要混用旧 DDR 测试”旧的 AXI-MM DDR 基线使用 H2C/C2H 对同一 FPGA 地址写入、读回和比较。当前方案是 AXI4-Stream C2H 固定包协议:
- 没有 FPGA DDR 地址;
- 不支持用
dd写随机数据再读回; - 不使用 AXI DMA S2MM;
- 必须解析 64-byte header 和 payload。
两套 bitstream、设备访问方式和验收标准必须分别保存。
17. 产物、哈希和复现闭环
跳转到“17. 产物、哈希和复现闭环”17.1 公开源码包
跳转到“17.1 公开源码包”file: adfpga-xdma-stream-source-20260816.zipcontents: RTL、仿真、Tcl、XDC、XDMA XCI、A200T XPR、真板 C 工具bitstream: 不包含Vivado cache/runs: 不包含源码包 SHA-256:
1404194a6ebfb92888ccb77c61356f298299cf8e6f46cc3274472cb5f9114b03下载后可在 PowerShell 验证:
(Get-FileHash -Algorithm SHA256 .\adfpga-xdma-stream-source-20260816.zip).Hash该 ZIP 及其 SHA-256 是本教程的公开、不可混淆源码快照;外部 adfpga 开发分支不作为本页复现依据。发布后应以包含本页和该 ZIP 的 VitaLogos Git commit 固定版本,避免把后续工作区内容误认为本次已验证源码。
17.2 已验证 A200T bitstream 记录
跳转到“17.2 已验证 A200T bitstream 记录”bitstream 不在公开源码包中,必须由 Vivado 2026.1 重建。已完成板测的本地产物记录为:
file: artifacts/a200t/capture_top.bitsize: 2,059,153 bytesSHA-256: 36AD9007714DE422B334BE9CC1480A64404BAC69FE0A00713FD785AA47DB73A7CSR: VERSION=0x00010001, BUILD_ID=0x20260816重新构建的 bitstream 即使 RTL 未改,也应重新计算哈希并执行真板回归,不能直接继承这份硬件验证结论。
18. 最短复现清单
跳转到“18. 最短复现清单”FPGA 主机
跳转到“FPGA 主机”# 1. 仿真powershell -ExecutionPolicy Bypass -File scripts\run_sim.ps1
# 2. 根工程结构与 XDMA 模式vivado -mode batch -source scripts\check_project.tcl
# 3. 35T route-only 可行性vivado -mode batch -source scripts\create_project.tcl -tclargs a35t impl
# 4. A200T bitstreamvivado -mode batch -source scripts\create_project.tcl -tclargs a200t build
# 5. A200T JTAG 下载vivado -mode batch -source scripts\program_a200t.tcl下载后硬复位或重启 i.MX8MP。
i.MX8MP
跳转到“i.MX8MP”lspci -nnmodprobe xdmals -l /dev/xdma0_user /dev/xdma0_c2h_0
sha256sum /tmp/capture_hw_test.cgcc -O2 -Wall -Wextra /tmp/capture_hw_test.c -o /tmp/capture_hw_test
dmesg > /tmp/dmesg.before.txt
/tmp/capture_hw_test info/tmp/capture_hw_test cycles 100/tmp/capture_hw_test race 100/tmp/capture_hw_test stream 1000/tmp/capture_hw_test pause 4000/tmp/capture_hw_test overflow 50000/tmp/capture_hw_test stream 10000
dmesg > /tmp/dmesg.after.txtdiff -u /tmp/dmesg.before.txt /tmp/dmesg.after.txt \ | grep '^+' | grep -v '^+++' \ | grep -Ei 'xdma.*timeout|aer.*error|completion timeout|link.*down'最终验收标准:仿真、A35T 实现门限、A200T build、身份检查、全部板端回归和内核日志检查同时通过。任何一项缺失,都只能声明相应子阶段通过,不能扩大成“35T 产品采集系统已经完成”。