Vivado 下 AD9767 双通道正弦波产生例程
1、实验简介
本实验基于 Xinlinx 黑金
AX7A035 FPGA 开发板,
练习使用 AN9767 模块,实验中使用的模块是采用
ANALOG DEVICES
公司的
AD9767
芯 片,支持独立双通道、14
位、
125MSPS
的数模转换。在教程中介绍了利用该模块与
FPGA
开发板相连输出双通道 14
位的正弦波,然后通过示波器查看把输出的正弦波的波形。
AN9767 模块实物照片如下:
AN9767 双通道 DA 模块的详细参数:
- DA 转换芯片:AD9767;
- 通道数:2 通道;
- DA 转换位数:14bit;
- DA 更新速率:125 MSPS;
- 输出电压范围:-5V~+5V;
- 模块 PCB 层数:4 层,独立的电源层和 GND 层;
- 模块接口:40 针 2.54mm 间距排座,方向向下;
- 工作温度:-40°~85° 模块使用芯片均满足工业级温度范围
- 输出接口:2 路 BNC 模拟输出接口(用 BNC 线可以直接连接到示波器);
2、实验原理
2.1、AN9767 模块原理框图
AN9767 模块的原理设计框图如下:
2.2、AD9767 芯片简介
AD9767
是双端口、高速、双通道、
14
位
CMOS DAC,
芯片集成两个高品质
TxDAC+®
内核、一 个基准电压源和数字接口电路,
采用
48
引脚小型
LQFP
封装。器件提供出色的交流和直流性能,同 时支持最高 125 MSPS
的更新速率。
AD9767
的功能框图如下:
2.3、电流电压转换及放大
AD9767
的两路
DA
输出都为补码形式的电流输出
IoutA
和
IoutB
。当
AD9767
数字输入为满量程时(DAC
的输入的
14
位数据都为高),
IoutA
输出满量程的电流输出
20mA
。
IoutB
输出的电流为 0mA
。具体的电流和
DAC
的数据的关系如下公式所示:
下表为数字输入信号和各级运放输出后的电压对照表:
AD9767
芯片的数字接口可以通过芯片的模式管脚
(MODE)
来配置成双端口模式
(Dual)
或者交叉 (Interleaved)模式。在
AN9767
模块设计中,
AD9767
芯片是工作在双端口模式,双通道的
DA
数字输入接口是独立分开的。双端口模式(Dual)
的数据时序图如下图所示:
给 AD9767 芯片的 DA 数据通过时钟 CLK 和写信号 WRT 的上升沿输入到芯片进行 DA 转换。
3、程序设计
例程中提供了
AN9767
模块的
DA
测试程序,通过
AN9767
模块来实现正弦波信号的输出。正弦波测试程序是通过读取 FPGA
内部的一个
ROM
中存储的正弦波数据,然后把正弦波的数据输出到 AN9767
模块进行数模的转换,从而得到正弦波的模拟信号。正弦波测试程序的示意图如下:
3.1、生成 ROM 初始化文件
程序中我们会用到一个
ROM
用于存储
1024
个
14
位的正弦波数据
,
首先我们需要准备
ROM 的初始化文件(
如果是
ALTERA
开发板的话是
mif
文件,如果是
Xilinx
开发板的话是
coe
文件
)
。以下为生成正弦波 ROM
数据文件的方法: 在软件工具及驱动文件夹下找到工具,其图标如下所示:
1. 双击.exe 打开工具,打开界面如下:
2. 可以根据需要自选波形,本例程中选择正弦波,数据长度 1024,数据位宽 14,其它默认:
3. 点击保存按钮,将生成的数据文件保存到工程目录文件下(注意保存的文件类型):
4. 保存后出现如下对话框表示保存成功,点击确定后关闭工具
将
.coe
文件保存到生成的
Rom IP
核中即可,在字符显示实验教程中已做介绍,这里不再重
复。
3.2、双通道正弦波发生程序
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/04/28 10:24:07
// Design Name:
// Module Name: ad9767_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//双通道14位 DA模块
//正弦波测试程序是通过读取 FPGA 内部的一个 ROM 中存储的正弦波数据,
//然后把正弦波的数据输出到 AN9767 模块进行数模的转换,从而得到正弦波的模拟信号。
//
//Two sine wave outputs: -10V ~ +10V
//
module ad9767_test
(
//differential system clocks
input sys_clk_p, // Differential input clock 200Mhz
input sys_clk_n, // Differential input clock 200Mhz
output da1_clk, //AD9767 CH1 clock
output da1_wrt, //AD9767 CH1 enable
output [13:0] da1_data, //AD9767 CH1 data output
output da2_clk, //AD9767 CH2 clock
output da2_wrt, //AD9767 CH2 enable
output [13:0] da2_data //AD9767 CH2 data output
);
reg [9:0] rom_addr; //Store the ROM address of the DA data
wire [13:0] rom_data; //ROM data of DA
wire clk_125M; //clock for DA data processing
assign da1_clk = clk_125M;
assign da1_wrt = clk_125M;
assign da1_data = rom_data;
assign da2_clk = clk_125M;
assign da2_wrt = clk_125M;
assign da2_data = rom_data;
///*************************************************************************
//generate single end clock //differential system clocks
//**************************************************************************/
//wire sys_clk; //single end clock
//IBUFDS sys_clk_ibufgds
//(
// .O (sys_clk ), //Differential clock converted to single terminal clock
// .I (sys_clk_p ),
// .IB (sys_clk_n )
//);
/*************************************************************************
Generate the clock required for DA
****************************************************************************/
PLL PLL_inst
(
// Clock in ports
// .clk_in1 (sys_clk ),
.clk_in1_p (sys_clk_p ), // input clk_in1_p
.clk_in1_n (sys_clk_n ), // input clk_in1_n
.clk_out1 ( ), // output clk_out1
.clk_out2 (clk_125M ), // output clk_out2
.reset (1'b0 ), // input reset
.locked ( ) // output locked
);
/*************************************************************************
Generate the frequency of DA
****************************************************************************/
always @(negedge clk_125M) begin
rom_addr <= rom_addr + 1'b1; //一个正选波采样点为 1024,输出正选波频率:125/1024=122Khz
// rom_addr <= rom_addr + 4; //一个正选波采样点为 256,输出正选波频率:125/256=488Khz
// rom_addr <= rom_addr + 128; //一个正选波采样点为 8,输出正选波频率:125/1024=15.6Mhz
end
/*************************************************************************
Read sine wave data in ROM
****************************************************************************/
ROM ROM_inst
(
.clka (clk_125M ), // input wire clka
.ena (da2_wrt ), // input wire ena
.addra (rom_addr ), // input wire [9 : 0] addra
.douta (rom_data ) // output wire [13 : 0] douta
);
endmodule
//通过一个 PLL IP 来产生 125M 的 DA 输出时钟,
//然后就是循环读取存放在 ROM 中的 1024 个数据,并输出到通道 1 和通道 2 的 DA 数据线上。
//程序中可以通过地址的加 1,加 4, 或者加 128 来选择输出不同的频率的正弦波。
通过一个 PLL IP 来产生 125M 的 DA 输出时钟,然后就是循环读取存放在 ROM 中的 1024 个数据,并输出到通道 1 和通道 2 的 DA 数据线上。程序中可以通过地址的加 1,加 4, 或者加 128 来选择输出不同的频率的正弦波。
3.3、通过一个 PLL IP 来产生 125M 的 DA 输出时钟
通过一个 PLL IP 来产生 125M 的 DA 输出时钟,详细步骤见:vivado下PLL实验
3.4、FPGA 片内 ROM 读写
FPGA 片内 ROM 读写见:
FPGA
片内
ROM
读写例程
3.5、添加约束文件.XDC
添加约束文件.XDC,详细步骤见:Vivado 下 LED 流水灯实验_OliverH-yishuihan的博客-CSDN博客中的 “4.3、添加 XDC管脚约束文件”
############## clock define#### //differential system clocks#####黑金-FPGA#####
create_clock -period 5.000 [get_ports sys_clk_p]
set_property PACKAGE_PIN R4 [get_ports sys_clk_p]
set_property IOSTANDARD DIFF_SSTL15 [get_ports sys_clk_p]
############### Reset key define##########################
#set_property PACKAGE_PIN F15 [get_ports rst_n]
#set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
############## output DAC 通道 1 数据 define##########################
set_property PACKAGE_PIN G21 [get_ports {da1_data[0]}]
set_property PACKAGE_PIN G22 [get_ports {da1_data[1]}]
set_property PACKAGE_PIN C22 [get_ports {da1_data[2]}]
set_property PACKAGE_PIN B22 [get_ports {da1_data[3]}]
set_property PACKAGE_PIN F19 [get_ports {da1_data[4]}]
set_property PACKAGE_PIN F20 [get_ports {da1_data[5]}]
set_property PACKAGE_PIN D20 [get_ports {da1_data[6]}]
set_property PACKAGE_PIN C20 [get_ports {da1_data[7]}]
set_property PACKAGE_PIN A18 [get_ports {da1_data[8]}]
set_property PACKAGE_PIN A19 [get_ports {da1_data[9]}]
set_property PACKAGE_PIN B20 [get_ports {da1_data[10]}]
set_property PACKAGE_PIN A20 [get_ports {da1_data[11]}]
set_property PACKAGE_PIN F18 [get_ports {da1_data[12]}]
set_property PACKAGE_PIN E18 [get_ports {da1_data[13]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[13]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[12]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da1_data[0]}]
############## DAC 通道 1 数据写时钟 define##########################
set_property IOSTANDARD LVCMOS33 [get_ports da1_clk]
set_property PACKAGE_PIN E19 [get_ports da1_clk]
#set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports da1_clk]
############## DAC 通道 1 数据写信号 define##########################
set_property IOSTANDARD LVCMOS33 [get_ports da1_wrt]
set_property PACKAGE_PIN D19 [get_ports da1_wrt]
#set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports da1_wrt]
############## output DAC 通道 2 数据 define##########################
set_property PACKAGE_PIN C18 [get_ports {da2_data[0]}]
set_property PACKAGE_PIN C19 [get_ports {da2_data[1]}]
set_property PACKAGE_PIN B17 [get_ports {da2_data[2]}]
set_property PACKAGE_PIN B18 [get_ports {da2_data[3]}]
set_property PACKAGE_PIN D17 [get_ports {da2_data[4]}]
set_property PACKAGE_PIN C17 [get_ports {da2_data[5]}]
set_property PACKAGE_PIN A15 [get_ports {da2_data[6]}]
set_property PACKAGE_PIN A16 [get_ports {da2_data[7]}]
set_property PACKAGE_PIN B15 [get_ports {da2_data[8]}]
set_property PACKAGE_PIN B16 [get_ports {da2_data[9]}]
set_property PACKAGE_PIN A13 [get_ports {da2_data[10]}]
set_property PACKAGE_PIN A14 [get_ports {da2_data[11]}]
set_property PACKAGE_PIN E16 [get_ports {da2_data[12]}]
set_property PACKAGE_PIN D16 [get_ports {da2_data[13]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[13]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[12]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da2_data[0]}]
############### DAC 通道 2 数据写时钟 define##########################
set_property PACKAGE_PIN C14 [get_ports da2_clk]
set_property IOSTANDARD LVCMOS33 [get_ports da2_clk]
############## DAC 通道 2 数据写信号 define##########################
set_property PACKAGE_PIN C15 [get_ports da2_wrt]
set_property IOSTANDARD LVCMOS33 [get_ports da2_wrt]
#set_property -dict {PACKAGE_PIN C15 IOSTANDARD LVCMOS33} [get_ports da2_wrt]
#############SPI Configurate Setting##################
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
4、实验现象
(
1
)将
AN9767
模块插入开发板,
AX7A035
接
J11
,
AX7A100/AX7A200
接
J13
,注意
1
脚对齐,
不要插错、插偏,不能带电操作。
(
2
)
用我们提供的 BNC 线
连接
AN9767
的输出到示波器 的输入如下图,然后开发板上电
, 下载程序就可以从示波器上观察从 DA
模块输出的模拟信号的波形了
(3)示波器上看到的正弦波如下:
(4)我们可以把程序中的地址修改成+4 的方式,如下修改,这样一个正弦波的输出的点为 256 个,输出的正弦波的频率会提高 4 倍:
程序修改后,重新下载 FPGA 后,正弦波的频率变高,示波器显示的波形如下: