当前位置: 首页 > news >正文

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

一、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-1fprintf(fid, '  %04X : %02X;\n', addr, sine_data(addr+1));
endfprintf(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) beginif (reset)phase_accumulator <= 32'd0;elsephase_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/1nsmodule 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 beginclk = 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 / 50e6fcw = 32'h00A3D70A; // 对应约1kHz// 仿真运行(至少覆盖多个周期)#2000000; // 仿真2ms(观察2个完整周期)$stop;
endendmodule

添加仿真文件:

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-1fprintf(fid, '  %04X : %02X;\n', addr, rom_data(addr+1));
endfprintf(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) beginif (reset)phase_accumulator <= 32'd0;elsephase_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/1nsmodule 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 beginclk = 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 / 50e6fcw = 32'h00A3D70A; // 对应约1kHz// 仿真运行#200000; // 仿真200us(观察多个周期)$stop;
endendmodule

添加仿真文件:

image-20250415223127381

仿真效果:

image-20250415223253217

参考链接:

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

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

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

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

FPGA_DDS生成正弦波

相关文章:

  • AI图片生成器
  • AIP-235 批量方法:Delete
  • idea如何使用git
  • Maybe:打造个人财务管理的开源操作系统
  • SpringBoot-基础特性
  • 前端vue3 实现倒计时功能 组件
  • 重返JAVA之路——图书管理系统
  • B2B2C多用户商城平台 的两种创新玩法
  • 华熙生物亮相消博会,这次又带来了什么样的变化?
  • springboot项目添加定时任务,用sftp推送zip包到目标服务器
  • 车载信息安全 --- 密钥管理
  • Anaconda笔记
  • C语言-习题整理(1)
  • 第 2 篇:快速上手 Framer Motion(实操入门)
  • 烽火ai场控接入deepseek自动回复话术软件
  • 【Python】列表的创建:[[] for _ in range(2)] 与 [[]] * 2有什么区别?
  • STM32F407实现内部FLASH的读写功能
  • 【MySQL】MySQL数据库 —— 简单认识
  • 第3篇:深入 Framer Motion Variants:掌握组件动画编排的艺术
  • django项目之添加资产信息功能
  • 中央和国家机关工委建立健全整治形式主义为基层减负长效机制
  • 部分人员无资质展业、投资建议无合理依据,天相财富被责令改正
  • 【社论】家政服务提质扩容,为何被一提再提
  • 人民日报钟声:经济霸凌损害美国国家信誉
  • 眨眼间能完成10亿次存储,上海科研团队研制出超高速闪存
  • 明确五项重点任务!市场监管总局开展广告市场秩序整治