下冰雹 · 2022年03月06日

【安路 EG4S20 版本】综合性实验设计与实现:实验12 DA及DDS

实验12.1 R-2R DA输出实验

实验设计目标

编写程序,使用FPGA驱动R-2R电路,输出正弦波。

实验设计思路

任意复杂的数字电路都可以使用FPGA实现,但当关联上模拟信号时,就需要AD、DA芯片作为转换器件。AD是把模拟信号转变成数字信号,再送给FPGA做数字算法处理;DA则是将FPGA处理过后的数字信号转变成模拟信号。
本实验由FPGA的8个管脚输出的二进制数值,经过R-2R电路转换后输出相应的模拟值,改变输入的数字值便可得到幅度变化的模拟信号输出。R-2R DAC的实物位置和电路原理图如图2.1所示。

image.png
image.png
图2.1 R-2R DAC电路
输出电压与DAC_D0-DAC_D7的码值关系为:DAC_VOUT = 3.3V * 码值/256
本实验使用FPGA驱动R-2R电路,由按键KEY0控制R-2R DAC的输入码值是来自拨动开关SW0-7,还是来自计数器产生的循环递增信号。

功能模块图与输入输出引脚说明

下面介绍一下顶层模块各引脚的功能:

  • CLK:50MHz的时钟信号输入。
  • DAC_Data:输送到R-2R电路的数字值,共有八位,引脚与LED复用。
  • row:矩阵按键的行信号;这里固定输出4’b1110;
  • col:矩阵按键的列信号;配合行线输出的4’b1110来判断KEY0和KEY1是否按下。其中col[0]/KEY0用来选通DAC输入数据来源,col[1]/KEY1用来实现低电平有效的全局复位。
  • SW_In:拨动开关输入;

程序设计

image.png

  • 21-31:从50MHz分频产生100KHz的时钟
  • 35-43:使用100KHz时钟产生0-255的循环计数
  • 46:使用按键KEY0选择送给DAC的码值是来自拨动开关还是计数器输出

FPGA管脚配置

set_pin_assignment { CLK } { LOCATION = R7; IOSTANDARD = LVCMOS33; }
set_pin_assignment { div_clk } { LOCATION = T4; IOSTANDARD = LVCMOS33; }
set_pin_assignment { col[0] } { LOCATION = E11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { col[1] } { LOCATION = D11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[0] } { LOCATION = B14; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[1] } { LOCATION = B15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[2] } { LOCATION = B16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[3] } { LOCATION = C15; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[4] } { LOCATION = C16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[5] } { LOCATION = E13; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[6] } { LOCATION = E16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { DAC_Data[7]} { LOCATION = F16; IOSTANDARD = LVCMOS33; }
set_pin_assignment { row[0] } { LOCATION = E10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { row[1] } { LOCATION = C10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { row[2] } { LOCATION = F9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { row[3] } { LOCATION = D9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[0] } { LOCATION = A9; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[1] } { LOCATION = A10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[2] } { LOCATION = B10; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[3] } { LOCATION = A11; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[4] } { LOCATION = A12; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[5] } { LOCATION = B12; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[6] } { LOCATION = A13; IOSTANDARD = LVCMOS33; }
set_pin_assignment { SW_In[7] } { LOCATION = A14; IOSTANDARD = LVCMOS33; }

实验结果

当KEY0未按下时,DAC输出为SW_In的数字码值转换为的模拟电压。例如当SW_In=8’b00111111时,示波器采到DAC输出为815mV,与计算得到的3.3V* 63/256 = 812mV是吻合的。其他码值与电压的关系可以自行验证。
image.png
当KEY0按下时,DAC输出dac_cnt的计数值,该计数值从0-255循环,输出的模拟波形如下图所采集,锯齿波的频率为100KHz/256 = 390Hz,峰峰值3.3V。
image.png
图2.6 R-2R DAC输出的锯齿波

实验12.2 DDS正弦信号发生器实验

实验设计目标

编写程序,使用FPGA调用存有正弦波表的ROM驱动R-2R DAC:
使用计数器生成地址线,产生固定频率的正弦波;
使用DDS方式产生地址信号驱动ROM,从而输出频率可调的正弦波。
实验设计思路
本实验中,第一步FPGA以500KHz时钟频率驱动一个计数器,产生0-1023的循环计数,并将其作为地址信号从ROM中顺序读取1024个点送给R-2R DAC,当ROM中存储一个完整的正弦波时,R-2R DAC输出的就是一个频率为500KHz/1024 = 488.28125Hz的正弦波。那么如何改变这个正弦波的频率呢?这就要使用DDS(直接数字合成)技术。
DDS信号源是能直接合成所需波形的一种频率合成器件,由频率合成器(相位累加器、波形查询表)和数模转换器构成。波形合成的基本思想与实验2.1中锯齿波的产生原理相同,只要控制送入数模转换器的数字值以一定规律周期性变化,便能得到所需的波形。
图2.7是DDS器件的核心部分流程图,包含相位累加器和波形查询表。CLK为工作脉冲,KW代表频率控制字。相位累加器内有一个N位寄存器,每来一个时钟脉冲CLK,相位累加器以步长KW递增,将相位累加器的高n位用作ROM的地址输入,即可完成从地址到波形幅值的映射工作。波形查询表ROM中存储了一个完整周期的正弦波,包含了2n个采样点的数据。查询表把送入的地址信息addr映射成所需波形的数字幅度信号,即输出Wave_Data。
image.png
图2.7 核心部分流程图
DDS合成公式为:
image.png
可以看出,当CLK的频率和N的值不变时,只要改变输入的频率控制字KW,即可改变输出波形的频率。

功能模块图与输入输出引脚说明

该工程包含顶层模块DAC_DDS,底层模块Phase_Acc和Sine_ROM。下面介绍一下顶层模块各引脚的功能:

  • CLK:50MHz的时钟信号输入。
  • SW_In:拨动开关输入,其中SW_In[0]是复位输入信号,低有效;SW_In[1]是ROM地址选择信号,为高时是计数器作为ROM地址,为低时是DDS的相位累加器输出的高10位作为ROM地址。
  • DAC_Data:输送到R-2R电路的数字值,共有八位总线。

程序设计

DAC的驱动和计算公式在上一个实验中已经描述,这里主要描述下面两个关键点:
1. 调用ROM IP,存储正弦波表
在上一个实验中,我们是以计数器的输出作为DAC的数据提供给R-2R DAC电路,而在这一个实验里,我们将在FPGA里存一张表,表里是一个完整的正弦波数字信号,接下来用计数器生成正弦波表的地址,就可以将正弦波表里的幅度数值输出给R-2R DAC,这样DAC的输出就是一个正弦信号。
首先我们需要生成一张正弦波表,可以用matlab,excel产生,也可以使用Mif_Maker2010来生成一个1024点8位数据宽度的正弦波表,程序如下:
如图2.15所示,打开Mif_Maker2010,点击设定波形里的全局参数。
image.png
图2.15 打开Mif_Maker2010,选择全局参数
2.设定全局参数如下,点击确定
image.png
3.设定波形中选择正弦波。
image.png
4.点击保存。
image.png
图2.16 保存正弦波表为sine_1024.mif
将产生的sine_1024.mif文件复制到工程文件夹里面,下面我们调用TD的IP核来建立一个 ROM 查找表,步骤如下:

  1. 打开TD中的IP Generator管理器。如图2.17所示。

6.选择“Create a new IP core”,点击OK,将IP命名为sin_rom并存在dds程序文件夹下。如图2.18所示。
image.png
图2.17 选择IP Generator
image.png
图2.18 创建IP名
在弹出来的IP核管理器中选择BRM下面的ROM。如图2.19所示。
image.png
图2.19 选择建立ROM IP
双击ROM后,进入ROM的设定页面。如图2.20所示设定ROM参数。
image.png
图2.20 配置ROM参数并将其初始化为sine_1024.mif的表
这样便生成了正弦ROM表的源文件。 在Top中可以直接调用这个ROM。
image.png
ROM的数据输出送到R-2R DAC的数据端口,ROM的地址ROM_ADDR由SW_In[1]选择是由计数器提供的0-1023循环,还是DDS的相位累加器模块产生的。两种地址的产生程序如下:
image.png

  • 15 -28:分频器从50MHz时钟输入分频得到500KHz的时钟。
  • 31-40: 500KHz时钟循环计数从0-1023,这样得到的正弦信号频率为500KHz/1024 = 488.2815Hz;
  • 42-51:调用相位累加器模块产生地址,步进量KW可以手动修改,计算方法为KW=f* 2^28/500000,这里2^28是指相位累加器的长度为28位,500000是我们的采样率500KHz。因此我们知道了期望频率后,就可以反推KW的值,例如本例中我们期望产生100Hz的正弦信号,通过上面公式计算得到KW=53,687.0912,我们这里取整得KW=53687,因此我们产生的100Hz实际上是99.99983Hz,并不是完美的100Hz,因此如果需要更精确的频率步进,可以使用更长的累加器位数,设计中上常用40位甚至更长。下面给出相位累加器的代码。
    2. 相位累加器模块
    image.png
    11-21: 设定一个28位的相位累加寄存器,然后在每个时钟(本例中是500KHz)的上升沿将其与频率控制字KW累加,一旦超过2^28,就折返回起始位置。
    23:将相位累加寄存器的高10位取出来送给ROM的地址线,实现地址与幅度之间的转换。

    FPGA管脚配置

    set_pin_assignment { CLK } { LOCATION = R7; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { div_clk } { LOCATION = T4; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[0] } { LOCATION = B14; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[1] } { LOCATION = B15; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[2] } { LOCATION = B16; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[3] } { LOCATION = C15; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[4] } { LOCATION = C16; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[5] } { LOCATION = E13; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[6] } { LOCATION = E16; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { DAC_Data[7]} { LOCATION = F16; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { SW_In[0] } { LOCATION = A9; IOSTANDARD = LVCMOS33; }
    set_pin_assignment { SW_In[1] } { LOCATION = A10; IOSTANDARD = LVCMOS33; }
    DAC_DDS输出实验IO Constraint

    实验结果

    SW0拨至“UP”,SW1也拨到“UP”,DAC输出由固定计数器查表产生的488Hz的正弦波,连接到口袋仪器的AIN1观察信号。如下图所示。
    image.png
    图2.6 ROM表使用计数器查表时输出的正弦波
    SW0拨至“UP”,SW1拨到“Down”,DAC输出由DDS模块产生100Hz的正弦波,连接到口袋仪器的AIN1观察信号。如下图所示。
    image.png
    图2.7 ROM表使用DDS查表法时输出的正弦波
    大家可以自行计算其他的正弦信号频率计算出KW值进行验证。当输出频率变高时,可能需要在DAC输出后面加入模拟低通滤波器来平滑波形。
    image.png
    图2.7 DDS查表法输出10KHz时的正弦波(KW=5368709)
    image.png
    图2.7 DDS查表法输出50KHz的正弦波(KW=26843545)

END

文章来源:https://www.yuque.com/yingmuketang/01/owq1vb

推荐内容

更多内容请关注走进FPGA专栏
推荐阅读
关注数
1615
内容数
27
本专栏将以【安路EG4S开发板】为例,从基础板卡信息及使用教程,基础实验设计与实现及综合性实验设计与实现带大家学习FPGA。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息