基于FPGA的DDS

基于FPGA的DDS

好,讲一讲原理
先上经典图
在这里插入图片描述

这个图就基本讲出了DDS的工作原理
DDS主要由相位累加器、相位调制器、波形存储器(FPGA是使用的ROM)、数模(D/A)转换器四大结构组成,后面还可以接一个滤波器,之就属于模电的内容了,这里就不提及了。

首先定义几个专有名词,f_word表示频率字,p_word表示相位字,fout表示输出频率,其位宽为N,fclk表示系统系统工作频率 。同时根据采样定理,K的最大值应小于2N / 2。这样就可以计算出dds大概的输出频率的范围了。

先给出一个频率字的计算公式

f_woard  = 2^N *  fclk / fclk

举个栗子:如果N为32,系统频率为50MHz,如果要输出10KHz的信号,则K就应该是859000,具体关于这个公式的理解可以看这个视频,讲的非常详细
这个视频

相位字就很好理解了,说白了就是对波形数据表中要寻址的地址加一个偏移量,就可以实现移相操作了。

然后ROM表中的数据可以参考野火的教程用MATLAB导出,小梅哥也提供了一个exe,可以直接导出。文末附上链接

上RTL,代码主要是基于野火的教程写的,野火的教程阵地良心

//用的wave_16384x8.m生成的ROM文档
module dds
#(
    parameter   f_word = 32'd8590,       //100Hz
                p_word = 12'd0
)
(   
    input       wire                sys_clk     ,
    input       wire                sys_rst_n   ,
    input       wire    [3:0]       wave_select ,

    output      wire    [7:0]       data_out
);

reg     [31:0]      fre_add;
reg     [11:0]      rom_addr_reg;
reg     [13:0]      rom_addr;

parameter   sine_wave       = 4'b0001,
            square_wave     = 4'b0010,
            triangular_wave = 4'b0100,
            sawtooth_wave   = 4'b1000;
            
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        fre_add <= 32'd0;
    else    
        fre_add <= fre_add + f_word;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            rom_addr_reg <= 12'd0;
            rom_addr     <= 14'd0;
        end
    else    
        case(wave_select)
            sine_wave:
                begin    
                    rom_addr_reg <= fre_add[31:20] + p_word;
                    rom_addr <= rom_addr_reg;
                end               
            square_wave:
                begin
                    rom_addr_reg <= fre_add[31:20] + p_word;
                    rom_addr <= rom_addr_reg + (15'd4096)*1;
                end
            triangular_wave:
                begin
                    rom_addr_reg <= fre_add[31:20] + p_word;
                    rom_addr <= rom_addr_reg + (15'd4096)*2;
                end
            sawtooth_wave:
                begin
                    rom_addr_reg <= fre_add[31:20] + p_word;
                    rom_addr <= rom_addr_reg + (15'd4096)*3;
                end
            default:
                begin      
                    rom_addr_reg <= fre_add[31:20] + p_word;
                    rom_addr <= rom_addr_reg;
                end
        endcase
            
rom_wave rom_wave_inst 
(
    .clka(sys_clk)     ,      // input wire clka
    .addra(rom_addr)   ,      // input wire [13 : 0] addra
    .douta(data_out)             // output wire [7 : 0] douta
);
endmodule

tb仿真如下

`timescale 1ns / 1ns

module tb_dds();

reg                 sys_clk;
reg                 sys_rst_n;
reg     [3:0]       wave_select;
wire    [7:0]       data_out1;
wire    [7:0]       data_out2;

dds
#(
    .f_word(32'd859000),       //10KHz
    .p_word(12'd0)
)
dds_inst0
(   
    .sys_clk     (sys_clk    ),
    .sys_rst_n   (sys_rst_n  ),
    .wave_select (wave_select),

    .data_out    (data_out1  )
);

dds
#(
    .f_word(32'd859000),       //10KHz
    .p_word(12'd2048)
)
dds_inst1
(   
    .sys_clk     (sys_clk    ),
    .sys_rst_n   (sys_rst_n  ),
    .wave_select (wave_select),

    .data_out    (data_out2  )
);

always #10 sys_clk = ~sys_clk;

initial
    begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20;
        sys_rst_n <= 1'b1;
        wave_select <= 4'b0001;
        #400000;
        wave_select <= 4'b0010;     
        #400000;  
        wave_select <= 4'b0100;   
        #400000;  
        wave_select <= 4'b1000;   
        #400000;  
        wave_select <= 4'b0000;   

    end

endmodule

仿真结果如下
在这里插入图片描述

附上链接嗝:
链接:https://pan.baidu.com/s/1J0vQfQZ2SL_c1uI5qCRuvg
提取码:wssb
–来自百度网盘超级会员V111的分享)

小声BB

刚刚入门FPGA,本次项目的博客写的非常简略(主要是懒),具体可以参考上面贴的那个链接还有野火的视频。
如果有问题欢迎来交流鸭,老师让我用黑金的AX7Z035为基础进行练习,但是封校了快递进不来,心痛痛。
以后一定会继续更新关于FPGA相关的文章,以后一定会好好写的>o<

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值