ZYNQ学习笔记——高速ADDA实验

高速AD/DA实验

AD/DA原理

D/A: 就是将_数字量转换成模拟量_
A/D: 就是将_模拟量转换成数字量_,模拟量可以是电压电流等电信号也可以是声、光、压力、湿度等连续变化的非电物理量,但是这些非电物理量最终都要通过一定手段转换成电信号

分类

DAC

网络权电阻DAC(本次实验所用类型)

倒梯形电阻网络DAC

权电流型DAC

权电容型DAC

开关树型DAC

ADC

直接ADC

间接ADC

输入/输出方式

并行

串行

高速AD/DA简介

本章我们使用的 AD-DA 模块是正点原子推出的一款高速模数-数模转换模块(ATK_HS_AD_DA) ,高速 AD 转换芯片和高速 DA 转换芯片都是由 ADI 公司生产的,分别是 AD9280/3PA9280(两款芯片兼容)和 AD9708。

ATK_HS_AD_DA 模块的硬件结构图如下图所示。

AD9708 芯片 AD9708 Data Sheet (waveshare.net)

AD9280 芯片 AD9280 Data Sheet (waveshare.net)

硬件设计

ATK_HS_AD_DA 模块由 DA 转换芯片(AD9708) 和 AD 转换芯片(AD9280) 组成。

AD9708 的原理图如下图所示。

由上图可知, AD9708 输出的一对差分电流信号先经过滤波器,再经过运放电路得到一个单端的模拟电压信号。 图中右侧的 W1 为滑动变阻器, 可以调节输出的电压范围,推荐通过调节滑动变阻器,使输出的电压范围在-5V 至+5V 之间, 从而达到 AD 转换芯片的最大转换范围。

AD9280 的原理图如下图所示

上图中输入的模拟信号 SMA_IN(VI) 经过衰减电路后得到 AD_IN2(VO) 信号,两个模拟电压信号之间的关系是 VO=VI/5+1, 即当 VI=5V 时, VO=2V; VI=-5V 时, VO=0V。

ATK_HS_AD_DA 模块的实物图如下图所示。

本实验中,各端口信号的管脚分配如下表所示。

高速AD-DA转换实验管脚分配
信号名方向管脚端口说明电平标准
sys_clkinputU18系统时钟, 50MhzLVCMOS33
sys_rst_ninputN16系统复位, 低有效LVCMOS33
da_clkoutputR18DA(AD9708)驱动时钟LVCMOS33
da_data[0]outputR17输出给DA的数据LVCMOS33
da_data[1]outputR16输出给DA的数据LVCMOS33
da_data[2]outputW19输出给DA的数据LVCMOS33
da_data[3]outputW18输出给DA的数据LVCMOS33
da_data[4]outputP16输出给DA的数据LVCMOS33
da_data[5]outputP15输出给DA的数据LVCMOS33
da_data[6]outputY19输出给DA的数据LVCMOS33
da_data[7]outputY18输出给DA的数据LVCMOS33
ad_data[0]inputV16AD输入数据LVCMOS33
ad_data[1]inputW16AD输入数据LVCMOS33
ad_data[2]inputT14AD输入数据LVCMOS33
ad_data[3]inputT15AD输入数据LVCMOS33
ad_data[4]inputY17AD输入数据LVCMOS33
ad_data[5]inputY16AD输入数据LVCMOS33
ad_data[6]inputT16AD输入数据LVCMOS33
ad_data[7]inputU17AD输入数据LVCMOS33
ad_otrinputV17模拟电压超出量程标志LVCMOS33
ad_clkoutputV18AD(AD9280)驱动时钟LVCMOS33

程序设计

​ 根据本章的实验任务, ZYNQ 需要连续输出正弦波波形的数据,才能使 AD9708 连续输出正弦波波形的模拟电压,如果通过编写代码使用三角函数公式运算的方式输出正弦波数据, 那么程序设计会变得非常复杂。在工程应用中, 一般将正弦波波形数据存储在 RAM 或者 ROM 中,由于本次实验并不需要写数据到 RAM 中,因此我们将正弦波波形数据存储在只读的 ROM 中,直接读取 ROM 中的数据发送给 DA 转换芯片即可

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

​ 高速 AD/DA 实验的系统框图如图 26.4.1 所示:

顶层模块的原理图如下图所示:

​ 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 转换完成的数据。

顶层模块(hs_ad_da)

module hs_ad_da(
    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  ila_0 (
    .clk         (sys_clk ), // input wire clk
    .probe0      (ad_otr ), // input wire [0:0]  probe0  
    .probe1      (ad_data)  // input wire [7:0]  probe0  
);

endmodule

​ DA 数据发送模块输出的读 ROM 地址(rd_addr) 连接至 ROM 模块的地址输入端, ROM 模块输出的数据(rd_data) 连接至 DA 数据发送模块的数据输入端, 从而完成了从 ROM 中读取数据的功能。
​ 在代码的第 32 至 36 行例化了 ROM 模块,由 Block Memory Generator IP 核配置生成。
​ 代码的第 48 行例化了一个 ILA 的 IP 核,用于捕获 ad_otr 和 ad_data 的数据。需要注意的是, ILA 的采样时钟必须使用 ad_clk(如果最后ILA调试时不显示波形,就将其改为系统时钟),否则数据可能采集错误。 ILA IP 核的配置如下图所示:

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

​ 我们将两个探针的位宽设置成 1 和 8,分别对应 ad_otr 和 ad_data 的位宽,设置完成后点击“OK”按钮即可。
​ 我们在前面说过, ROM 中存储的波形数据可以使用上位机波形转 COE 软件生成, 在这里我们介绍一个简单易用的波形转 COE 工具的使用方法,双击“WaveToMem_V1.2.exe”运行软件。
​ 接下来我们对软件进行设置,如图 26.4.5 所示,这里对软件界面做个简单的介绍。
​ 位宽:波形数据的位宽。由于 ATK_HS_AD_DA 模块的 DA 芯片数据位宽为 8 位,因此这里保持默认,即设置成 8 位。
​ 深度:一个波形周期包含了多少个数据量。这里保持默认,即设置成 256。需要说明的是,在用 Block Memory Generator IP 核生成 ROM 时,配置 ROM 的宽度和深度和上位机设置的位宽和深度保持一致。
​ 波形频率设置:对波形倍频,倍数值越大,最终生成的波形频率越快(频率太高,可能导致波形失真),这里保持默认,即设置成 1 位。
​ 波形类型:软件支持将正弦波、方波、锯齿波和三角波的波形转换成存储波形格式的文件。
​ 生成文件:软件支持将波形转换成 COE(Vivado 软件支持的存储格式)和 MIF(Quartus 软件支持的存储格式)格式文件,这里保持默认,即选中 COE 文件格式。
​ 然后点击“一键生成”按钮,在弹出的界面中选择 COE 文件的存放路径并输入文件名,这里将 COE文件保存在工程的 doc 文件夹下。 WaveToMem 转换过程中的软件界面如下图所示

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

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

AD 数据接收模块

module ad_wave_rec(
    input                 clk         ,  //时钟
    input                 rst_n       ,  //复位信号,低电平有效
    
    input         [7:0]   ad_data     ,  //AD输入数据
    //模拟输入电压超出量程标志(本次试验未用到)
    input                 ad_otr      ,  //0:在量程范围 1:超出量程
    output   wire        ad_clk         //AD(TLC5510)驱动时钟,最大支持20Mhz时钟
    );
wire locked;
//*****************************************************
//**                    main code 
//*****************************************************
//parameter       DIV_END =  8'D3;
//reg         [7:0]   div_cnt;
//reg                 div_clk_o;
四分频12.5Mhz
//always @ (posedge clk or negedge rst_n)
//    if(rst_n == 1'b0)
//        div_cnt <= 'd0;
//    else if(div_cnt == DIV_END)
//        div_cnt <= 'd0;
//    else
//        div_cnt <= div_cnt + 1'b1;
//always @ (posedge clk or negedge rst_n)
//    if(rst_n == 1'b0)
//        div_clk_o <= 1'b0;
//    else if(div_cnt == 'd1)
//        div_clk_o <= 1'b1;
//    else if(div_cnt == 'd3)
//        div_clk_o <= 1'b0;
//assign ad_clk = div_clk_o;
//分频(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    

  clk_wiz_0 u_clk_wiz_0
   (
    // Clock out ports
    .clk_out_25m_45(ad_clk),     // output clk_out_25m_45
    // Status and control signals
    .reset(~rst_n), // input reset
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(clk));  // input clk_in1
// INST_TAG_END ------ End INSTANTIATION Template ---------


endmodule

DA数据发送模块

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

遇到的问题

最后进行下载验证时ila调试时,不显示波形:

解决方案是将ila的采样时钟改成系统时钟

顶层模块中原代码如下:

//ILA采集AD数据
ila_0  ila_0 (
    .clk         (ad_clk ), // input wire clk
    .probe0      (ad_otr ), // input wire [0:0]  probe0  
    .probe1      (ad_data)  // input wire [7:0]  probe0  
);

将其中的采样时钟ad_clk改成sys_clk:

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

修改后虽然显示出来了,但是结果如图,并不是预期的正弦信号:

原因是超过了量程,所以对AD/DA模块的滑动电阻进行调整:

调节过后虽然显示出正弦波的形状但是有太多的毛刺。如图所示:

分析后产生毛刺的原因为:信号在AD/DA之间传递的时候受到了干扰主要是ILA采样时钟和AD采样时钟冲突造成的。

解决方法有:降低AD采样时钟的频率调整相位

方法一:首先试着进行降低AD采样时钟的频率

在ad_wave_rec模块将AD时钟从原来的25MHZ改为12.5MHZ,即将2分频改为4分频

原来代码:

//分频(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 

修改后:

parameter       DIV_END =  8'D3;        
reg         [7:0]   div_cnt;            
reg                 div_clk_o;          
//四分频12.5Mhz                            
always @ (posedge clk or negedge rst_n) 
    if(rst_n == 1'b0)                   
        div_cnt <= 'd0;                 
    else if(div_cnt == DIV_END)         
        div_cnt <= 'd0;                 
    else                                
        div_cnt <= div_cnt + 1'b1;      
always @ (posedge clk or negedge rst_n) 
    if(rst_n == 1'b0)                   
        div_clk_o <= 1'b0;              
    else if(div_cnt == 'd1)             
        div_clk_o <= 1'b1;              
    else if(div_cnt == 'd3)             
        div_clk_o <= 1'b0;              
assign ad_clk = div_clk_o;              

结果如图,并没有得到改善:

方法二:调整相位

添加例化一个PLL,然后用PLL输出一个25M时钟,且相位偏移系统时钟45度,设置如下:

生成了veo文件如下:

  clk_wiz_0 instance_name
   (
    // Clock out ports
    .clk_out_25m_45(clk_out_25m_45),     // output clk_out_25m_45
    // Status and control signals
    .reset(reset), // input reset
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(clk_in1));      // input clk_in1
// INST_TAG_END ------ End INSTANTIATION Template ---------

将其例化到ad_wave_rec模块,并将之前的分频给注释掉,代码如下:

  clk_wiz_0 u_clk_wiz_0
   (
    // Clock out ports
    .clk_out_25m_45(ad_clk),     // output clk_out_25m_45
    // Status and control signals
    .reset(~rst_n), // input reset
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(clk));  // input clk_in1
// INST_TAG_END ------ End INSTANTIATION Template ---------

再重新生成Bit流文件,中途如果出现如下问题,

原因在于PLL生成时钟时在Clocking Options界面没有将系统输入时钟的Sourse改成Global buffer,具体解决方案参考来自:(vivado implementation执行时候报错:Unsupported PLLE2_ADV connectivity…_黑猫学长呀的博客-CSDN博客

成功生成Bit流文件后下载到板子,得到结果正确,如下所示:


  • 8
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: zynq-linux移植学习笔记应包含以下内容: 1. 对zynq架构和硬件资源的理解,包括PS和PL部分的特点。 2. 如何使用Xilinx SDK来编译和配置u-boot和Linux内核。 3. 如何在硬件平台上运行和调试Linux系统。 4. 怎样在Linux系统中配置和使用各种硬件资源,如DMA、Ethernet、Flash等。 5. 如何在Linux系统中移植和运行应用程序,并与硬件资源进行交互。 6. 如何进行系统优化和资源管理,以提高系统性能和稳定性。 ### 回答2: Zynq是一款Xilinx公司开发的一种嵌入式系统芯片,其使用了双核Cortex-A9处理器和可编程逻辑器件(FPGA)的组合。移植Linux到Zynq芯片中,可以使其具备无限的扩展能力,极大地拓展了其应用领域,因此掌握Zynq-Linux移植技术是非常重要的。 Zynq-Linux移植分为四个主要步骤: 第一,准备工作 在移植前,需要确认硬件平台是否支持Linux运行,并且需要对硬件进行配置,最好使用Zynq开发板的官方配置; 第二,内核移植 内核移植是整个移植过程中最关键的一步。需要根据硬件平台的特性对内核进行选择和配置。可以从内核源代码库中获取内核代码,然后进行交叉编译。移植内核的过程中需要注意内核配置参数的设置,同时也要确保内核模块和驱动程序的编写。 第三,文件系统移植 在移植Linux的过程中,文件系统也是非常重要的。可以使用开发板官方Linux镜像,也可以自己编译镜像。移植文件系统还涉及到root文件系统的配置、挂载方式、网络配置和各种服务的配置等问题。 第四,驱动移植 驱动程序是连接硬件和软件的关键部分,需编写相应的驱动程序来实现对硬件的控制。移植驱动程序的过程中需要关注各种硬件接口和设备驱动API的使用,确保驱动程序与硬件配合良好。 总结来说,Zynq-Linux移植技术的掌握需要具备较强的Linux基础知识、驱动开发经验和交叉编译工具链的使用能力。同时,还需要有耐心和细心,对每个步骤进行仔细的分析和处理。 在学习中,需要结合实际开发项目,多进行实践操作才能更好地掌握Zynq-Linux移植技术,为后续项目的开发和应用提供更好的支持。 ### 回答3: Zynq-7000系列是一种由Xilinx开发的SoC(系统级芯片),它将双ARM Cortex-A9处理器和可编程逻辑(FPGA)集成在一起。这使得开发人员可以使用硬件加速加速器来加速运行在Linux上的各种应用。然而,实现这个目标需要进行移植。 在开始Zynq Linux移植学习笔记之前,需要一些基本的知识。首先,需要了解Linux内核的基本工作原理和Linux驱动程序的编写技术。然后,需要了解FPGA和SoC体系结构。 在开始移植之前,需要为SoC开发板选择正确的Linux发行版。这通常需要考虑处理器体系结构,内存大小和设备驱动程序的可用性。另外,还需要考虑是否需要自定义内核或驱动程序以满足应用程序的需求。 接下来,需要编写设备树文件(DT)来描述SoC架构。设备树文件是一种描述硬件配置信息的特殊语言。它会告诉内核有哪些设备可用以及如何访问这些设备。 接下来,需要配置Linux内核以支持Zynq-7000处理器。这可能包括启用适当的内核配置选项,编写设备驱动程序以及配置启动过程。 最后,需要启动Zynq板并验证Linux系统稳定运行。这些步骤包括在启动过程中将设备树文件加载到内存中,以及启动用户空间应用程序。 总之,移植Zynq Linux是一项复杂的任务,需要广泛的专业知识和技术。但是,它可以为开发人员提供强大的硬件加速支持,使他们能够加速处理一系列计算密集型应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值