AD9253 LVDS 高速ADC驱动开发

1、查阅AD9253器件手册

2、查阅Xilinx xapp524手册

3、该款ADC工作在125Msps下,14bit - 2Lane - 1frame 模式。

对应:data clock时钟为500M DDR mode。data line rate:1Gbps。frame clock:1/4 data clock

具体内容:下文的参考博客写的很清楚,我就不详细写了。参考博客clock align模块不完整,本文新增这个模块。

objectivec 复制代码
`timescale 1ns / 1ps

module bit_clk_align(
    input  i_clk_p,
    input  i_clk_n,
    input  i_clk_200m,
    input  i_reset,
    output o_bitclk_align_done,
    output o_bitclk_Monclk,
    output o_bitclk_Refclk

);

//------------------ variable declare ------------------
localparam PHASE_ADJ_FAILED  =  1; // 0: OK   1:FAILED

wire s_BitClk_MonClkOut;
wire s_BitClk_RefClkOut;
wire s_bitclk;
wire s_idelayctrl_rdy;
wire s_bitclk_align_ena;
wire s_IntBitClk;
wire [07:00]s_bitclk_para;
wire [04:00]s_cntvalueout;
reg  r_idelay_ce    = 1;
reg  r_idelay_inc   = 1;

reg  [3:0]r_clk_div_reset   = 4'hf;    // high active
wire s_clk_div_reset;
reg  r_phase_adj_status   = 0;
reg  r_bitclk_align_done   = 0;
reg  [03:00] r_adj_cnt = 0;
reg  [03:00] r_bitclk_align_state = 0;
reg  [01:00] s_iserdesout_dly_cnt = 0;



//------------------ main body of code ------------------
assign  o_bitclk_Monclk  =  s_BitClk_MonClkOut;
assign  o_bitclk_Refclk  =  s_BitClk_RefClkOut;

// generate iserdes reset
always@(posedge s_BitClk_RefClkOut)begin
    r_clk_div_reset   <= r_clk_div_reset   >> 1;
end
assign s_clk_div_reset = (|r_clk_div_reset);

//
// state:  adjust local clock phase align to input clk
//
assign s_bitclk_align_ena = s_idelayctrl_rdy && (~i_reset);
always@(posedge s_BitClk_RefClkOut)begin
    case(r_bitclk_align_state)
        0:begin
            r_idelay_ce  <= 0;
            r_idelay_inc <= 0;
            r_phase_adj_status <= 0;
            r_bitclk_align_done <= 0;
            
            if(s_bitclk_align_ena)begin
                r_bitclk_align_state <= 1;
            end
        end
        1:begin
            //wait iserdes Q8~Q1 output stablely
            r_idelay_ce  <= 0;
            r_idelay_inc <= 0;
            if(s_iserdesout_dly_cnt >= 2)begin
                s_iserdesout_dly_cnt <= 0;
                r_bitclk_align_state <= r_bitclk_align_state + 1;
            end
            else begin
                s_iserdesout_dly_cnt <= s_iserdesout_dly_cnt + 1;
            end
        end
        2:begin
            // search first patarn
            // 8'h00 - rising clk align
            // 8'hff - falling clk align
            if(s_bitclk_para == 8'h00)begin
                r_bitclk_align_state <= 3;
            end
            else begin
                if(s_cntvalueout == 31)begin
                    // phase adjust flow failed
                    r_idelay_ce  <= 0;
                    r_idelay_inc <= 0;
                    r_phase_adj_status <= PHASE_ADJ_FAILED;
                end
                else begin
                    r_idelay_ce  <= 1;
                    r_idelay_inc <= 1;
                    r_bitclk_align_state <= 1;
                end
            end
        end
        3:begin
            // find datain: riding edge
            if(s_bitclk_para != 8'h00)begin
                r_bitclk_align_state <= 5;
            end
            else begin
                if(s_cntvalueout == 31)begin
                    // phase adjust flow failed
                    r_idelay_ce  <= 0;
                    r_idelay_inc <= 0;
                    r_phase_adj_status <= PHASE_ADJ_FAILED;
                end
                else begin
                    r_idelay_ce  <= 1;
                    r_idelay_inc <= 1;
                    r_bitclk_align_state <= 4;
                end
            end
        end
        4:begin
            //wait iserdes Q8~Q1 output stablely
            r_idelay_ce  <= 0;
            r_idelay_inc <= 0;
            if(s_iserdesout_dly_cnt >= 2)begin
                s_iserdesout_dly_cnt <= 0;
                r_bitclk_align_state <= 3;
            end
            else begin
                s_iserdesout_dly_cnt <= s_iserdesout_dly_cnt + 1;
            end
        end
        5:begin
            // adjust s_cntvalueout: -1
                r_idelay_ce  <= 1;
                r_idelay_inc <= 0;
                r_bitclk_align_state <= 6;
        end
        6:begin
                r_idelay_ce  <= 0;
                r_idelay_inc <= 0;
                r_bitclk_align_done  <= 1;
                r_bitclk_align_state <= 6;
        end

        default:r_bitclk_align_state = 0;
    endcase
end

assign  o_bitclk_align_done  =  r_bitclk_align_done;



//
//
//
IBUFDS #(
    .IOSTANDARD("LVDS_25")     // Specify the input I/O standard
 ) IBUFDS_inst (
    .O(s_bitclk),  // Buffer output
    .I(i_clk_p),  // Diff_p buffer input (connect directly to top-level port)
    .IB(i_clk_n) // Diff_n buffer input (connect directly to top-level port)
 );


 (* IODELAY_GROUP = "bitclk_group" *) // Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
 IDELAYCTRL IDELAYCTRL_inst (
    .RDY(s_idelayctrl_rdy),       // 1-bit output: Ready output
    .REFCLK(i_clk_200m), // 1-bit input: Reference clock input
    .RST(1'b0)        // 1-bit input: Active high reset input
 );

 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("VARIABLE"),           // 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_inst (
    .CNTVALUEOUT(s_cntvalueout), // 5-bit output: Counter value output
    .DATAOUT(s_IntBitClk),         // 1-bit output: Delayed data output
    .C(s_BitClk_RefClkOut),                     // 1-bit input: Clock input
    .CE(r_idelay_ce),                   // 1-bit input: Active high enable increment/decrement input
    .CINVCTRL(1'b0),       // 1-bit input: Dynamic clock inversion input
    .CNTVALUEIN(5'd0),   // 5-bit input: Counter value input
    .DATAIN(1'b0),           // 1-bit input: Internal delay data input
    .IDATAIN(s_bitclk),         // 1-bit input: Data input from the I/O
    .INC(r_idelay_inc),                 // 1-bit input: Increment / Decrement tap delay input
    .LD(0),                   // 1-bit input: Load IDELAY_VALUE input
    .LDPIPEEN(1'b0),       // 1-bit input: Enable PIPELINE register to load data input
    .REGRST(0)            // 1-bit input: Active-high reset tap-delay input
  );


  BUFIO BUFIO_inst (
    .O(s_BitClk_MonClkOut), // 1-bit output: Clock output (connect to I/O clock loads).
    .I(s_IntBitClk)  // 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(s_BitClk_RefClkOut),     // 1-bit output: Clock output port
    .CE(1),   // 1-bit input: Active high, clock enable (Divided modes only)
    .CLR(0), // 1-bit input: Active high, asynchronous clear (Divided modes only)
    .I(s_IntBitClk)      // 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect
 );



 ISERDESE2 #(
    .DATA_RATE         ("SDR"), // DDR, SDR
//    .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 - INIT_Q4: Initial value on the Q outputs (0/1)
    .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
    .IOBDELAY          ("NONE"), // NONE, BOTH, IBUF, IFD
    .NUM_CE            (1), // Number of clock enables (1,2)
    .OFB_USED          ("FALSE"), // Select OFB path (FALSE, TRUE)
    .SERDES_MODE       ("MASTER"), // MASTER, SLAVE
    // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
    .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 - Q8: 1-bit (each) output: Registered data outputs
    .Q1           (s_bitclk_para[0]),
    .Q2           (s_bitclk_para[1]),
    .Q3           (s_bitclk_para[2]),
    .Q4           (s_bitclk_para[3]),
    .Q5           (s_bitclk_para[4]),
    .Q6           (s_bitclk_para[5]),
    .Q7           (s_bitclk_para[6]),
    .Q8           (s_bitclk_para[7]),
    // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
    .SHIFTOUT1    (),
    .SHIFTOUT2    (),
    .BITSLIP      (0), // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
    // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
    // to Q8 output ports will shift, as in a barrel-shifter operation, one
    // position every time Bitslip is invoked (DDR operation is different from
    // SDR).
    // CE1, CE2: 1-bit (each) input: Data register clock enable inputs
    .CE1          (1'b1),
    .CE2          (1'b0),
    .CLKDIVP      (1'b0), // 1-bit input: TBD
    // Clocks: 1-bit (each) input: ISERDESE2 clock input ports
    .CLK          (s_BitClk_MonClkOut), // 1-bit input: High-speed clock
    .CLKB         (0), // 1-bit input: High-speed secondary clock
    .CLKDIV       (s_BitClk_RefClkOut), // 1-bit input: Divided clock
    .OCLK         (1'b0), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY"
    // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
    .DYNCLKDIVSEL (1'b0), // 1-bit input: Dynamic CLKDIV inversion
    .DYNCLKSEL    (1'b0), // 1-bit input: Dynamic CLK/CLKB inversion
    // Input Data: 1-bit (each) input: ISERDESE2 data input ports
    .D            (s_bitclk), // 1-bit input: Data input
//    .DDLY         (s_IntBitClk), // 1-bit input: Serial data from IDELAYE2
    .DDLY         (0), // 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), // 1-bit input: Active high asynchronous reset
    .RST          (s_clk_div_reset ), // 1-bit input: Active high asynchronous reset
    // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
    .SHIFTIN1     (1'b0),
    .SHIFTIN2     (1'b0)
);


// note:ISERDES/OSERDES需要复位,才会生效。
// 虽然支持异步复位,但是推荐用CLKDIV这个时钟来进行同步复位,或采用异步复位同步释放。
// 即.RST          (i_reset), // 1-bit input: Active high asynchronous reset
// i_reset可以替换为由s_BitClk_RefClkOut来内部逻辑产生s_clk_div_reset 。

endmodule

补充知识:

  • OSERDES2原语
  • ISERDES2原语

参考博客:

LVDS接口程序设计框架及仿真_lvds接口仿真-CSDN博客

xilinx原语详解及仿真------OSERDESE2 - 知乎 (zhihu.com)

相关推荐
soulermax4 小时前
华为数字芯片机考2025合集2已校正
嵌入式硬件·华为·fpga开发·系统架构·硬件架构
156082072195 小时前
全国产V7-690T核心板/算法验证板/FPGA开发板
fpga开发·信号处理·v7-690t·pcie信号处理模块·jfm7vx690t
做一个优雅的美男子5 小时前
【特权FPGA】之SRAM读写
fpga开发
&Cheems7 小时前
Verilog:LED呼吸灯
fpga开发
soulermax11 小时前
华为数字芯片机考2025合集5已校正
华为·fpga开发
做一个优雅的美男子20 小时前
【特权FPGA】之乘法器
fpga开发
SunshineBooming21 小时前
DirectX12 - 基本知识 - 图形驱动的本质
c++·驱动开发
anhuihbo1 天前
XILINX FPGA万兆光电口PXIE板卡设计
fpga开发
碎碎思1 天前
国产FPGA搭建的复古游戏平台
游戏·fpga开发