写在前面:最近一段时间在总结以前做过的项目,都是关于FPGA的接口技术和设计方法,让技术沉淀下来。会陆陆续续发表到博客,希望对大家理解FPGA有一点点帮助。
LVDS
即Low-Voltage Differential Signaling。FPGA的selecteIO非常强大,支持各种IO接口标准,电压电流都可以配置。其接口速率可以达到几百M甚至上千M。使用lvds来接收高速ADC产生的数据会很方便。像ISERDES,IDDR,IDELAY,OSERDES,ODDR这种资源在FPGA的IOB中多得是(每个IO都对应有,最后具体介绍),根本不担心使用。最近刚在项目中用到,提供一个思路,具体的器件使用参考FPGA手册。
使用的AD芯片是ADI的AD9653,125M16bit高精度高速ADC,用到的采样速率是80M。其SPI配置会单独开一篇来讲,SPI配置里面有个大坑,本来以为调好了的,后来又发现了问题,调了三天才定位到问题在哪,这就是硬件的魅力(坑爹)所在了吧。这里主要介绍FPGA的接收部分。
接收ADC数据的时序图,
有几点需要注意:
0 , 可以看出分成三种信号,数据采样时钟DCLK,帧同步信号FCLK,和输入数据DATA
1,输入数据采样时钟默认是已经对齐了输入数据的中点,但帧时钟是和数据字节边缘对齐的。
2,使用Iserdes接收数据,Idelay调整时钟延迟。
1,对数据采样时钟的处理如下
通过控制延时,使得CLK和经过IBUFDS的BitClk对齐,从而消除IBUFIO和BUFR还有net的延时。这样所有的输入信号都只经过了一个IBUFDS,延时相等。对Idelay的控制,可以手动调节,也可以用自动算法。(参考xapp524)
IBUFDS #(
.DIFF_TERM("TRUE"), // Differential Termination
.IBUF_LOW_PWR("TRUE"), // Low power="TRUE", Highest performance="FALSE"
.IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFDS_inst10 (
.O(W0_dc_clk), // Buffer output
.I(I_AD_FPGA_DC_p), // Diff_p buffer input (connect directly to top-level port)
.IB(I_AD_FPGA_DC_n) // Diff_n buffer input (connect directly to top-level port)
);
wire W_delay_rdy;
wire [4:0] W_delay_cnt;
wire [7:0] W_allign_word;
vio_0 vio_u (
.clk(W_fc_clk), // input wire clk
.probe_in0(W_delay_rdy), // input wire [0 : 0] probe_in0
.probe_in1(W_allign_word),// input wire [7 : 0] probe_in1
.probe_out0(W_delay_cnt) // output wire [4 : 0] probe_out0
);
(* IODELAY_GROUP = "delay1" *)
IDELAYCTRL IDELAYCTRL_inst1 (
.RDY(W_delay_rdy), // 1-bit output: Ready output
.REFCLK(I_ref_clk_200m), // 1-bit input: Reference clock input
.RST(~I_reset_n) // 1-bit input: Active high reset input
);
(* IODELAY_GROUP = "delay1" *)
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN("CLOCK") // DATA, CLOCK input signal
)
IDELAYE2_inst1 (
.CNTVALUEOUT(), // 5-bit output: Counter value output
.DATAOUT(W1_dc_clk), // 1-bit output: Delayed data output
.C(W_fc_clk), // 1-bit input: Clock input
.CE(1'b0), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(1'b0), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(W_delay_cnt), // 5-bit input: Counter value input
.DATAIN(1'b0), // 1-bit input: Internal delay data input
.IDATAIN(W0_dc_clk), // 1-bit input: Data input from the I/O
.INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
.LD(1'b1), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
);
BUFIO BUFIO_p (
.O(W_dc_clk), // 1-bit output: Clock output (connect to I/O clock loads).
.I(W2_dc_clk)