← 返回技术博客

Technical Writing

FPGA DDS 从频率控制字到测量显示:一条可验证的实现路径

说明相位累加器、波形查表、采样有效信号、统计模块和板级显示应如何分层设计与验证。

DDS 的核心不是波形表,而是相位

直接数字频率合成器的核心是相位累加器。每个系统时钟到来时,相位增加一个固定步长,再用相位高位查询波形表。只要相位按照模二进制自然回绕,就能连续产生周期波形。

当相位累加器宽度为 N、系统时钟为 f_clk、频率控制字为 phase_inc 时,理想输出频率为:

f_out = phase_inc × f_clk / 2^N

因此频率分辨率由 f_clk / 2^N 决定。增加相位位宽可以提高分辨率,但波形表地址不一定要使用全部相位位;常见做法是用高若干位作为 LUT 地址。

相位累加器保持简单

相位核心只需要处理复位、使能和步长更新,不应混入数码管或 ADC 控制:

reg [PHASE_WIDTH-1:0] phase_acc;

always @(posedge clk or negedge reset_n) begin
  if (!reset_n)
    phase_acc <= {PHASE_WIDTH{1'b0}};
  else if (sample_en)
    phase_acc <= phase_acc + phase_inc;
end

assign lut_addr = phase_acc[PHASE_WIDTH-1 -: LUT_ADDR_WIDTH];

sample_en 的含义必须写清。如果它不是每个时钟都有效,输出频率公式中的有效更新频率也会随之改变。验证频率时应以真正的相位更新速率为准。

多种波形可以共享相位

正弦波、方波、三角波和锯齿波可以使用同一个相位累加器。正弦波通过 LUT 输出;方波可直接使用相位最高位;锯齿波可截取相位高位;三角波则根据象限对相位做折返。

共享相位的好处是切换波形时频率定义一致,测试平台也能用同一套周期测量方法。切换控制应在明确的时钟边界采样,避免组合选择信号在 DAC 输出路径上产生毛刺。

LUT 生成过程也需要版本管理

正弦表通常由 MATLAB 或 Python 生成。生成脚本应固定以下参数:

  • 表深度和地址位宽。
  • 输出是否有符号、是否带直流偏置。
  • 幅值范围和量化方式。
  • 输出文件的进制、位宽和排列顺序。

ROM 初始化文件与生成脚本应一起提交。只保存 .mif.hex 而没有生成方法,会让后续修改位宽时难以确认量化规则。

ADC 数据必须带有效信号

测量链路中,ADC 接口、统计模块和显示模块的更新频率不同。不要假设 ADC 数据总是有效,应把数据和 sample_valid 一起传递。最小值、最大值和平均值只在有效采样到达时更新:

always @(posedge clk or negedge reset_n) begin
  if (!reset_n || clear) begin
    min_value <= {WIDTH{1'b1}};
    max_value <= {WIDTH{1'b0}};
    avg_acc   <= {(WIDTH+AVG_SHIFT){1'b0}};
  end else if (sample_valid) begin
    if (sample_in < min_value) min_value <= sample_in;
    if (sample_in > max_value) max_value <= sample_in;
    avg_acc <= avg_acc - (avg_acc >> AVG_SHIFT) + sample_in;
  end
end

这里的平均值是指数平均,不等同于固定窗口算术平均。它的优点是资源开销小、无需保存整段样本;代价是结果带有时间权重。因此页面和文档应准确说明统计定义。

显示模块不要反向控制算法模块

数码管扫描速度通常远高于人眼观察需要,显示数据更新又远低于扫描频率。正确结构是先把测量结果锁存为显示快照,再由扫描模块循环输出段选和位选。显示链路不应改变 DDS 或统计模块的更新条件。

74HC595 还涉及串行位序、锁存时刻和有效电平。出现全灭或乱码时,先用固定段码验证移位链路,再接入动态数字;不要一开始就同时怀疑 DDS、ADC 和显示。

仿真应分四层推进

相位层

检查相位差是否恒定、回绕是否正确、使能关闭时是否保持。

波形层

分别检查正弦表地址、方波占空比、三角折返和锯齿单调性。此阶段不接 ADC 与显示。

测量层

向统计模块输入人工序列,明确最小值、最大值和指数平均的期望结果,并插入无效周期检查门控。

系统层

最后连接顶层,检查模式切换、显示快照、复位和跨模块有效信号。系统仿真通过后再进行 Quartus 全编译和 TimeQuest 检查。

TimeQuest 中需要关注什么

编译成功只说明语法和布局布线完成,不代表时序一定满足。至少应确认所有主时钟已创建、外部接口约束有依据、关键路径没有负裕量、没有意外的未约束时钟。

如果设计含多个时钟域,应使用同步器、握手或异步 FIFO,不要直接跨域传递多位数据。显示慢时钟可以优先使用时钟使能,而不是在逻辑中随意分频生成新的时钟。

上板前后的验收边界

仿真可以证明数字逻辑在测试条件下符合预期,Quartus 和 TimeQuest 可以证明工程能够实现并满足约束;但 DAC 波形幅值、ADC 模拟输入、数码管亮度和引脚电平仍需实物确认。

一份可靠的项目记录应明确区分“仿真通过”“编译通过”“时序通过”和“实物验证通过”,避免把不同层级的证据混为一个结论。