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原语
参考博客: