目录
[一、Bug 现象汇总](#一、Bug 现象汇总)
[1.1 正常现象(证明通信完全没问题)](#1.1 正常现象(证明通信完全没问题))
[1.2 异常现象(核心故障)](#1.2 异常现象(核心故障))
[误区 1:怀疑 FTW 高位为 0 导致无波形](#误区 1:怀疑 FTW 高位为 0 导致无波形)
[误区 2:怀疑 CH2 地址偏移错误](#误区 2:怀疑 CH2 地址偏移错误)
[误区 3:怀疑时钟、复位、RAM IP、波形选择逻辑](#误区 3:怀疑时钟、复位、RAM IP、波形选择逻辑)
[四、终极根因定位(致命底层 Bug)](#四、终极根因定位(致命底层 Bug))
[4.1 问题模块](#4.1 问题模块)
[4.2 故障代码真相](#4.2 故障代码真相)
[4.3 致命后果](#4.3 致命后果)
[4.4 综合日志铁证](#4.4 综合日志铁证)
[六、深度复盘 & 工程师经验总结](#六、深度复盘 & 工程师经验总结)
[1. 最隐蔽的 FPGA Bug 特征](#1. 最隐蔽的 FPGA Bug 特征)
[2. 高频踩坑点](#2. 高频踩坑点)
[3. 调试思维升华](#3. 调试思维升华)
前言
本次调试为自研任意波形发生器 FPGA+MCU 联合调试 经典疑难 Bug: 上位机正常下发参数、MCU 正常计算 FTW 频率字、FMC 总线写入 FPGA 寄存器完全正常,示波器无波形输出,正弦波 / 三角波 / 梯形波 / 自定义 RAM 波形全部卡死为直流电平,CH1、CH2 双通道同时失效。
这是典型的参数写入成功、硬件运算链路卡死的隐蔽逻辑 Bug,并非配置、时钟、复位、上位机协议问题。本文完整记录从现象迷惑、误区踩坑、逐层剥壳、最终定位底层逻辑缺陷的完整排错流程。
一、Bug 现象汇总
1.1 正常现象(证明通信完全没问题)
- 上位机可正常下发频率、波形类型、幅值参数
- MCU 端正常计算 64 位 FTW 频率控制字
- 通过 ARM 在线 Debug 观察:
FreqHHW / FreqHLW / FreqLHW / FreqLLW四分频写入正常- 低频 1Hz 场景下高两位为 0、低两位数值精准正确
- FPGA 寄存器映射区可读到完整 FTW 值,通信链路 100% 通畅
1.2 异常现象(核心故障)
- CH1、CH2 所有波形类型全部无法刷新
- 波形 RAM 地址不递增,始终固定在 0 地址
- 输出波形卡死为固定直流电平,无周期性变化
- 并非单通道故障,双通道共用逻辑卡死
二、初期排查误区(绝大多数人会踩坑)
误区 1:怀疑 FTW 高位为 0 导致无波形
调试初期观察:
pFpgaData->FreqHHW = 0;
pFpgaData->FreqHLW = 0;
下意识误以为高位归零是异常。
✅ 正确结论: 本项目 DDS 公式:

FPGA 实际仅使用 低 45bit 参与累加运算。
- 频率<610Hz:
FreqHLW必然为 0 - 频率<40MHz:
FreqHHW必然为 0
高位归零是数学正常现象,不是 Bug!
误区 2:怀疑 CH2 地址偏移错误
前期排查出 MCU 端 CH2 波形寄存器偏移写为 0x1000(错误),正确应为 0x2000。
但本次是 双通道全部失效 ,因此可以直接排除单通道偏移问题,锁定 双通道共用核心逻辑故障。
误区 3:怀疑时钟、复位、RAM IP、波形选择逻辑
逐层排查:
- DDS 工作时钟
CLK_DDS正常振荡 - 全局复位、模块局部复位正常
- 波形选择
Wave_Select多路选择逻辑无误 - RAM 读写端口、地址位宽、数据位宽配置无误
- 100us 参数刷新同步时钟正常锁存参数
所有外围逻辑全部正常,问题收敛到:DDS 相位累加器不工作。
三、逐层剥壳:完整波形运行链路复盘
完整波形输出流水线:
MCU计算FTW → FMC写入FPGA寄存器 → armm4_if寄存器解析
→ RefDataUpdate 100us 节拍锁存 → WaveCtrl DDS累加运算
→ RAM波形查表 → Wave_Select选波 → DA输出
通过逐段隔离法:
- 前级:寄存器写入 正常
- 中级:参数锁存、使能信号 正常
- 后级:RAM、多路选择 正常
- 唯一异常:相位累加器地址不递增
四、终极根因定位(致命底层 Bug)

4.1 问题模块
WaveCtrl.v DDS 核心累加器 lpm_add 模块
4.2 故障代码真相
工程中原版累加器例化 缺失 en 使能引脚:
// 原始错误代码
lpm_add inst2(
.aclr(lpm_add_aclr),
.clock(INPUT_CLK_DDS),
.dataa(acc_outreg),
.datab(INPUT_ftw[44:0]),
.result(acc_inreg));
lpm_add.v 内部逻辑:只有 en=1 才执行累加
if(en == 1'b1)begin
result <= dataa + datab;
end
4.3 致命后果
- Verilog 未连接的输入引脚 默认被综合器赋值为 0
en=0→ 累加器永久停止更新- 相位地址恒为 0 → RAM 永远只读取第 0 个点
- 所有波形卡死、无刷新、无周期变化
4.4 综合日志铁证
W: Adm-4083: Removed bmsWIDEDFFRSE inst result[44:0] that is stuck at constant 0
45bit 全部被综合器判定为恒 0,直接优化删除寄存器 这就是「有参数、不运算、无波形」的最核心根因。
五、问题修复
给累加器补上全局使能,开启 DDS 持续累加能力:
lpm_add inst2(
.aclr(lpm_add_aclr),
.clock(INPUT_CLK_DDS),
.en(1'b1), // 关键修复:补上累加使能
.dataa(acc_outreg),
.datab(INPUT_ftw[44:0]),
.result(acc_inreg));
修改代码后,清理工程缓存、重新综合编译、生成 BIT 文件下载至 FPGA,波形功能即可恢复。
六、深度复盘 & 工程师经验总结
1. 最隐蔽的 FPGA Bug 特征
- 寄存器参数完全正常
- 时钟复位完全正常
- 协议通信完全正常
- 纯逻辑使能缺失导致运算单元被综合器优化死锁
这类 Bug 无法通过打印、信号抓取快速发现,只能通过流水线分段隔离定位。
2. 高频踩坑点
- 不要通过「高位 FTW 为 0」判断异常,必须结合算法公式
- LPM 运算模块、移位模块、累加模块 所有使能引脚必须显式连接,绝不悬空
- 综合警告不是无关紧要,
stuck at constant 0几乎 100% 是致命逻辑故障 - 双通道同时失效 → 优先排查公共运算链路,而非通道独立偏移
3. 调试思维升华
遇到「参数写入成功,输出无变化」的 DDS 问题,固定排查顺序:
- 查参数锁存节拍
- 查 DDS 累加器使能
- 查相位地址是否递增
- 查 RAM 读端口输出
- 查后级多路选择输出
七、最终修复效果
- DDS 相位累加器正常持续累加
- RAM 波形地址连续递增
- 正弦波 / 三角波 / 自定义波形全部正常输出
- 频率跟随 FTW 精准可调,高低频全部正常
- 双通道链路恢复正常
后记 这是典型的「低级语法问题导致顶级疑难 Bug」,看似简单的引脚悬空,却造成整机波形功能瘫痪。FPGA 调试中,综合警告远比报错更可怕,很多致命逻辑错误只会报 Warning 不会报 Error,需要工程师逐行审视硬件行为,而非只看编译通过与否。