LVDS应用之AD7626

一、硬件平台

ZYNQ7020、AD7626


二、软件平台

vivado2018.3


三、硬件介绍

ZYNQ7020
 使用的是黑金的AC7020核心板
 因为AD7626使用的是2.5V的逻辑电平,连接的是ZYNQ PL端的Bank35
 所以需要修改Bank35的电平为2.5V,默认3.3V

AD7626
 串行LVDS接口、16位ADC、10MSPS吞吐率
 上电的第一次转化是无效的
 该芯片拥有两种数据输出模式,本次实验使用的是回波模式
 ①自时钟模式
  只返回18bit的数据,其中高2bit是10,用于同步使用
  格式如下:10_xxxx_xxxx_xxxx_xxxx
在这里插入图片描述

 ②回波时钟模式
  返回16bit的数据,同时返回与数据同步的时钟(0~1ns的误差)
在这里插入图片描述
 时序解读
 ①DCO+/-是输入时钟CLK+/-的副本,与数据D+/-同步。(说人话就是,时钟在内部缓存了一会儿,等有数据了,再与数据同步输出)
 ②CNV数据转换信号,必须持续一段时间高电平后,要返回低电平
 ③一旦开始转换数据之后,在转换的过程中,不认其他的CNV转换信号
 ④转换信号拉高之后,等待tMSB时间后,就可以给时钟信号,获取数据了
 ⑤DCO+/-就是AD7626输出的与数据同步的时钟,在上升沿采集数据,下降沿改变数据
 ⑥经过tCLKL之后,上次转换的数据就是无效的了
 ⑦没有输入时钟到AD7626的时候,CLK+/-、DCO+/-、D+/-都是低电平

配置AD7626
 1、设置工作模式
  配置EN0和EN1引脚,直接在FPGA的驱动程序里面设置
在这里插入图片描述

 2、设置接口模式
  设置AD7626的DCO+引脚,该引脚接地,选择的是自时钟模式。未接地选择的是回波时钟模式,会从DCO+/DCO-输出与数据同步的时钟。


四、FPGA程序

OBUFDS、IBUFDS

编程思路
 因为整个采集的过程是一个周期性的,所以可以找出采集过程的最大周期,将其定义为一个计数器,再在不同的计数值执行不同的功能,即可。由时序图明显可以看出最大的就是tCYC。

module ad7626_drive(
    input                   sys_clk     ,   /* 输入100MHz */
    input                   sys_rst_n   ,

    output                  EN0         ,
    output                  EN1         ,
    output                  CNV_P       ,
    output                  CNV_N       ,
    input                   D_P         ,
    input                   D_N         ,
    input                   DCO_P       ,   //回波模式,采集时钟
    input                   DCO_N       ,
    output                  CLK_P       ,
    output                  CLK_N       ,

    output  reg [15:0]      Data        ,
    output                  Valid                   
    );

/*********************************************************************
                                 AD7626 Config
*********************************************************************/
/*
    EN1 = 0,EN0 = 0:掉电状态。
    EN1 = 0,EN0 = 1:使能内部缓冲器,禁用内部基准源。要求1.2 V外部基准电压连接到REFIN引脚。
    EN1 = 1,EN0 = 0:禁用内部基准源和缓冲器。要求4.096 V外部基准电压连接到REF引脚。
    EN1 = 1,EN0 = 1:使能内部基准源和缓冲器。
*/
assign  EN1 = 1'b1;
assign  EN0 = 1'b0;

//单位ns
parameter   tCYC    =   200;        /* 100~10000 */
parameter   tCNVH   =   20;         /* 10~40 */
parameter   tMSB    =   100;        /* 0~100 */
parameter   tCLKL   =   72;         /* 0~72 */

/*********************************************************************
                                 Variable define
*********************************************************************/
//mmcm
wire    clk_250;
wire    mmcm_lock;

//interface
reg     ad7626_cnv;
wire    ad7626_d;
wire    ad7626_dco;
wire    ad7626_clk;

parameter   tCYC_CNT_MAX    =   tCYC/4 - 1;  
parameter   tCNVH_CNT_MAX   =   tCNVH/4 - 1; 
parameter   tMSB_CNT_MAX    =   tMSB/4 - 1;  
parameter   tCLKL_CNT_MAX   =   tCLKL/4 - 1; 

reg     [13:0]      tCYC_cnt;

reg                 msb_flag;
reg                 clk_flag;   //时钟输出flag

/*********************************************************************
                                 IP Core
*********************************************************************/
MMCM_AD7625 MMCM_AD7625_inst(
        .clk_250    (clk_250    ),
        .resetn     (sys_rst_n  ),
        .locked     (mmcm_lock  ),
        .clk_100    (sys_clk    )
);

/*********************************************************************
                                 AD7626 CNV 
*********************************************************************/
always @(posedge clk_250 or negedge mmcm_lock)
    if(!mmcm_lock)
        tCYC_cnt <= 14'd0;
    else    if(tCYC_cnt == tCYC_CNT_MAX)    //达到转换最大周期
        tCYC_cnt <= 14'd0;
    else
        tCYC_cnt <= tCYC_cnt + 1'b1;

always @(posedge clk_250 or negedge mmcm_lock)
    if(!mmcm_lock)
        ad7626_cnv <= 1'b0;
    else    if(tCYC_cnt == tCNVH_CNT_MAX)
        ad7626_cnv <= 1'b0;
    else    if(tCYC_cnt == tCYC_CNT_MAX)
        ad7626_cnv <= 1'b1;

/*********************************************************************
                                 AD7626 CLK
*********************************************************************/
always @(posedge clk_250 or negedge mmcm_lock)
    if(!mmcm_lock)
        msb_flag <= 1'b0;
    else    if(tCYC_cnt == tCYC_CNT_MAX)
        msb_flag <= 1'b1;
    else    if(tCYC_cnt == tMSB_CNT_MAX)
        msb_flag <= 1'b0;

always @(posedge clk_250 or negedge mmcm_lock)
    if(!mmcm_lock)
        clk_flag <= 1'b0;
    else    if(tCYC_cnt == tCYC_CNT_MAX)
        clk_flag <= 1'b1;
    else    if(tCYC_cnt == tMSB_CNT_MAX + 16)
        clk_flag <= 1'b0;

assign  ad7626_clk = (clk_flag == 1'b1 && msb_flag == 1'b0)? clk_250 : 1'b0;

/*********************************************************************
                                 data
*********************************************************************/
always@(posedge ad7626_dco or negedge mmcm_lock)
    if(!mmcm_lock)
        Data <= 16'd0;
    else
        Data <= {Data[14:0],ad7626_d};

assign Valid = (clk_flag == 1'b0)? 1'b1 : 1'b0;

/*********************************************************************
                                Diff 
*********************************************************************/
OBUFDS #(
   .IOSTANDARD   ("LVDS_25"),   // Specify the output I/O standard
   .SLEW         ("SLOW"   )    // Specify the output slew rate
) OBUFDS_CNV_inst (
   .O    (CNV_P     ),          // Diff_p output (connect directly to top-level port)
   .OB   (CNV_N     ),          // Diff_n output (connect directly to top-level port)
   .I    (ad7626_cnv)           // Buffer input
);

OBUFDS #(
   .IOSTANDARD   ("LVDS_25"),   // Specify the output I/O standard
   .SLEW         ("SLOW"   )    // Specify the output slew rate
) OBUFDS_CLK_inst (
   .O    (CLK_P     ),          // Diff_p output (connect directly to top-level port)
   .OB   (CLK_N     ),          // Diff_n output (connect directly to top-level port)
   .I    (ad7626_clk)           // Buffer input
);

IBUFDS #(
   .DIFF_TERM   ("FALSE"  ),    // Differential Termination
   .IBUF_LOW_PWR("TRUE"   ),    // Low power="TRUE", Highest performance="FALSE" 
   .IOSTANDARD  ("LVDS_25")     // Specify the input I/O standard
) IBUFDS_D_inst (
   .O   (ad7626_d   ),          // Buffer output
   .I   (D_P        ),          // Diff_p buffer input (connect directly to top-level port)
   .IB  (D_N        )           // Diff_n buffer input (connect directly to top-level port)
);

IBUFDS #(
   .DIFF_TERM   ("FALSE"  ),    // Differential Termination
   .IBUF_LOW_PWR("TRUE"   ),    // Low power="TRUE", Highest performance="FALSE" 
   .IOSTANDARD  ("LVDS_25")     // Specify the input I/O standard
) IBUFDS_DCO_inst (
   .O   (ad7626_dco ),          // Buffer output
   .I   (DCO_P      ),          // Diff_p buffer input (connect directly to top-level port)
   .IB  (DCO_N      )           // Diff_n buffer input (connect directly to top-level port)
);


endmodule

五、仿真测试

在这里插入图片描述


  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值