AD9361芯片进行数据接口逻辑代码的编写

描述

FPGA实现AD9361数据接口逻辑

1 引言

  

本文通过以高速AD9361芯片为例进行数据接口逻辑代码的编写,利用SelectIO IP快速高效完成芯片驱动的生成。

2 AD9361

2.1 芯片简介

  AD9361是一款面向3G和4G基站应用的高性能、高集成度的射频(RF)Agile Transceiver捷变收发器。该器件的可编程性和宽带能力使其成为多种收发器应用的理想选择。该器件集RF前端与灵活的混合信号基带部分为一体,集成频率合成器,为处理器提供可配置数字接口,从而简化设计导入。AD9361接收器LO工作频率范围为70 MHz至6.0 GHz,发射器LO工作频率范围为47 MHz至6.0 GHz,涵盖大部分特许执照和免执照频段,支持的通道带宽范围为200 kHz以下至56 MHz,整体结构图如图 1 AD9361整体结构图所示。

芯片图 1 AD9361整体结构图

• 集成12位DAC和ADC的RF 2 × 2收发器
• TX频段:47 MHz至6.0 GHz
• RX频段:70 MHz至6.0 GHz
• 支持TDD和FDD操作
• 可调谐通道带宽:<200 kHz至56 MHz
• 双通道接收器:6路差分或12路单端输入
• 出色的接收器灵敏度,噪声系数为2 dB (800 MHz LO)
• RX增益控制
  o 实时监控和控制信号用于手动增益
  o 独立的自动增益控制
• 双发射器:4路差分输出
• 高线性度宽带发射器
  o TX EVM:≤−40 dB
  o TX噪声:≤−157 dBm/Hz本底噪声
  o TX监控器:动态范围≥66 dB,精度=1 dB
• 集成式小数N分频频率合成器
• 2.4 Hz最大本振(LO)步长
• 多器件同步
• CMOS/LVDS数字接口

 

2.2 参数配置

  用户可以根据自己的需求将数据接口通过SPI配置成LVDS或CMOS接口,也可以还可以选择FDD或TDD工作方式,以及数据速率可以选择SDR或DDR。只需要通过配置软件设置即可,如图 2 AD9361数据接口配置参数所示,详细的配置教程见AD936x Evaluation Software 详细配置。

芯片图 2 AD9361数据接口配置参数

  在进行数据验证时,也可以使用测试模式,对收发数据进行验证以保证系统的正确性。另外,还可以对输入时钟进行延时调节或者通过SelectIO的delay、delayctrl功能对时钟信号进行微调,以满足时序要求。芯片数据时钟与数据之间的时序可靠性也可以通过芯片内部的延时寄存器0x006、0x007进行条件,以此达到要求,具体的SPI配置寄存器时序如图 3 AD9361 寄存器配置接口SPI时序所示。此方面不是本文重点,不做展开,更多内容参考官方data sheet。

芯片图 3 AD9361 寄存器配置接口SPI时序

  本小节使用的数据接口参数:LVDS、FDD、DDR,对应的时序逻辑也是根据该参数进行设计。

2.3 引脚

RX数据时序接口如下:

芯片芯片芯片芯片

TX数据时序接口如下:

芯片芯片芯片芯片

2.4 接口时序

  以下使用的数据接口参数:LVDS、FDD、DDR,根据不同的通道数可以得到不同的数据时序,用户在解析数据时只要按照对应的结构进行拼接即可。

芯片图 4 AD9361接收数据路径 芯片图 5 AD9361发射接口路径

3 参考代码

3.1 SelectIO配置

  根据以上对AD9361的了解,就可以轻松的配置SelectIO IP的GUI界面了。芯片既包括发射模块TX又包括接收模块RX,所以IO类型选择chip to chip。

芯片图 6 SelectIO配置界面1

  根据上述参数配置部分,自然就选择DDR。数据接口包括时钟CLK、Frame对齐信号与差分数据端Data[05:0],要同时对Frame与Data信号进行时序解析,所以端口宽度设置为7.

芯片图 7 SelectIO配置界面2

  由于芯片内部寄存器0x006、0x007可以确保时钟与数据满足时序要求,所以不需要延时模块,以节约FPGA逻辑资源。

芯片芯片

3.2 数据解析

 

//-------------------------------------------------------------------
// 用于将接收时钟与数据进行单端与差分的变换
//-------------------------------------------------------------------
selectio_ip u_selectio_ip (
 // From the system into the device
   .DATA_IN_FROM_PINS_P (ad_rx_data_in_p),  
  //从AD接收端接收到的单端数据与标志
   .DATA_IN_FROM_PINS_N (ad_rx_data_in_n),  
  //从AD接收端接收到的单端数据与标志
   .DATA_IN_TO_DEVICE  (ad_rx_data),  
  //将AD接收端接收到的数据与标志转换为单端数据
    // From the device out to the system
   .DATA_OUT_FROM_DEVICE (ad_tx_data),  
  //将要发送的DA数据与标志转换为单端数据
   .DATA_OUT_TO_PINS_P  (ad_tx_data_out_p),  
  //发送端的单端DA数据与标志
   .DATA_OUT_TO_PINS_N  (ad_tx_data_out_n), 
  //发送端的单端DA数据与标志
   .CLK_TO_PINS_P   (ad_fb_clk_p),    
  //将AD接收端的输入时钟用于发射时钟
   .CLK_TO_PINS_N   (ad_fb_clk_n),    
  //将AD接收端的输入时钟用于发射时钟
   .CLK_IN_P     (ad_data_clk_p),      
  //AD接收端的单端输入时钟
   .CLK_IN_N     (ad_data_clk_n),      
  //AD接收端的单端输入时钟
   .CLK_OUT     (ad9361_data_clk),        
  //将AD接收端的差分输入时钟转变为单端时钟
   .CLK_RESET     (reset),      
  //用于AD输入时钟的复位,高有效
   .IO_RESET     (reset)      
  //用于单端、差分变换的复位,高有效
 );

//-------------------------------------------------------------------
//发送数据的生成
//-------------------------------------------------------------------
 assign ad_tx0_msb_q=ad_tx0_data[23:18];
 assign ad_tx0_lsb_q=ad_tx0_data[17:12];
 assign ad_tx0_msb_i=ad_tx0_data[11:06];
 assign ad_tx0_lsb_i=ad_tx0_data[05:00];
 assign ad_tx1_msb_q=ad_tx1_data[23:18];
 assign ad_tx1_lsb_q=ad_tx1_data[17:12];
 assign ad_tx1_msb_i=ad_tx1_data[11:06];
 assign ad_tx1_lsb_i=ad_tx1_data[05:00];
 
 reg [13:0] ad_tx_data;

//-------------------------------------------------------------------
//选择要发送的I与Q数据
//-------------------------------------------------------------------
 always @(posedge ad9361_data_clk or posedge reset) begin
  if(reset)
   ad_tx_data<=0;
  else if((ad_tx_frame_reg==0)&&(ad_tx_frame==1))
   ad_tx_data<={ad_tx_frame,ad_tx0_msb_q,ad_tx_frame,ad_tx0_msb_i};
  else if((ad_tx_frame_reg==1)&&(ad_tx_frame==1))
   ad_tx_data<={ad_tx_frame,ad_tx0_lsb_q,ad_tx_frame,ad_tx0_lsb_i};
  else if((ad_tx_frame_reg==1)&&(ad_tx_frame==0))
   ad_tx_data<={ad_tx_frame,ad_tx1_msb_q,ad_tx_frame,ad_tx1_msb_i};
  else if((ad_tx_frame_reg==0)&&(ad_tx_frame==0))
   ad_tx_data<={ad_tx_frame,ad_tx1_lsb_q,ad_tx_frame,ad_tx1_lsb_i};  
 end 

//-------------------------------------------------------------------
//选择接收的I与Q数据
//-------------------------------------------------------------------
 always @(posedge ad9361_data_clk or posedge reset) begin
  if(reset) begin
   ad_rx0_msb_i<=0;
   ad_rx0_msb_q<=0;
   ad_rx0_lsb_i<=0;
   ad_rx0_lsb_q<=0;
   ad_rx1_msb_i<=0;
   ad_rx1_msb_q<=0;
   ad_rx1_lsb_i<=0;
   ad_rx1_lsb_q<=0;   
  end
  else if((ad_rx_frame_reg==0)&&(ad_rx_frame==1)) begin
   ad_rx0_msb_i<=ad_rx_data[05:0];
   ad_rx0_msb_q<=ad_rx_data[12:7];
  end
  else if((ad_rx_frame_reg==1)&&(ad_rx_frame==1)) begin
   ad_rx0_lsb_i<=ad_rx_data[05:0];
   ad_rx0_lsb_q<=ad_rx_data[12:7];
  end
  else if((ad_rx_frame_reg==1)&&(ad_rx_frame==0)) begin
   ad_rx1_msb_i<=ad_rx_data[05:0];
   ad_rx1_msb_q<=ad_rx_data[12:7];
  end
  else if((ad_rx_frame_reg==0)&&(ad_rx_frame==0)) begin
   ad_rx1_lsb_i<=ad_rx_data[05:0];
   ad_rx1_lsb_q<=ad_rx_data[12:7];
  end 
 end
 
 wire [23:0]  ad_rx0_fifo_data;
 wire [23:0]  ad_rx1_fifo_data;
 assign ad_rx0_fifo_data={ad_rx0_msb_q,ad_rx0_lsb_q,ad_rx0_msb_i,ad_rx0_lsb_i};
 assign ad_rx1_fifo_data={ad_rx1_msb_q,ad_rx1_lsb_q,ad_rx1_msb_i,ad_rx1_lsb_i};

 

 

 

原文标题:FPGA实现AD9361数据接口逻辑

文章出处:【微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。  

      审核编辑:彭静

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分