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)

相关推荐
unicrom_深圳市由你创科技2 小时前
高帧率机器视觉 FPGA 图像板卡及传输开发定制解决方案
fpga开发
万物智能信息科技3 小时前
LoRa串口透传驱动开发—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
驱动开发·嵌入式硬件·华为·开源·harmonyos
幻智星科技19 小时前
纯FPGA网络通信实现微秒级确定性延迟
网络协议·fpga开发·硬件架构
泡泡糖的中文规格书20 小时前
HDLbits 1.5 学习笔记
fpga开发
幻智星科技1 天前
FPGA不同品牌开发平台约束文件迁移难题解析
fpga开发·架构·硬件架构
Keith Guo1 天前
Event Task Matrix(ETM)工作机制
驱动开发·esp32·etm
幻智星科技1 天前
Karatsuba与CSD优化FPGA大数乘法
c++·fpga开发·密码学
星夜离尘561 天前
FPGA 实战:W1C 中断状态寄存器,事件置位与软件清除撞在同一拍怎么办
fpga开发
像枫一样1 天前
STM32串口轮询收发实战教程
arm开发·c++·stm32·单片机·嵌入式硬件·fpga开发·51单片机
传感器与混合集成电路1 天前
DLM8676计数控制集成电路DC-DC一体化与RS422隔离接口设计
fpga开发