目录
从上一章节,芯片资料可以看到,串行输出LVDS数据的bit clock,都是400MHZ以上的。这显然不能用fpga Verilog 语言直接写代码进行采样,需要用到专门的 iserdese 原语。
1. 数据接口时序图
数据接口有很多中模式,这里只贴了一种的图
上图可以看到以下几点:
- 信号线分3类,数据采集时钟DCLK,帧同步信号FCLK,输入数据DATA
- 输入数据采样时钟默认是已经对齐了输入数据的中点,但帧时钟是和数据字边缘对齐
- 使用iserdese接收数据,idelay调整时钟延迟
2 采样时钟同步处理
这里主要对 采样时钟 bitclk 做延迟处理,使其能正确采样到数据。框图中的模块,都不是IP 核,而是原语。在tools---language templates中可以搜索到。
2.1 delayctrl 原语
因FPGA的电压偏置、制造过程、电压、温度的不同,可能会对整个芯片的时序造成一些小的影响。IDELAYCTRL可以通过一个较高频率的参考时钟REFCLK为IDELAY或ODELAY提供延时抽头,可选0~31。参考时钟的频率可选200MHz或者300MHz,它们的每个抽头的分辨率分别约是78ps和52ps。假设我们的LVDS输入为600Mbps,则选用200MHz需要21taps,300MHz需要32taps,所以最终选择200MHz为参考时钟。(1/600M = 1666ps, 1666ps/78ps = 21 ,1666ps/52ps= 32。抽头个数21更合理)
使用时还需要注意需要对IDELAYCTRL进行LOC约束,实现工具将IDELAYCTRL实例自动复制到整个器件,甚至复制到未使用延迟单元的时钟区域中。这样做资源占用率较高,在每个时钟区域内都要使用一个全局 时钟资源,并且使用布线资源较多,因此功耗较大。参考文档:输入输出延迟单元IODELAY简介
思考:
1. IDELAYCTRL 的输入时钟refclk 决定idelay2 每个抽头的延迟有多少ps , idelay2 原语,根据器件不同在原语选择上可以有不同的抽头,比如CNTVALUEOUT [4:0] 2^5 就是 0 - 31个抽头。0 就是没有延迟。
2. IDELAYCTRL 的输出RDY 代表 IDELAYCTRL使能有效
IDELAYCTRL模块是为IDELAY模块服务的。delayctrl的位置需要手动约束。可以利用plananead找到delayctrl的位置,在Device视图中,找到约束文件中所定义的delay的位置,就是下图橙色方块。在他附近找到delayCtrl,图中白色的矩形,读出她的位置信息,再添加到你的约束文件里就可以了。
2.2 idelay2 原语
C: Clock input ,分频时钟
CNTVALUEIN: 5-bit input, Counter value input 。 这个值控制输出抽头个数。比如一个抽头延迟78ps.这里输入2 ,就是延迟78*2 = 156ps .
IDATAIN : 需要延迟的输入数据,在这里就是DCLK 时钟。
DATAOUT :延迟输出
2.3 ISERDESE2
先说ISERDESE2。该模块接收外部输入FPGA的高速源同步串行信号,在FPGA内部将其转换为用户需要的并行数据信号。如图1所示为ISERDESE2的功能框图,咱们可以将按照功能分成5个部分:
CLK: -- 1-bit input: High-speed clock 。DDLY 输入,逻辑组合后产生 O ,看总框图,应该是O 是DDLY 直接输出的结果
CLKB : ---- High-speed secondary clock 。 CLK 时钟取反
CLKDIV: ---- 经过 BUFR 分频的时钟
CLKDIVP:---- 接地
D : 需要对齐的信号
DDLY : 需要对齐的信号经过 DELAY 延迟后的结果
RST : 和 delay_ctrl 复位信号一致
SHIFTIN1 SHIFTIN2: ISERDESE级联的时候需要用,对接上一个模块的 SHIFTOUT1 ,SHIFTOUT2
BITSLIP : 这里没用到,在frame对齐的时候需要用到
2.4 手动调节对齐
module lvds_data (
input I_AD_FPGA_DC_p ,
input I_AD_FPGA_DC_n ,
input I_ref_clk_200m ,
input I_reset_n
);
wire W0_dc_clk;
wire W_delay_rdy;
wire [4:0] W_delay_cnt;
wire [7:0] W_allign_word;
wire W_dc_clk;
wire W2_dc_clk ;
wire W_fc_clk;
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)
);
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: Delaye