ZYNQ从入门到秃头09 DDS IP 数字波形合成(基于ALINX 7020 && AN108)

Posted “逛丢一只鞋”

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZYNQ从入门到秃头09 DDS IP 数字波形合成(基于ALINX 7020 && AN108)相关的知识,希望对你有一定的参考价值。

文章目录


DDS Direct Digital Synthesizer)即直接数字式频率合成器,是一种新型的频率合成技术。 与传统的频率合成器相比, DDS具有相对带宽大,频率转换时间短,稳定性好,分辨率高,可灵活产生多种信号等优点。较容易实现频率、相位及幅度的数控调制

因此,在现代电子系统及设备的频率源设计中,尤其在通信领域,直接数字频率合成器的应用越来越广泛。作为设计人员,我们习惯称它为信号发生器,一般用它产生正弦、锯齿、方波等不同波形或不同频率的信号波形,在电子设计和测试中得到广泛应用。

高速AD/DA 简介

本节实验任务是 使用 ALINX ZYNQ开发板及高速 AD-DA扩展模块AN108模块,实现数模及模数的转换。

高速AD 转换芯片和高速DA 转换芯片都是由ADI 公司生产的,分别是AD9280/3PA9280(两款芯片兼容)和AD9708。

AD9708 芯片输出的是一对差分电流信号,为了防止受到噪声干扰,电路中接入了低通滤波器,然后通过高性能和高带宽的运放电路,实现差分变单端以及幅度调节等功能,使整个电路性能得到了最大限度的提升,最终输出的模拟电压范围是 - 5V ~ +5V。

AD9280 芯片的输入模拟电压转换范围是0V~ 2V,所以电压输入端需要先经过电压衰减电路,使输入的 - 5V ~ +5V 之间的电压衰减到0V~2V 之间,然后经过AD9280 芯片将模拟电压信号转换成数字信号。

数模转换(DA)电路


DAC原理通过权电阻进行举例



对于实际的DA芯片,显然要更加的复杂,但是原理基本一致

如硬件结构图所示,DA 电路由高速DA 芯片、7 阶巴特沃斯低通滤波器、幅度调节电路和信号输出接口组成。

我们使用的高速DA 芯片是AD 公司推出的AD9708。AD9708 是ADI 公司(Analog Devices,Inc.,亚德诺半导体技术有限公司)生产的TxDAC 系列数模转换器,具有高性能、低功耗的特点。AD9708 的数模转换位数为8 位,最大转换速度为125MSPS(每秒采样百万次Million Samples per Second)。内置1.2V 参考电压,差分电流输出。芯片内部结构图如下图所示

AD9708 在时钟(CLOCK)的驱动下工作,内部集成了+1.2V 参考电压(+1.20V REF)、运算放大器、电流源(CURRENT SOURCE ARRAY)和锁存器(LATCHES)。

两个电流输出端IOUTA 和IOUTB 为一对差分电流,当输入数据为0(DB7~ DB0=8’h00)时,IOUTA 的输出电流为0,而IOUTB 的输出电流达到最大,最大值的大小跟参考电压有关;

当输入数据全为高点平(DB7~DB0=8’hff)时,IOUTA 的输出电流达到最大,最大值的大小跟参考电压有关,而IOUTB 的输出电流为0。

AD9708 必须在时钟的驱动下才能把数据写入片内的锁存器中,其触发方式为上升沿触发,AD9708 的时序图如下图所示:

上图中的DBO-DB7 和CLOCK 是AD9708 的8 位输入数据和输入时钟,IOUTA 和IOUTB 为AD9708输出的电流信号。由上图可知,数据在时钟的上升沿锁存,因此我们可以在时钟的下降沿发送数据

需要注意的是,CLOCK 的时钟频率越快,AD9708 的数模转换速度越快,AD9708 的时钟频率最快为125Mhz

IOUTA 和IOUTB 为AD9708 输出的一对差分电流信号,通过外部电路低通滤波器与运放电路输出模拟电压信号,电压范围是-5V 至+5V 之间。

当输入数据等于0 时,AD9708 输出的电压值为5V;

当输入数据等于255(8’hff)时,AD9708 输出的电压值为-5V。

AD9708 芯片差分输出以后,为了防止噪声干扰,电路中接入了7 阶巴特沃斯低通滤波器,带宽为40MHz,频率响应如下图所示

滤波器参数如下图所示

滤波器之后,我们使用了2 片高性能145MHz 带宽的运放AD8056,实现差分变单端,以及幅度调节等功能,使整个电路性能得到了最大限度的提升。

幅度调节,使用的是5K 的电位器U6,最终的输出范围是-5V~5V(10Vpp)

注:由于电路器的精度不是很精确,最终的输出有一定误差,有可能波形幅度不能达到10Vpp,也有可能出现波形削顶等问题,这些都属正常情况。

AD9708 是一款数字信号转模拟信号的器件,内部没有集成DDS(Direct Digital Synthesizer,直接数字式频率合成器)的功能,但是可以通过控制AD9708 的输入数据,使其模拟DDS 的功能

例如,我们使用AD9708 输出一个正弦波模拟电压信号,那么我们只需要将AD9708 的输入数据按照正弦波的波形变化即可,下图为AD9708 的输入数据和输出电压值按照正弦波变化的波形图。

由上图可知,数据在0 至255 之间按照正弦波的波形变化,最终得到的电压也会按照正弦波波形变化,当输入数据重复按照正弦波的波形数据变化时,那么AD9708 就可以持续不断的输出正弦波的模拟电压波形。

需要注意的是,最终得到的AD9708 的输出电压变化范围由其外部电路决定的,当输入数据为0时,AD9708 输出+5V 的电压;当输入数据为255 时,AD9708 输出-5V 的电压。

由此可以看出,只要输入的数据控制的得当,AD9708 可以输出任意波形的模拟电压信号,包括正弦波、方波、锯齿波、三角波等 波形。

模数转换(AD)电路



实际中通常是最高频率的4倍,8倍

AD电路设计如图所示

如硬件结构图中所示,AD 电路由高速AD 芯片、衰减电路和信号输入接口组成。

AD9280是 ADI公司生产 的 一款单芯片、 8位、 32MSPS Million Samples Per Second,每秒采样百万次) 模数转换器,具有高性能 、低 功耗 的 特点。内部结构图如下图所示

AD9280在 时钟( CLK )的 驱动下工作, 用于控制所有内部转换的周期; AD9280内置片内采样保持放大器( SHA),同时采用多级差分流水线架构,保证了 32MSPS的数据转换速率下全温度范围内无失码;AD9280内部集成了可编程的基准源,根据系统需要也可以选择外部高精度基准满足系统的要求。

AD9280输出的数据以二进制格式表示,当输入的模拟电压超出量程时,会拉高 OTR out-of-range信号;当输入的模拟电压在量程范围内时, OTR信号为低电平,因此可以通过 OTR信号来判断输入的模拟电压是否在测量范围内。

AD9280的 时序图 如下 图所示:

模拟信号转换成数字信号并不是当前周期就能转换完成 从采集模拟信号开始到 输出 数据需要经过 3个 时钟周期。

比如上图 中 在 时钟 CLK的上升沿 沿采集的 模拟电压 信号 S1 经过 3个 时钟周期后 (实际上再加上 25ns的时间延时),输出 转换后的数据 DATA1。需要 注意的是, AD9280芯片 的最大转换速度是32MSPS,即 输入的时钟最大频率为 32MHz。

在信号进入AD 芯片之前,我们用一片AD8056 芯片构建了衰减电路,接口的输入范围是-5V~ +5V(10Vpp)。

衰减以后,输入范围满足AD 芯片的输入范围(0~2V)。转换公式如下:

当输入信号Vin=5(V)的时候,输入到AD 的信号Vad=2(V);

当输入信号Vin=-5(V)的时候,输入到AD 的信号Vad=0(V);

AD9280 支持输入的模拟电压范围是0V 至2V,0V 对应输出的数字信号为0,2V 对应输出的数字信号为255。而AD9708 经外部电路后,输出的电压范围是-5V~ +5V,因此在AD9280 的模拟输入端增加电压衰减电路,使-5V~+5V 之间的电压转换成0V 至2V 之间。

那么实际上对我们用户使用来说,得到的是AD9280输出的8bit数据

当AD9280的模拟输入接口连接-5V 电压时,AD 输出的数据为0;

当AD9280 的模拟输入接口连接+5V 电压时,AD输出的数据为255。

当AD9280 模拟输入端接-5V 至+5V 之间变化的正弦波电压信号时,其转换后的数据也是成正弦波波形变化,转换波形如下图所示:

由上图可知,输入的模拟电压范围在-5V 至5V 之间,按照正弦波波形变化,最终得到的数据也是按照正弦波波形变化。

ADDA模块硬件电路

ADDA模块引脚定义


ZYNQ7020接口电路

ADDA程序设计

根据本章的实验任务,FPGA需要连续输出正弦波波形的数据,才能使AD9708连续输出正弦波波形的模拟电压,如果通过编写代码使用三角函数公式运算的方式输出正弦波数据,那么程序设计会变得非常复杂。

在工程应用中,一般将正弦波波形数据存储在RAM或者ROM中,由于本次实验并不需要写数据到RAM中,因此我们将正弦波波形数据存储在只读的ROM中,直接读取ROM中的数据发送给DA转换芯片即可。

根据本章实验任务画出的系统框图。ROM里面事先存储好了正弦波波形的数据,DA数据发送模块从ROM中读取数据,将数据和时钟送到AD9708的输入数据端口和输入时钟端口;AD数据接收模块给AD9280输出驱动时钟信号和使能信号,并采集AD9280输出模数转换完成的数据。


FPGA 通过ROM IP 产生正弦波数据输出到DA 芯片进行DA 转换,产生正选波模拟信号,把模块的AD 和DA 端口连接起来就形成环路。

例化ROM

生成COE

生成文件:软件支持将波形转换成COE Vivado软件支持的存储格式)和 MIF Quartus软件 支持的存储格式)格式文件,这里保持默认,即选中 COE文件格式。

然后点击“一键生成 ”按钮,在弹出的界面中选择 COE文件的存放路径并输入文件名,这里将 COE文件保存在工程的 doc文件夹下。

WaveToMem转换过程中的软件界面如下图所示:

使用Notepad++代码编辑器打开生成 的 COE文件后 如下图所示:

例化ROM

例化 了 ROM模块,由 Block Memory Generator IP核配置生成 。

工程中创建了一个单端口ROM,并命名为 rom_256x8b”,在调用 Block Memory Generator IP核时,“ Basic”选项也配置如下图所示

我们将其接口类型设置为“Native”、 Memory Type设置为“ Single Port ROM”,即单端口 ROM。

我们将PortA的位宽设置为 8,深度设置为 256,以存储上位机生成的 256个数据。此外,将使能引脚的类型设置为“ Always Enabled”,即 ROM一直处于使能的状态。

接下来配置“Other Options”选项页,加载刚才生成的 .coe文件,如下图所示:

最后点击“OK”按钮完成 IP核的配置。

例化ILA

例化了一个 ILA的 IP核,用于捕获 ad_otr和 ad_data的数据。

需要注意的是, ILA的采样时钟必须使用 ad_clk,否则数据可能采集错误。

ILA IP核的配置如下图所示:

我们把探针数量设置为2,并且把采样深度设置为 4096。探针宽度的设置如下图所示:

我们将两个探针的位宽设置成1和 8,分别对应 ad_otr和 ad_data的位宽,设置完成后点击“ OK”按钮即可。

代码

FPGA顶层模块 hs_ad_da 例化 了 以下三个 模块: DA数据 发送模块 da_wave_send)、 ROM波形存储 模块( rom_256x8b)和 AD数据 接收模块 ad_wave_rec 。

DA数据 发送模块 da_wave_send DA数据 发送模块 输出 读 ROM地址, 将 输入的 ROM数据发送至 DA转换 芯片的数据 端口。

ROM波形 存储 模块( rom_256x8b ROM波形 存储 模块 由 Vivado软件自带的 Block Memory Generator IP核 实现, 其存储 的波形数据可以 使用 波形 转 存储文件的上位机来 生成 .coe文件。

AD数据 接收模块 ad_wave_rec AD数据 接收模块 输出 AD转换 芯片的驱动时钟和使能信号,随后 接收 AD转换 完成的数据。

顶层模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/02/25 16:37:25
// Design Name: 
// Module Name: hs_adda
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module hs_adda(

    input sys_clk,                      // 系统时钟
    input sys_rst_n,                    // 系统复位,低电平有效

    // DA 芯片接口
    output da_clk,                      // DA(AD9708)驱动时钟,最大支持125MHz时钟
    output [7 : 0] da_data,             // 输出给DA的数据

    // AD 芯片接口
    input [7 : 0] ad_data,              // AD输入数据

    // 模拟输入电压超出量程标识(本次实验未用到)
    input ad_otr,                       // 0:在量程范围    1:超出量程
    output ad_clk                       // AD(AD9280)驱动时钟,最大支持32MHz时钟
    );

// wire define
wire [7 : 0] rd_addr;                   // ROM读地址
wire [7 : 0] rd_data;                   // ROM读出的数据

// *************************
// ** main code
// *************************

// DA数据发送
da_wave_send u_da_wave_send (
    .clk    (sys_clk),                     
    .rst_n  (sys_rst_n),
    .rd_data(rd_data),
    .rd_addr(rd_addr),
    .da_clk (da_clk),
    .da_data(da_data)
);

// ROM存储波形
rom_256x8b u_rom_256x8b (
    .clka   (sys_clk),      // input wire clka
    .addra  (rd_addr),      // input wire [7 : 0] addra
    .douta  (rd_data)       // output wire [7 : 0] douta
);

// AD数据接收
ad_wave_rec u_ad_wave_rec (
    .clk    (sys_clk),
    .rst_n  (sys_rst_n),
    .ad_data(ad_data),
    .ad_otr (ad_otr),
    .ad_clk (ad_clk)
);

// ILA采集AD数据
ila_0 u_ila_0 (
	.clk(ad_clk),          // input wire clk

	.probe0(probe0),       // input wire [0:0]  probe0  
	.probe1(ad_data)       // input wire [7:0]  probe1
);

endmodule

DA数据 发送模块输出的读 ROM地址 rd_addr 连接 至 ROM模块 的 地址 输入端, ROM模块输出 的数据( rd_data 连接 至 DA数据 发送模块的 数据 输入端, 从 而完成了从 ROM中 读取数据的功能。

在代码的例化 了 ROM模块,由 Block Memory Generator IP核配置生成 。

代码的例化了一个 ILA的 IP核,用于捕获 ad_otr和 ad_data的数据。需要注意的是, ILA的采样时钟必须使用 ad_clk,否则数据可能采集错误。

DA数据发送模块的代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/02/27 16:01:20
// Design Name: 
// Module Name: da_wave_send
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module da_wave_send(
    input clk,                  // 时钟
    input rst_n,                // 复位信号,低电平有效

    input [7 : 0] rd_data,      // ROM读出数据
    output reg [7 : 0] rd_addr, // 读ROM地址

    // DA 芯片接口
    output da_clk,              // DA(AD9708)驱动时钟,最大支持125MHz时钟
    output [7 : 0] da_data      // 输出给DA的数据
    );

// parameter
// 频率调节控制
parameter FREQ_ADJ = 8'd5;      // 频率调节,FREQ_ADJ的值越大,最终输出的频率越低,范围0~255

// reg define
reg [7 : 0] freq_cnt;           // 频率计数器

// *****************************
// ** main code
// *****************************

// 数据rd_data是在clk的上升沿更新的,所以DA芯片在clk的下降沿锁频存数据是最稳定的时刻
// 而DA实际上在da_clk的上升沿锁存数据,所以时钟取反,这样clk的下降沿相当于da_clk的上升沿
assign da_clk = ~clk;
assign da_data = rd_data;       // 将读到的ROM数据幅值给DA数据端口

// 频率调节计数器
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        freq_cnt <= 8'd0;
    else if(freq_cnt == FREQ_ADJ)
        freq_cnt <= 8'd0;
    else
        freq_cnt <= freq_cnt + 8'd1;
end

// 读ROM地址
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        rd_addr <= 8'd0;
    else begin
        if(freq_cnt == FREQ_ADJ) begin
            rd_addr <= rd_addr + 8'd1;
        end
    end
end

endmodule

在代码的定义了一个参数 FREQ_ADJ(频率 调节 ),可以 通过控制 频率调节参数 的大小 来控制最终输出 正弦波的频率 大小, 频率 调节参数的值越小正弦波频率越大 。

频率调节参数调节正弦波频率的方法是通过控制读 ROM的速度实现的, 频率调节参数越小 freq_cnt计数到频率调节参数值的时间越短,读 ROM数据的速度越快,那么正弦波输出频率也就越高;反过来频率调节参数越大 freq_cnt计数到频率调节参数值的时间越长,读 ROM数据 的速度越慢 ,那么正弦波输出频率也就越低 。

由于 freq_cnt计数器 的位宽为 8位 ,计数范围是 0~ 255 所以 频率 调节 参数 FREQ_ADJ支持的调节 范围是 0~255 可通过修改 freq_cnt计数器 的位宽 来 修改 FREQ_ADJ支持的调节 范围 。

WaveToMem软件 设置 ROM深度 为 256 倍频系数为 1,而输入 时钟为 50Mhz,那么一个 完整的正弦波 周期 长度为 256*20ns = 5120ns 当 FREQ_ADJ的 值为 0时 ,即正弦波的最快输出频率为 1s/5120ns(1s = 1000000000ns) ≈ 195.3Khz。

当 我们 把 FREQ_ADJ的 值设置为 5时 一个 完整的正弦波 周期 长度 为5120ns*(5+1) = 30720ns,频率约 为 32.55KHz。 也可以在 WaveToMem软件设置中增加 倍频 系数 或者 增加AD的 驱动时钟来提高正弦波输出频率 。

AD数据接收模块的代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/02/27 17:09:28
// Design Name: 
// Module Name: ad_wave_rec
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ad_wave_rec(
    input clk,                                      // 时钟
    input rst_n,                                    // 复位信号,低电平有效

    input [7 : 0] ad_data,                          // AD输入数据

    // 模拟输入电压超出量程标志(本次实验为用到)
    input ad_otr,                                   // 0:在量程范围 1:超出量程
    output reg ad_clk                               // AD(AD9280)驱动时钟,最大支持32Mhz时钟
    );

// *****************************
// ** main code
// *****************************

// 时钟分频(2分频,时钟频率为25MHz),产生AD时钟
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        ad_clk <= 1'b0;
    else
        ad_clk <= ~ad_clk;
end

endmodule

由于AD转换 芯片 支持 的最大时钟频率为 32Mhz,而 ZYNQ PL的 系统时钟频率为 50Mhz,所以需要先对时钟进行分频 ,将分频后的时钟作为AD转换芯片的驱动时钟 。时钟分频(2分频,时钟频率为25MHz),产生AD时钟。

需要说明的是,AD数据接收 模块 没有对输入的 ad_otr(输入的模拟电压超出量程指示)和 ad_dataAD输入的数据)做任何处理,这两个信号是在 ILA中观察信号的变化的。

IO约束

############## clock and reset define##################
create_clock -period 20.000 [get_ports sys_clk]
set_property iosTANDARD LVCMOS33 [get_ports sys_clk]
set_property PACKAGE_PIN U18 [get_ports sys_clk]

set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
set_property PACKAGE_PIN N15 [get_ports sys_rst_n]

########AN108 ON AX7020 and AX7010  J11##################
set_property PACKAGE_PIN F20 [get_ports da_clk]
set_property PACKAGE_PIN F19 [get_ports da_data[7]]
set_property PACKAGE_PIN G20 [get_ports da_data[6]]
set_property PACKAGE_PIN G19 [get_ports da_data[5]]
set_property PACKAGE_PIN H18 [get_ports da_data[4]]
set_property PACKAGE_PIN J18 [get_ports da_data[3]]
set_property PACKAGE_PIN L20 [get_ports da_data[2]]
set_property PACKAGE_PIN L19 [get_ports da_data[1]]

set_property PACKAGE_PIN M20 [get_ports da_data[0]]
set_property PACKAGE_PIN L17 [get_ports ad_data[0]]
set_property PACKAGE_PIN L16 [get_ports ad_data[1]]
set_property PACKAGE_PIN M18 [get_ports ad_data[2]]
set_property PACKAGE_PIN M17 [get_ports ad_data[3]]
set_property PACKAGE_PIN D20 [get_ports ad_data[4]]
set_property PACKAGE_PIN D19 [get_ports ad_data[5]]
set_property PACKAGE_PIN E19 [get_ports ad_data[6]]
set_property PACKAGE_PIN E18 [get_ports ad_data[7]]
set_property PACKAGE_PIN G18 [get_ports ad_clk]

set_property IOSTANDARD LVCMOS33 [get_ports da_clk]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[7]]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[6]]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[5]]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[4]]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[3]]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[2]]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[1]]
set_property IOSTANDARD LVCMOS33 [get_ports da_data[0]]

set_property IOSTANDARD LVCMOS33 [get_ports ad_data[0]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_data[1]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_data[2]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_data[3]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_data[4]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_data[5]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_data[6]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_data[7]]
set_property IOSTANDARD LVCMOS33 [get_ports ad_clk]

set_property IOSTANDARD LVCMOS33 [get_ports ad_otr]
set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets ad_clk_OBUF]

因为代码主要参考了正点原子,但AD108是黑金的,虽然大体大同小异,但是对于AD_OTR引脚,黑金的AN108没有引出,因此,这里悬空没有配置

RTL


生成testbench


管理员身份打开顶层模块的代码

ctrl+shift+p,输入Testbench,在命令行就会自动输出Testbench代码

//~ `New testbench
`timescale  1ns / 1ps

module tb_dds_ip;

// dds_ip Parameters
parameter PERIOD  = 10;


// dds_ip Inputs
reg   sys_clk                              = 0 ;
reg   sys_rst_n                            = 0 ;
reg   [7 : 0]  ad_data                     = 0 ;
reg   ad_otr                               = 0 ;

// dds_ip Outputs
wire  da_clk                               ;
wire  [7 : 0]  da_data                     ;
wire  ad_clk                               ;


initial
begin
    forever #(PERIOD/2)  sys_clk=~sys_clk;
end

initial
begin
    #(PERIOD*2) sys_rst_n  =  1;
end

dds_ip  u_dds_ip (
    .sys_clk                 ( sys_clk            ),
    .sys_rst_n               ( sys_rst_n          ),
    .ad_data                 ( ad_data    [7 : 0] ),
    .ad_otr 

以上是关于ZYNQ从入门到秃头09 DDS IP 数字波形合成(基于ALINX 7020 && AN108)的主要内容,如果未能解决你的问题,请参考以下文章

ZYNQ从入门到秃头10 DDS增强版实验ADDA测试(基于ALINX 7020 && AN108)

ZYNQ从入门到秃头10 DAC FIFO实验(AXI-stream FIFO IP核配置)

ZYNQ从入门到秃头06 Vivado下的IP核MMC/PLL实验

ZYNQ从入门到秃头06 Vivado下的IP核MMC/PLL实验

ZYNQ从入门到秃头11 DAC FIFO实验(AXI-stream FIFO IP核配置)

ZYNQ从入门到秃头03 Vivado软件的硬件调试