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的误差)
配置AD7626
1、设置工作模式
配置EN0和EN1引脚,直接在FPGA的驱动程序里面设置
2、设置接口模式
设置AD7626的DCO+引脚,该引脚接地,选择的是自时钟模式。未接地选择的是回波时钟模式,会从DCO+/DCO-输出与数据同步的时钟。
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