【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博客

相关推荐
静心问道6 小时前
XLSR-Wav2Vec2:用于语音识别的无监督跨语言表示学习
人工智能·学习·语音识别
懒惰的bit9 天前
STM32F103C8T6 学习笔记摘要(四)
笔记·stm32·学习
Jay_5159 天前
C++ STL 模板详解:由浅入深掌握标准模板库
c++·学习·stl
冰茶_9 天前
ASP.NET Core API文档与测试实战指南
后端·学习·http·ui·c#·asp.net
丶Darling.9 天前
深度学习与神经网络 | 邱锡鹏 | 第五章学习笔记 卷积神经网络
深度学习·神经网络·学习
尤老师FPGA10 天前
使用DDR4控制器实现多通道数据读写(十六)
fpga开发·ddr4
cwtlw10 天前
Excel学习03
笔记·学习·其他·excel
牛大了202310 天前
【LLM学习】2-简短学习BERT、GPT主流大模型
gpt·学习·bert
HX科技10 天前
STM32给FPGA的外挂FLASH进行升级
stm32·嵌入式硬件·fpga开发·flash·fpga升级
Ting-yu10 天前
零基础学习RabbitMQ(1)--概述
分布式·学习·rabbitmq