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实验