【FPGA开发】DDS信号发生器设计

一、常见IP模块介绍

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

根据实现方式的不同,IP核可以分为软核(softcore)、固核(firmcore)和硬核(hardcore),三种IP核的特点如表所示。 

IP软核是FPGA设计中常用的预构建功能模块,可以显著提高开发效率。下面介绍RAM、ROM和FIFO这三种常见IP核的使用方法。

1.1 RAM IP核的使用

ROM简介

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

参数设置要点
(1)存储器类型:
    ·单端口RAM
    ·简单双端口RAM(一个读端口一个写端口)
    ·真双端口RAM(两个独立读写端口)

(2)数据宽度:设置存储单元的位宽(如8位、16位、32位等)

(3)存储深度:设置存储单元的数量(如1024、2048等)

(4)操作模式:写优先模式、读优先模式、不变模式

(5)初始化文件:可选.hex或.mif文件初始化RAM内容

调用过程(以Xilinx Vivado为例)
(1)在IP Catalog中搜索Block Memory Generator

(2)选择RAM类型和接口类型(Native或AXI)

(3)设置数据宽度和存储深度

(4)配置操作模式和时钟选项

(5)生成IP核并添加到设计中

示例代码(Verilog实例化):

ram_8x1024 your_ram_instance (.clka(clk),       // 时钟输入.ena(ram_en),     // 使能信号.wea(ram_we),     // 写使能.addra(ram_addr), // 地址总线.dina(ram_din),   // 数据输入.douta(ram_dout)  // 数据输出
);

1.2 ROM IP核的使用

参数设置要点
(1)数据宽度:与RAM类似,设置输出数据的位宽

(2)存储深度:决定ROM的大小

(3)初始化文件:必须提供.mif或.hex文件初始化ROM内容

(4)输出寄存器:可选择是否在输出端添加寄存器

调用过程
(1)在IP Catalog中搜索"Block Memory Generator"

(2)选择ROM类型

(3)设置数据宽度和存储深度

(4)指定初始化文件路径

(5)配置其他选项(如输出寄存器)

(6)生成IP核

示例代码:

rom_16x512 your_rom_instance (.clka(clk),       // 时钟输入.addra(rom_addr), // 地址输入.douta(rom_data)  // 数据输出
);

1.3 FIFO IP核的使用

参数设置要点
(1)FIFO类型:
同步FIFO(单时钟)
异步FIFO(读写不同时钟)

(1)数据宽度:设置FIFO存储数据的位宽

(2)FIFO深度:设置FIFO能存储的数据量

(3)满/空标志:设置满和空标志的生成方式

(4)握手信号:可选添加读写确认信号

(5)存储类型:选择使用Block RAM或Distributed RAM

调用过程
(1)在IP Catalog中搜索"FIFO Generator"

(2)选择同步/异步FIFO

(3)设置数据宽度和深度

(4)配置标志信号和握手信号

(5)选择存储资源类型

(6)生成IP核

示例代码:

fifo_32x256 your_fifo_instance (.clk(clk),        // 时钟输入(同步FIFO).rst(reset),      // 复位信号.din(fifo_in),    // 数据输入.wr_en(wr_en),    // 写使能.rd_en(rd_en),    // 读使能.dout(fifo_out),  // 数据输出.full(full),      // 满标志.empty(empty)     // 空标志
);

1.4 通用注意事项

1. 时钟域处理:特别是异步FIFO,要确保跨时钟域信号正确处理
2. 资源选择:根据设计需求选择Block RAM或Distributed RAM
3. 时序约束:使用IP核后要添加适当的时序约束
4. 仿真模型:大多数IP工具会生成仿真模型,便于验证设计
5. 功耗考虑:大容量存储器可能显著影响功耗,需合理选择

掌握这些IP核的使用可以大大提高FPGA设计的效率,特别是在需要存储和缓冲数据的应用中。

二、实操演练 

2.1 DDS信号发生器设计

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

2.1.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,点击添加

img

找到刚才保存的文件添加

img

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

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

img

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

img

2.1.2波形存储器ROM的设计
(1)方波模块

步骤跟上面的一样,文件名为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文件后该模块的符号如图

img

(2)正弦波形存储器模块

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文件

img

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

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

img编辑

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

img

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

img

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

img

点击Next,配置如下

img

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

img

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

img

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

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

img

2.2 锁相环倍频电路设计

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

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

img

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

img

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

img

其余的按如下图片设置

img

img

最后选择需要生成的文件

img

2.3 顶层电路设计

代码如下:

//========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.pswp.cn/pingmian/84040.shtml

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

相关文章

板凳-------Mysql cookbook学习 (九--3)

4.3 使用临时表 Drop table 语句来删除表&#xff0c; 选择使用create temporary table 语句&#xff0c;创建的是一张临时表。 Create temporary table tb1_name(…列定义…) 克隆表 Create temporary table new_table like original_table 根据查询结果建表 Create temporary…

Python Web项目打包(Wheel)与服务器部署全流程

目录 一、本地开发环境准备二、创建setup.py打包配置三、创建WSGI入口文件四、打包生成Wheel文件五、服务器端部署流程1. 传输文件到服务器2. 服务器环境准备3. 配置生产环境变量4. 使用Gunicorn启动服务 六、高级部署方案&#xff08;Systemd服务&#xff09;1. 创建Systemd服…

c++ 基于openssl MD5用法

基于openssl MD5用法 #include <iostream> #include <openssl/md5.h> using namespace std; int main(int argc, char* argv[]) { cout << "Test Hash!" << endl; unsigned char data[] "测试md5数据"; unsigned char out[1024…

如何通过外网访问内网服务器?怎么让互联网上连接本地局域网的网址

服务器作为一个数据终端&#xff0c;是很多企事业单位不可获缺的重要设备&#xff0c;多数公司本地都会有部署服务器供测试或部署一些网络项目使用。有人说服务器就是计算机&#xff0c;其实这种说法不是很准确。准确的说服务器算是计算机的一种&#xff0c;它的作用是管理计算…

安装Openstack

基本按照Ubuntu官网的指南来安装&#xff0c;使用单节点模式&#xff0c;官网步骤参见网址&#xff1a;https://ubuntu.com/openstack/install 系统为Ubuntu 24.04.2&#xff0c;全新安装. Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.11.0-24-generic x86_64)kaiexperiment…

‌Kafka与RabbitMQ的核心区别

‌1.设计目标与适用场景‌ ‌Kafka‌&#xff1a;专注于高吞吐量的分布式流处理平台&#xff0c;适合处理大数据流&#xff08;如日志收集、实时数据分析&#xff09;&#xff0c;强调消息的顺序性和扩展性。‌‌ ‌RabbitMQ‌&#xff1a;作为消息中间件&#xff0c;侧重于消…

深入理解 Spring Cache 及其核心注解

一、Spring Cache 概述​ Spring Cache 并不是一个具体的缓存实现方案&#xff0c;而是一套抽象的缓存规范。它支持多种缓存技术&#xff0c;如 Ehcache、Redis、Caffeine 等&#xff0c;开发者可以根据项目需求灵活选择合适的缓存技术。其核心思想是通过在方法上添加注解&…

STM32H562----------串口通信(UART)

1、串口介绍 1.1、 数据通信概念 在单片机中我们常用的通信方式有 USART、IIC、SPI、CAN、USB 等; 1、数据通信方式 根据数据通信方式可分为串行通信和并行通信两种,如下图: 串行通信基本特征是数据逐位顺序依次传输,优点:传输线少成本低,抗干扰能力强可用于远距离传…

20-Oracle 23 ai free Database Sharding-特性验证

对于Oracle 23ai Sharding 新特性的验证脚本&#xff0c;目标是涵盖其核心改进和新增功能。基于 Oracle 23ai 的 Sharding 特性总结&#xff08;Raft 协议、True Cache、Vector等&#xff09;&#xff0c;结合常见场景验证。 通过SQL脚本验证这些特性。例如&#xff1a; 1.基于…

✅ 常用 Java HTTP 客户端汇总及使用示例

在 Java 开发中,HTTP 客户端是与服务端交互的关键组件。随着技术发展,出现了多种 HTTP 客户端库,本文汇总了常用的 Java HTTP 客户端,介绍其特点、适用场景,并附上简单使用示例,方便开发者快速选择和上手。 1.常用 HTTP 客户端一览 名称简介特点HttpClient(JDK 自带)Ja…

MCP(Model Context Protocol)与提示词撰写

随着大模型&#xff08;LLM&#xff09;在复杂任务中的普及&#xff0c;如何让模型高效调用外部工具和数据成为关键挑战。传统函数调用&#xff08;Function Calling&#xff09;依赖开发者手动封装 API&#xff0c;而 MCP&#xff08;Model Context Protocol&#xff09; 通过…

RootSIFT的目标定位,opencvsharp。

首先截取匹配模板&#xff0c;然后使用rootsift特征匹配&#xff0c;最后定位目标。 对于微弱变化&#xff0c;还是能够识别定位的&#xff0c;对于传统算法来说已经不错了。 目标定位效果&#xff1a; 使用的模板图片。 using OpenCvSharp; using OpenCvSharp.Features2D;u…

Appium如何支持ios真机测试

ios模拟器上UI自动化测试 以appiumwebdriverio为例&#xff0c;详细介绍如何在模拟器上安装和测试app。在使用ios模拟器前&#xff0c;需要安装xcode&#xff0c;创建和启动一个simulator。simulator创建好后&#xff0c;就可以使用xcrun simctl命令安装被测应用并开始测试了。…

近几年字节飞书测开部分面试题整理

文章目录 一、面试问题1. 创建索引2. 拦截器&#xff08;Interceptor&#xff09;和过滤器&#xff08;Filter&#xff09;的区别3. 为什么jwt令牌代替session&#xff1f;4. 有一个100行的数据&#xff0c;和一个1万行的数据&#xff0c;写sql 的时候要注意什么&#xff1f;5.…

JDBC基础关键_001_认识

目 录 一、概述 二、原理 三、接口的作用 四、JDBC 模拟 1.JDBC 接口 2.驱动 3.配置文件 4.调用者 一、概述 JDBC&#xff08;Java DataBase Connectivity&#xff09;&#xff0c;Java 数据库连接&#xff1b;是用 Java 语言操作数据库&#xff0c;使用 Java 语言向数…

SWAN(Scade One) 语言原理介绍

SCADE 团队于2024年推出了下一代 SCADE 工具 Scade One&#xff0c;工具的建模语言也基于Scade 6 进行了演化。在语言命名方面&#xff0c;并没有复用"Scade"这一标志性的名称&#xff0c;而是使用了新的名字&#xff1a;Swan。在本篇中&#xff0c;将叙述 Swan 语言…

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项

一、条形码识别改名使用教程 打开软件并选择处理模式&#xff1a;打开软件后&#xff0c;根据要处理的文件类型&#xff0c;选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件&#xff0c;就选择 “PDF 识别模式”&#xff1b;若是处理图片文件&…

sql中group by使用场景

GROUP BY语句在SQL中用于将多个记录分组为较小的记录集合&#xff0c;以便对每个组执行聚合函数&#xff0c;如COUNT(), MAX(), MIN(), SUM(), AVG()等。GROUP BY的使用场景非常广泛&#xff0c;以下是一些典型的应用场景&#xff1a; 统计数量 当你想要计算某个字段的唯一值数…

MongoDB慢查询临时开启方法讲解

1、首先连接数据库 mongosh "mongodb://localhost:27017" 2、选择目标数据库 show databases;#显示所有数据库 use lidb;#使用某数据库 3、查看当前分析级别 db.getProfilingStatus() 输出 { was: 0, slowms: 100, sampleRate: 1, ok: 1 } #was0表示关闭&…

UML活动图与泳道图

活动图的作用&#xff0c;与用例图类似&#xff0c;也是帮助我们捕获用户的需求。 活动图主要是用来描述用户的业务流程&#xff0c;如果能把用户的这个业务流程描述的很清楚的话&#xff0c;就可以帮助我们做用例分析。 1 活动图定义 活动图描述了在一个过程中&#xff0c;…