目录

1.  数据接口时序图

2 采样时钟同步处理

2.1 delayctrl 原语

2.2  idelay2 原语

2.3 ISERDESE2

2.4 手动调节对齐

2.5 自动调节对齐

3. 帧同步信号

4.数据的处理


从上一章节,芯片资料可以看到,串行输出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: 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)   // 1-bit input: Clock input (connect to an IBUF or BUFMR).);BUFR #(.BUFR_DIVIDE("4"),   // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8" .SIM_DEVICE("7SERIES")// Must be set to "7SERIES" )BUFR_inst (.O(W_fc_clk),   // 1-bit output: Clock output port.CE(1'b1),      // 1-bit input: Active high, clock enable (Divided modes only).CLR(1'b0),     // 1-bit input: Active high, asynchronous clear (Divided modes only).I(W2_dc_clk)   // 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect);ISERDESE2 #(.DATA_RATE("SDR"),           // DDR, SDR.DATA_WIDTH(8),              // Parallel data width (2-8,10,14).DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE).DYN_CLK_INV_EN("FALSE"),    // Enable DYNCLKINVSEL inversion (FALSE, TRUE).INIT_Q1(1'b0),.INIT_Q2(1'b0),.INIT_Q3(1'b0),.INIT_Q4(1'b0),.INTERFACE_TYPE("NETWORKING"),// MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE.IOBDELAY("IBUF"),           // NONE, BOTH, IBUF, IFD.NUM_CE(2),                  // Number of clock enables (1,2).OFB_USED("FALSE"),          // Select OFB path (FALSE, TRUE).SERDES_MODE("MASTER"),      // MASTER, SLAVE.SRVAL_Q1(1'b0),.SRVAL_Q2(1'b0),.SRVAL_Q3(1'b0),.SRVAL_Q4(1'b0) )ISERDESE2_inst0 (.O(W2_dc_clk),               // 1-bit output: Combinatorial output.Q1(W_allign_word[0]),       // Q1 - Q8: 1-bit (each) output: Registered data outputs.Q2(W_allign_word[1]),.Q3(W_allign_word[2]),.Q4(W_allign_word[3]),.Q5(W_allign_word[4]),.Q6(W_allign_word[5]),.Q7(W_allign_word[6]),.Q8(W_allign_word[7]),.SHIFTOUT1(),.SHIFTOUT2(),.BITSLIP(),           .CE1(1'b1),.CE2(1'b1),.CLKDIVP(1'b0),              // 1-bit input: TBD.CLK(W_dc_clk),              // 1-bit input: High-speed clock.CLKB(~W_dc_clk),            // 1-bit input: High-speed secondary clock.CLKDIV(W_fc_clk),           // 1-bit input: Divided clock.OCLK(1'b0),                 // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" .DYNCLKDIVSEL(1'b0),         // 1-bit input: Dynamic CLKDIV inversion.DYNCLKSEL(1'b0),            // 1-bit input: Dynamic CLK/CLKB inversion.D(W0_dc_clk),               // 1-bit input: Data input.DDLY(W1_dc_clk),            // 1-bit input: Serial data from IDELAYE2.OFB(1'b0),                  // 1-bit input: Data feedback from OSERDESE2.OCLKB(1'b0),                // 1-bit input: High speed negative edge output clock.RST(~I_reset_n),            // 1-bit input: Active high asynchronous reset.SHIFTIN1(1'b0),.SHIFTIN2(1'b0) );endmodule 

首先来看看手动调节算法,用vivado的vio可以很方便的输入输出,可手动在线修改观察现象,对后面的自动训练算法也有一定的启发作用。
默认R_delay_cnt=0时,可以看到输入的正弦波形很乱

慢慢的增加R_delay_cnt,当R_delay_cnt=12时,开始出现稳定的正弦波,实验发现R_delay_cnt=14,15,16时恰好采到时钟的边缘,也就是跟输入的原始时钟对齐了,可以看到采到边缘是allign_word一直在跳变,有的是0,有的是1。一直到R_delay_cnt=18,正弦波都很稳定。有效窗口可以准确计算出来,200M的Idelay参考时钟,78ps/tap。7tap*78ps=546ps。说明数据的有效窗口很小,毕竟是320M的DDR,半个周期都才1.56ns

继续增加R_delay_cnt,当R_delay_cnt=20时,正弦波又变得不规则了。最后取R_delay_cnt=15,可以在代码里面写死。

2.5 自动调节对齐

既然有了手动调节的算法,为什么还要用自动训练对齐的算法呢?在高低温测试的时候,器件的延迟会受温度的影响发生变化,特别是在时钟频率很高,数据有效窗口很小的时候,这时候就需要能够动态的改变R_delay_cnt的值去自适应delay的变化,增加了鲁棒性。
有了上面的手动调节算法,自动训练的思路也很简单了。上电复位后R_delay_cnt一直自加,记下最后一个全0和第一个全1的值,取中点。这里只考虑了一种情况,还可能是从全1到全0的情况。代码如下

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/06/11 16:23:34
// Design Name:
// Module Name: lvds_autodelay
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module lvds_autodelay(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));reg  [4:0] R_delay_cnt  ;
reg        R_allign_done;
reg  [4:0] R_cnt_low    ;
reg  [4:0] R_cnt_high   ;
reg  [5:0] R_cnt_sum    ;
wire [4:0] W_half_cnt   ;
wire [4:0] W_delay_cnt  ;
wire [7:0] W_allign_word;//auto allign fsm
//00000000->11111111
//        |
//      halfalways @(posedge W_fc_clk or negedge I_reset_n)
beginif(~I_reset_n) beginR_allign_done <= 0;end else if(&W_delay_rdy)beginR_allign_done <= 0;endelse if(W_allign_word==8'hff)beginR_allign_done <= 1;end
endalways @(posedge W_fc_clk or negedge I_reset_n)
beginif(~I_reset_n) beginR_delay_cnt <= 0;end else if(&W_delay_rdy)beginR_delay_cnt <= 5'b1;endelse if(~R_allign_done)beginR_delay_cnt <= R_delay_cnt + 1'b1;end
endalways @(posedge W_fc_clk or negedge I_reset_n)
beginif(~I_reset_n) beginR_cnt_low <= 0;end else if(W_allign_word==8'h00)beginR_cnt_low <= R_delay_cnt;end
endalways @(posedge W_fc_clk or negedge I_reset_n)
beginif(~I_reset_n) beginR_cnt_high <= 0;end else if(W_allign_word==8'hff)beginR_cnt_high <= R_delay_cnt;end
end
always @(posedge W_fc_clk or negedge I_reset_n)
beginif(~I_reset_n) beginR_cnt_sum <= 0;end else if(R_allign_done)beginR_cnt_sum <= {{R_cnt_low[4],R_cnt_low} + {R_cnt_high[4],R_cnt_high}};end
end
assign W_half_cnt = R_cnt_sum[5:1];
assign W_delay_cnt = R_allign_done? W_half_cnt: R_delay_cnt;//   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)   // 1-bit input: Clock input (connect to an IBUF or BUFMR).);BUFR #(.BUFR_DIVIDE("4"),   // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8" .SIM_DEVICE("7SERIES")// Must be set to "7SERIES" )BUFR_inst (.O(W_fc_clk),   // 1-bit output: Clock output port.CE(1'b1),      // 1-bit input: Active high, clock enable (Divided modes only).CLR(1'b0),     // 1-bit input: Active high, asynchronous clear (Divided modes only).I(W2_dc_clk)   // 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect);ISERDESE2 #(.DATA_RATE("SDR"),           // DDR, SDR.DATA_WIDTH(8),              // Parallel data width (2-8,10,14).DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE).DYN_CLK_INV_EN("FALSE"),    // Enable DYNCLKINVSEL inversion (FALSE, TRUE).INIT_Q1(1'b0),.INIT_Q2(1'b0),.INIT_Q3(1'b0),.INIT_Q4(1'b0),.INTERFACE_TYPE("NETWORKING"),// MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE.IOBDELAY("IBUF"),           // NONE, BOTH, IBUF, IFD.NUM_CE(2),                  // Number of clock enables (1,2).OFB_USED("FALSE"),          // Select OFB path (FALSE, TRUE).SERDES_MODE("MASTER"),      // MASTER, SLAVE.SRVAL_Q1(1'b0),.SRVAL_Q2(1'b0),.SRVAL_Q3(1'b0),.SRVAL_Q4(1'b0) )ISERDESE2_inst0 (.O(W2_dc_clk),               // 1-bit output: Combinatorial output.Q1(W_allign_word[0]),       // Q1 - Q8: 1-bit (each) output: Registered data outputs.Q2(W_allign_word[1]),.Q3(W_allign_word[2]),.Q4(W_allign_word[3]),.Q5(W_allign_word[4]),.Q6(W_allign_word[5]),.Q7(W_allign_word[6]),.Q8(W_allign_word[7]),.SHIFTOUT1(),.SHIFTOUT2(),.BITSLIP(),           .CE1(1'b1),.CE2(1'b1),.CLKDIVP(1'b0),              // 1-bit input: TBD.CLK(W_dc_clk),              // 1-bit input: High-speed clock.CLKB(~W_dc_clk),            // 1-bit input: High-speed secondary clock.CLKDIV(W_fc_clk),           // 1-bit input: Divided clock.OCLK(1'b0),                 // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" .DYNCLKDIVSEL(1'b0),         // 1-bit input: Dynamic CLKDIV inversion.DYNCLKSEL(1'b0),            // 1-bit input: Dynamic CLK/CLKB inversion.D(W0_dc_clk),               // 1-bit input: Data input.DDLY(W1_dc_clk),            // 1-bit input: Serial data from IDELAYE2.OFB(1'b0),                  // 1-bit input: Data feedback from OSERDESE2.OCLKB(1'b0),                // 1-bit input: High speed negative edge output clock.RST(~I_reset_n),            // 1-bit input: Active high asynchronous reset.SHIFTIN1(1'b0),.SHIFTIN2(1'b0) );endmodule 

3. 帧同步信号

Dclk模块功能完成之后,用上面产生的数据采样时钟同时去采样FCLK和DATA,只能保证采集到的数据的每一位都是对的,但并不知道一个10bit数据的首尾在哪,fclk模块就是用来寻找并行数据的正确起始与结束位置,因此业界也称fclk为帧时钟,但它并不是用作时钟,只用来判断data数据的位置。要使用一个bit_slip对串转并的结果进行移位,移位的同时检测FCLK转换的输出,当输出是8’b11110000的时候就停止移位。

该模块又称作Bitslip模块,Bitslip就专门用来找到用户需要的并行数据边界。

下图给出了Bitslip是如何确定并行数据的边界:对于SDR模式,Bitslip使能1次,则数据会左移1次,对于8bit并行数据,移动8次完成一个循环,可以这样无止境的循环,直到找到用户定义的并行数据。对于DDR模式,Bitslip工作方式不同,Bitslip使能1次,数据会右移1次或者左移3次,两者交替进行,同样移动8次完成一个循环。

思考:

1) 注意这个模块没有对FCLK 进行delay延迟,只是用上面产生的时钟对FCLK进行采样。

2) 判断移位输出的结果W_fc_patten,如果检测结果是我们想要的数据,则R_bit_slip 拉低,否则R_bit_slip拉高进行上图的移位操作。

3)R_wait 的描述,为什么要有这个信号呢?为了减少R_bit_slip 拉高移位的频率吗?

//-------------------------------------FC handle bit_slip-------------------------------------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_inst9 (.O(W_fc_refclk),          // Buffer output.I(I_AD_FPGA_FC_p),       // Diff_p buffer input (connect directly to top-level port).IB(I_AD_FPGA_FC_n)       // Diff_n buffer input (connect directly to top-level port));ISERDESE2 #(.DATA_RATE("DDR"),           // DDR, SDR.DATA_WIDTH(8),              // Parallel data width (2-8,10,14).DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE).DYN_CLK_INV_EN("FALSE"),    // Enable DYNCLKINVSEL inversion (FALSE, TRUE).INIT_Q1(1'b0),.INIT_Q2(1'b0),.INIT_Q3(1'b0),.INIT_Q4(1'b0),.INTERFACE_TYPE("NETWORKING"),// MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE.IOBDELAY("NONE"),           // NONE, BOTH, IBUF, IFD.NUM_CE(2),                  // Number of clock enables (1,2).OFB_USED("FALSE"),          // Select OFB path (FALSE, TRUE).SERDES_MODE("MASTER"),      // MASTER, SLAVE.SRVAL_Q1(1'b0),.SRVAL_Q2(1'b0),.SRVAL_Q3(1'b0),.SRVAL_Q4(1'b0) )ISERDESE2_inst9 (.O(),                        // 1-bit output: Combinatorial output.Q1(W_fc_patten[0]),         // Q1 - Q8: 1-bit (each) output: Registered data outputs.Q2(W_fc_patten[1]),.Q3(W_fc_patten[2]),.Q4(W_fc_patten[3]),.Q5(W_fc_patten[4]),.Q6(W_fc_patten[5]),.Q7(W_fc_patten[6]),.Q8(W_fc_patten[7]),.SHIFTOUT1(),.SHIFTOUT2(),.BITSLIP(R_bit_slip),           .CE1(1'b1),.CE2(1'b1),.CLKDIVP(1'b0),              // 1-bit input: TBD.CLK(W_dc_clk),            // 1-bit input: High-speed clock.CLKB(~W_dc_clk),           // 1-bit input: High-speed secondary clock.CLKDIV(W_fc_clk),           // 1-bit input: Divided clock.OCLK(1'b0),                 // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" .DYNCLKDIVSEL(1'b0),         // 1-bit input: Dynamic CLKDIV inversion.DYNCLKSEL(1'b0),            // 1-bit input: Dynamic CLK/CLKB inversion.D(W_fc_refclk),             // 1-bit input: Data input.DDLY(1'b0),                 // 1-bit input: Serial data from IDELAYE2.OFB(1'b0),                  // 1-bit input: Data feedback from OSERDESE2.OCLKB(1'b0),                // 1-bit input: High speed negative edge output clock.RST(~I_reset_n),            // 1-bit input: Active high asynchronous reset.SHIFTIN1(1'b0),.SHIFTIN2(1'b0) );always @(posedge W_fc_clk or negedge I_reset_n)
beginif(~I_reset_n) beginR_bit_slip <= 0;R_wait <= 0;end elsebeginif (R_wait==2'd3 && W_fc_patten!=8'b11110000) beginR_bit_slip <= 1;R_wait <= 2'd1;endelsebeginR_bit_slip <= 0;R_wait <= R_wait + 1'd1;endend
end

另外一种思路是:用1111判断对应数据的奇数通道,0000对应数据的偶数通路。如果输出的14bit数据为11111111111111,说明找到了fclk的高电平状态,对应数据的偶数通道,此时取数即得到偶数通道的数据。如果输出的14bit数据为00000000000000,说明找到了fclk的低电平状态,对应数据的奇数通道,此时取数即得到奇数通道的数据

4.数据的处理

数据采样代码和上面的差不多

   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_inst1 (.O(W_data_in1[0]),         // Buffer output.I(I_ad_lvds_d0_p[0]),     // Diff_p buffer input (connect directly to top-level port).IB(I_ad_lvds_d0_n[0])     // Diff_n buffer input (connect directly to top-level port));ISERDESE2 #(.DATA_RATE("DDR"),           // DDR, SDR.DATA_WIDTH(8),              // Parallel data width (2-8,10,14).DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE).DYN_CLK_INV_EN("FALSE"),    // Enable DYNCLKINVSEL inversion (FALSE, TRUE).INIT_Q1(1'b0),.INIT_Q2(1'b0),.INIT_Q3(1'b0),.INIT_Q4(1'b0),.INTERFACE_TYPE("NETWORKING"),// MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE.IOBDELAY("NONE"),           // NONE, BOTH, IBUF, IFD.NUM_CE(2),                  // Number of clock enables (1,2).OFB_USED("FALSE"),          // Select OFB path (FALSE, TRUE).SERDES_MODE("MASTER"),      // MASTER, SLAVE.SRVAL_Q1(1'b0),.SRVAL_Q2(1'b0),.SRVAL_Q3(1'b0),.SRVAL_Q4(1'b0) )ISERDESE2_inst1 (.O(),                        // 1-bit output: Combinatorial output.Q1(W_ad_data1[0]),          // Q1 - Q8: 1-bit (each) output: Registered data outputs.Q2(W_ad_data1[1]),.Q3(W_ad_data1[2]),.Q4(W_ad_data1[3]),.Q5(W_ad_data1[4]),.Q6(W_ad_data1[5]),.Q7(W_ad_data1[6]),.Q8(W_ad_data1[7]),.SHIFTOUT1(),.SHIFTOUT2(),.BITSLIP(R_bit_slip),           .CE1(1'b1),.CE2(1'b1),.CLKDIVP(1'b0),              // 1-bit input: TBD.CLK(W_dc_clk),              // 1-bit input: High-speed clock.CLKB(~W_dc_clk),            // 1-bit input: High-speed secondary clock.CLKDIV(W_fc_clk),           // 1-bit input: Divided clock.OCLK(1'b0),                 // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" .DYNCLKDIVSEL(1'b0),         // 1-bit input: Dynamic CLKDIV inversion.DYNCLKSEL(1'b0),            // 1-bit input: Dynamic CLK/CLKB inversion.D(W_data_in1[0]),           // 1-bit input: Data input.DDLY(1'b0),                 // 1-bit input: Serial data from IDELAYE2.OFB(1'b0),                  // 1-bit input: Data feedback from OSERDESE2.OCLKB(1'b0),                // 1-bit input: High speed negative edge output clock.RST(~I_reset_n),            // 1-bit input: Active high asynchronous reset.SHIFTIN1(1'b0),.SHIFTIN2(1'b0) );

另一个思路:

Dclk和fclk的功能完成后,该模块就只需要取数就就行了,不需要任何控制操作。然后在奇状态下将取到的数通过fifo1同步到系统时钟域,在偶状态下将取到的数通过fifo2同步到系统时钟域即可,如图所示

推荐好用的学习网址:

https://blog.csdn.net/sinat_31206523/article/details/107325880?utm_medium=distribute.pc_relevant.none-task-blog-title-4&spm=1001.2101.3001.4242

https://blog.csdn.net/sinat_31206523/article/details/107346082

ADS6445开发笔记(2)---- LVDS 高速接口相关推荐

  1. ADS6445开发笔记(1)---- 芯片介绍

    写这篇博客的时候,暂未调试ADS6445,只是想资料整理一下,方便自己理解.查看.中间可能会有一些理解错误的地方,欢迎大家批评指正. 目录 1. 芯片特性 2.应用范围 3. 芯片简介 4. 芯片功能 ...

  2. AR502H-CN开发笔记01:硬件接口

    本系列文章将向大家讲述华为网关AR502H的开发方法. 本文介绍AR502H的硬件接口. 一.外观结构

  3. 海思3518E开发笔记4.2——sensor数据交互接口(MIPI、LVDS、DVP并口),以AR0130和OV9712为例

    目录 前言 DVP(并口) LVDS MIPI(MIPI-CSI2) 总结 前言 摄像头是一个独立的芯片,和主控芯片是弧线独立的,两者通过接口进行交互,交互的信息有控制信号和数据信号 控制信号常用I2 ...

  4. Android开发笔记(五十四)数据共享接口ContentProvider

    ContentProvider 前面几节介绍了进程间通信的几种方式,包括消息包级别的Messenger.接口调用级别的AIDL.启动页面/服务级别的Notification,还有就是本节这个数据库级别 ...

  5. Android开发笔记(五十三)远程接口调用AIDL

    AIDL概述 AIDL全称是"Android Interface Definition Language",即Android的接口定义语言.AIDL用来协助开发者来处理进程间通信, ...

  6. Android开发笔记(四十七)Runnable接口实现多线程

    Runnable概述 Runnable接口可声明一连串的事务,常用于多线程处理.但是实现Runnable接口并不意味着开启了一个新线程,只是定义了接下来要做的事情,至于说这些事情要在主线程处理,还是在 ...

  7. 双通道14位、500 MSPS采样率的AD9684 高速并行LVDS ADC接口介绍

    双通道14位.500 MSPS采样率的AD9684 高速并行LVDS ADC接口 本文为明德扬原创文章,转载请注明出处! AD9684是一款双通道14位.500 MSPS采样率 ,并行LVDS接口的模 ...

  8. 硬件开发笔记(一):高速电路设计Cadence Aleegro软件介绍和安装过程

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/124356904 红胖子(红模仿)的博文大全:开发技术集 ...

  9. (硅谷课堂项目)Java开发笔记2:项目概述,搭建项目环境和开发讲师管理接口

    文章目录 (硅谷课堂项目)Java开发笔记2:项目概述,搭建项目环境和开发讲师管理接口 1.项目概述 1.1 项目介绍 1.2 硅谷课程流程图 1.3 硅谷课堂功能架构 1.4 硅谷课堂技术架构 1. ...

最新文章

  1. 马化腾公开信:AI将成为基础设施,腾讯要打造“数字生态共同体”
  2. 织梦添加幻灯片的方法
  3. jQuery计数子元素
  4. python(5)- 基础数据类型
  5. 智能关机软件 c语言,智能关机软件
  6. 毕业生共享屏幕3小时 被骗70万
  7. html如何实现页面懒加载,浏览器HTML自带懒加载技术
  8. 文件描述符(0、1、2)的用法
  9. 【二分】【线段树】hdu6070 Dirt Ratio
  10. VIM+LaTexSuite配置
  11. setValuesForKeysWithDictionary:的用途
  12. 下拉列表—DropDownMenu的使用解析
  13. 考研英语阅读理解技巧总结
  14. Parallel Scavenge收集器
  15. python算法—1234能组成不重复3位数
  16. 文本生成的几种简单方法
  17. uniapp小程序文字与语音互相转化
  18. C++中的dynamic_cast和static_cast转化
  19. kingcms php,KingCMS php版网站标签模版制作教程(二)
  20. oppo怎么打开科学计算机,OPPOr11的计算器怎么打开

热门文章

  1. python仿真图_基于Python的DTN仿真平台
  2. Android Kotlin 学习总结(一) 《KAE 优缺点并且深入字节码分析工作原理》
  3. pytion基础之OS和文件操作
  4. 嵌入式 shell 学习之for语句
  5. chkrootkit
  6. Scala知识点总结-思维导图
  7. 计算机项目(毕设课设) 之 含文档+PPT+源码等]精品基于PHP实现的网上买卖管理系统购物商城
  8. pandas归一化某一列_十分钟带你了解pandas常用方法
  9. 从 0 到 1 建设完一个系统,我不再瞎吐槽前人
  10. 【Android开发】使用Bottom Navigation Activity去掉顶部栏(标题栏)