FPGA实现频率、幅度、相位可调的DDS以及DDS Compiler IP核的使用验证

06-01 1358阅读

文章目录

  • 一、DDS介绍
  • 二、DDS原理
    • 2.1 频率计算
    • 2.2 相位改变
    • 2.3 波形切换
    • 三、Matlab生成波形文件
    • 四、FPGA实现DDS
      • 4.1 Verilog代码
      • 4.2 仿真验证
        • 4.2.1 改变频率
        • 4.2.2 切换波形
        • 4.2.3 相位调节
        • 4.2.4 幅度调节
        • 五、Xilinx DDS Compiler的使用
          • 5.1 功能框图
            • 5.1.1 相位累加器
            • 5.1.2 SIN/COS LUT
            • 5.2 端口说明
            • 5.3 工作原理
              • 5.3.1 光栅化
              • 5.3.2 输出频率计算
              • 5.3.3 相位增量Δθ的计算
              • 5.3.4 累加器位宽计算
              • 5.4 配置通道
                • 5.4.1 CONFIG 通道 TDATA 结构
                • 5.4.2 输入相位通道TDATA结构
                • 5.4.3 输出数据通道TDATA结构
                • 5.5 IP配置
                • 5.6 仿真验证IP输出
                • 5.7 仿真验证IP动态改变频率

                  一、DDS介绍

                    DDS(Direct Digital Synthesizer)也叫直接数字式频率合成器,用于生成精确的模拟信号波形。它通过数字方式直接合成信号,而不是通过模拟信号生成技术。DDS通常由相位累加器、波形存储器(如ROM或RAM)、DAC和低通滤波器组成,DDS结构图如下所示:

                  FPGA实现频率、幅度、相位可调的DDS以及DDS Compiler IP核的使用验证

                  FPGA实现频率、幅度、相位可调的DDS以及DDS Compiler IP核的使用验证

                  二、DDS原理

                    如上图所示,DDS输出给DAC的波形来源于ROM表,相位累加器作为ROM表的输入地址,然后读出数据。这个ROM表里面存放的就是完整的波形数据,例如:正弦波、方波、三角波、锯齿波等等。

                  2.1 频率计算

                    假设ROM的深度的位宽为N,所以ROM一共有 2 N 2^N 2N个数据。读取ROM的时钟为 f c l k f_{clk} fclk​,如果一个时钟周期读地址+1,那么读出一个完整的波形需要的时间为:

                  t i m e = 2 N ∗ 1 f c l k time = 2^N * \frac{1}{f_{clk}} time=2N∗fclk​1​

                    那么读出的波形频率 f o u t f_{out} fout​:

                  f o u t = 1 t i m e = f c l k 2 N f_{out} =\frac{1}{time} = \frac{f_{clk}}{2^N } fout​=time1​=2Nfclk​​

                    如果每一个时钟周期读地址+2,那么读出一个完整的波形需要的时间为:

                  t i m e = 2 N ∗ 1 f c l k ∗ 1 2 time = 2^N * \frac{1}{f_{clk}}*\frac{1}{2} time=2N∗fclk​1​∗21​

                    那么读出的波形频率 f o u t f_{out} fout​:

                  f o u t = 1 t i m e = f c l k 2 N ∗ 2 f_{out} =\frac{1}{time} = \frac{f_{clk}}{2^N } * 2 fout​=time1​=2Nfclk​​∗2

                    我们可以看出,只要控制读rom地址的时间,就能得到不同频率的波形,如果一个时钟周期读地址+B,那么我们可以得到 f o u t f_{out} fout​:

                  f o u t = f c l k 2 N ∗ B f_{out} = \frac{f_{clk}}{2^N } * B fout​=2Nfclk​​∗B

                    这个B就是DDS结构图中的频率控制字,那么对上式进行变形可以得到:

                  B = f o u t ∗ 2 N f c l k B= \frac{f_{out} * 2^N}{f_{clk}} B=fclk​fout​∗2N​

                  2.2 相位改变

                    已知我们整个波形的采样点是 2 N 2^N 2N个,我们改变读rom的起始地址,就能改变读出来的波形相位,假设每次相位变换为1°,则相位控制字p_word:

                  p w o r d = 2 N 360 p_{word} = \frac{ 2^N}{360 } pword​=3602N​

                    假设每次相位变换为N°,则相位控制字p_word:

                  p w o r d = N ∗ 2 N 360 p_{word} =N*\frac{ 2^N}{360 } pword​=N∗3602N​

                  2.3 波形切换

                    我们通过波形切换信号来选择波形输出的是正弦波还是三角波还是其他波。

                  三、Matlab生成波形文件

                    从上一章我们可以知道,实现DDS最关键的就是ROM,所以我们需要提前在rom里存放一个完整的波形文件,我们就用Matlabl来生成四个声正弦波、方波、三角波、锯齿波的coe文件。深度都是2048、数据位宽根据DA芯片的位宽来选择,我们这里生成的数据位宽是14位无符号数据。三角波matlab代码如下:

                  % 参数设置
                  bitWidth = 14;   % 位宽
                  depth = 2048;    % 深度
                  maxValue = 2^bitWidth - 1; % 无符号数的最大值
                  % 生成三角波
                  t = linspace(0, 1, depth);
                  triangleWave = round(maxValue * (abs(2 * (t - floor(t + 0.5)))));
                  % 将三角波限制在无符号范围内
                  triangleWave = uint16(triangleWave);
                  % 打开文件以写入
                  fileID = fopen('triangle_wave.coe', 'w');
                  % 写入COE文件头
                  fprintf(fileID, 'memory_initialization_radix=10;\n');
                  fprintf(fileID, 'memory_initialization_vector=\n');
                  % 写入数据
                  for i = 1:depth
                      fprintf(fileID, '%d', triangleWave(i));
                      if i  
                  

                    其它波形也同样生成。

                  四、FPGA实现DDS

                  4.1 Verilog代码

                    本次实验实现从10Hz 到10Mhz的DDS,频率分别为 10hz、50hz、100hz、500hz、

                  1khz、5khz、10khz、50khz、100khz、500khz、1mhz、2mhz、3mhz、4mhz、5mhz、10mhz、

                    我们来算一下各种频率控制字:我们频率控制字的位宽设置为32位(越大精度越高),给dds读取的时钟频率用50M系统倍频到125M,根据上面的频率控制字的公式,我们算出10hz的频率控制字为:

                  B = f o u t ∗ 2 N f c l k = 10 ∗ 2 32 125 ∗ 1 0 6 = 344 B= \frac{f_{out} * 2^N}{f_{clk}}= \frac{10 * 2^{32}}{125*10^{6}}=344 B=fclk​fout​∗2N​=125∗10610∗232​=344

                    以此类推可以算出其它频率的频率控制字,整个dds代码如下:

                  module dds (
                      inputsys_clk ,           //输入125M时钟
                      inputrst     ,           //锁相环lock信号
                      inputwave_change ,       //波形切换信号
                      inputpha_change  ,       //相位改变信号
                      inputfre_change  ,       //频率改变信号
                      inputran_change  ,       //幅度改变信号
                      output  reg     [13:0]                              wave_data   
                  );
                      
                  /***************function**************/
                  /***************parameter*************/
                  /***************port******************/             
                  /***************mechine***************/
                  /***************reg*******************/
                  reg             [31:0]                              fre_word        ;   //32位宽的频率控制字
                  reg             [31:0]                              fre_add         ;   //32位宽的相位累加器
                  reg             [3:0]                               fword_sel       ;   //频率选择
                  reg             [10:0]                              p_word          ;   //11位宽的相位控制字
                  reg             [1:0]                               wave_sel        ;   //波形选择
                  reg             [1:0]                               ran_sel         ;   //幅度选择
                  reg             [13:0]                              r_wave_data     ;   //输出波形数据存储器
                  /***************wire******************/
                  wire            [13:0]                              triangular_wave ;
                  wire            [13:0]                              square_wave     ;
                  wire            [13:0]                              sin_wave        ;
                  wire            [13:0]                              sawtooth_wave   ;
                  wire            [10:0]                              addr            ;   //一共2048个采样点
                  /***************component*************/
                     
                  sawtooth_rom u0_sawtooth_rom (
                    .clka (sys_clk        ),      
                    .addra(addr           ),      
                    .douta(sawtooth_wave  )       
                  );
                  sin_rom u0_sin_rom (
                    .clka (sys_clk    ),      
                    .addra(addr       ),      
                    .douta(sin_wave   )       
                  );
                  square_rom u0_square_rom (
                    .clka (sys_clk        ),      
                    .addra(addr           ),      
                    .douta(square_wave    )       
                  );
                  triangular_rom u0_triangular_rom (
                    .clka (sys_clk            ),      
                    .addra(addr               ),      
                    .douta(triangular_wave    )       
                  );
                  /***************assign****************/
                  assign addr = fre_add[31 : 21] + p_word;
                  /***************always****************/
                  //每当改变频率信号拉高时,切换频率控制字
                  always @(posedge sys_clk) begin
                      if(rst == 1'b0)
                          fword_sel 
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码