基于ROM的任意波形发生器(DDS)

描述

设计背景: 

    DDS(Direct Digital Synthesizer)直接数字式频率合成器,是一种新型频率合成技术,具有低成本、低功耗、高分辨率、相对带宽大和频率转换时间短等优点。较容易实现频率、相位以及幅度的数控调制,广泛应用在电信与电子仪器和通信领域。波形发生器是一种数据信号发生器,在调试硬件时,常常需要加入一些信号,以观察电路工作是否正常。加入的信号有:正弦波、三角波、方波和任意波形等。

设计原理: 

    相位(phase)是对于一个波,特定的时刻在它循环周期中的位置:一种它是否在波峰、波谷或它们之间的某点的标度。相位描述信号波形变化的度量,通常以度 (角度)作为单位,也称作相角。 当信号波形以周期的方式变化,波形循环一周即为360°。那么相位可调也可以简单的理解为:改变初始相位。

    频率,是单位时间内完成周期性变化的次数,是描述周期运动频繁程度的量,常用符号fν表示,单位为秒分之一,符号为s-1。频率可调也就是改变单位时间内完成周期性变化的次数。

    本设计采用DDS技术设计相位频率可调的波形发生器,已经知道了相位和频率可调分别代表什么,那么接下来就要知道怎样依靠DDS技术实现波形发生器,并且相位和频率可以调控。DDS的基本结构如下图所示:

    DDS

    根据上图可以看出:DDS主要由相位累加器、波形数据表(ROM)、D/A转换器构成,本设计暂时不涉及D/A转换部分。相位累加器位宽为N,波形数据表的大小为2^P,累加器的高P位则用于寻址波形数据表,即ROM,从ROM中输出的数据则是产生的波形。如果累加器在系统时钟(CLOCK)的作用下,以步进为M累加直至溢出,则M为频率控制字(即图中的FWORD),相位控制字(PWORD)则作为累加器的输入初始值。这里的累加器,也可以理解为ROM的地址发生器。

    上段所述我们可具体理解为:改变地址的初值(PWORD)就可以改变初始的相位,由于我们设计中,ROM的数据为256,所以PWORD 的值在0~255之间,PWORD= 256*(初始相位/360度)。

    我们设计的系统时钟(CLOCK)为50MHz,周期为20ns,而正弦波被分成了256个点,波形发生器的频率就是195.31KHz。若想要输出别的频率,则可通过改变输出的点的个数,即改变有效地址的数量。我们用位宽为N位的累加器,假设FWORD为1,要产生一个完整波形的周期则为20ns*2^N,则产生波形的频率=系统时钟/2^N,即Fout = Fclk/2^N,如果FWORD为B,每次步进的间隔提高了B倍,所以计满一个波形周期的时间就缩小了B倍,即频率就提高了B倍。则波形频率的公式为:Fout = B*(Fclk/2^N)。之后我们取累加器的高8位,去寻址波形数据,对应点的还是个数一样的。本设计中我们将N取为32,当B=1,Fout约为0.012Hz,0.012就相当于最小精度,所以我们就实现了频率为0.012倍数的调制,但因为0.012值很小了,所以可以说基本实现了所有频率的调制。

设计架构图: 

    根据上述的原理图分析,本设计的架构如下图:

      DDS

    

    架构图中的端口功能描述如下表:

    DDS

    

    dds_addr模块是实现相位累加器的模块,这里用参数来调制FWORD和PWORD的值,累加之后,将地址高八位(addr_out)输出到rom模块,从而产生波形数据。

 

设计代码: 

    在具体写代码之前,我们需要先制作载有波形数据的mif文件,这时需要一个小软件(Mif_Maker2010),软件的链接如下:

    链接:http://pan.baidu.com/s/1gfzcOzL 密码:ietw

    具体操作步骤如下

    打开Mif_Maker2010,在查看中点击全局参数,如下图:

    DDS

    将全局参数设置如下图:数据长度为256,数据位宽为8,数据格式为无符号10进制,采样频率为1000。

    DDS

    点击设定波形,选择想要生成的波形,这里我们以正弦波为例,如需要其他波形,都可进行修改:

    DDS

    

    之后点击保存,则可生成mif文件,这里我们命名为sin.mif。打开sin.mif后,如下图所示:

    DDS

    

    dds_addr模块代码:

    这里我们以初始相位为180度,频率为5KHz为例:

    

0   module dds_addr (clk, rst_n, addr_out);

1 

2       input clk, rst_n;   //系统时钟复位

3       output [7:0] addr_out;  //输出的地址,对应到ROM内的数据

4        

5       parameter N = 32;

6       parameter PWORD = 128;  //相位控制字 (x/360)*256

7       parameter FWORD = 429497; //频率控制字F_out=B*(F_clk/2**32)fword=B

8       //5KHZ

9       reg [N-1:0] addr;  //32位累加器

10      

11      always @ (posedge clk or negedge rst_n)

12      begin

13          if (!rst_n)

14              begin

15                  addr <= 0;  

16              end

17          else

18              begin

19      /*每隔fword的大小,输出一位地址,若频率控制字FWORD等于2,那么地址计数器输出的就依次是024.....*/       

20                  addr <= addr + FWORD;

21              end     

22      end 

23      /*将累加器器的地址的高八位赋值给输出的地址(ROM的地址*/

24      assign addr_out = addr[N-1:N-8] + PWORD;

25

26  endmodule 

    rom模块为调用的IP核,该rom IP核中存储了sin.mif的数据。

    dds顶层模块代码:

    

0   module dds (clk, rst_n, q);

1 

2       input clk, rst_n;   //系统时钟复位

3       output [7:0] q;     //输出波形数据

4       

5       wire [7:0] addr_out;  //8位地址,对应到ROM内的数据

6       

7       /*****相位累加器模块*****/

8       dds_addr dds_addr_inst(

9           .clk(clk), 

10          .rst_n(rst_n),

11          .addr_out(addr_out)

12      );

13      

14      /*****波形数据模块*****/

15      rom rom_inst (

16          .address ( addr_out ),

17          .clock ( clk ),

18          .q ( q )

19      );

20

21  endmodule 

    dds_tb顶层模块的测试模块:

0   `timescale 1ns/1ps

1 

2   module dds_tb;

3 

4       reg clk, rst_n;

5       wire [7:0] q;

6       

7       initial begin

8           clk = 1;

9           rst_n = 0;

10          #200.1

11          rst_n = 1;

12          

13          #50_000_000 $stop;

14      end 

15

16      dds dds_dut(

17          .clk(clk), 

18          .rst_n(rst_n),

19          .q(q)

20      );

21      

22      always #10 clk = ~clk;

23

24  endmodule 

仿真图:

DDS

    根据上图可知,我们的设计正确。并且可以实现相位和频率可调

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分