基于 Xilinx XDMA 和 FFT IP,实现一个实时音乐频谱分析仪。PC 端通过 Python 解码 MP3 音频并经 PCIe DMA 写入 FPGA,FPGA 内部完成 FFT 变换后将频谱数据 DMA 回传 PC,PC 端通过 Web 界面实时可视化频谱。
┌─────────────────────────────────────────────────────────────────────────┐
│ Linux Server (Python) │
│ │
│ MP3文件 → 解码为PCM → 声道合并(立体声→单声道) → 分帧(1024点) │
│ ↓ │
│ XDMA H2C ──── PCIe ────► FPGA PL │
│ │ │
│ ┌────▼─────┐ ┌─────────┐ ┌──────────┐ │
│ │ Input │───►│ FFT │───►│ 幅度计算 │ │
│ │ FIFO │ │ IP │ │ (|X[k]|) │ │
│ └──────────┘ └─────────┘ └────┬─────┘ │
│ │ │
│ Web浏览器 ◄── WebSocket ◄── Python ◄── XDMA C2H ◄─────────┘ │
│ (频谱可视化) │
└─────────────────────────────────────────────────────────────────────────┘
采用 BD Wrapper + RTL 顶层 的混合架构:
- Block Design 包含 XDMA IP + CDC FIFO(Independent Clock 模式),完成 axi_aclk → clk_100m 跨时钟域转换
- BD 引出的 AXI-Stream 接口已在 clk_100m 域,外部无需感知 axi_aclk
- 顶层 RTL (
top.v) 例化 BD Wrapper、Clock Wizard、FFT IP 和幅度计算模块,所有用户逻辑运行在 100 MHz
top.v (RTL 顶层,全部 clk_100m 域)
┌──────────────────────────────────────────────────────────────────┐
│ │
│ ┌────────────┐ │
│ │ Clock Wiz │ 100M diff in → clk_100m + locked │
│ └─────┬──────┘ │
│ │ clk_100m, locked │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ BD Wrapper │ │
│ │ ┌───────┐ ┌───────────┐ │ (clk_100m域) ┌─────────┐ │
│ │ │ XDMA │───►│ Input CDC │─│────────────────►│ FFT │ │
│ │ │ │ │ FIFO │ │ │ IP │ │
│ │ │ │◄───│Output CDC │◄│──────┐ └────┬────┘ │
│ │ │ │ │ FIFO │ │ │ │ │
│ │ └───────┘ └───────────┘ │ │ ┌────────────▼───────┐ │
│ └──────────────────────────────┘ └──│ magnitude_calc │ │
│ │ 幅度计算(|Re|+|Im|)│ │
│ PCIe ◄─────────────────────────────── └────────────────────┘ │
│ (金手指) │
└──────────────────────────────────────────────────────────────────┘
| 组件 | 选型 | 说明 |
|---|---|---|
| 目标器件 | xcku3p-ffvb676-2-e | Kintex UltraScale+ |
| PCIe DMA | Xilinx XDMA IP | PCIe Gen3 x4,AXI4-Stream 模式,128-bit 数据宽度 |
| FFT | Xilinx FFT IP (xfft) | 1024 点,Pipelined Streaming 架构 |
| 时钟 | Clocking Wizard IP | 100 MHz 差分输入 → 100 MHz 单端输出 |
| 音频格式 | 16-bit signed PCM | MP3 解码后标准格式,44.1kHz 采样率 |
| PC 驱动 | Xilinx XDMA Linux 驱动 | /dev/xdma0_h2c_0, /dev/xdma0_c2h_0 |
| 上位机 | Python + FastAPI + WebSocket | 实时推送频谱数据 |
| 前端 | HTML5 Canvas | 频谱柱状图 + 可选瀑布图 |
| 参数 | 值 | 说明 |
|---|---|---|
| FFT 点数 | 1024 | 频率分辨率 ≈ 44100/1024 ≈ 43 Hz |
| 数据位宽 | 16-bit | 与 PCM 采样精度一致 |
| 采样率 | 44100 Hz | CD 质量标准采样率 |
| PCIe 配置 | Gen3 x4 | 带宽远超音频需求 |
| 频谱更新率 | ~43 帧/秒 | 44100 / 1024 ≈ 43 fps |
| 用户时钟 | 100 MHz | Clock Wizard 输出,驱动 FFT 和所有用户逻辑 |
| AXI 时钟 | ~250 MHz | XDMA 内部 axi_aclk,封闭在 BD 内不引出 |
本项目分为以下阶段,每个阶段对应一份子任务书:
目标:创建 Vivado 工程,搭建包含 XDMA + FIFO 的 Block Design,生成输出产物与 HDL Wrapper。
核心工作:
- 创建 Vivado 工程,目标器件
xcku3p-ffvb676-2-e - 搭建 Block Design:
- XDMA IP(PCIe Gen3 x4,AXI4-Stream 模式,1 个 H2C + 1 个 C2H 通道)
- Input FIFO(H2C → FFT 方向的缓冲)
- Output FIFO(幅度计算 → C2H 方向的缓冲)
- 验证 BD 设计,生成输出产物 + HDL Wrapper
交付物:子任务书 phase1_block_design.md
目标:创建并配置 FFT IP(独立 IP,不在 BD 内),并通过仿真验证其功能正确性。
核心工作:
- 创建 FFT IP:1024 点,16-bit 输入,Pipelined Streaming 架构
- 生成 IP 输出产物
- 编写 FFT IP 仿真 testbench(SystemVerilog),13 项测试全部 PASS:
- 单频正弦波 bin 64 → ratio=100.0 dB(旁瓣抑制 >40 dB)
- 多频叠加信号 → bin 64 + bin 256 正确分离
- AXI4-Stream 间歇 tvalid 握手正确
- 连续 4 帧处理,帧间无串扰,tlast 正确
- Config 通道握手 + 全零 / DC / 最大幅值 / Nyquist 验证
关键发现:
- FFT IP (Pipelined Streaming) 上电有 phantom config slot,需发送 warm-up 帧对齐
- xsim 行为模型与
$urandom_range随机 gap 不兼容,改用确定性 gap
交付物:子任务书 phase2_fft_ip.md
目标:编写幅度计算 RTL 模块,对 FFT 输出的复数结果取近似幅度,并通过仿真全面验证。
核心工作:
- 编写
magnitude_calc.v(L1 近似幅度:|Re| + |Im|),纯组合直通 AXI4-Stream- 17-bit 符号扩展正确处理 -32768 边界
- 18-bit 加法 + 饱和到 16-bit unsigned(仅 Re=Im=-32768 时触发)
- 编写
tb_magnitude_calc.v单元 testbench(TC-01~TC-05):- TC-01:9 组已知复数幅度验证(含 -32768、饱和、零值)
- TC-02:1024 样本随机反压,无数据丢失
- TC-03:2 帧 × 1024 点 tlast 传递
- TC-04:快速翻转反压(每 1~2 拍),无数据损坏
- TC-05:背靠背帧,帧边界无混淆
- 编写
tb_fft_magnitude.v级联 testbench(TC-06):- TC-06a:FFT → magnitude_calc 端到端,bin 64 peak=4096, ratio=100.0 dB
- TC-06b:双帧连续处理,bin 64 + bin 256 均正确
交付物:子任务书 phase3_magnitude_calc.md
目标:编写顶层 RTL,例化所有子模块并完成信号连接,通过系统级仿真验证完整数据通路。
核心工作:
- 创建 Clock Wizard IP
clk_wiz_0:100 MHz 差分输入 → 100 MHz 单端输出,active-low reset,OOC 综合完成 - 编写
top.v,例化 BD Wrapper + Clock Wizard + FFT IP + magnitude_calc- H2C 位宽适配(128→32):取低 16-bit PCM,虚部补零
- C2H 位宽适配(16→128):零扩展,tkeep=16'hFFFF
- FFT Config 驱动:cfg_sent 标志位,每帧 tlast 后自动清零重发 CFG_WORD=16'h0557
- 单时钟域:所有用户逻辑运行在 clk_100m (100 MHz)
- 语法检查通过
- 编写
tb_datapath.v系统级仿真(14 秒完成),4 项测试全部 PASS:- TC-01:单频正弦 bin=64,peak=4000,noise=0
- TC-02:连续 4 帧 (bin 64/128/256/32),6144 samples,全部正确
- TC-03:复位恢复,复位后系统正常工作
- TC-04:反压测试(4/2 周期模式),无数据丢失
交付物:子任务书 phase4_top_integration.md
目标:创建约束文件,完成综合与布局布线,确保时序收敛,生成比特流。
核心工作:
- 创建 XDC 约束:sys_clk(E18/D18 LVDS)、pcie_refclk(T7)、pcie_txp、pcie_perstn(A9)、led(B12)
- 综合耗时 46 秒,WNS = 1.358 ns
- 实现完成,WNS = 0.631 ns, WHS = 0.010 ns — 全部时序满足
- opt_design 优化:LUT 20201→15861 (-21.5%), FF 24796→22716 (-8.4%)
- 资源利用率:LUT 9.75%, FF 6.98%, BRAM 12.5%, DSP 0.88%, GT 25%, PCIE 100%
- 比特流生成耗时 66 秒,DRC 仅 3 Warning 无 Error
交付物:子任务书 phase5_synthesis_implementation.md
目标:在 Linux 服务器上安装 XDMA 驱动,完成基本的 DMA 读写验证。
核心工作:
- 通过本地 Vivado Hardware Manager 烧录比特流,reboot 远程服务器完成 PCIe 枚举
- PCIe Link: Gen3 x4 (8GT/s), BDF 01:00.0, Device ID 9034
- XDMA 驱动预编译
xdma.ko已安装,开机自动加载,/dev/xdma0_{h2c,c2h}_0 正常创建 test_dma.py:ramp 数据 16384 bytes H2C→C2H 通道畅通test_fft.py:三项测试全部 PASS- 单频 bin64: peak=4000(与仿真一致)
- 多频 bin64+256: 两频均=2000,镜像正确
- 静音: 输出全零
交付物:子任务书 phase6_driver_verification.md
目标:开发完整的上位机应用,实现 MP3 解码、DMA 传输、Web 实时频谱显示。
核心工作:
- Python 音频处理管线:MP3 解码 → 立体声合并 → 分帧 → DMA 写入
- Python 频谱读取管线:DMA 读回 → 归一化 → WebSocket 推送
- FastAPI 服务端 + WebSocket 端点
- 前端频谱可视化:Canvas 绘制频谱柱状图
- 集成测试:端到端播放 MP3 并观察频谱
交付物:子任务书 phase7_host_application.md
F:\synthpilot_tutorial\
├── doc\
│ └── 06_xdma_fft_音乐频谱分析仪\
│ ├── 主任务书.md ← 本文件
│ ├── phase1_block_design.md
│ ├── phase2_fft_ip.md
│ ├── phase3_magnitude_calc.md
│ ├── phase4_top_integration.md
│ ├── phase5_synthesis_implementation.md
│ ├── phase6_driver_verification.md
│ └── phase7_host_application.md
└── prj\
└── 04\ ← 工程根目录
├── prj\ ← Vivado 工程
├── rtl\ ← 自定义 RTL(top.v, magnitude_calc.v)
├── sim\ ← 仿真文件
└── host\ ← Python 上位机
├── pyproject.toml
├── fft_spectrum.py ← 主程序(DMA + WebSocket)
├── static\
│ └── index.html ← 频谱前端页面
└── test_dma.py ← DMA 基础测试脚本
| 项目 | 要求 |
|---|---|
| FPGA | xcku3p-ffvb676-2-e (Kintex UltraScale+) |
| 服务器 | Linux,PCIe x4 插槽可用 |
| Vivado | 2024.1 或更高 |
| Python | 3.10+ |
| XDMA 驱动 | Xilinx dma_ip_drivers(GitHub) |
| 编号 | 验证项 | 通过条件 |
|---|---|---|
| V-01 | PCIe 枚举 | lspci 可见 FPGA 设备 |
| V-02 | DMA 回环 | H2C 写入数据经 FFT 处理后 C2H 正确读回 |
| V-03 | 正弦波测试 | 输入单频正弦波,频谱在对应频率 bin 出现尖峰 |
| V-04 | 音乐频谱 | 播放 MP3,Web 页面实时显示频谱变化,视觉流畅 |
| V-05 | 长时间稳定性 | 连续运行 5 分钟以上,无 DMA 错误或页面卡顿 |