**这是本文档旧的修订版!**

学习目标

在这个项目中,我们将通过FPGA串行DAC构成一个简单的任意波形发生器,从而学习信号合成的基本原理以及如何用FPGA内部的SRAM构成存储波表的ROM,通过产生能够访问这些波表的地址指针达到调整输出信号频率的目的。在本项目训练中需要掌握的知识点:

  • 按键输入及防抖处理
  • DDS的基本原理及FPGA实现
  • FPGA内部软核的调用及ROM构成
  • 信号的频谱变化
  • 串行DAC的工作原理及数据/控制接口
  • 信号流程中的时序及各级时钟产生
  • 通过示波器频谱仪观察信号的构成及质量

项目要求

本项目采用Analog Devices公司的8位串行DAC芯片AD5601,小脚丫FPGA模块通过SPI总线与AD5601连接,AD5601输出模拟信号,通过一个RC低通滤波器进行抗混叠滤波,得到最高频率为200KHz以内的信号。具体要求如下:

  • 输入:5个按键,用于控制输出信号的波形以及频率选择
  • 时钟:25MHz晶振,FPGA内如需更高频率的时钟可以通过FPGA内置的PLL电路来实现
  • 输出波形可调:正弦波、三角波、阶梯波、方波、白噪声
  • 频率可调:可以输出频率从5Hz-200KHz的波形,调节精度达到1Hz
  • 输出信号的幅度为0-3.3V

硬件构成

小脚丫FPGA

5个按键

DAC - AD5601:

  • 2.7 V至5.5 V,在本系统中工作电压为3.3V,其DAC转换用参考电压也为3.3V
  • 工作电流小于100µA
  • 8位nanoDAC®,由于本项目只是掌握原理,不追求更高的性能,因此采用了8位的器件,如需更高的性能可以选用管脚兼容的其它器件
  • SPI接口
  • 采用LFCSP和SC70封装

逻辑架构

DDS的构成框图

通过DDS产生的信号频谱

DDS系统中的抗混叠滤波器的使用

核心代码

  • top.v: 系统的顶层文件
  • keyin.v: 按键输入控制,选择波形以及调整频率,需要防抖处理
  • dds.v: 根据频率控制字能够改变的相位累加器
  • rom.v: Lattice Diamond软核构成的波表存储器,可以配置成宽度8位、深度256Byte的ROM,如果要存储多个波形方便切换,可以生成对应于不同波形的ROM文件
  • spidac.v: 通过SPI总线协议将ROM表中的数据串行发送給AD5601

代码实现

<code C> module MAX548A (CLOCK, DACSCLK, DACDIN, DACCS, DACLD, DATABYTEA, DATABYTEB, RESET); input CLOCK; 96MHz system clock input RESET; system reset input [7:0] DATABYTEA,DATABYTEB; Data Byte Register output DACSCLK; 6MHz Serial Clock output DACDIN; Serial Data output output DACCS; Serial Interface Select output DAC_LD; DAC Load output DAC input for 2 channels, datareg is used for buffer 2 address and 2 data reg [31:0] datareg; Create 6MHz clock from system clock reg [3:0] cnt6; wire clk6mhz; always @ (posedge CLOCK or posedge RESET) begin if (RESET) cnt6 ⇐ 0; else cnt6 ⇐ cnt6 + 1; end assign clk6mhz = cnt6[3]; Detect changing of control byte and data byte reg [15:0] compreg; reg datachg; always @ (negedge clk6mhz or posedge RESET) begin if (RESET) {compreg, datachg} ⇐ 0; else begin compreg ⇐ {DATABYTEA, DATABYTEB}; if (compreg != {DATABYTEA, DATABYTEB}) datachg ⇐ 1; else datachg ⇐ 0; end end Shift datareg reg [5:0] cnt32; reg DAC_CS; always @ (posedge clk6mhz or posedge RESET) begin if (RESET) begin DACCS ⇐ 1; cnt32 ⇐ 0; datareg ⇐{32'h0}; end else if (datachg) begin DACCS ⇐0;
cnt32 ⇐ 0; datareg ⇐{8'h0a,DATABYTEA,8'h09,DATABYTEB}; end else if(cnt32 < 31) begin cnt32 ⇐ cnt32 + 1; datareg ⇐ datareg «1; end else DACCS ⇐ 1; end wire clk12mhz; assign clk12mhz = cnt6[2]; assign DACLD = 1'b1; assign DACDIN = data_reg[31]; reg DACSCLK; always @ (negedge clk12mhz or posedge RESET) begin if (RESET) DACSCLK ⇐ 0; else if (!DACCS) DACSCLK ⇐ !DAC_SCLK ; end endmodule /* </code C> ====结果及资源报告==== ====参考资料==== * AD5601产品页面 * AD5601数据手册 * 采用DDS构成PLL * Tektronix公司关于信号发生器的基本原理介绍文档 * Agilent公司关于任意波形发生器产生的原理介绍 * Analog Devices公司关于直接数字合成技术的综述文章