AD9361和Zynq及其参考设计说明

万字警告,建议收藏后食用。             

目录

一、AD9361概述

1.1  AD9361芯片结构

1.2  AD9361性能特点

1.3 AD-FMCOMMS2-EBZ性能特点

二、Zynq-7000概述

2.1  Zynq的芯片结构

2.2 ZC702简介和结构

三、AD9361和ZC702之间的数据通路

四、AD9361参考设计说明(PL侧硬件部分)

4.1 IP核的概念

4.2 硬件设计

五、AD9361 参考设计说明(PS侧软件部分)

5.1 AD9361 no-OS Software 概述

5.2 AD9361 no-OS Software 顶层目录说明

5.3 main.c文件

5.4 dac_init函数

5.5 adc_capture函数

 

一、AD9361概述

1.1  AD9361芯片结构

AD9361是一款面向3G和4G基站应用的高性能、高集成度的射频(RF)Agile Transceiver™捷变收发器。芯片采用了零中频架构,将整个射频以及中频信号电路集成在一个芯片中,包括射频放大器、 模拟滤波器、混频器、解调器、 12 位的 ADC 和 DAC 的 RF 2x2(接收和发送通道各两路) 收发器, 另外还集成了收发通道的频率合成器, 同时为每个接收子系统集成了独立的自动增益控制( AGC) 、直流失调校正、正交校正和数字滤波电路,消除了数字基带中提供这些功能的必要性,每个通道搭载两个高动态范围 ADC, 先将收到的I 信号和 Q 信号进行数字化处理,然后将其传给可配置抽取滤波器和抽头有限脉冲响应( FIR) 滤波器,以相应的采样率生成 12 路输出信号。

图 1 AD9361芯片结构

1.2  AD9361性能特点

AD9361 的工作频率为 70 MHz ~ 6 GHz,涵盖了大部分特许执照和免执照频段,支持可调谐 200 kHz ~ 56 MHz 的通道带宽,且具有高度的可编程能力, 发射器采用了直接变频架构,可实现较高的调制精度和较低的噪声,在接收通道,接收噪声系数可以做到小于 2. 5 dB,此外,该芯片的 EVM 可以做到小于-40 dB,可为外部功率放大器的选择留出客观的系统裕量,并且,芯片还支持 AGC 自动增益和更加灵活的手动增益模式,支持外部控制。公众号:OpenFPGA

1.3 AD-FMCOMMS2-EBZ性能特点

AD-FMCOMMS2-EBZ是一款高速模拟模块,设计用于展示AD9361的硬件评估板。AD-FMCOMMS2-EBZ使射频工程师能够将AD9361连接到射频测试平台(矢量信号分析仪、信号发生器等)并测量性能。

图 2为AD-FMCOMMS2-EBZ的外观:

图 2  AD-FMCOMMS2-EBZ外观

通俗来讲,AD9361就是一个集成度很高的信号收发器,用户不需要向普通收发器那样准备放大器,混频器等等部件;它可以通过搭载它的评估板上的FMC接口与各种母板连接,连接后,在母板上用户可以使用ADI公司提供的API编程来配置AD9361的一些参数例如滤波器系数等等,达到灵活控制收发器的目的,而且工作频率宽,设计也很简单。

AD-FMCOMMS2-EBZ就是是搭载AD9361的评估板,用于外围设备(例如天线和FMC接口)与AD9361的连接。

二、Zynq-7000概述

2.1  Zynq的芯片结构

Zynq-7000 AP SOC是Zynq-7000全可编程片上系统的缩写(Zynq-7000 All Programmable System on Chip),它通过将一个双核ARM Cortex-A9处理系统(Processing System,简称PS)和Xilinx 7-Series 28nm 可编程逻辑(Programmable Logic,简称PL)及各种接口等周边设备集成到一个芯片上组成一个片上系统(SOC),来减少系统的复杂性。图 3为一个最简单的Zynq结构模型:

图 3  Zynq简单结构模型

Zynq最为简单的结构模型就只有两部分:PS和PL,PS和PL之间通过AXI接口进行数据通信,这样,使用Zynq SOC既可以单独使用ARM来实现嵌入式系统的设计,又可以使用FPGA来实现各种时序和逻辑的设计,最为关键的是可以同时使用二者来进行更为灵活的系统设计。公众号:OpenFPGA

值得注意的是,Zynq的处理系统(PS)并不是只包含ARM处理器,还包含应用处理单元(Application Processing Unit,APU)和外围接口,缓存区,内存接口和时钟电路;Zynq可以单独使用PS部分,但无法单独使用PL部分,要想使用PL部分必须得启动PS侧,通过PS来配置PL。

      图 4为较为详细的Zynq结构图,上半部分PS侧结构,其中为绿色部分为APU;下半部分为PL侧结构。

图 4  Zynq结构模型

2.2 ZC702简介和结构

Xilinx ZC702是一个评估板,为Zynq SoC提供一个开发和评估的硬件环境。ZC702和一些嵌入式处理系统有共同的特性,包括DDR3内存,三模式以太网,通用I/O和两个URAT接口。另外ZC702还支持FMC。使用ZC702作为平台连接AD-FMCOMMS2-EBZ板子可以生成需要发送的信号、对采集到的信号进行处理等功能。图 5为ZC702的外观结构,图 6为ZC702的简略的框架结构

图 5  ZC702外观结构

图 6  ZC702结构框图

三、AD9361和ZC702之间的数据通路

ADI公司提供了基于ZC702的硬件(PL侧)和软件(PS侧)设计,作为AD9361和Zynq之间的连接和使用的基础。在其提供的硬件设计的基础上,AD9361和ZC702之间的数据通路如所示:

 

图 7  AD9361和ZC702之间数据通路

右边为AD9361部分,左边为ZC702部分;二者通过FMC接口传输数据。在ZC702部分的蓝色区域为zynq的PL部分,命名为AD9361Core;上方为ARM部分,其余为接口部分,为PS和PL及AD9361之间建立数据通道。

ADI公司也提供了代码用于配置AD9361的参数和一些API用于数据的传输和接收;

与DDR进行传输数据的传输方式为DMA传输方式:在DMAC(DMA控制器)的操作下,数据直接由源地址传输到目的地址,(DDR<->AD9361)不需CPU的干预,因此可以极大的提高了CPU的效率。

注意:如果使用PL侧来产生用户数据而是直接通过PS侧来产生数据并发送的话,用户数据应该使用DMA传输方式和DDR。

在PFGA部分中DDS(直接数字式频率合成器)产生的信号数据和从AD9361接收到的信号数据都需要进行IQ调制和解调后,通过DMA方式传输到DDR中存储,这样方便ARM读取数据,并进行处理。

以上的数据通路是通过硬件设计来实现的,若想真正配置和使用AD9361,还需通过运行在ARM上的软件部分。

 

四、AD9361参考设计说明(PL侧硬件部分)

4.1 IP核的概念

       IP(Intellectual Property)内核模块是一种预先设计好的甚至已经过验证的具有某种确定功能的集成电路、器件或部件。它有几种不同形式。IP内核模块有行为 (behavior)、结构(structure)和物理(physical)3级不同程度的设计,对应有主要描述功能行为的“软IP内核(soft IP core)”、完成结构描述的“固IP内核(firm IP core)”和基于物理描述并经过工艺验证的“硬IP内核(hard IP core)”3个层次。这相当于集成电路(器件或部件)的毛坯、半成品和成品的设计技术。

软核是用VHDL等硬件描述语言描述的功能块,但是并不涉及用什么具体电路元件实现这些功能。软IP通常是以硬件描述 语言HDL源文件的形势出现,应用开发过程与普通的HDL设计也十分相似,只是所需的开发硬软件环境比较昂贵。软IP的设计周期短,设计投入少。由于不涉 及物理实现,为后续设计留有很大的发挥空间,增大了IP的灵活性和适应性。其主要缺点是在一定程度上使后续工序无法适应整体设计,从而需要一定程度的软 IP修正,在性能上也不可能获得全面的优化。

因此,在AD9361参考设计中给出的IP核全为软IP内核

4.2 硬件设计

打开Vivado,打开…\hdl-hdl_2014_r2\projects\fmcomms2\zc702路径下的AD9361的Vivado工程文件fmcomms2_zc702.xpr

点击右侧导航栏里的IP Integrator—Open Block Design

打开ADI公司给的AD9361的参考设计IP核框图,每个蓝色方块即为硬件部分的各个IP核,如图 8所示的部分(可放大观看),该部分为AD9361 Core和DMA控制器部分(其余可在Vivado中查看)。

各IP核的源Verilog HDL代码在hdl-hdl_2014_r2\library中,这些设计就是图 7中左半部分的设计

图 8  AD9361参考设计IP核框图(DMA和AD9361部分)

 

五、AD9361 参考设计说明(PS侧软件部分)

5.1 AD9361 no-OS Software 概述

AD9361 no-OS Software是ADI公司提供的AD9361的软件部分,运行在CPU(也就是Zynq的ARM)中,该程序为裸机程序(即无操作系统的程序),可以AD9361各个参数进行配置,对PL中的一些寄存器进行读写,控制发送数据源,控制DMAC(DMA控制器)对发送和接收的数据进行传输,从而实现AD9361的基本功能:对数据的接收、处理和发送。整个程序是使用C语言来完成的。

5.2 AD9361 no-OS Software 顶层目录说明

      在ADI官网可以下载到no-OS-Software的源码,下载到的源码包含了很多ADI的收发器, 表 1列出的是AD9361的no-OS-Software中的文件和文件夹目录结构

目录

子文件

解释说明

console_commands

command.h 、command.c

包含用于控制AD9361的命令行的文件

console.h、console.c

包含用于命令行操作、显示等的与平台串口相关的文件

platform_altera

Altera平台的相关文件(使用Xilinx平台无需该文件)

platform_generic

通用平台的相关文件(使用Xilinx平台无需该文件)

platform_linux

Linux平台相关的文件(使用Xilinx平台无需该文件)

platform_xilinx

adc_core.h、adc_core.c

模数转换模块控制文件,包括模块的初始化和数据传输等

dac_core.h、dac_core.c

模数转换模块控制文件,包括模块的初始化和数据传输等

Platform.c、platform.h

Xilinx平台一些驱动文件

parameters.h

以上文件所用到的参数的宏定义文件

ad9361.c

AD9361的驱动文件,比如增益控制函数等

ad9361.h

ad9361_api.c

AD9361应用编程接口驱动文件,比如AD9361的初始化函数

ad9361_api.h

common.h

通用驱动文件,包含时钟结构体和通用宏定义

config.h

AD9361和 AD9361 API的配置文件

main.c

整个软件部分的main函数文件

util.c

util驱动文件

util.h

表 1AD9361 no-OS-Software源码目录结构


5.3 main.c文件

main.c文件是main函数所在文件,是整个程序的入口。

main.c文件的开头是需要条件编译的头文件和宏定义。

/*****************************************************************************
                              Include Files *****************************************************************************/9
#include"config.h"
#include"ad9361_api.h"
#include"parameters.h"
#include"platform.h"
#ifdef CONSOLE_COMMANDS
#include"command.h"
#include"console.h"
#endif
#ifdef XILINX_PLATFORM
#include<< span="">xil_cache.h>
#endif
#ifdefined XILINX_PLATFORM ||defined LINUX_PLATFORM
#include"adc_core.h"
#include"dac_core.h"
#include"adc_interrupt.h"
#include"SD_card.h"
#endif

因此,在使用时需要根据情况在程序最开始对一些参数进行宏定义,

使用ZC702需要添加语句:

#define XILINX_PLATFORM

       如需使用命令行控制AD9361,需要添加语句:

      #define CONSOLE_COMMANDS

      如需使用ADC的数据捕获功能,需要添加语句:

      #defineCAPTURE_SCRIPT

然后是命令行函数所用到的一些变量的定义、对AD9361初始化所需要参数的变量定义和AD9361接收和发射端滤波器的定义。

AD9361_InitParam default_init_param ={

  /* Identification number */

  0,    //id_no;

  /* Reference Clock */

  40000000UL,//reference_clk_rate

  /* Base Configuration */

  0,    //two_rx_two_tx_mode_enable *** adi,2rx-2tx-mode-enable

  1,    //one_rx_one_tx_mode_use_rx_num *** adi,1rx-1tx-mode-use-rx-num

  1,    //one_rx_one_tx_mode_use_tx_num *** adi,1rx-1tx-mode-use-tx-num

  1,    //frequency_division_duplex_mode_enable *** adi,frequency-division-duplex-mode-enable

  0,    //frequency_division_duplex_independent_mode_enable *** adi,frequency-division-duplex-independent-mode-enable

  0,    //tdd_use_dual_synth_mode_enable *** adi,tdd-use-dual-synth-mode-enable

  0,    //tdd_skip_vco_cal_enable *** adi,tdd-skip-vco-cal-enable

  0,    //tx_fastlock_delay_ns *** adi,tx-fastlock-delay-ns

  0,    //rx_fastlock_delay_ns *** adi,rx-fastlock-delay-ns

  0,    //rx_fastlock_pincontrol_enable *** adi,rx-fastlock-pincontrol-enable

  0,    //tx_fastlock_pincontrol_enable *** adi,tx-fastlock-pincontrol-enable

  0,    //external_rx_lo_enable *** adi,external-rx-lo-enable

  0,    //external_tx_lo_enable *** adi,external-tx-lo-enable

  5,    //dc_offset_tracking_update_event_mask *** adi,dc-offset-tracking-update-event-mask

  6,    //dc_offset_attenuation_high_range *** adi,dc-offset-attenuation-high-range

之后的部分是整个软件部分的主函数,主函数的程序流程图如图 6所示(默认定义了XILINX_PLATFORM常量):

图 9 main函数流程图

DAC模块初始化使用的函数为dac_init函数

ADC数据捕获使用到的函数为adc_capture函数

这两个函数是控制数据传输的主要函数,下面的章节将会详细介绍这两个函数。

5.4 dac_init函数

dac_init为DAC模块初始化函数,也负责DMA传输部分,将DDR中的数据送给AD9361。

dac_init函数的函数声明为:

第一个参数struct ad9361_rf_phy *phy 为指向AD9361的射频设备结构体的指针。

第二个参数uint8_t data_sel为 需要发送的数据源的选择:

enum dds_data_select

{

  DATA_SEL_DDS,

  DATA_SEL_SED,

  DATA_SEL_DMA,

  DATA_SEL_ZERO,  /* OUTPUT 0 */

  DATA_SEL_PN7,

  DATA_SEL_PN15,

  DATA_SEL_PN23,

  DATA_SEL_PN31,

  DATA_SEL_LB,  /* loopback data (ADC) */

  DATA_SEL_PNXX,  /* (Device specific) */

  USER_DATA,

};

0表示发送DDS生成的信号;

2表示通过DMA发送DDR中的信号数据,该数据在dac_core.c开头定义;

3表示发送全0信号;

4-7表示发送随机数信号;

8表示发送从ADC中接收到的数据信号;

9表示发送选定设备的信号;

10为用户数据(需要在函数中添加代码)

第三个参数为DMA设置的标准位,0表示设置;1表示不设置。

DMA传输支持2维传输(即按行列传输),但是目前只需要一维传输,因此,在源代码里向AXI_DMAC_REG_SRC_ADDRESS和AXI_DMAC_REG_Y_LENGTH写入0表示只使用一维传输。

在传输用户数据时,也应该在将用户数据进行调制后,参照以上代码,使用DMA方式发送数据

 

5.5 adc_capture函数

       adc_capture函数为数据捕获函数,也负责DMA传输数据到      DDR

adc_init函数的函数声明为:

第一个参数size为要捕获的数据量(个);

第二个参数为start_adress存储捕获数据的目的地址。

图 9为dac_init函数的流程图:

图 12  adc_captur函数流程图

 

源代码如下:

int32_t adc_capture(uint32_t size, uint32_t start_address)

{

  uint32_t reg_val;

  if(adc_st.rx2tx2)

  {

    length =(size *8);

  }

  else

  {

    length =(size *4);

  }

上图的源码为adc_capture函数的第一部分——数据单位转换部分,adc_capture函数的第一个参数size为用户想要捕获到的数据量,单位是“个”,但是在DMAC的很多寄存器中,比如AXI_DMAC_REG_X_LENGTH寄存器,其中的数值为传输的数据的总字节数,单位为“字节”,因此需要将size单位转换为“字节”。如果打开了双通道,那么捕获的数据数据会占用双倍的存储空间。

adc_dma_write(AXI_DMAC_REG_CTRL, 0x0); //初始化DMA通道

adc_dma_write(AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);//DMA通道使能

adc_dma_write(AXI_DMAC_REG_IRQ_MASK,0x0);//取消屏蔽.

//adc_dma_read(AXI_DMAC_REG_TRANSFER_ID, &transfer_id);//读取下一个传输的ID号(5位)

adc_dma_read(AXI_DMAC_REG_IRQ_PENDING,&reg_val);    /*读取中断状态:一个传输完成后 END_OF_TRANSFER 即 [1]位 置 1,

                                                一个传输加入队列后 START_OF_TRANSFER 即 [0]位 置 1 */

adc_dma_write(AXI_DMAC_REG_IRQ_PENDING, reg_val);//写入中断状态寄存器,使中断寄存器初始化

adc_dma_write(AXI_DMAC_REG_DEST_STRIDE,0x0);//设置目的地址中从一行的开始和下一行之间的字节数

adc_dma_write(AXI_DMAC_REG_X_LENGTH, length -1);//传输的字节数

adc_dma_write(AXI_DMAC_REG_Y_LENGTH,0x0);//传输的行数

adc_dma_write(AXI_DMAC_REG_DEST_ADDRESS, start_address);//设置传输的目的地址(destination address)

adc_dma_write(AXI_DMAC_REG_START_TRANSFER,0x1);//加入传输队列

上图为adc_capture函数的第二部分——DMA配置部分,其中与ADC模块相比不同的寄存器为:

AXI_DMAC_REG_IRQ_MASK:中断屏蔽寄存器,[1]位为EOT(End Of Transfer)IRQ,[0]位为SOT(Start Of Transfer) IRQ,哪一位置1,就表示那一位的中断请求被屏蔽;

AXI_DMAC_REG_IRQ_PENDING:读取中断状态:一个传输完成后 END_OF_TRANSFER 即 [1] 位 置 1,一个传输加入队列后 START_OF_TRANSFER 即 [0] 位 置 1 */

AXI_DMAC_REG_TRANSFER_ID:该寄存器的数值为下一次传输的ID号。

   //Wait until the new transfer is queued.

  do

  {

    adc_dma_read(AXI_DMAC_REG_START_TRANSFER,&reg_val);

  }

  while(reg_val ==1);*/

  // Wait until the current transfer is completed.

do

  {

    adc_dma_read(AXI_DMAC_REG_IRQ_PENDING,&reg_val);

  }

  while(1);//reg_val !=0011b*/

  //Wait until the transfer with the ID transfer_id is completed.

do

  {

    adc_dma_read(AXI_DMAC_REG_TRANSFER_DONE,&reg_val);//读取传输完成的ID号

   }

  while((reg_val &(1<<< span=""> transfer_id))!=(1<<< span=""> transfer_id));

      上图为上图为adc_capture函数的第三部分——判断与等待

1.等待,直到一个新的传输加入传输队列

读取AXI_DMAC_REG_START_TRANSFER寄存器的值,值为1时循环,值为0时跳出循环。

之前已经向AXI_DMAC_REG_START_TRANSFER写入了1,在这时判断AXI_DMAC_REG_START_TRANSFER的值,若是1,表示新的传输仍然在排队,若是0,表示新的传输已经开始。

2.等待,直到目前的传输完成。

读取AXI_DMAC_REG_IRQ_PENDING的值,当传输进行时,AXI_DMAC_REG_IRQ_PENDING的[0]位SOT位始终为1,当传输完成时,[1]为EOT位由0置为1,之后两位都会被清0。因此,当AXI_DMAC_REG_IRQ_PENDING的值为3时,表示传输完成。

3.等待,直到ID为transfer_id的传输完成

这一步是为了验证之前设置的传输已经完成。

作者: 刘恒良   

版权归作者所有
 

  • 23
    点赞
  • 247
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OpenFPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值