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

news2025/4/16 5:44:05

一、IP核简介

IP核的定义与核心作用

  1. 定义
    IP核是芯片设计中独立功能的成熟模块,例如处理器、存储器、接口协议等。它们以硬件描述语言(HDL)、网表或物理版图形式交付,供其他设计者直接调用,避免重复开发

  2. 核心作用

    • 缩短设计周期:通过复用已验证的模块,减少从零开发的时间,加速产品上市

    • 降低成本与风险:避免重复设计错误,降低研发投入和测试成本

IP的种类

​ IP核有行为(Behavior)级、结构(Structure)级和物理(Physical)级三个层次的分类,对应着三个种类型的IP核,它们是由硬件描述语言设计的软核(Soft IP Core)、完成结构描述的固核(Firm IP Core) 和基于物理描述并经过工艺验证的硬核(Hard IP Core)。

软核: 它是用硬件描述语言(HDL)设计的独立功能的电路模块。从芯片设计程度来看,它只经过了RTL级设计优化和功能验证,通常是以HDL文本形式提交给用户。所以它不包含任何物理实现信息,因此,IP软核与制造工艺无关。软核相当于软件编程的库,比如Python调用一个四舍五入round(num,n) 函数一样。FPGA设计中也可以调用一个四舍五入的IP,这样就不用自己写代码了。

固核: 它的设计程度介于IP软核和IP硬核之间,它除了完成IP软核所有的设计外,还完成了门级电路综合和时序仿真等设计环节。一般地,它以门级电路网表的形式提供给用户。

硬核: 它提供了电路设计最后阶段掩模级的电路模块。它以最终完成的布局布线网表形式提供给用户。IP硬核既具有结果的可预见性,也可以针对特定工艺或特定IP提供商进行功耗和尺寸的优化。

二、采用DDS设计制作波形发生器

1.DDS简介

DDS技术最初是作为频率合成技术提出的,由于其易于控制,相位连续,输出频率稳定度高,分辨率高, 频率转换速度快等优点,现在被广泛应用于任意波形发生器(AWG)。基于DDS技术的任意波形发生器用高速存储器作为查找表,通过高速D/A转换器来合成出存储在存储器内的波形。所以它不仅能产生正弦、余弦、方波、三角波和锯齿波等常见波形,而且还可以利用各种编辑手段,产生传统函数发生器所不能产生的真正意义上的任意波形。

直接频率合成(Direct Dgital Sythesizer, DDS) 是种把-系列数字信号通过数字模拟转换器(igital to Analog Converter, DAC) 转换为模拟信号的新型频率合成技术。其优点有频率切换时间短,频率分析率高,输出信号的频率和相位可以快速切换,输出相位连续,并且很容易地实现信号频率、相位和幅度的控制。

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按钮。

image-20250415202621897

image-20250415202926126

2)选择一个port,在路径后输入文件名称/rom_sine_wave.v,点击next

image-20250415224313228

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

image-20250415224404989

4).全不选择即可,next

image-20250415204443443

5).点击browse,选择项目路径下mif文件,完成后点击next

image-20250415224449020

6).默认next即可,点击finish

image-20250415211659898

点击yes

image-20250415211730348

7).完成后再文件中可以看到生成的rom_sine_wave.v文件

image-20250415224517733

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

添加仿真文件:

image-20250415224648816

image-20250415224729657

image-20250415224823530

然后一直ok到底

仿真效果

image-20250415225320367

这里我遇到一个问题就是modesim只输出方波,我一开始以为是我代码的问题,后来才发现是,需要设置modesim的输出格式:

image-20250415225524509

方波

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

% 参数设置
addr_width = 10;       % ROM地址位宽(1024点)
data_width = 8;        % 数据位宽(8位)
duty_cycle = 0.5;      % 占空比(50%)
filename = 'square_wave.mif'; % 输出文件名

% 生成方波数据
rom_depth = 2^addr_width;
high_value = 2^data_width - 1; % 最大值(8'hFF)
low_value = 0;
split_point = round(rom_depth * duty_cycle);

% 初始化ROM数据
rom_data = [high_value * ones(1, split_point), ...
            low_value * ones(1, rom_depth - split_point)];

% 写入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, rom_data(addr+1));
end

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

image-20250415222318695

image-20250415222437683

后面的步骤与正弦波的操作相似

DDS模块设计(方波合成)

module dds_square_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_square_wave rom_inst (
    .address(rom_address),
    .clock(clk),
    .q(wave_out)
);

endmodule

编写Testbench

`timescale 1ns/1ns

module tb_dds_square_wave;

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

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

// 例化DDS模块
dds_square_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

    // 仿真运行
    #200000; // 仿真200us(观察多个周期)
    $stop;
end

endmodule

添加仿真文件:

image-20250415223127381

仿真效果:

image-20250415223253217

参考链接:

零基础学FPGA(四):IP是什么东西(什么是软核,硬核)

FPGA开发——IP核的RAM调用(单端口)

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

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

FPGA_DDS生成正弦波

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2335717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux ceres库编译注意事项及测试demo

最近linux编译了ceres库,因为要涉及到一个程序源代码的编译&#xff0c;但是反复测试&#xff0c;一直各种错误&#xff0c;所以一个个问题排除&#xff1b; 虽然前面ceres库编译成功了&#xff0c;但是版本自定义扔进去的&#xff0c;所以在进行代码编译的时候各种报错。 参考…

Flux.1+ComfyUI组合实战!本地部署生成高质量AI图片全流程指南

文章目录 前言1. 本地部署ComfyUI2. 下载 Flux.1 模型3. 下载CLIP模型4. 下载 VAE 模型5. 演示文生图6. 公网使用 Flux.1 大模型6.1 创建远程连接公网地址 7. 固定远程访问公网地址 前言 在这个AI技术风起云涌的时代&#xff0c;图像生成模型已经从科幻变成了现实中的‘印钞机…

css hover 实现鼠标放上去后略微放大的效果

代码如下&#xff1a; <div class"button">文字</div>css代码如下&#xff1a; .button{width: 100px;height: 50px;margin-top: 100px;margin-left: 100px;color: white;background-color: gray;line-height: 50px;text-align: center;transition: all…

UWB定位技术目前主要应用在哪些行业(更新2025)

UWB定位技术的主要行业应用 ‌一、工业制造领域‌ ‌人员与设备定位‌&#xff1a;通过厘米级精度追踪工人、叉车及设备位置&#xff0c;优化生产流程并提升安全管理效率&#xff08;如高危区域实时报警&#xff09;‌。‌防撞预警与工时统计‌&#xff1a;结合电子围栏实现设…

vscode格式化为什么失效?自动保存和格式化(Prettier - Code formatter,vue-format)

vscode自动格式化保存最终配置 博主找了好多的插件&#xff0c;也跟着教程配置了很多&#xff0c;结果还是没有办法格式化&#xff0c;最终发现了一个隐藏的小齿轮&#xff0c;配置完后就生效了 关键步骤 关键配置 一定要点小齿轮&#xff01;&#xff01;&#xff01; 这个小…

鸿蒙应用元服务开发-Account Kit配置登录权限

一、场景介绍 华为账号登录是基于OAuth 2.0协议标准和OpenID Connect协议标准构建的OAuth2.0 授权登录系统&#xff0c;元服务可以方便地获取华为账号用户的身份标识&#xff0c;快速建立元服务内的用户体系。 用户打开元服务时&#xff0c;不需要用户点击登录/注册按钮&#…

React ROUTER之嵌套路由

第一张是需要修改router文件createBrowserRouterd参数数组中的路由关系 第二张是需要在一级路由的index.js中选择二级路由的位置 第一步是在全局的router.js文件中加入新的children属性&#xff0c;如图 第二步是在一级路由的index.js文件中声明outLet组件 默认二级路由 在…

TestNG 单元测试详解

1、测试环境 jdk1.8.0 121 myeclipse-10.0-offline-installer-windows.exe TestNG 插件 org.testng.eclipse 6.8.6.20130607 0745 2、介绍 套件(suite):由一个 XML 文件表示,通过<suite>标签定义,包含一个或更多测试(test)。测试(test):由<test>定义&#xf…

通过python实现bilibili缓存视频转为mp4格式

需要提前下好ffmpeg import os import fnmatch import subprocess Bilibili缓存的视频&#xff0c;*280.m4s结尾的是音频文件&#xff0c;*050.m4s结尾的是视频&#xff0c;删除16进制下前9个0&#xff0c;即为正常音/视频 使用os.walk模块&#xff0c;遍历每一个目录&#xf…

【分享】Ftrans文件摆渡系统:既保障传输安全,又提供强集成支持

【分享】Ftrans文件摆渡系统&#xff1a;既保障传输安全&#xff0c;又提供强集成支持&#xff01; 在数字化浪潮中&#xff0c;企业对数据安全愈发重视&#xff0c;网络隔离成为保护核心数据的关键防线&#xff0c;比如隔离成研发网-办公网、生产网-测试网、内网-外网等。网络…

python每日一练

题目一 输入10个整数,输出其中不同的数,即如果一个数出现了多次,只输出一次(要求按照每一个不同的数第一次出现的顺序输出)。 解题 错误题解 a list(map(int,input().split())) b [] b.append(a[i]) for i in range(2,11):if a[i] not in b:b.append(a[i]) print(b)但是会…

算法思想之前缀和(二)

欢迎拜访&#xff1a;雾里看山-CSDN博客 本篇主题&#xff1a;算法思想之前缀和(二) 发布时间&#xff1a;2025.4.11 隶属专栏&#xff1a;算法 目录 算法介绍核心思想大致步骤 例题和为 K 的子数组题目链接题目描述算法思路代码实现 和可被 K 整除的子数组题目链接题目描述算法…

硬件知识积累 单片机+ 光耦 + 继电器需要注意的地方

1. 电路图 与其数值描述 1.1 单片机引脚信号为 OPtoCoupler_control_4 PC817SB 为 光耦 继电器 SRD-05VDC-SL-A 的线圈电压为 67Ω。 2. 需注意的地方 1. 单片机的推挽输出的电流最大为 25mA 2. 注意光耦的 CTR 参数 3. 注意继电器线圈的 内阻 4. 继电器的开启电压。 因为光耦…

Dockerfile 学习指南和简单实战

引言 Dockerfile 是一种用于定义 Docker 镜像构建步骤的文本文件。它通过一系列指令描述了如何一步步构建一个镜像&#xff0c;包括安装依赖、设置环境变量、复制文件等。在现实生活中&#xff0c;Dockerfile 的主要用途是帮助开发者快速、一致地构建和部署应用。它确保了应用…

MCU屏和RGB屏

一、MCU屏 MCU屏‌&#xff1a;全称为单片机控制屏&#xff08;Microcontroller Unit Screen&#xff09;&#xff0c;在显示屏背后集成了单片机控制器&#xff0c;因此&#xff0c;MCU屏里面有专用的驱动芯片。驱动芯片如&#xff1a;ILI9488、ILI9341、SSD1963等。驱动芯片里…

Elasticsearch 向量数据库,原生支持 Google Cloud Vertex AI 平台

作者&#xff1a;来自 Elastic Valerio Arvizzigno Elasticsearch 将作为第一个第三方原生语义对齐引擎&#xff0c;支持 Google Cloud 的 Vertex AI 平台和 Google 的 Gemini 模型。这使得联合用户能够基于企业数据构建完全可定制的生成式 AI 体验&#xff0c;并借助 Elastics…

蓝桥杯基础数论入门

一.试除法 首先我们要了解&#xff0c;所有大于1的自然数都能进行质因数分解。试除法作用如下&#xff1a; ​质数判断 试除法通过验证一个数是否能被小于它的数&#xff08;一般是用2到用根号x&#xff09;整除来判断其是否为质数。根据定义&#xff0c;质数只能被1和自身整除…

Spring 事件机制与观察者模式的深度解析

一、引言 在软件设计中&#xff0c;观察者模式&#xff08;Observer Pattern&#xff09;是一种非常经典且实用的设计模式。它允许一个对象&#xff08;Subject&#xff09;在状态发生改变时通知所有依赖它的对象&#xff08;Observers&#xff09;&#xff0c;从而实现对象之…

【软考系统架构设计师】信息安全技术基础知识点

1、 信息安全包括5个基本要素&#xff1a;机密性、完整性、可用性、可控性与可审查性。 机密性&#xff1a;确保信息不暴露给未授权的实体或进程。&#xff08;采取加密措施&#xff09; 完整性&#xff1a;只有得到允许的人才能修改数据&#xff0c;并且能够判断出数据是否已…