FPGA 20个例程篇:20.USB2.0/RS232/LAN控制并行DAC输出任意频率正弦波、梯形波、三角波、方波(二)
通过上面的介绍相信大家对数字变频已经有了一个较为整体性的认识,下面笔者来对照XILINX的DDS IP核对数字变频技术展开更进一步的说明,做到了理论和实践很好地结合,这样大家再带入Modelsim进行仿真测试就不仅掌握了数字变频的理论知识,也明白了其IP核的使用方法。
查阅XILINX的DDS IP核官方手册pg141-dds-compiler,如图1所示是DDS IP核的简化图,大家可以看到这里和前面数字变频理论基础介绍大同小异,XILINX的DDS IP核内部由累加器、寄存器、查找表等组成。

图1 DDS IP核的简化图
如图2所示是DDS IP核的频率控制字计算说明,这里XILINX也举实例说明频率控制字的计算方法,接着再归纳推导出一般性公式,大家可以看到例子当中fclk是120Mhz的 时钟频率即FPGA内部时钟,相位位宽Bθ(n)是10即正弦查找表是2的10次方,Δθ是十进制的12即每个时钟周期累加器在做12的递增操作。
整个操作合起来看就是FPGA内部以120Mhz的时钟频率,对一个累加器进行每个周期12的自加操作,同时每个周期再把累加器值映射到一张2的10次方正弦查找表中,取出表中的对应数值送到外部DAC中,外部DAC再通过硬件上的运放调理,输出给定幅值的特定频率正弦波,那么问题来了即经过这样一番操作后,输出正弦波的频率到底是多少赫兹呢?这里XILINX官方手册也给出了计算结果:fout=fclk*Δθ/2^Bθ(n)即fout=120*10^6*12/2^10=1.406250Mhz,当然对一般应用场景来说都是已知FPGA内部时钟频率fclk、DDS期望输出频率fout以及正弦查找表的位宽去求频率控制字Δθ,所以变换整理公式即可以得到:Δθ= fout*2^Bθ(n)/ fclk。

图2 DDS IP核的频率控制字计算说明
搞明白DDS IP核频率控制字的计算方法,相信细心的同学在思考过后肯定会抱有一些疑惑其中最典型的应该就是fclk是FPGA内部时钟频率这点好理解,fout是DDS期望输出频率也同样直观易懂,但是公式中的Bθ(n)正弦查找表位宽要怎么去选定呢,这个值的选取有没有什么特定的含义呢?
其实笔者刚接触到DDS IP核的时候在看完XILINX官方手册给出的频率控制字计算公式后同样抱有这样的困惑,当时也在网络上搜索了很多博客资料等,但遗憾的是很少看到真正有价值的文章,如图3所示是Bθ(n)正弦查找表位宽选取的计算说明,这个值的选取将会直接影响到DDS IP核输出的频率分辨率。
如下图所示,这里XILINX官方手册同样也人性化地举了一个例子进行说明,对于fclk为100Mhz的时钟频率系统,要想得到最小输出精度为1hz的正弦波波形,则要对应的正弦查找表是2的27次方位宽,可以看到XILINX官方给出的计算公式是fclk/Δf的比值再以2为底数向下取对数,在这里猛地一看感觉非常绕脑,但是仔细分析就不难发现其中的含义:对于给定fclk的时钟频率系统,每个时钟周期都会进行频率控制字的自加操作,显然在这里累加值至少为1,那么当累加器为1时则对应了系统的最小分辨率即fclk/2^Bθ(n),这个值代表了DDS IP核可以设定的最小频率精度。

图3 DDS IP核的频率分辨率的计算说明
在结合XILINX的DDS IP核手册对数字变频参数进行说明后,我们再来看一看IP核的具体设置和各个信号量所代表的含义,以方便后续对其进行仿真测试,搞明白整个IP核的行为特征,细心的同学不难发现在XILINX的VIVADO环境下支持旗下所有7系列的芯片,而相比于ISE环境,大部分XILINX的官方IP核都支持AXI总线协议,AXI总线协议引入了握手机制等,当然在这里篇幅原因笔者就不展开叙述了,感兴趣的同学可以查阅XILINX的官方手册。
如图4所示是DDS IP核CONFIG输入通道的数据格式,顾名思义地用户通过这个输入通道就可以初始化DDS IP核,以输出给定频率和相位的正弦波波形,可以看到XILINX的官方手册对DDS IP核的组包格式进行了详细说明,同时注意到s_axis_config_tdata信号在s_axis_config_tvalid信号为高时有效,且s_axis_config_tdata信号是由PINC和POFF两者共同拼接而成的。
这里XILINX官方也举例进行说明方便用户理解,如下图所示当相位phase位宽是11位时即相位累加器总位宽是11位,则相位控制字POFF和频率控制字PINC位宽都是11位,那么对于总位宽是32的s_axis_config_tdata的0-10位是PINC的输入值,16-26位是POFF的输入值。
频率控制字PINC即每个fclk时钟周期内DDS IP核内部自加值,相位控制字POFF即在相位累加器中频率控制字自加的基础上再增加的一个固定值,这样即可实现改变频率相位的效果,当然具体的细节会笔者会在后面仿真DDS IP核中做进一步说明。

图4 DDS IP核CONFIG输入通道的数据格式
如下图5所示是DDS IP核DATA输出通道的数据格式,在IP核中默认选择Sine和Cosine都输出的情况下,m_axis_data_tdata也是由SINE和COSINE共同组成,在这里XILINX官方手册同样举例做了说明,对于总位宽是32的m_axis_data_tdata的0-10位是COSINE的输出值,16-26位是SINE的输出值。
如图6所示是DDS IP核复位信号的说明,大家可以清楚地看到XILINX的DDS IP核支持了两种接口方式,一种是不含TREADY握手信号的而另一种是含TREADY握手信号的,官方手册中指出aresetn信号默认为高当其为低时则表示对DDS IP核的复位,同时该信号作为复位信号时需要至少2个时钟周期持续为低才生效。
注意到m_axis_data_tvalid在复位起效果后会被拉低若干个时钟周期,而当其作为输出信号重新再被DDS IP核置高后,此时m_axis_data_tdata输出数据才是用户所期望的正弦波波形数据,对照XILINX的官方手册简单地总结几点也为后续仿真DDS IP核提供依据:
- s_axis_config_tdata信号在s_axis_config_tvalid信号为高时有效,且s_axis_config_tdata信号是由PINC和POFF两者共同拼接而成的;
- m_axis_data_tdata信号在m_axis_data_tvalid信号为高时有效,且m_axis_data_tvalid信号在默认SINE和COSINE输出状态下也是由Sine和Cosine两者共同拼接而成的;
- aresetn信号低时则表示对DDS IP核的复位至少拉低2个时钟周期DDS IP核才可实现内部复位,复位完成后波形输出信号m_axis_data_tdata在m_axis_data_tvalid为高时有效,相似的相位输出信号m_axis_phase_tdata在m_axis_phase_tvalid为高时有效;
图5 DDS IP核DATA输出通道的数据格式


图6 DDS IP核复位信号的说明
最后想补充说明一点如图7所示是DDS IP核对SFDR无杂散动态范围的说明,其实说真这个名词也很少听过,但在XILINX的DDS IP核初始化中需要去单独配置,所以至少我们需要搞清楚这个值的设定取决哪些因素,XILINX官方手册同样很贴心地给出了计算公式,即DDS IP核的最终输出位宽在None and Dithering模式下是SFDR/6的向下去余,在Taylor模式下是SFDR/6的向下去余后再加1,再去结合原理图我们选取的DAC芯片型号是AD9708,其对应的位宽是8位,所以在None and Dithering和Auto模式下我们需要配置SFDR的值是48,当然感兴趣的同学可以再对照手册理解下SFDR的具体含义。
图7 DDS IP核对SFDR无杂散动态范围的说明
通过以上对数字变频理论分析和对XILINX的DDS IP核手册信息提取为后期的程序设计提供了有力支撑,下面笔者就通过配置和仿真IP核等具体操作,带着大家实际观察波形去验证前面的知识点,大家打开Vivado在IP核的搜索栏中输入关键字DDS,如图8所示选中DDS IP核即可,如图9到11所示是该IP核的具体配置,笔者在这里不想再像写说明书一样每个选项都逐一赘述列举,具体的细节完全可以去查阅XILINX的DDS IP核官方手册pg141-dds-compiler。
对于DDS IP核的配置说明几点核心问题,首先我们选择了0.5Mhz作为fclk即系统时钟,然后把分辨率设置为高精度的0.01hz,根据上面的公式大家可以计算得出需要累加器位宽是26(500000/2^26=0.00745<0.01),其次在SFDR中选择48对应了硬件上AD9708的8位输出位宽,再次把PINC和POFF都设置为支持用户设定和DDS IP核输出Sine和Cosine模式,最后选择自动分配延迟周期节约IP核底层硬件资源,并引出aresetn复位信号。

图8 Vivado的搜索栏中搜索DDS IP核

图9 DDS IP核的Configuration界面

图10 DDS IP核的Implementation界面

图11 DDS IP核的Detailed Implementation界面
在配置完DDS IP核,我们就要开始写对应的Testbench带入Modelsim进行仿真验证帮助朋友们进一步理解整个IP核的行为特征,在写激励之前不妨问自己几个问题即想验证哪些功能。
在这个例程中我们希望用DDS IP核输出可设定频率和偏移的正弦波,那么对于fclk是0.5Mhz,正弦波形查找表位宽Bθ(n)是26位且最小分辨率是0.01hz,DDS正弦波输出位宽为8位的情况下,fout正弦波输出频率即为fout=fclk*Δθ/2^Bθ(n)=500000*Δθ/2^26。
显然在这里输出正弦波频率fout是已知的,而频率控制字Δθ是未知的,那么对fout是1hz时,Δθ=fout*2^Bθ(n)/fclk=1*2^26/500000=134.217728,2hz时Δθ=134.217728*2=268.435456,即通俗易懂的Δθ=134*fout,这也非常好理解当PINC频率控制字Δθ越大,那么遍历完整个正弦波形查找表的速度也就越快,反应出来的直观结果就是频率越来越大其周期越来越小。
同时我们也想在这个Testbench中验证DDS IP核的相位控制字和复位功能,那么我们还需要计算出POFF相位控制字的值,通过前面的分析可知fclk是0.5Mhz,正弦波形查找表位宽Bθ(n)是26位,那么按照数学上对于正弦波的定义,一个完整的正弦波周期是360deg折合成一张总地址是2^26的查找表,相对应的偏移90deg则POFF相位控制字是2^25,偏移180deg则POFF相位控制字是2^26,所以激励中我们可以设计每次在拉低aresetn两个周期后,通过拉高s_axis_config_tvalid信号再向s_axis_config_tdata写入POFF和PINC,观察m_axis_data_tvalid和m_axis_data_tdata、m_axis_phase_tvalid和m_axis_phase_tdata是否符合我们的设计预期。
也需要注意到一点细节在DDS IP核的极性配置中我们没有勾选负半轴的Sine和Cosine,所以在这里需要简单地做一下波形拼接成一个完全周期的正弦波,具体细节大家可以参考如图12所示的DDS IP核的输入信号激励设计。





图12 DDS IP核的输入信号激励设计
大家带入到Modelsim里仿真即可观察到如图13所示DDS IP核的仿真结果,注意到在Testbench激励中,我们开始第一次输入的s_axis_config_tdata值是64'd134即对应为1hz频率的正弦波;而第二次输入的s_axis_config_tdata值是{6'd0,1'd1,25'd0,32'd1340}即对应为10hz频率偏移180deg的正弦波;第三次输入的s_axis_config_tdata值是{6'd0,2'd1,24'd0}即对应为10hz频率偏移90deg的正弦波,每次在拉低aresetn两个时钟周期后,再对应地拉高s_axis_config_tvalid,通过s_axis_config_tdata信号写入PINC和POFF的值,大家可以带入Modelsim中观察其仿真结果完全符合预期设计。
图13 DDS IP核的仿真结果
相关文章:
FPGA 20个例程篇:20.USB2.0/RS232/LAN控制并行DAC输出任意频率正弦波、梯形波、三角波、方波(二)
通过上面的介绍相信大家对数字变频已经有了一个较为整体性的认识,下面笔者来对照XILINX的DDS IP核对数字变频技术展开更进一步的说明,做到了理论和实践很好地结合,这样大家再带入Modelsim进行仿真测试就不仅掌握了数字变频的理论知识…...
接口中新增方法,接口应用和适配器设计模式
目录 JDK8以后接口中新增方法 接口中默认方法注意事项: 新增方法static 接口中静态方法的注意事项: JDK9新增的方法 JDK8以后接口中新增方法 允许在接口中定义默认的方法,需要使用关键字default修饰作用:解决接口升级的问题 …...
自主HttpServer实现(C++实战项目)
文章目录项目介绍CGI技术概念原理设计框架日志文件TCPServer任务类初始化与启动HttpServerHTTP请求结构HTTP响应结构线程回调EndPoint类EndPoint主体框架读取HTTP请求处理HTTP请求CGI处理非CGI处理构建HTTP响应发送HTTP响应接入线程池简单测试项目扩展项目介绍 该项目是一个基…...
第26篇:Java数组API总结
目录 1、数组基本概念 2、Java如何声明数组 2.1中括号在数据类型之前 2.2 中括号在数据类型之后...
[C++] 信号
前言 信号与槽是QT的一个概念,原版C里并没有 使用 先声明一些类 Receiver负责接收信号,Emitter2则是负责发送 class Receiver : public ntl::Reflectible { public:void received(int num){std::cout << "received:" << num &…...
单片机——矩阵按键模块
主要目的 学会按键扫描 1.延时函数 延时函数部分详见链接: 单片机控制一盏灯的亮与灭程序解释 void delay (uint k) //定义延时函数{uint i,j;for(i<0;i<k;i){for(j0;j<113;j){;}}}这个程序里面的延时函数的目的是按键消抖。 2.按键扫描模块 这是本次实验的重点&a…...
Android学习之网络操作
网络操作 Android平台下的原生网络操作可以分为以下几步: 创建URL对象;通过URL对象获取HttpURLConnection对象;通过HttpURLConnection对象设置请求头键值对、网络连接超时时间等;通过HttpURLConnection对象的connect()方法建立网…...
Delphi XE开发android开发环境搭建
Delphi xe为使用Delphi作为开发工具的程序员,提供了开发APP的便捷工具,它的开发环境也是非常容易搭建,这里我简述一下Android的开发环境搭建,Delphi XE开发Android程序的开发环境需要三个软件支持:Java SE Development开发环境、Android SDK和Android Ndk开发环境。 1、安…...
flink入门-流处理
入门需要掌握:从入门demo理解、flink 系统架构(看几个关键组件)、安装、使用flink的命令跑jar包flink的webUI 界面的监控、常见错误、调优 一、入门demo:统计单词个数 0、单词txt 文本内容(words.txt): hello world …...
【数据结构】单链表中,如何实现 将链表中所有结点的链接方向“原地”逆转
一.实现一个单链表(无头单向不循环) 我们首先实现一个无头单向不循环单链表。 写出基本的增删查改功能,以及其它的一些功能(可忽略)。 #include<stdio.h> #include<assert.h> #include<stdlib.h>…...
摘花生(简单DP)
Hello Kitty想摘点花生送给她喜欢的米老鼠。她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。Hel…...
2022济南大学acm新生赛题解
通过答题情况的难度系数: 签到:A 简单:BL 中等:D 困难:CM 极难:KNO A-和 算出n个数的和判断正负性即可!!! 发现很多同学的代码错误:要么sum未赋初值&…...
策略模式教程
策略模式是一种行为型设计模式,它允许在运行时根据不同的情况选择不同的算法实现,从而使得算法可以独立于客户端而变化。本文将介绍策略模式的概念、应用场景、优点和缺点,并提供最佳的代码实践。本文的代码实现将使用Java语言,但…...
什么是刺猬理念
一、什么是刺猬理念刺猬理念是指把复杂的世界简化成单个有组织性的观点,一条基本原则或一个基本理念,发挥统帅和指导作用。核心是把事情简单化,把所有的挑战和进退维谷的局面压缩为简单的。二、刺猬理念的寓言故事狐狸是一种狡猾的动物&#…...
RPC通信相关
RPCRPC, 远程过程调用(Remote Procedure Call,RPC)是一个计算机通信协议,该协议允许运行于一台计算机的程序程调用另一台计算机的上的程序。通俗讲,RPC通过把网络通讯抽象为远程的过程调用,调用远程的过程就…...
Node.js + MongoDB 搭建博客 -- 登录页面
准备工作 安装Node.js安装express等相关库MongoDB数据库电脑系统:win11 功能分析 搭建一个简单的具有多人注册、登录、发表文章以及登出功能的博客。 设计目标 未登录:主页左侧导航栏显示home、login、register,右侧显示已发表的文章、发…...
互联网新理念,对于WEB 3.0 你怎么看?
WEB 3.0 这个名词走进大众视野已经有一段时间了,也曾在各个圈子里火热一时,至今各大互联网企业任旧在 WEB 3.0 上不断探索。但关于 WEB 3.0 是什么这个问题,其实大部分人都没有一个比较明确的认知,包括区块链和元宇宙等相关行业的…...
Git使用教程:最详细、最傻瓜、最浅显、真正手把手教
GITGIT版本控制版本控制的意义分布式图形化客户端环境搭建仓库的操作分支使用场景命令远程仓库操作生成公钥命令冲突忽略列表的配置时机配置方式版本回退练习:GIT 版本控制 把文件系统中的文件,按照修改的版本进行记录,进行管理的操作。 版…...
【面试题】Redis面试题汇总(无解答)
Redis为何这么快?缓存问题及解决入库和缓存策略问题及处理redis数据类型缓存过期删除策略内存淘汰机制Redis 回收进程如何工作的?Redis持久化RDB和AOFredis流式pipeline处理原生批命令 (mset, mget) 与 Pipeline 区别?Pipeline 有什么好处,为…...
RHCSA-用户和组管理和文件系统权限(3.11)
目录 用户(UID) 用户类别(UID): 用户的增删改查: 修改用户密码: 查看用户是否存在: 组(GID) 组的增删改查: 设置组密码: 用户…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
