FPGA驱动"/>
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 0∼5V ,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} CLKLast−tCLKL,其中 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) beginif(!rst_n)beginCNV <= 1'b0;data <= 8'd0;out_available <= 1'b0;CS <= 1'b0;state <= 8'd0;endelse beginif(state<=15) beginCS <= 1'b1; //产生16个CLKstate <= state + 1'b1;if(state==0) beginCNV <= 1'b1; //启动转换endelse if(state>=5) beginout_available <= 1'b0; //无效数据读取标志CNV <= 1'b0; //CNV拉低endendelse if(state==16) beginCS <= 1'b0;state <= state + 1'b1;endelse if(state==17) begindata <= data_tmp; //寄存数据state <= state + 1'b1;endelse if(state==18) beginout_available <= 1'b1; //有效数据读取标志state <= state + 1'b1;endelse if(state<N-1) begin //等待state <= state + 1'b1;endelse beginstate <= 0;endend
endassign CLK = CS & clk_100M;always @(posedge DCO or negedge rst_n) beginif(!rst_n) begindata_tmp <= 16'd0;endelse begindata_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/1psmodule AD7961_tb();//----------------------- 100MHz -------------------------
reg clk_100M = 1;
always #5 beginclk_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 beginrst_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;beginwait(CNV_p); //CNV+上升沿开始转换//#(200); //转换时间200nsD_p <= data[15];D_n <= ~data[15];for(i=1; i<=16; i=i+1) beginwait(CLK_p);#(2); //模拟DCO相对于CLK的延时,2nsDCO_p <= 1; //回声时钟DCO+-DCO_n <= 0;wait(~CLK_p);#(2);DCO_p <= 0;DCO_n <= 1;if(i<16) beginD_p <= data[15-i]; //DCO+-下降沿改变D+-D_n <= ~data[15-i];endelse beginD_p <= 0; //输出完毕,D+-拉到0D_n <= 1;endendend
endtaskendmodule
综合后时序仿真如下:
更多推荐
AD7961介绍及FPGA驱动
发布评论