一、前言

  会FPGA硬件描述语言、设计思想和接口协议,掌握些基本的算法是非常重要的,因此开设本专题探讨些基于AD DA数字信号处理系统的一些简单算法,在数字通信 信号分析与检测等领域都会或多或少有应用。我们还是从老生常谈的DDS函数发生器开始,讲解DAC ADC基本使用以及DDS算法原理与设计方式。

二、设计预期

功能:基于ROM的频率可调DDS正弦函数发生器

  DAC ADC型号与设计参数:DAC为AD9708,更新速率125MSPS,精度8bit;ADC为AD9280,采样率32MSPS,精度8bit。由于ADC采样率限制,设计使用32MHZ频率时钟更新与采样数据,并将ROM深度定义为1024.

  验证手段:MATLAB产生正弦函数,经过8bit量化后存储在ROM中,数据经过DAC 电缆 ADC环回到FPGA,ILA抓取ADC接收数据波形,观察对比发送与接收数据是否相近。

三、DDS原理

  这里只介绍DDS的基本思想,关于详细原理,请参考:【图文】DDS原理_百度文库 https://wenku.baidu.com/view/11cfbf85a0116c175f0e4818.html

  实际上,DDS的核心就是将正弦或余弦函数存储在ROM中,利用相位累加特性通过采用不同的步长对ROM寻址的方式产生频率可调正弦波。另外需要注意产生信号的频率范围要满足奈奎斯特采样定理,该定理支持若想无失真恢复原始信号,采样频率必须大于等于信号最高频率成分的2倍。反过来说:产生信号的最高频率小于等于采样率的1/2.采样频率即为FPGA是时钟频率。为防止信号混叠,一般取最高频率成分的1/3.

四、MATLAB产生正弦序列.coe文件及ROM初始化

  MATLAB产生频率为1/2*pi标准正弦序列。验证无误后,在VIVADO中调用Block Memory Generator IP核,配置为单口ROM,使用刚才产生的系数文件初始化ROM地址数据。

五、DAC ADC驱动

  该设计使用的DAC ADC均为为低速并口转换芯片,无需配置,只要FPGA给出时钟信号,并输出/入并行数据即可。根据AD9708 datasheet时序图,其在时钟上升沿采样,故FPGA在输出时钟下降沿更新数据可满足建立与保持时间要求。ADC同样上升沿开始更新数据,接收端在时钟是上升沿采集数据,这样每一时钟周期可以采到上一拍送出的数据。

六、函数发生器及测试工程设计

  1. `timescale 1ns / 1ps
  2.  
  3. module sin_generator#(parameter FCW_W = ,
  4. DAC_W = )
  5. (
  6. input clk,//DAC采样时钟 由PLL产生
  7. input rst_n,
  8.  
  9. input [FCW_W-:] fcw,
  10. output [DAC_W-:] dac_data,
  11. output dac_clk
  12. );
  13.  
  14. reg [ (FCW_W-):] sum ;
  15. wire [:] addra;
  16. //reg [9:0] addra;//地址测试信号
  17. wire ena;
  18. wire [:] douta;
  19.  
  20. //相位累加器
  21. //时钟下降沿产生数据 DAC上升沿采样
  22. always @(negedge clk or negedge rst_n )begin
  23. if(rst_n==) begin
  24. sum <= () ;
  25. end
  26. else begin
  27. sum <= (sum+fcw) ;
  28. end
  29. end
  30.  
  31. assign addra = sum[FCW_W--:];
  32.  
  33. //rom地址测试
  34. /*always @(posedge clk or negedge rst_n )begin
  35. if(rst_n==0) begin
  36. addra <= (0) ;
  37. end
  38. else begin
  39. addra <= (addra+1) ;
  40. end
  41. end*/
  42.  
  43. blk_mem_gen_0 u_bram (
  44. .clka(clk), // input wire clka
  45. .ena(ena), // input wire ena
  46. .addra(addra), // input wire [9 : 0] addra
  47. .douta(douta) // output wire [7 : 0] douta
  48. );
  49. assign ena = 'b1;
  50. //输出信号
  51. assign dac_data = douta;
  52. assign dac_clk = ~clk;
  53.  
  54. endmodule

sin_generator

  函数发生器模块由输入端口fcw数值确定频率控制字。测试工程顶层包括差分时钟转单端时钟原语,用于产生DAC ADC时钟的PLL 函数发生器模块,生成特定频率控制字的VIO IP核,还有接收端ADC数据采样逻辑以及ILA 调试IP核。

  1. `timescale 1ns / 1ps
  2.  
  3. module DDS_Demo_top
  4. #(parameter AD_DA_W = )
  5. (
  6. input sys_clk_p,
  7. input sys_clk_n,
  8. input rst_n,
  9.  
  10. output [AD_DA_W-:] DAC_data,
  11. output DAC_clk,
  12.  
  13. input [AD_DA_W-:] ADC_data,
  14. output ADC_clk
  15. );
  16.  
  17. localparam FCW_W = ;
  18.  
  19. wire sys_clk_ibufg;
  20. wire clk_dac,clk_adc;
  21. reg [ (AD_DA_W-):] data_ad ;
  22.  
  23. wire [FCW_W- : ] probe_out0;
  24. wire [AD_DA_W*-:] probe0;
  25.  
  26. //ADC接口信号
  27. //ADC在时钟上升沿后送出数据,FPGA下一个上升沿采样
  28. assign ADC_clk = clk_adc;
  29.  
  30. always @(posedge clk_adc or negedge rst_n )begin
  31. if(rst_n==) begin
  32. data_ad <= () ;
  33. end
  34. else begin
  35. data_ad <= (ADC_data) ;
  36. end
  37. end
  38.  
  39. /***************************************子模块例化***************************************/
  40. IBUFGDS #
  41. (
  42. .DIFF_TERM ("FALSE"),
  43. .IBUF_LOW_PWR ("FALSE")
  44. )
  45. u_ibufg_sys_clk
  46. (
  47. .I (sys_clk_p),
  48. .IB (sys_clk_n),
  49. .O (sys_clk_ibufg)
  50. );
  51.  
  52. clk_wiz_0 u_pll
  53. (
  54. // Clock out ports
  55. .clk_out1(clk_dac), // output clk_out1
  56. .clk_out2(clk_adc), // output clk_out2
  57. // Status and control signals
  58. .resetn(rst_n), // input resetn
  59. .locked(), // output locked
  60. // Clock in ports
  61. .clk_in1(sys_clk_ibufg)); // input clk_in1
  62.  
  63. sin_generator#(.FCW_W(FCW_W),
  64. .DAC_W(AD_DA_W))
  65. u_sin_gen
  66. (
  67. .clk (clk_dac) ,//DAC采样时钟 由PLL产生
  68. .rst_n (rst_n) ,
  69. .fcw (probe_out0) ,
  70. .dac_data (DAC_data) ,
  71. .dac_clk (DAC_clk) //由clk_dac产生
  72. );
  73.  
  74. //debug cores
  75. vio_0 u_vio (
  76. .clk(clk_dac), // input wire clk
  77. .probe_out0(probe_out0) // output wire [15 : 0] probe_out0
  78. );
  79.  
  80. ila_0 u_ila (
  81. .clk(clk_adc), // input wire clk
  82. .probe0(probe0) // input wire [15:0] probe0
  83. );
  84.  
  85. assign probe0[:] = DAC_data;
  86. assign probe0[:] = ADC_data;
  87.  
  88. endmodule

DDS_Demo

  最后添加引脚约束文件:

  1. #################################clock && reset###############################################
  2. create_clock -period [get_ports sys_clk_p]
  3. set_property PACKAGE_PIN R4 [get_ports {sys_clk_p}]
  4. set_property IOSTANDARD DIFF_SSTL15 [get_ports {sys_clk_p}]
  5.  
  6. set_property PACKAGE_PIN T6 [get_ports rst_n]
  7. set_property IOSTANDARD LVCMOS15 [get_ports rst_n]
  8.  
  9. #####################DAC PIN connect J4 expansion interface##########################
  10. set_property PACKAGE_PIN H14 [get_ports {DAC_clk}]
  11. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_clk}]
  12.  
  13. set_property PACKAGE_PIN J14 [get_ports {DAC_data[]}]
  14. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  15. set_property PACKAGE_PIN H15 [get_ports {DAC_data[]}]
  16. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  17. set_property PACKAGE_PIN J15 [get_ports {DAC_data[]}]
  18. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  19. set_property PACKAGE_PIN G13 [get_ports {DAC_data[]}]
  20. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  21. set_property PACKAGE_PIN H13 [get_ports {DAC_data[]}]
  22. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  23. set_property PACKAGE_PIN J21 [get_ports {DAC_data[]}]
  24. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  25. set_property PACKAGE_PIN J20 [get_ports {DAC_data[]}]
  26. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  27. set_property PACKAGE_PIN G16 [get_ports {DAC_data[]}]
  28. set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[]}]
  29.  
  30. #####################ADC PIN connect J4 expansion interface##########################
  31.  
  32. set_property PACKAGE_PIN D22 [get_ports {ADC_clk}]
  33. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_clk}]
  34.  
  35. set_property PACKAGE_PIN G21 [get_ports {ADC_data[]}]
  36. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]
  37. set_property PACKAGE_PIN G22 [get_ports {ADC_data[]}]
  38. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]
  39. set_property PACKAGE_PIN H20 [get_ports {ADC_data[]}]
  40. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]
  41. set_property PACKAGE_PIN G20 [get_ports {ADC_data[]}]
  42. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]
  43. set_property PACKAGE_PIN J22 [get_ports {ADC_data[]}]
  44. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]
  45. set_property PACKAGE_PIN H22 [get_ports {ADC_data[]}]
  46. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]
  47. set_property PACKAGE_PIN K21 [get_ports {ADC_data[]}]
  48. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]
  49. set_property PACKAGE_PIN K22 [get_ports {ADC_data[]}]
  50. set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[]}]

clk_pin

七、实验结果分析

  依据之前的参数和DDS信号频率公式,所生成正弦函数频率最好在32/2^16~32/3MHZ之内,使用VIO改变频率控制字数值,观察ILA抓取的发送与接收数据模拟形式波形。任意给出三组频率范围内波形,频率依次由低到高。

  总体来讲还是比较简单。搭建好DAC ADC环路,后面可以验证些滤波 同步算法,或者做些数字频率计、示波器之类的实用设计。

数字信号处理专题(1)——DDS函数发生器环路Demo的更多相关文章

  1. 数字信号处理专题(3)——FFT运算初探

    一.前言 FFT运算是目前最常用的信号频谱分析算法.在本科学习数字信号处理这门课时一直在想:学这些东西有啥用?公式推来推去的,有实用价值么?到了研究生后期才知道,广义上的数字信号处理无处不在:手机等各 ...

  2. 数字信号处理专题(2)——利用FPGA进行基本运算及特殊函数定点运算

    一.前言 FPGA以擅长高速并行数据处理而闻名,从有线/无线通信到图像处理中各种DSP算法,再到现今火爆的AI应用,都离不开卷积.滤波.变换等基本的数学运算.但由于FPGA的硬件结构和开发特性使得其对 ...

  3. FPGA与数字信号处理

    过去十几年,通信与多媒体技术的快速发展极大地扩展了数字信号处理(DSP)的应用范围.眼下正在发生的是,以更高的速度和更低的成本实现越来越复杂的算法,这是针对高级信息服更高带宽以及增强的多媒体处理能力等 ...

  4. 数字信号处理--FFT与蝶形算法

    在数字信号处理中常常需要用到离散傅立叶变换(DFT),以获取信号的频域特征.尽管传统的DFT算法能够获取信号频域特征,但是算法计算量大,耗时长,不利于计算机实时对信号进行处理.因此至DFT被发现以来, ...

  5. 数字信号处理与音频处理(使用Audition)

    前一阵子由于考博学习须要,看了<数字信号处理>,之前一直不清除这门课的理论在哪里应用比較广泛. 这次正巧用Audition处理了一段音频,猛然发现<数字信号处理>这门课还是很实 ...

  6. 数字信号处理MATLAB简单序列

    数字信号处理应用的几个基本序列: 1 单位样本序列 function mainImseq() clc clear disp('生成抽样序列'); y=imseq(,,); %调用样本函数,此时序列下标 ...

  7. 现代数字信号处理——AR模型

    1. AR模型概念观       AR模型是一种线性预测,即已知N个数据,可由模型推出第N点前面或后面的数据(设推出P点),所以其本质类似于插值,其目的都是为了增加有效数据,只是AR模型是由N点递推, ...

  8. 如何使用Matlab做数字信号处理的仿真1

    例如 第三版数字信号处理P51 -1.14习题时域离散信号的相关性研究x(n)=Asin(ωn)+u(n),其中ω=π/16,u(n)是白噪声,现要求 ⑴.产生均值为0,功率P=0.1的均匀分布白噪声 ...

  9. FS,FT,DFS,DTFT,DFT,FFT的联系和区别 数字信号处理

    DCT变换的原理及算法 文库介绍 对于初学数字信号处理(DSP)的人来说,这几种变换是最为头疼的,它们是数字信号处理的理论基础,贯穿整个信号的处理. 学习过<高等数学>和<信号与系统 ...

随机推荐

  1. 一文掌握 Linux 性能分析之网络篇(续)

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 这是 Linu ...

  2. java中 try catch finally和return联合使用时,代码执行顺序的小细节

    代码1测试 public static void main(String[] args) { aa(); } static int aa() { try { int a=4/0; } catch (E ...

  3. 【Spark篇】---Spark中Shuffle机制,SparkShuffle和SortShuffle

    一.前述 Spark中Shuffle的机制可以分为HashShuffle,SortShuffle. SparkShuffle概念 reduceByKey会将上一个RDD中的每一个key对应的所有val ...

  4. Python内置函数(30)——hex

    英文文档: hex(x) Convert an integer number to a lowercase hexadecimal string prefixed with “0x”, for exa ...

  5. Zara带你快速入门WPF(1)---开篇

    一.引言 我们时常可以看到园友们在讨论WPF与WinForm!它们两个的激情对决,看到大家热情洋溢的评论,搞技术的我也是深受感动. 二.走势 但抱歉的是,我无法预测未来WPF会怎么样.乔布斯说过这么一 ...

  6. 『Kruscal重构树 Exkruscal』

    新增一道例题及讲解 Exkruscal \(Exkruscal\)又称\(Kruscal\)重构树,是一种利用经典算法\(Kruscal\)来实现的构造算法,可以将一张无向图重构为一棵具有\(2n-1 ...

  7. 带着新人学springboot的应用06(springboot+RabbitMQ 中)

    上一节说了这么多废话,看也看烦了,现在我们就来用鼠标点点点,来简单玩一下这个RabbitMQ. 注意:这一节还是不用敲什么代码,因为上一节我们设置了那个可视化工具,我们先用用可视化工具熟悉一下流程. ...

  8. JS执行环境,作用域链及非块状作用域

    JS中的执行环境,顾名思义就是变量或函数所执行时的环境.在我的理解中,执行环境和作用域相差不大. 每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中.而在函数执行之后 ...

  9. synchronized学习

    现代软件开发中并发已经成为一项基础能力,而Java精心设计的高效并发机制,正是构建大规模应用的基础之一.本文中我们将学习synchronized关键字的基本用法. synchronized是Java内 ...

  10. springboot+mybatis+dubbo+aop日志终结篇

    之前的几篇文章把dubbo服务层都介绍完毕,本篇文章咱们主要写web层如何调用服务层的方法.文章底部附带源码. 启动服务 服务启动时,会向zk注册自己提供的服务,zk则会记录服务提供者的IP地址以及暴 ...