AD7961介绍及FPGA驱动

AD7961介绍

AD7961是一款16位模数转换芯片,最高采样率可达5MSPS,串行LVDS接口,真差分输入。

所谓真差分输入,指电压输入端口 I N + IN+ IN+ I N − IN- IN 均可参与信号传输,其中 I N + IN+ IN+ 与信号相同, I N − IN- IN 反相,注意,反相不是指电压为负,实际上 I N + IN+ IN+ I N − IN- IN 的电压范围均在 0 ∼ 5 V 0\sim 5V 05V ,ADC采样值为 I N + IN+ IN+ I N − IN- IN 的差值。真差分输入可以有效抑制共模噪声。

与之相对应的伪差分输入, I N − IN- IN 仅作为直流参考端,并不参与信号传输。

LVDS(Low-Voltage Differential Signaling),低电压差分信号,是一种差分数字信号传输技术,最高传输速率可达几百Mbps,由于采用差分信号,其具有低噪声的特点。

在这里插入图片描述

如上图所示,IN±即模拟电压信号的差分输入端,CNV±、D±、DCO±、CLK±为四个LVDS差分信号对,用于控制ADC的数据采集。EN0~EN3用于配置ADC的工作模式。

CNV±为转换控制信号,ADC在CNV±的上升沿转换IN±的电压差;D±为数据端口;CLK±为时钟输入;DCO±为时钟输出,在回声时钟模式下输出回声时钟用于数据同步。

AD7961有两种采样工作模式:自时钟模式(Self Clocked Mode)、回声时钟模式(Echoed Clock Interface Mode)。

当DCO+被接地时,选中自时钟模式;当DCO+不接地时,DCO±被用作回声时钟,选中回声时钟模式。

回声时钟模式

回声时钟模式下,CNV±上升沿启动转换,转换时间t_MSB=200ns(因此对应5MSPS采样率)。CNV±必须在 t C N V H = 0.6 × t C Y C t_{CNVH}=0.6\times t_{CYC} tCNVH=0.6×tCYC内拉低, t C Y C t_{CYC} tCYC为采样周期(两个CNV上升沿间的时间)。

该模式使用全部LVDS对,DCO±为CLK±的缓冲,与D±同步,DCO+下降沿对应D±的更新。DCO最大比CLK延迟5ns,经典值为2ns延迟。host端(FPGA、单片机等)可通过DCO+的上升沿抓取D±的数据,由于DCO±上升沿对应数据的稳定状态,因此建议在此时进行数据读取,尽管在DCO±下降沿也是可以读取的。

注意,第16个CLK必须出现在转换阶段完成之前,即下一个CNV不能早于 C L K L a s t − t C L K L CLK_{Last}-t_{CLKL} CLKLasttCLKL,其中 t C L K L = 160 n s t_{CLKL}=160ns tCLKL=160ns,,否则会造成数据丢失。

在Last Data发送完成后(第16个CLK下降沿),到下一次转换结束之前,D±与DCO±均被拉到0。

在回声时钟模式下,CLK空闲位为0。

该模式下,host端仅需要维护一个16位移位寄存器,因此实现起来比较方便。

在这里插入图片描述

自时钟模式

自时钟模式不使用DCO±进行数据同步,而是使用数据头010进行同步。自时钟模式下,CLK空闲位为1。

在转换结束后,D±自动输出0,在CLK的前两个下降沿,1、0被输出锁存,其中第一个下降沿出现在CLK由空闲进入工作状态时

与回声时钟模式类似,第18个CLK必须出现在转换阶段完成之前。

在这里插入图片描述

FPGA驱动与仿真

FPGA驱动:

/******************************FILE HEAD**********************************
 * file_name	: AD7961.v
 * function		: AD7961驱动
 * author		: 今朝无言
 * date			: 2022-04-15
 *************************************************************************/
module AD7961(
input				clk_100M,
input				rst_n,

output	reg	[15:0]	data,
output	reg			out_available,	//上升沿指示数据可用

input				D_p,			//LVDS Data Output
input				D_n,

input				DCO_p,			//LVDS Buffered Clock Output
input				DCO_n,

output				CLK_p,			//LVDS Clock input,type val: 4ns(250MHz)
output				CLK_n,

output				CNV_p,			//LVDS Convert Input
output				CNV_n,

output				EN0,			//Enable
output				EN1,
output				EN2,
output				EN3
);

parameter N = 20; //t_CYC=N*T_100M,应大于200ns,所以N至少20

//------------------------ Single --------------------------
wire	D;
wire	DCO;
wire	CLK;
reg		CNV;

//----------------------- 配置EN0~3 -------------------------
assign {EN3,EN2,EN1,EN0}	= 4'b0001;
// X001,输入采样网络带宽28MHz    X101,带宽9MHz    XX11,休眠,对CNV无响应
// 更具体配置详见官方文档

//------------------------- 采样 ----------------------------
reg	[15:0]	data_tmp	= 16'd0;
reg	[7:0]	state		= 8'd0;
reg			CS			= 0;       //CLK的使能信号

always @(negedge clk_100M or negedge rst_n) begin
	if(!rst_n)begin
		CNV				<= 1'b0;
		data			<= 8'd0;
		out_available	<= 1'b0;
        CS			    <= 1'b0;
		state			<= 8'd0;
	end
	else begin
        if(state<=15) begin
			CS			    <= 1'b1;			//产生16个CLK
			state			<= state + 1'b1;

			if(state==0) begin
				CNV				<= 1'b1;		//启动转换
			end
            else if(state>=5) begin
                out_available	<= 1'b0;		//无效数据读取标志
			    CNV				<= 1'b0;		//CNV拉低
		    end
		end
		else if(state==16) begin
            CS			    <= 1'b0;
			state			<= state + 1'b1;
		end
		else if(state==17) begin
			data			<= data_tmp;		//寄存数据
			state			<= state + 1'b1;
		end
		else if(state==18) begin
			out_available	<= 1'b1;			//有效数据读取标志
			state			<= state + 1'b1;
		end
        else if(state<N-1) begin				//等待
            state			<= state + 1'b1;
        end
		else begin
			state			<= 0;
		end
	end
end

assign CLK    	= CS & clk_100M;

always @(posedge DCO or negedge rst_n) begin
	if(!rst_n) begin
		data_tmp	<= 16'd0;
	end
	else begin
    	data_tmp[15:0]	<= {data_tmp[14:0], D};   //移位寄存
	end
end

//-------------------- LVDS <-> Single -----------------------

// Data In LVDS -> Single
IBUFDS #( 
    .DIFF_TERM		("TRUE"),		// Differential Termination
    .IBUF_LOW_PWR	("FALSE"),		// Low power="TRUE", Highest performance="FALSE" 
    .IOSTANDARD		("LVDS")		// Specify the input I/O standard
)
Data_In_IBUFDS(
    .O				(D),			// Buffer output
    .I				(D_p),			// Diff_p buffer input
    .IB				(D_n)			// Diff_n buffer input
);

// DCO In LVDS -> Single
IBUFDS #( 
    .DIFF_TERM		("TRUE"),
    .IBUF_LOW_PWR	("FALSE"),
    .IOSTANDARD		("LVDS")
)
DCO_In_IBUFDS(
    .O				(DCO),
    .I				(DCO_p),
    .IB				(DCO_n)
);

// CLK Out Single -> LVDS    
OBUFDS #(
	.IOSTANDARD		("LVDS"),		// Specify the output I/O standard
	.SLEW			("FAST")		// Specify the output slew rate
)
CLK_Out_OBUFDS(
    .O				(CLK_p),		// Diff_p output
    .OB				(CLK_n),		// Diff_n output
    .I				(CLK)			// Buffer input 
);

// CNV Out Single -> LVDS    
OBUFDS #(
	.IOSTANDARD		("LVDS"),
	.SLEW			("FAST")
)
CNV_Out_OBUFDS(
    .O				(CNV_p),
    .OB				(CNV_n),
    .I				(CNV)
);

endmodule
//END OF AD7961.v FILE***************************************************

testbench:

`timescale 1ns/1ps

module AD7961_tb();

//----------------------- 100MHz -------------------------
reg	clk_100M	= 1;
always #5 begin
	clk_100M	<= ~clk_100M;
end

//------------------------ AD7961 ------------------------
reg 		rst_n;
wire [15:0]	data;
wire		out_available;
reg			D_p,D_n;
reg			DCO_p,DCO_n;
wire		CLK_p,CLK_n;
wire		CNV_p,CNV_n;
wire		EN0,EN1,EN2,EN3;

AD7961 AD7961_inst(
	.clk_100M			(clk_100M),
	.rst_n				(rst_n),

	.data				(data),
	.out_available		(out_available),

	.D_p				(D_p),
	.D_n				(D_n),

	.DCO_p				(DCO_p),
	.DCO_n				(DCO_n),

	.CLK_p				(CLK_p),
	.CLK_n				(CLK_n),

	.CNV_p				(CNV_p),
	.CNV_n				(CNV_n),

	.EN0				(EN0),
	.EN1				(EN1),
	.EN2				(EN2),
	.EN3				(EN3)
);

//-------------------------- tb --------------------------
initial begin
	rst_n	<= 0;
	#(100);

	rst_n	<= 1;

	AD_sim(16'd123);

	AD_sim(16'd54321);

	AD_sim(16'd2468);

	#(1000);
	$stop;
end

//---------------------- 模拟一次AD采样 ---------------------
task AD_sim;
	input	[15:0]	data;

	integer i;
	begin
		wait(CNV_p);	//CNV+上升沿开始转换
		//#(200);			//转换时间200ns

		D_p		<= data[15];
		D_n		<= ~data[15];

		for(i=1; i<=16; i=i+1) begin
			wait(CLK_p);
			#(2);			//模拟DCO相对于CLK的延时,2ns
			DCO_p	<= 1;	//回声时钟DCO+-
			DCO_n	<= 0;

			wait(~CLK_p);
			#(2);
			DCO_p	<= 0;
			DCO_n	<= 1;
			if(i<16) begin
				D_p		<= data[15-i];	//DCO+-下降沿改变D+-
				D_n		<= ~data[15-i];
			end
			else begin
				D_p		<= 0;	//输出完毕,D+-拉到0
				D_n		<= 1;
			end
		end
	end
endtask

endmodule

综合后时序仿真如下:
在这里插入图片描述

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

今朝无言

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

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

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

打赏作者

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

抵扣说明:

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

余额充值