FPGA系列之DDS信号发生器设计(DE2-115开发板)

一、IP核

IP(Intellectual Property)原指知识产权、著作权等,在IC设计领域通常被理解为实现某种功能的设计。IP模块则是完成某种比较复杂算法或功能(如FIR滤波器、FFT、SDRAM控制器、PCIe接口、CPU核等)并且参数可修改的电路模块,又称为IP核(IP Core)。随着CPLD/FPGA器件的集成度越来越高,设计越来越复杂,使用IP核是EDA设计的发展趋势。根据实现方式的不同,IP核可以分为软核(soft core)、固核(firm core)和硬核(hard core)。

Intel公司以及第三方合作伙伴提供的IP模块可以分为两类:可修改参数的IP核(Library of Parameterized Modules, LPM)和需要授权才能在生产设计中使用的IP核(功能更复杂的模块,也称为MegaCore)​。这些模块专门针对不同的器件结构进行了优化,在设计数字系统时,我们可以充分利用这些IP模块,加快设计进度,同时提高器件资源的利用率。

注:该内容引用自Verilog HDL与FGPGA数字系统设计(第二版)

二、DDS信号发生器设计

1.DDS信号发生器

(1)概念

直接数字频率合成(Direct Digital Frequency Synthesis,简称DDS或DDFS)是一种应用数字技术产生信号波形的方法,它是由美国学者J. Tierncy、C.M. Rader和B. Gold在1971年提出的,他们以数字信号处理理论为基础,从相位概念出发提出了一种新的直接合成所需波形的全数字频率合成方法。

DDS系统通常包含以下模块:
相位累加器(Phase Accumulator)
波形查找表(Waveform ROM/LUT)
数模转换器(DAC)
​​抗混叠滤波器(Anti-Aliasing Filter)

(2)DDS工作流程

2. DDS信号发生器设计

使用Quartus Prime Lite创建工程,顶层文件名为DDS_top,芯片选择EP4CE115F29C7(详细步骤看其余FPGA文章)。

(1)相位累加器的设计

新建Verilog HDL File文件,文件名为addr_cnt.v(如果与VS Code连用代码写好后另存为就好)

//=====相位累加器和数据锁存器=====
module addr_cnt(CPi,K,ROMaddr,Address);input CPi;                     //系统基准时钟(100MHz)input [12:0] K;                //13位频率控制字output reg [9:0] ROMaddr;      //10位ROM地址output reg [16:0] Address;     //17位相位累加器地址信号always @(posedge CPi)beginAddress = Address + K;ROMaddr = Address[16:7];end
endmodule

在项目中添加addr_cnt.v文件,选择Files,右键点击Files,点击添加

找到刚才保存的文件添加

选择Set as Top-Level Entity将其设为顶层文件,点击编译

右键点击addr_cnt.v文件,选择CreateSymbol Files for Current File命令,生成该模块的符号

在Quartus中打开生成的addr_cnt.bsf文件,生成的该模块的符号如图

(2)波形存储器ROM的设计
A.方波模块

步骤跟上面的一样,文件名为squwave.v,其代码如下

//=====方波产生模块:squwave.v ======
module squwave(CPi,RSTn,Address,Qsquare);input CPi;                          //系统基准时钟(100MHz)input RSTn;                         //同步清零input [16:0] Address;               //17位地址输入信号output reg [11:0] Qsquare;          //输出方波信号,12位宽,送至DACalways @(posedge CPi)        if(!RSTn) Qsquare=12'h000;          //同步清零else begin                   if(Address<=17'h0FFFF)  Qsquare=12'hFFF;            //输出高电平else Qsquare=12'h000;           //输出低电平end
endmodule

打开生成的squwave.bsf文件后该模块的符号如图

B.正弦波形存储器模块

Quartus Prime软件接受两种格式的初始化文件MemoryInitialization File(.mif)和Hexadecimal(Intel-Format)File(.hex)。使用时,将初始化文件放在当前工程项目子目录中,在配置LPM_ROM时会对其进行初始化。而建立.mif格式文件有两种方法,一种是直接编辑法,另一种是用C语言等软件生成初始化文件(初始化储存单元较多时更加实用)

打开c语言编译器,建立sinewave.c文件,代码如下

#include <stdio.h>
#include <math.h>
#define PI 3.141592
#define DEPTH 1024     //数据深度,即存储单元的个数
#define WIDTH 12       //存储单元的宽度
int main(void)
{int n,temp;float v;FILE *fp;
/*建立文件名为Sine1024.mif的新文件,允许写入数据,对文件名没有特殊要求,但扩展名必须为.mif*/fp=fopen("Sine1024.mif","w+");if(NULL==fp)printf("Can not creat file!\r\n");else{printf("File created successfully!\n");/*生成文件头,注意不要忘了“;” */fprintf(fp,"DEPTH =%d;\n",DEPTH);fprintf(fp,"WIDTH =%d;\n",WIDTH);fprintf(fp,"ADDRESS_RADIX=HEX;\n");fprintf(fp,"DATA_RADIX=HEX;\n");fprintf(fp,"CONTENT\n");fprintf(fp,"BEGIN\n");/*以十六进制输出地址和数据*/for(n=0;n<DEPTH;n++){/*周期为1024个点的正弦波*/v=sin(2*PI*n/DEPTH);/*将-1~1之间的正弦波的值扩展到0~4095之间*/temp=(int)((v+1)*4095/2); //v+1将数值平移到0~2之间/*以十六进制输出地址和数据*/fprintf(fp,"%x\t:\t%x;\n",n,temp);}fprintf(fp,"END;\n");fclose(fp);    //关闭文件}
}

运行此文件后会生成sinewave.exe文件,双击运行就会生成Sine1024.mif文件

接着,验证生成的数据是否正确。用记事本打开生成的mif文件,同时用Quartus Prime软件打开mif文件,若能成功导入数据且数据一致,则说明生成文件正确,将其添加到工程文件中。

在Quartus Prime主界面选择Tool→IP Catalog

在查找框内输入ROM, IP核目录(IP Catalog)栏中会列出相关的IP核,选择ROM:1-PORT并双击

弹出如图所示的保存IP设置界面,输入文件名SineROM.v,并选中Verilog,单击OK按钮

设置ROM的数据位宽为12,存储容量(字数)为1024,单击Next按钮

点击Next,配置如下

点击Browse...选择生成的Sine1024.mif文件,这是指明初始化ROM所使用的数据文件名

然后Next直到最后一页,弹出如图所示的选择输出文件的对话框(最重要的是.v文件,其余文件按需要勾选,.bsf文件也可以选上),选择好后点击Finish

SineROM.v等相关文件就生成好了

该模块的符号如下图所示:

3.锁相环倍频电路设计

定制一个名称为PLL100M_CP的时钟模块,该模块的输入inclk0为50MHz时钟信号,输出c0为100MHz的脉冲信号,占空比为50%,带有相位锁定指示输出端locked。

在右侧查找框内输入ALTPLL(嵌入式锁相环)​

双击打开,输入文件名PLL100M_CP.v,并选中Verilog,单击OK按钮

设置输入时钟(inclk0)频率为50MHz

其余的按如下图片设置 

最后选择需要生成的文件

4.顶层电路设计

代码如下

//========DDS的顶层模块:DDS_top.v ======
module DDS_top(CLOCK_50, RSTn, WaveSel, K,
WaveValue, LEDG, CLOCK_100);input CLOCK_50;                           //50MHz时钟input RSTn;                               //控制方波清零,低电平有效input [1:0] WaveSel;                      //波形选择:SW[17:16]=10时为方波;SW//[17:16]=01时为正弦波input [12:0] K;                           //频率控制字SW12..SW0output reg [11:0] WaveValue;              //输出波形数据wire [9:0] ROMaddr;                       //波形存储器地址wire [16:0] Address;                      //17位相位累加器地址wire [11:0] Qsine, Qsquare;               //正弦、方波数据输出output [0:0]LEDG;                         //锁相环相位锁定指示灯,亮表示锁定output CLOCK_100;                         //锁相环输出时钟,频率为100MHzwire CPi =CLOCK_100;PLL100M_CP PLL100M_CP_inst (              //实例引用锁相环子模块.inclk0 ( CLOCK_50 ),                     //50MHz时钟输入.c0 ( CLOCK_100 ),                        //100MHz时钟输出.locked ( LEDG[0] )                       //相位锁定指示
);addr_cnt U0_instance(CPi,K,ROMaddr,Address);//实例引用地址累加器SineROM ROM_inst (                        //实例引用正弦LPM_ROM子模块.address (ROMaddr),.clock ( CPi ),.q ( Qsine )
);squwave U1(CPi,RSTn, Address,Qsquare);    //实例引用方波子模块always @(posedge CPi)
begincase(WaveSel)                             //选择输出波形2'b01:WaveValue=Qsine;                //输出正弦波2'b10:WaveValue=Qsquare;              //输出方波default:WaveValue=Qsine;endcase
end
endmodule

写好后添加到工程中,将此文件设为顶层模块并进行编译。

三、设计实现

使用DE2-115开发板来验证上述设计。用板上的50MHz晶振作为时钟输入,用KEY3控制方波清零,用SW12~SW0设置频率控制字,SW17、SW16用来选择输出波形的种类,用LEDG0作为PLL的相位锁定指示。

有DE2_115_pin_assignments.csv文件可以直接导入不用手动配置引脚,没有的话参考DE2-115文档配置。为了方便导入文件DE2_115_pin_assignments.csv进行引脚分配,将使用该文件中的端口名称代替上述DDS_top.v(代码如下)中的信号名称。为此再编写一个顶层文件DE2_DDS_top.v代码如下:

//=====在开发板上运行的DDS的顶层模块:DE2_115_DDS_top.v ======
module DE2_115_DDS_top(CLOCK_50, KEY, SW, GPIO_0, LEDG);input CLOCK_50;                          //50MHz时钟input[3:3] KEY;                          //按键KEY3,控制方波清零input[17:0] SW;                          //拨动开关output [12:0] GPIO_0;                    //扩展接口,送出波形数据给DACoutput [0:0]LEDG;                        //绿色LED指示相位是否锁定wire CLOCK_100;                          //100MHz时钟assign GPIO_0[12]=CLOCK_100;             //送给DAC的时钟wire RSTn = KEY[3];                      //控制方波清零,低电平有效wire [1:0] WaveSel = SW[17:16];          //选择输出波形wire [12:0] K = SW[12:0];                //设置频率控制字,最小值必须为1wire [11:0] WaveValue;assign GPIO_0[11:0] = WaveValue;         //输出波形数据DDS_top DE2(CLOCK_50, RSTn, WaveSel, K, WaveValue, LEDG, CLOCK_100);
endmodule

对其进行全编译

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

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

相关文章

Java单例模式详解:实现线程安全的全局访问点

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、什么是单例模式&#xff1f; 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;它保证一个类仅有一个实例&#xff…

JVM 生产环境问题定位与解决实战(七):实战篇——OSSClient泄漏引发的FullGC风暴

本文已收录于《JVM生产环境问题定位与解决实战》专栏&#xff0c;完整系列见文末目录 引言 在前六篇博客中&#xff0c;我们系统性地学习了 JVM 生产环境问题定位与解决的全套工具链&#xff0c;涵盖jps、jmap、jstat、jstack、jcmd 等基础工具的使用技巧&#xff0c;深入剖析…

Spark集群搭建-spark-local

&#xff08;一&#xff09;安装Spark 安装Spark的过程就是下载和解压的过程。接下来的操作&#xff0c;我们把它上传到集群中的节点&#xff0c;并解压运行。 1.启动虚拟机 2.通过finalshell连接虚拟机&#xff0c;并上传安装文件到 /opt/software下 3.解压spark安装文件到/op…

Java 异常 SSLException: fatal alert: protocol_version 全解析与解决方案

在 Java 网络通信中&#xff0c;SSLException: fatal alert: protocol_version 是典型的 TLS/SSL 协议版本不兼容异常。本文结合 Java 官方规范、TLS 协议标准及实战经验&#xff0c;提供体系化解决方案&#xff0c;帮助开发者快速定位并解决协议版本冲突问题。 一、异常本质&…

虚拟列表技术深度解析:原理、实现与性能优化实战

虚拟列表技术深度解析&#xff1a;原理、实现与性能优化实战 引言 在当今数据驱动的互联网应用中&#xff0c;长列表渲染已成为前端开发的核心挑战。传统的一次性全量渲染方式在数据量超过千条时&#xff0c;往往导致页面卡顿、内存飙升等问题。虚拟列表&#xff08;Virtual L…

2025-04-20 李沐深度学习4 —— 自动求导

文章目录 1 导数拓展1.1 标量导数1.2 梯度&#xff1a;向量的导数1.3 扩展到矩阵1.4 链式法则 2 自动求导2.1 计算图2.2 正向模式2.3 反向模式 3 实战&#xff1a;自动求导3.1 简单示例3.2 非标量的反向传播3.3 分离计算3.4 Python 控制流 硬件配置&#xff1a; Windows 11Inte…

Redis的使用总结

Redis 核心使用场景 缓存加速 高频访问数据缓存&#xff08;如商品信息、用户信息&#xff09; 缓解数据库压力&#xff0c;提升响应速度 会话存储 分布式系统共享 Session&#xff08;替代 Tomcat Session&#xff09; 支持 TTL 自动过期 排行榜/计数器 实时排序&#x…

富文本编辑器实现

&#x1f3a8; 富文本编辑器实现原理全解析 &#x1f4dd; 基本实现路径图 #mermaid-svg-MO1B8a6kAOmD8B6Y {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MO1B8a6kAOmD8B6Y .error-icon{fill:#552222;}#mermaid-s…

LeetCode热题100——283. 移动零

给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0] 输出:…

与Ubuntu相关命令

windows将文件传输到Ubuntu 传输文件夹或文件 scp -r 本地文件夹或文件 ubuntu用户名IP地址:要传输到的文件夹路径 例如&#xff1a; scp -r .\04.py gao192.168.248.129:/home/gao 如果传输文件也可以去掉-r 安装软件 sudo apt-get update 更新软件包列表 sudo apt insta…

Kafka 在小流量和大流量场景下的顺序消费问题

一、低流量系统 特点 消息量较少&#xff0c;吞吐量要求低。系统资源&#xff08;如 CPU、内存、网络&#xff09;相对充足。对延迟容忍度较高。 保证顺序消费的方案 单分区 单消费者 将消息发送到单个分区&#xff08;例如固定 Partition 0&#xff09;&#xff0c;由单个…

小程序 GET 接口两种传值方式

前言 一般 GET 接口只有两种URL 参数和路径参数 一&#xff1a;URL 参数&#xff08;推荐方式&#xff09; 你希望请求&#xff1a; https://serve.zimeinew.com/wx/products/info?id5124接口应该写成这样&#xff0c;用 req.query.id 取 ?id5124&#xff1a; app.get(&…

小白学习java第14天(中):数据库

1.DML data manage language数据库管理语言 外键:外键是什么&#xff1f;就是对其进行表与表之间的联系&#xff0c;就是使用的键进行关联&#xff01; 方法一&#xff1a;我们在数据库里面就对其进行表与表之间的连接【这种是不建议的&#xff0c;我不太喜欢就是将数据里面弄…

NO.95十六届蓝桥杯备战|图论基础-单源最短路|负环|BF判断负环|SPFA判断负环|邮递员送信|采购特价产品|拉近距离|最短路计数(C++)

P3385 【模板】负环 - 洛谷 如果图中存在负环&#xff0c;那么有可能不存在最短路。 BF算法判断负环 执⾏n轮松弛操作&#xff0c;如果第n轮还存在松弛操作&#xff0c;那么就有负环。 #include <bits/stdc.h> using namespace std;const int N 2e3 10, M 3e3 1…

K8s pod 应用

/** 个人学习笔记&#xff0c;如有问题欢迎交流&#xff0c;文章编排和格式等问题见谅&#xff01; */ &#xff08;1&#xff09;编写 pod.yaml 文件 pod 是 kubernetes 中最小的编排单位&#xff0c;一个 pod 里包含一个或多个容器。 apiVersion: v1 # 指定api版本 kind…

Oracle创建触发器实例

一 创建DML 触发器 DML触发器基本要点&#xff1a; 触发时机&#xff1a;指定触发器的触发时间。如果指定为BEFORE&#xff0c;则表示在执行DML操作之前触发&#xff0c;以便防止某些错误操作发生或实现某些业务规则&#xff1b;如果指定为AFTER&#xff0c;则表示在执行DML操作…

Filename too long 错误

Filename too long 错误表明文件名超出了文件系统或版本控制系统允许的最大长度。 可能的原因 文件系统限制 不同的文件系统对文件名长度有不同的限制。例如&#xff0c;FAT32 文件名最长为 255 个字符&#xff0c;而 NTFS 虽然支持较长的文件名&#xff0c;但在某些情况下也…

网络不可达network unreachable问题解决过程

问题&#xff1a;访问一个环境中的路由器172.16.1.1&#xff0c;发现ssh无法访问&#xff0c;ping发现回网络不可达 C:\Windows\System32>ping 172.16.1.1 正在 Ping 172.16.1.1 具有 32 字节的数据: 来自 172.16.81.1 的回复: 无法访问目标网。 来自 172.16.81.1 的回复:…

Python设计模式:备忘录模式

1. 什么是备忘录模式&#xff1f; 备忘录模式是一种行为设计模式&#xff0c;它允许在不暴露对象内部状态的情况下&#xff0c;保存和恢复对象的状态。备忘录模式的核心思想是将对象的状态保存到一个备忘录对象中&#xff0c;以便在需要时可以恢复到之前的状态。这种模式通常用…

Python基础语法3

目录 1、函数 1.1、语法格式 1.2、函数返回值 1.3、变量作用域 1.4、执行过程 1.5、链式调用 1.6、嵌套调用 1.7、函数递归 1.8、参数默认值 1.9、关键字参数 2、列表 2.1、创建列表 2.2、下标访问 2.3、切片操作 2.4、遍历列表元素 2.5、新增元素 2.6、查找元…