【FPGA学习】DDS信号发生器设计

目录

一、设计原理与准备​

[1.1 DDS 原理​](#1.1 DDS 原理)

[1.2 IP 核学习与准备​:FPGA开发中常用IP核------ROM/RAM/FIFO](#1.2 IP 核学习与准备:FPGA开发中常用IP核——ROM/RAM/FIFO)

2、ROM文件的设置

[1.3 开发环境搭建​](#1.3 开发环境搭建)

[二、DDS 信号发生器设计实现](#二、DDS 信号发生器设计实现)

[2.1 系统架构设计​](#2.1 系统架构设计)

[2.2 代码编写与模块实现​](#2.2 代码编写与模块实现)

三、测试结果与总结​

参考文献:


引言:

在电子技术领域,信号发生器是不可或缺的工具。直接数字频率合成(Direct Digital Frequency Synthesis,DDS)技术凭借其频率转换速度快、分辨率高、相位连续性好等优势,成为信号生成的热门选择。本文将详细介绍基于 DDS 技术的信号发生器设计过程,实现正弦波和方波的合成,并满足特定频率范围与分辨率要求,同时利用嵌入式逻辑分析仪进行实时测试。

一、设计原理与准备​

1.1 DDS 原理​

DDS 的核心思想是通过数字计算和数模转换来生成模拟信号。其基本结构包括相位累加器、波形存储器(ROM)、数字模拟转换器(DAC)等。相位累加器在时钟信号的驱动下,不断进行累加操作,其输出作为波形存储器的地址,从波形存储器中读取预先存储的波形数据,再经过 DAC 转换为模拟信号输出。通过改变相位累加器的累加步长,就可以实现输出信号频率的调整。​

1.2 IP 核学习与准备​:FPGA开发中常用IP核------ROM/RAM/FIFO

常见的 FPGA 存储器有 3 种:RAM (随机访问内存)、ROM (只读存储器)、FIFO (先入先出)。这三种存储器的区别如下:

  • RAM:通常掉电后数据丢失,支持随机读写操作。根据特性可分为:

    • SRAM(静态随机存储器):速度快,无需刷新,但集成度低,常用于高速缓存
    • DRAM(动态随机存储器):需周期性刷新,集成度高,用于大容量存储
    • BRAM(块随机存储器):FPGA 内部专用存储块,低延迟、高带宽
  • ROM:系统断电后数据不丢失,数据写入需特定编程方式。在 FPGA 中常见类型:

    • MROM(掩膜只读存储器):数据由制造商写入,不可更改
    • PROM(可编程只读存储器):用户可一次性编程
    • EPROM(可擦除可编程只读存储器):通过紫外线擦除重写
    • EEPROM(电可擦可编程只读存储器):支持电信号擦除,常用于配置数据存储
  • FIFO:数据遵循先入先出原则,地址由内部指针自动管理。关键参数:

    • 满标志 (Full):指示 FIFO 已写满
    • 空标志 (Empty):指示 FIFO 已读空
    • 可编程满 / 空阈值:支持自定义触发条件
    • 同步 / 异步时钟域:分同步 FIFO(单时钟域)和异步 FIFO(跨时钟域)

应用场合对比

存储器类型 典型应用场景 关键优势 FPGA 实现方式
RAM 数据缓存、图像处理帧缓冲、高速数据暂存 随机读写、高速访问 BRAM、分布式 RAM
ROM 波形表存储(如 DDS)、配置参数存储、查找表 (LUT) 非易失性、数据稳定 初始化 BRAM、专用 ROM IP 核
FIFO 跨时钟域数据传输、数据流速率匹配、突发数据缓冲 自动地址管理、同步隔离 专用 FIFO IP 核

在 DDS 设计中:

  • ROM:用于存储预计算的正弦 / 方波波形数据,需配置为同步读模式
  • FIFO:可用于缓存 DAC 输出数据,解决时钟域不匹配问题
  • RAM:可扩展用于存储多组波形参数,支持动态切换波形类型

在调用 IP 核时,需特别注意:

  1. 同步与异步模式:跨时钟域设计必须使用异步 FIFO
  2. 深度与宽度权衡:增加深度可提高缓冲能力,但会占用更多 BRAM 资源
  3. 复位策略:合理设置同步复位或异步复位,确保系统可靠启动
  4. 数据对齐:注意数据位宽匹配,避免数据截断或扩展带来的精度损失

1、ROM简介

​ ROM 是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据的固态半导体存储器。其特性是一旦储存资料就无法再将之改变或删除,且资料不会因为电源关闭而消失。而事 实上在 FPGA 中通过 IP 核生成的 ROM 或 RAM(RAM 将在下一节为大家讲解)调用的都是FPGA 内部的 RAM 资源,掉电内容都会丢失(这也很容易解释,FPGA 芯片内部本来就没有掉电非易失存储器单元)。用 IP 核生成的 ROM 模块只是提前添加了数据文件(.coe 格式)(.mif/.hex格式),在 FPGA 运行时通过数据文件给 ROM 模块初始化,才使得 ROM 模块像个"真正"的掉电非易失存储器;也正是这个原因,ROM 模块的内容必须提前在数据文件中写死,无法在电路中修改。

最简单的使用有效时钟CLKA、有效地址ADDRA和有效使能EA,就可以输出DOUTA

单端口ROM:只提供一个独立的地址端口核一个读数据端口

2、ROM文件的设置

1.3 开发环境搭建​

本次设计基于 DE2-115 开发板,开发环境选用 Quartus Prime 等 FPGA 开发工具。在开始设计之前,确保开发环境已经正确安装和配置,熟悉开发工具的基本操作流程,包括工程创建、IP 核调用、代码编写、编译综合、下载调试等环节,为后续的设计实现奠定基础。

二、DDS 信号发生器设计实现

2.1 系统架构设计​

根据设计要求,DDS 信号发生器系统主要由相位累加器模块、波形存储器模块、频率控制字输入模块、波形转换模块(用于生成正弦波和方波)以及嵌入式逻辑分析仪模块组成。相位累加器模块根据输入的频率控制字,在时钟信号的驱动下进行相位累加;波形存储器模块存储正弦波和方波的数字化波形数据;频率控制字输入模块接收用户设置的频率参数,生成相应的频率控制字;波形转换模块根据相位累加器的输出,从波形存储器中读取数据,并进行相应的处理,生成正弦波和方波信号;嵌入式逻辑分析仪模块用于实时采集和分析输出波形的离散数据。​

2.2 代码编写与模块实现​

在 Quartus Prime 中创建工程,按照系统架构设计,分别编写各个模块的 Verilog HDL 代码。​

  1. 相位累加器模块:根据输入的时钟信号和频率控制字,实现相位的累加功能。代码如下:

    module phase_accumulator(
    input wire clk,
    input wire rst_n,
    input wire [31:0] freq_control_word,
    output reg [31:0] phase_accumulator_output
    );
    always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
    phase_accumulator_output <= 32'd0;
    end else begin
    phase_accumulator_output <= phase_accumulator_output + freq_control_word;
    end
    end
    endmodule

2.DDS技术合成正弦波和方波

​ 利用DDS技术合成正弦波和方波,很多EDA软件都需要.mif文件,比如使用Quartus 调用ROM IP核产生一个正弦波就需要对ROM IP核加载.mif文件,然后从.mif文件中读取数据产生正弦波

正弦波

1)利用matlab生成ROM初始化文件mif

复制代码
% 参数设置
addr_width = 10;       % ROM地址位宽(1024点)
data_width = 8;        % 数据位宽(8位)
filename = 'sine_wave.mif'; % 输出文件名

% 生成正弦波数据
rom_depth = 2^addr_width;
t = linspace(0, 2*pi, rom_depth); % 0到2π的相位
sine_data = sin(t);               % 生成正弦波(范围[-1, 1])

% 量化到8位无符号整数(0~255)
sine_data = round((sine_data + 1) * (2^(data_width-1) - 1));

% 写入mif文件
fid = fopen(filename, 'w');
fprintf(fid, 'WIDTH=%d;\n', data_width);
fprintf(fid, 'DEPTH=%d;\n', rom_depth);
fprintf(fid, 'ADDRESS_RADIX=HEX;\n');
fprintf(fid, 'DATA_RADIX=HEX;\n\n');
fprintf(fid, 'CONTENT BEGIN\n');

for addr = 0:rom_depth-1
    fprintf(fid, '  %04X : %02X;\n', addr, sine_data(addr+1));
end

fprintf(fid, 'END;\n');
fclose(fid);
disp('mif文件生成成功!');

在运行完上面一段代码后也就在同一文件夹下生成了一个sine_wave.mif文件如下图所示

设置模块LPM_ROM参数的具体步骤如下:

1)在QuartusPrime主界面选择Tool一IPCatalog命令,在查找框内输入ROM,IP核目录(IPCatalog)栏

中会列出相关的IP核,选择ROM:1-PORT并双击,弹出保存IP设置界面,输入文件名,并选中Verilog,单击OK按钮。

3).输入mif文件中宽度和深度,要匹配上(8、1024)

4).全不选择即可,next

DDS模块设计

复制代码
module dds_sine_wave (
    input clk,         // 系统时钟
    input reset,       // 复位
    input [31:0] fcw,  // 频率控制字(Frequency Control Word)
    output [7:0] wave_out // 正弦波输出
);

// 相位累加器(32位)
reg [31:0] phase_accumulator;

// 相位累加器更新
always @(posedge clk or posedge reset) begin
    if (reset)
        phase_accumulator <= 32'd0;
    else
        phase_accumulator <= phase_accumulator + fcw;
end

// 取高10位作为ROM地址(相位截断)
wire [9:0] rom_address = phase_accumulator[31:22];

// 实例化ROM
rom_sine_wave rom_inst (
    .address(rom_address),
    .clock(clk),
    .q(wave_out)
);

endmodule

Testbench仿真

复制代码
`timescale 1ns/1ns

module tb_dds_sine_wave;

// 输入信号
reg clk;
reg reset;
reg [31:0] fcw;

// 输出信号
wire [7:0] wave_out;

// 例化DDS模块
dds_sine_wave uut (
    .clk(clk),
    .reset(reset),
    .fcw(fcw),
    .wave_out(wave_out)
);

// 时钟生成(50MHz)
initial begin
    clk = 0;
    forever #10 clk = ~clk; // 20ns周期 → 50MHz
end

// 仿真流程
initial begin
    // 初始化
    reset = 1;
    fcw = 32'h0000_0000; // 初始频率控制字
    #100;
    reset = 0;

    // 设置fcw生成1kHz正弦波(示例值)
    // Fout = (50e6 * fcw) / 2^32 → fcw = Fout * 2^32 / 50e6
    fcw = 32'h00A3D70A; // 对应约1kHz

    // 仿真运行(至少覆盖多个周期)
    #2000000; // 仿真2ms(观察2个完整周期)
    $stop;
end

endmodule

添加仿真文件:

然后一直ok到底

仿真效果

三、测试结果与总结​

经过仿真和开发板实践测试,DDS 信号发生器能够成功生成正弦波和方波信号,输出信号的频率范围满足 10Hz~5MHz 的要求,最小频率分辨率小于 1kHz。通过嵌入式逻辑分析仪采集到的离散数据,也与设计预期相符,证明了设计的有效性和准确性。​

在设计过程中,深入学习了 DDS 技术的原理和 IP 核的使用方法,掌握了 FPGA 开发的全流程。同时,也遇到了一些问题,如 IP 核参数设置不合理导致波形失真、代码逻辑错误等,通过查阅资料和调试解决了这些问题。本次设计为进一步深入研究 DDS 技术和 FPGA 应用奠定了坚实的基础,后续可以在此基础上进行功能扩展,如增加更多类型的波形生成、提高频率分辨率等。​

以上分享了 DDS 信号发生器的设计过程。如有不妥之处还望各位海涵。祝好!

参考文献:

用FPGA实现dds的方案详解(保姆级入门教学)(VIVADO18.3、quartus13.1)_fpga开发_Jefferymeng-2048 AI社区

FPGA中级项目1------IP核(ROM 与 RAM)

【FIFO IP系列】FIFO IP参数配置与使用示例

【FPGA基础学习】DDS信号发生器设计-CSDN博客

DDS信号发生器原理与经典DDS信号发生器设计方案-CSDN博客

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
ZPC82105 天前
docker 镜像备份
人工智能·算法·fpga开发·机器人
ZPC82105 天前
docker 使用GUI ROS2
人工智能·算法·fpga开发·机器人
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习