双通道幅频相可调DDS 信号发生器

 

  1. DDS 基本原理

DDS(Direct Digital Synthesizer)即数字合成器,是一种新型的频率合成技术,具有相对带宽大,频率转换时间短、分辨率高和相位连续性好等优点。较容易实现频率、相位以及幅度的数控调制,广泛应用于通信领域。DDS 的基本结构图如图所示。

 

 

图1 DDS基本结构图

由图1可以看出,DDS 主要由相位累加器、相位调制器、波形数据表以及 D/A 转换器构成。

 其中相位累加器由 N 位加法器与N 位寄存器构成。每来一个时钟,加法器就将频率控制字与累加寄存器输出的相位数据相加,相加的结果又反馈至累加寄存器的数据输入端,以使加法器在下一个时钟脉冲的作用下继续与频率控制字相加。这样,相位累加器在时钟作用下,不断对频率控制字进行线性相位累加。即在每一个时钟脉冲输入时,相位累加器便把频率控制字累加一次。 位累加器输出的数据就是合成信号的相位。相位累加器的溢出频率,就是 DDS 输出的信号频率。用相位累加器输出的数据,作为波形存储器的相位采样地址,这样就可以把存储在波形存储器里的波形采样值经查表找出,完成相位到幅度的转换。波形存储器的输出数据送到 D/A 转换器,由 D/A 转换器将数字信号转换成模拟

信号输出。

图2 DDS原理流程图

这里相位累加器位数为N 位(N 的取值范围实际应用中一般为24~32),相当于把正弦信号在相位上的精度定义为N 位,所以其分辨率为1⁄2^。 

若DDS 的时钟频率为频率控制字fword 为 1,则输出频率为 ,这个频率相当于“基频”。若fword 为 B,则输出频率为

因此理论上由以上三个参数就可以得出任意的输出频率。且可得出频率分辨率由时钟频率和累加器的位数决定。当参考时钟频率越高,累加器位数越高,输出频率分辨率就越高。 从上式分析可得,当系统输入时钟频率不变时,输出信号频率由频率控制字B 所决定,由上式可得:fout = B*fclk/2^N 。其中B 为频率字且只能取整数。

为了合理控制ROM 的容量此处选取ROM 查询的地址时,可以采用截断式,即只取32 位累加器的高M 位。这里相位寄存器输出的位数一般取10~16 位。

以上通过理论计算加数据变换的形式对DDS 原理进行了较为严谨的解释,但是DDS 究竟是怎么实现频率和相位的控制的呢,通过一个简化的实例来描述DDS 实现频率和相位控制的过程。图3 为一个完整周期的正弦信号的波形,总共有33 个采样点,其中第1点和第33 点的值相同,第33 点为下一个周期的起始点,因此,实际一个周期为32 个采样点(1~32)。

图3 32个采样点的正弦信号波形

 

实现DDS 输出时,将横坐标上的数据作为ROM 的地址,纵坐标上的数据作为ROM 的输出,那么指定不同的地址就可实现对应值的输出。DDS输出控制频率和相位,归结到底就是控制ROM 的地址。                  

图4 16个采样点的正弦信号波形

当使用FPGA 控制DAC 输出一个周期的正弦信号时,每1ms 输出一个数值。如果每个点都输出,则总共输出这一个完整的周期信号需要输出32 个点,因此输出一个完整的信号需要32ms,则输出信号的频率为1000/32Hz。当需要用这一组数据来输出一个2*(1000/32)Hz 的正弦信号,因为输出信号频率为2*(1000/32)Hz,那么输出一个完整的周期的正弦波所需要的时间为32/2,即16ms。为了保证输出信号的周期为16ms,我们需要对我们的输出策略进行更改,上面输出周期为32ms 的信号时,我们采用的为逐点输出的方式,以32 个点来输出一个完整的正弦信号,而我们FPGA 控制DAC 输出信号的频率固定为1ms,因此,我们要输出周期为16ms 的信号,只能输出16 个点来表示一个完整的周期。我们就选择以每隔一个点输出一个数据的方式来输出即可。我们可以选择输出(1、3、5、7……29、31)这些点,因为采用这些点,我们还是能够组成一个完整的周期的正弦信号,而输出时间缩短为一半,即频率提高了一倍。最终结果如图4所示。如果需要使用该组波形数据输出频率为(1/2)*(1000/32)Hz 的信号,即周期为64ms,则只需要以此组数据为基础,每2ms 输出一个数据即可,例如第1ms 和第2ms 输出第一个点,第3ms 和第4ms 输出第二个点,以此类推,第63ms 和第64ms 输出第32 个点,即可实现周期加倍,即频率减半的效果。 对于相位的调整,则更加简单。只需要在每个取样点的序号上加上一个偏移量,便可实现相位的控制。例如,上面默认的是第1ms 时输出第一个点的数据,假如我们现在在第1ms 时从第9 个点开始输出,则将相位左移了90 度,这就是控制相位的原理。

  1. DDS设计过程

在本设计中参考时钟频率为50 MHz,相位累加器位数N 取24位,频率控制字位数M 取8 位,所设计的系统是通过矩阵键盘来控制双通道正弦信号的幅频相,并且将输出的数据通过SignalTap II来进行实时显示双通道的波形数据。如下图5为本次设计的RTL视图。

图5 系统RTL视图

通过系统的RTL视图可以看出来,系统主要是通过矩阵模块,幅频相控制模块,以及DDS模块来实现双通道DDS信号发生器。其中具体工作流程为矩阵按键控制模块输出键值给幅频相控制模块,幅频相控制模块在接收到按键值之后就进行幅度,频率和相位的计算,并将实时计算的幅频相传输给DDS发生模块,两个DDS模块输出的双通道数据通过SignalTap II来进行抓取数据波形。

  1. ROM

 

首先是设计一个ROM来存储基本的波形数据,如图6所示为建立的ROM的IP核,其中ROM为8位,深度为256,ROM部分将会在DDS模块中进行例化。

图6 ROM的IP核

 

ROM中存储基本的波形数据是通过MIF文件来进行初始化的,其中MIF文件中的数据可以自己设置,比如可以是正弦数据也可以是锯齿波数据,如图7所示为建立的ROM的IP核中的MIF文件。

图7 ROM的MIF文件

  1. 矩阵按键模块

矩阵键盘有两组,共8 根信号线,其中COL 将每一列的四个按键的一端连接起来,而ROW 则将每一行的4 个按键的一端连接起来,通过4 行4 列的8 根信号线,总共能够管理16 个按键,如果没有按键被按下的情况下,使用FPGA 的IO 坚持ROW 信号上的电平,应该默认都是高电平。那我们如何去检测某一个按键被按下,并且还能找到其具体的位置,思路其实并不复杂,假如我们让COL0=0,然后去读取ROW 的值,如果4 个ROW 信号的电平全部为高,则表明当前列并无按键按下,则切换到扫描下一列,再去读取4 个ROW 信号的值,根据读到的ROW 值判断当前是哪一个按键被按下。例如当扫描第三列的时候,即COL=4’b1011 时,检测到ROW=4’b1011,则说明“A”被按下。

 

在按键过程中由于要处理消抖以及读取键值等问题,涉及到多个状态,所以采用了状态机进行了设计,这里采用了性能最好的三段式状态机,图8为按键控制模块状态转移图,图9为各个状态。

 

图8 按键控制模块状态转移图

图9 按键控制模块状态

  1. 幅度、频率和相位控制模块

 

幅度、频率和相位控制模块是在按键控制模块之后,接收按键控制模块输出的键值,通过键值来进行幅度、频率和相位的控制。由于需要控制三个参数,而且需要控制两路通道,所以输入的键值需要进行严格的区分,幅度、频率以及相位在计算的时候需要分成多个状态,所以也用到了状态机进行了设计。如下图10所示为CTRL模块的引脚。   

                     

图10 CTRL模块引脚

 

因为幅度、频率以及相位在计算的时候需要分成很多个状态,所以在CTRL模块也用到了状态机进行了设计,在CTRL模块中也是用到了三段式状态机。如图11所示为CTRL模块的状态机的各个状态。

                     

图11 CTRL模块状态机的各个状态

 

图12为CTRL模块的三段式转态机状态转移图。


图12 CTRL模块状态转移图

  1. DDS控制模块

 

DDS控制模块的设计就是参考图1来进行设计。由图1可以看出,DDS 主要由相位累加器、同步寄存器、波形数据表构成。根据设计需求,如图13所示为Fword和Pword 的同步寄存器,图14为相位累加器也就是输出ROM地址。

                                

图13 同步寄存器

图14 相位累积器ROM地址

  1. 时序分析

 

由于所设计DDS信号发生器需要严格的时钟控制,所以对时序要求很高,必须对时序进行约束,如果不进行约束可能由于设计中存在乘法运算以及除法运算会造成时序的建立时间和保持时间不满足时序条件,也就是时间裕量不满足条件,也就达不到预计的频率,可能会因为这些路径导致错误。所以根据本次设计时钟为50MHz,设计了时序约束,如下图15所示。

图15时序约束

 

  1. DDS实验验证

 

首先对矩阵键盘进行仿真验证,如图16所示为对矩阵键盘的仿真程序,其中对于矩阵的键盘仿真专门写了一个模块,如图17所示为矩阵键盘的仿真数据图。

 

 图16 矩阵键盘模块仿真程序

图17 矩阵键盘模块仿真数据

             

然后对矩阵键盘的键值控制模块进行仿真,矩阵键盘的控制模块的目的是为了使频率控制字以及相位控制字还有幅度的输出给DDS模块使用,如图18所示为键值控制模块的程序,图19为仿真数据。   

图18 键值控制模块仿真程序

图19键值控制模块仿真波形数据

 

然后对所设计的DDS双通道波形数据系统进行了ModelSim仿真,仿真分为了两部分,一部分是专门针对DDS模块进行仿真,还有一部分是对整个设计进行仿真,加入了按键。首先对DDS模块进行了仿真,仿真设计程序以及仿真结果如图20和21所示。

 

图20 DDS模块仿真程序                  

图21 DDS模块仿真波形数据

从仿真结果可以看出,通过在仿真脚本文件中设置了频率和相位这两个参数,仿真出来的波形数据可以完好的展现出来。然后就加入了按键部分,通过模拟按键来进行整个顶层文件的仿真设计。

 

如图22所示为顶层仿真的程序设计,图23所示为顶层仿真的结果。

图22 仿真文件中模拟按键的键值

图23 顶层仿真结果

 

 

                     

系统在结果验证时也采用了SignalTap II来抓取双通道DDS输出的正弦波形数据。SignaTap II 逻辑分析仪,用于辅助设计调试过程,提供了用户设计全速运行在FPGA 芯片上时不使用外部I/O 引脚就能检查内部信号状态的解决方案。其与传统的外部物理逻辑分析仪类似,可以在不使用硬件测试设备的前提下,调试正常操作期间的FPGA 设计。如图25为SignalTap II配置时钟。

图25 SignalTap II配置时钟

 

如图26为配置数据输出引脚。   

                       

图26 SignalTap II配置数据输出

 

如图27所示为配置存储深度。

图27 SignalTap II配置数据存储深度

SignaTap II 逻辑分析仪相当于示波器可以观察数据,在这里实验验证除了通过硬件键盘可以输出幅频相,也可以通过ISSP的源来进行这几个参数的输入。为了更便捷地进行板级调试,Qusrtus Prime 自带的的In system sources and probes editor(ISSP)调试工具,测试过程中可以只用其提供的源,通过In system sources and probes editor(ISSP)调试工具提供的源来设置幅频相这三个参数,如图28所示为使用In system sources and probes editor(ISSP)调试工具来进行设置两个通道的频率和相位数据。

                                                            图28 ISSP的源使用

 

如图29所示为SignalTap II逻辑分析仪抓取的双通道DDS输出的数据。

                           

图29 SignalTap II抓取ISSP设置的波形数据

 

由于本次实验搭配了硬件系统,所以最后进行了实际的板级验证,如图30所示为通过控制按键来控制双通道DDS的输出端来输出可以配置幅度、频率以及相位的正弦波形数据。

其中按键配置两个DDS信号通道的参数需要一定的顺序,此次设计中先是通过按键键值C、D和E来控制此时要配置是幅度、频率还是相位,键值C是用来选择此时来配置两个通道信号的频率,键值D是用来选择此时是来配置两个通道的相位,最后按键按下E代表此时要进行配置两个通道输出信号的幅值。在选择配置模式之后就依次对两个通道的参数进行顺序设计,配置顺序是先按下A键,然后输入需要配置的参数,然后再输入B键,代表了通道1的配置已经完成,接着需要继续按下A键来进行配置通道2输出信号的参数,然后也是输入想要配置的参数,配置完成之后就需要输入B键代表通道2配置数据完成,最后按下F键,代表了这次配置的数据已经完成了,等待下一次参数的配置。

如图31所示为通过按键的键值来设置双通道DDS信号发生器输出信号的频率以及相位。

图31 SignalTap II抓取按键设置的波形数据

 

通过按键可以设置两个DDS信号发生器通道所输出的正弦信号的频率以及相位,如图32所示为通过按键的键值来设置两个通道的幅度、频率和相位的参数。

图32 SignalTap II抓取按键设置的波形数据

到这里双通道幅频相可调DDS 信号发生器的实验验证就完成了,分别通过ModelSim仿真、ISSP设置参数通过SignalTap II抓取按键设置的波形数据以及最后上板验证,直接通过按键来设置幅度、频率和相位参数来用SignalTap II抓取按键设置的波形数据。

*最后验证能运行的最低和最高频率问题:

最高频率:

正弦信号输出的最大频率问题和一个周期有多少个采样点被输出有很大关系,为了不使波形失真,输出7个采样点的话大致不会使波形失真。7个采样点就是7*2ns=14ns(本次设计系统时钟最高可以跑到90多M,如图15时序约束所示,通过优化程序也可以更高,这里默认硬件外设50MHz频率)。也就是大约7MHz频率。

 

如图33所示为本次实验通过按键设置运行在7MHz频率下,每个周期采样了7个采样点。

图33 7MHz频率下

大约采集了7个采样点,波形不会失真,如果再提高频率每个周期采集到的采样点就会更少,就会失真,所以是8位ROM查找(系统时钟50MHz)条件下,系统最高可以跑到7MHz。

如果想要提高频率一个方法是提高系统时钟,这样就可以把频率提高。通过提高系统时钟,假如在本次实验中不考虑外部的50MHz晶振,程序是可以跑到90MHz(如图15时序分析),那么一个周期采样七个点,频率大致就是将近14MHz。如果此程序继续提高频率则需要继续优化,提高系统能运行的最高频率。

最低频率:

 

最低运行频率一个取决因素是根据系统时钟,还有一个是根据频率控制字位数。例如本次设计是24位的频率控制字,如果在50MHz系统时钟下,则系统输出波形数据最低运行频率为50MHz/(2^24)=2.98Hz。如图34所示为10KHz下的波形,因为再低的话FPGA资源有限,不能将完整的波形存储显示,因此用10KHz来进行显示。

图34 10KHz频率下

如果想要运行更低的频率则可以使用更多位数的频率控制字和更低的系统时钟。例如频率控制字32位,系统时钟还是50MHz,则最低频率为50MHz/(2^32)=0.01161Hz。

综上所述,本次硬件设计在固定了系统外部时钟为50MHz(本身程序是可以跑到90MHz),频率控制字为24位条件下,输出波形的最高频率大约为7MHz,最低频率约为2.98Hz。

 

附录程序:

(由于程序过多,所占篇幅过大,只粘贴了顶层模块和顶层仿真程序,详细在程序文件中)

  1. 顶层程序设计:

module DDS_top(clk,rst_n,row,col,qa,qb);

 

input clk;

input rst_n;

input [3:0]row;

output [3:0]col;

output [7:0]qa,qb;

 

wire key_flag;

wire [3:0]key_value;

wire [23:0]Fword_A,Fword_B;

wire [7:0]Pword_A,Pword_B;

wire [7:0]Fuzhi_A,Fuzhi_B;

wire [7:0]qaf,qbf;

wire en_DDS;

 

assign qa = qaf * Fuzhi_A >>7;

assign qb = qbf * Fuzhi_B >>7;

 

DDS DDS_A(

.clk(clk),

.rst_n(rst_n),

.en_DDS(en_DDS),

.Fword(Fword_A),

.Pword(Pword_A),

.q(qaf)

);

 

DDS DDS_B(

.clk(clk),

.rst_n(rst_n),

.en_DDS(en_DDS),

.Fword(Fword_B),

.Pword(Pword_B),

.q(qbf)

);

 

key_4 key_40(

.Clk(clk),

.Rst_n(rst_n),

.Key_Board_Col_o(col),

.Key_Board_Row_i(row),

.Key_Flag(key_flag),

.Key_Value(key_value)

);

 

ctrl ctrl1(

.clk(clk),

.rst_n(rst_n),

.key_flag(key_flag),

.key_value(key_value),

.Fword_A(Fword_A),

.Fword_B(Fword_B),

    .Pword_A(Pword_A),

.Pword_B(Pword_B),

.Fuzhi_A(Fuzhi_A),

.Fuzhi_B(Fuzhi_B),

.en_DDS(en_DDS)

);

endmodule

  1. 顶层仿真程序:

`timescale 1ns/1ns

module test1_tb;

reg clk;

reg rst_n;

reg [3:0]key_value;

reg key_flag;

 

wire [23:0]Fword_A,Fword_B;

wire [7:0]Pword_A,Pword_B;

wire en_DDS;

wire [7:0]qa,qb;

 

DDS DDS_A0(

.clk(clk),

.rst_n(rst_n),

.en_DDS(en_DDS),

.Fword(Fword_A),

.Pword(Pword_A),

.q(qa)

);

 

DDS DDS_B0(

.clk(clk),

.rst_n(rst_n),

.en_DDS(en_DDS),

.Fword(Fword_B),

.Pword(Pword_B),

.q(qb)

);

 

ctrl ctrl1(

.clk(clk),

.rst_n(rst_n),

.key_flag(key_flag),

.key_value(key_value),

.Fword_A(Fword_A),

.Fword_B(Fword_B),

.Pword_A(Pword_A),

.Pword_B(Pword_B),

.Fuzhi_A(),

.Fuzhi_B(),

.en_DDS(en_DDS)

);

 

initial clk = 1;

always#10 clk = ~clk;

 

initial begin

rst_n = 0;

key_value=0;

key_flag=0;

#200;

rst_n = 1;

#200;

 

key_value=4'ha;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h6;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h5;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h5;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h3;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h6;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'hb;

key_flag=1;#20;key_flag=0;

#200;

 

key_value=4'ha;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h6;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h5;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h5;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h3;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'h6;

key_flag=1;#20;key_flag=0;

#200;

key_value=4'hb;

key_flag=1;#20;key_flag=0;

#200;

 

key_value=4'hf;

key_flag=1;#20;key_flag=0;

#200;

 

#2000_00;

$stop;

end

 

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值