彻底理解DDS(信号发生器)的fpga实现(verilog设计代码)

DDS(Direct Digital Synthesis)是一种把一系列数字信号通过D/A转换器转换成模拟信号的数字合成技术。

它有查表法和计算法两种基本合成方法。在这里主要记录DDS查表法的fpga实现。

**查表法:**由于ROM查询法结构简单,只需要在ROM中存放不同相位对应的幅度序列,然后通过相位累加器的输出对其寻址,经过数/模转换和低通滤波(LPF)输出便可以得到所需要的模拟信号。

查表法示意图:

设计:

输入:频率控制字f,相位控制字,系统时钟Fclk,复位信号reset

输出:幅度数据dout。

关系:Tout = M * Tclk 即 Fout = Fclk / M 。其中,M为一个波形的离散点数。

简单解释一下:比如我们把一个正弦波形分为16个点,而ROM容量为8,那么我们的点数间隔就要取16 / 8 = 2 ,即频率控制字为 2 。

**细节:**由于在设计时点数间隔不一定为1,即相位累加器的值可能大于ROM容量,所以我们要取它的高位到ROM中取相位对应的幅度点。如:频率控制字=4,则相位累加器的值为:0(00000),4(00100),8(01000),12(010100) ....... 也就是说因为步进4(100),后两位将一直保持不变,高位每次加1(1个4),可以类比十进制理解:每次加10:000,010,020,030...最后一位不变。

代码实现:

复制代码
module DDS_Module(
    clk ,
    reset ,
    f_ctrl ,
    p_ctrl ,
    dout
    );
    input clk ;
    input reset ;
    input [2:0]f_ctrl ;//(取值限制为2的倍数)
    input [9:0]p_ctrl ;
    output [9:0]dout ;
    
    //频率控制字寄存器(频率)(大于1的时候,后面相位累加器输出到实时相位时要砍掉它的位宽)
    reg [2:0]f_regist ;//(取值限制为2的倍数)
    always @ (posedge clk)
        f_regist <= f_ctrl ;
    
    //相位累加器  (f * t)  
    reg [12:0]p_add ;
    always@(posedge clk or negedge reset )
        if(!reset )
            p_add <= 0 ;
        else
            p_add <= p_add + f_regist ;
    
    //相位控制字寄存器(初始相位)(相位偏移量)
    reg [9:0]p_regist ;
    always @ (posedge clk)
        p_regist <= p_ctrl ;
    
    //实时相位
    reg [9:0]p_now ;
    always@(posedge clk or negedge reset )
        if(!reset )
            p_now <= 0 ;
        else
            p_now <= p_add[12:3] + p_regist ; //取相位累加器的前10位,因为f每次+4,后三位是不变的
        
      DDS_ROM   DDS_ROM(
      .clka(clk),
      .addra(p_now),
      .douta(dout)
    );
    
    
endmodule

这里是需要引用ROM的IP核的,上节内容。

复制代码
`timescale 1ns / 1ps
module DDS_tb(
    );
    reg clk ;
    reg reset ;
    reg [2:0]f_ctrl1 ;
    reg [2:0]f_ctrl2 ;
    reg [9:0]p_ctrl1 ;
    reg [9:0]p_ctrl2 ;
    wire [9:0]dout1 ;
    wire [9:0]dout2 ;
    DDS_Module  DDS_Module1(
    .clk(clk) ,
    .reset(reset) ,
    .f_ctrl(f_ctrl1) ,
    .p_ctrl(p_ctrl1) ,
    .dout(dout1)
    );
    
    DDS_Module  DDS_Module2(
    .clk(clk) ,
    .reset(reset) ,
    .f_ctrl(f_ctrl2) ,
    .p_ctrl(p_ctrl2) ,
    .dout(dout2)
    );
    
    initial clk = 1 ;
    always #10 clk = !clk ;
    initial begin 
    reset = 0 ;
    f_ctrl1 = 0 ; 
    p_ctrl1 = 0 ;
    f_ctrl2 = 0 ; 
    p_ctrl2 = 0 ;
    #201 ;
    reset = 1 ;
    #201 ;
    f_ctrl1 = 3'd4;
    p_ctrl1 = 10'd0 ;
    f_ctrl2 = 3'd4;
    p_ctrl2 = 10'd0 ;
    #90000 ;
    #90000 ;
    #90000 ;
    #90000 ;
    f_ctrl1 = 3'd4;
    p_ctrl1 = 10'd0 ;
    f_ctrl2 = 3'd4;
    p_ctrl2 = 10'd256 ;
    #90000 ;
    #90000 ;
    #90000 ;
    f_ctrl1 = 3'd4;
    p_ctrl1 = 10'd0 ;
    f_ctrl2 = 3'd4;
    p_ctrl2 = 10'd512 ;
    #90000 ;
    #90000 ;
    #90000 ;
    $stop;
    end
endmodule

**效果:**分别是相位差 0° ,90 °,180°

相关推荐
fei_sun16 小时前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto17 小时前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安21 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈21 小时前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun1 天前
【Verilog】第二章作业
fpga开发·verilog
碎碎思1 天前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望1 天前
fpga-状态机的设计及应用
fpga开发
晓晓暮雨潇潇1 天前
Xilinx IP核(3)XADC IP核
fpga开发·vivado·xadc·ip核
CWNULT1 天前
AMD(Xilinx) FPGA配置Flash大小选择
fpga开发
碎碎思2 天前
很能体现FPGA硬件思维的一道面试题
fpga开发