Post Go back to editing

IP Core Issue, rst output stuck High

Category: Hardware
Product Number: AD9364

Hi, 
I'm using an AD9364 on a custom PCB, I programmed it with the No-Os Software implemented on a Digilent Zybo (Zynq7020). 
The custom transceiver board I use output the baseband I/Q serialized on only one LVDS pair. (the rx_frame and rx_clk_in signal are also LVDS) 
What I did then was to add a new source called : axi_ad9361_custom_if.v 

Basically what I want to do is to implement a ISERDES primitive (ILOGICE3 primitive from Zynq7) so that the rx data path with look like : IBUFDS -> IDELAYE -> ISERDES (DDR or SDR) (by doing so all should be located in just one Tile of the SoC.)
exept for the rx data path the other signal path remain unchanged from the LVDS interface ( meaning using ad_data_in, ad_data_out, ad_data_clk). 
I also made changes  on the rx_clk_in because it is 6 time faster than the LVDS data clock should be because of the serialization, so Iimplemented a PLL (also tried with MMCM) to have my l_clk back to right output rate. 

Now the issue I have is that the output rst out the IP core is stuck high. It is generetad from the up_core_preset, meaning the ADC_RST_REGISTER bit[0] which is enabled and disabled correctly in the adc_init function of the No-Os driver. 

Please find attach a snippet of the custom intefarce I made from the axi_ad9361_lvds_if.v 

// ***************************************************************************
// **************************************************************************
// Custom interface with integrated IBUF->IDELAYE2->ISERDES
// ***************************************************************************
// ***************************************************************************

// =========================================================================
// ad_data_clk.v
// =========================================================================
  generate
  begin

  ad_data_clk #(
    .SINGLE_ENDED (0)
  ) i_clk (
    .rst (1'd0),
    .locked (),
    .clk_in_p (rx_clk_in_p),
    .clk_in_n (rx_clk_in_n),
    .clk (rx_clk_in));
  end
  endgenerate


// =========================================================================
// CUSTOM RX DATA PATH
// =========================================================================
wire clk_48mhz_raw;      // Horloge série 48 MHz
wire clk_8mhz_raw;       // Horloge intermédiaire 8 MHz
wire clk_48mhz;          // Horloge 48 MHz après BUFG
wire clk_8mhz;           // Horloge 8 MHz après BUFG
wire pll_locked;

// Génération des horloges avec MMCM ou PLL selon la configuration
generate
  if (ELIOT_CLK_PLL_OR_MMCM_N == 0) begin : gen_mmcm

    wire clk_fb;

    MMCME2_ADV #(
      .BANDWIDTH("OPTIMIZED"),
      .CLKFBOUT_MULT_F(32.0),         // VCO = 24 * 32 = 768 MHz
      .DIVCLK_DIVIDE(1),
      .CLKIN1_PERIOD(41.667),         // 24 MHz input
      .CLKOUT0_DIVIDE_F(16.0),        // 768/16 = 48 MHz (horloge série)
      .CLKOUT1_DIVIDE(96),            // 768/96 = 8 MHz (horloge intermédiaire)
      .CLKOUT0_DUTY_CYCLE(0.5),
      .CLKOUT1_DUTY_CYCLE(0.5),
      .CLKOUT0_PHASE(0.0),
      .CLKOUT1_PHASE(0.0),
      .COMPENSATION("ZHOLD"),
      .STARTUP_WAIT("FALSE"),
      .REF_JITTER1(0.010)
    ) mmcm_inst (
      .CLKIN1(rx_clk_in),                 // 24 MHz depuis rx_clk_in
      .CLKIN2(1'b0),
      .CLKINSEL(1'b1),
      .CLKFBIN(clk_fb),
      .CLKFBOUT(clk_fb),
      .CLKOUT0(clk_48mhz_raw),        // 48 MHz
      .CLKOUT1(clk_8mhz_raw),         // 8 MHz
      .LOCKED(pll_locked),
      .PWRDWN(1'b0),
      .RST(pll_rst),
      .CLKFBOUTB(),
      .CLKOUT0B(),
      .CLKOUT1B(),
      .CLKOUT2(),
      .CLKOUT2B(),
      .CLKOUT3(),
      .CLKOUT3B(),
      .CLKOUT4(),
      .CLKOUT5(),
      .CLKOUT6(),
      .CLKINSTOPPED(),
      .CLKFBSTOPPED(),
      .DADDR(7'h0),
      .DCLK(1'b0),
      .DEN(1'b0),
      .DI(16'h0),
      .DO(),
      .DRDY(),
      .DWE(1'b0),
      .PSCLK(1'b0),
      .PSEN(1'b0),
      .PSINCDEC(1'b0),
      .PSDONE()
    );

  end else begin : gen_pll

    wire clk_fb;

    PLLE2_ADV #(
      .BANDWIDTH("OPTIMIZED"),
      .CLKFBOUT_MULT(32),             // VCO = 24 * 32 = 768 MHz
      .DIVCLK_DIVIDE(1),
      .CLKIN1_PERIOD(41.667),
      .CLKOUT0_DIVIDE(16),            // 768/16 = 48 MHz
      .CLKOUT1_DIVIDE(96),            // 768/96 = 8 MHz
      .CLKOUT0_DUTY_CYCLE(0.5),
      .CLKOUT1_DUTY_CYCLE(0.5),
      .CLKOUT0_PHASE(0.0),
      .CLKOUT1_PHASE(0.0),
      .COMPENSATION("ZHOLD"),
      .STARTUP_WAIT("FALSE"),
      .REF_JITTER1(0.010)
    ) pll_inst (
      .CLKIN1(rx_clk_in),
      .CLKIN2(1'b0),
      .CLKINSEL(1'b1),
      .CLKFBIN(clk_fb),
      .CLKFBOUT(clk_fb),
      .CLKOUT0(clk_48mhz_raw),
      .CLKOUT1(clk_8mhz_raw),
      .LOCKED(pll_locked),
      .PWRDWN(1'b0),
      .RST(pll_rst),
      .CLKOUT2(),
      .CLKOUT3(),
      .CLKOUT4(),
      .CLKOUT5(),
      .DADDR(7'h0),
      .DCLK(1'b0),
      .DEN(1'b0),
      .DI(16'h0),
      .DO(),
      .DRDY(),
      .DWE(1'b0)
    );

  end
endgenerate


BUFG bufg_48mhz (
  .I(clk_48mhz_raw),
  .O(clk_48mhz)
);

BUFG bufg_8mhz (
  .I(clk_8mhz_raw),
  .O(clk_8mhz)
);

// 8 MHz -> 4 MHz
reg clk_4mhz_reg;
always @(posedge clk_8mhz or posedge rst) begin
  if (rst)
    clk_4mhz_reg <= 1'b0;
  else
    clk_4mhz_reg <= ~clk_4mhz_reg;
end
wire clk_4mhz;
BUFG bufg_4mhz (
  .I(clk_4mhz_reg),
  .O(clk_4mhz)
);

// 8 MHz -> 2 MHz
reg [1:0] clk_2mhz_reg;
always @(posedge clk_8mhz or posedge rst) begin
  if (rst)
    clk_2mhz_reg <= 2'b0;
  else if (clk_2mhz_reg == 2'd3)
    clk_2mhz_reg <= 2'b0;
  else
    clk_2mhz_reg <= clk_2mhz_reg + 1;
end

wire clk_2mhz_raw;  // Signal brut avant le BUFG
assign clk_2mhz_raw = (clk_2mhz_reg == 2'd0) ? clk_8mhz : 1'b0;

wire clk_2mhz;  // Signal après le BUFG
BUFG bufg_2mhz (
  .I(clk_2mhz_raw),
  .O(clk_2mhz)
);

// =========================================================================
// Rx Data path : IBUFDS -> IDELAYE -> ISERDES
// =========================================================================

// IBUFDS - Input Buffer
wire rx_data_ibuf;
IBUFDS i_rx_data_ibuf (
  .I(rx_data_in_eliot_p),
  .IB(rx_data_in_eliot_n),
  .O(rx_data_ibuf)
);

// IDELAYE2 - Input Delay
wire rx_data_idelay;
(* IODELAY_GROUP = IO_DELAY_GROUP *)
IDELAYE2 #(
  .CINVCTRL_SEL("FALSE"),
  .DELAY_SRC("IDATAIN"),
  .HIGH_PERFORMANCE_MODE("TRUE"),
  .IDELAY_TYPE("VAR_LOAD"),
  .IDELAY_VALUE(0),
  .REFCLK_FREQUENCY(DELAY_REFCLK_FREQUENCY),
  .PIPE_SEL("FALSE"),
  .SIGNAL_PATTERN("DATA")
) i_rx_data_idelay (
  .C(up_clk),
  .IDATAIN(rx_data_ibuf),
  .DATAOUT(rx_data_idelay),
  .LD(up_adc_dld[0]),
  .CNTVALUEIN(up_adc_dwdata[4:0]),
  .CNTVALUEOUT(up_adc_drdata[4:0]),
  .CE(1'b0),
  .INC(1'b0),
  .DATAIN(1'b0),
  .LDPIPEEN(1'b0),
  .CINVCTRL(1'b0),
  .REGRST(1'b0)
);


// ISERDESE2 - Désérialiseur SDR
wire [5:0] iserdes_q;

ISERDESE2 #(
  .DATA_RATE("SDR"),
  .DATA_WIDTH(6),
  .INTERFACE_TYPE("NETWORKING"),
  .NUM_CE(1),
  .SERDES_MODE("MASTER"),
  .IOBDELAY("IFD")
) i_rx_data_iserdes (
  .D(1'b0),
  .DDLY(rx_data_idelay),
  .CLK(clk_48mhz),
  .CLKB(~clk_48mhz),
  .CLKDIV(clk_4mhz),
  .CE1(1'b1),
  .CE2(1'b1),
  .RST(rst),
  .Q1(iserdes_q[0]),
  .Q2(iserdes_q[1]),
  .Q3(iserdes_q[2]),
  .Q4(iserdes_q[3]),
  .Q5(iserdes_q[4]),
  .Q6(iserdes_q[5]),
  .SHIFTIN1(1'b0),
  .SHIFTIN2(1'b0),
  .SHIFTOUT1(),
  .SHIFTOUT2(),
  .CLKDIVP(1'b0),
  .OCLK(1'b0),
  .OCLKB(1'b0),
  .BITSLIP(1'b0),
  .OFB(1'b0),
  .DYNCLKDIVSEL(1'b0),
  .DYNCLKSEL(1'b0)
);

// =========================================================================
// ISERDES -> Divide /2 -> AD9361 data type
// =========================================================================

reg [5:0] iserdes_q_reg;
always @(posedge clk_4mhz) begin
  if (rst)
    iserdes_q_reg <= 6'b0;
  else
    iserdes_q_reg <= iserdes_q;
end

reg [5:0] sample_phase0;    // First sample in 2MHz period
reg [5:0] sample_phase1;    // Second sample in 2MHz period
reg phase;                  // Phase

always @(posedge clk_4mhz) begin
  if (rst) begin
    sample_phase0 <= 6'b0;
    sample_phase1 <= 6'b0;
    phase <= 1'b0;
  end else begin
    if (phase == 1'b0) begin
      sample_phase0 <= iserdes_q_reg;
      phase <= 1'b1;
    end else begin
      sample_phase1 <= iserdes_q_reg;
      phase <= 1'b0;
    end
  end
end

reg [5:0] rx_data_2mhz_p;
reg [5:0] rx_data_2mhz_n;

always @(posedge clk_2mhz) begin
  if (rst) begin
    rx_data_2mhz_p <= 6'b0;
    rx_data_2mhz_n <= 6'b0;
  end else begin
    // Échantillonner au milieu de la période stable
    rx_data_2mhz_p <= sample_phase1;  // "P" side (bits pairs ou MSB)
    rx_data_2mhz_n <= sample_phase0;  // "N" side (bits impairs ou LSB)
  end
end


 assign rx_data_1_s = rx_data_2mhz_p;
 assign rx_data_0_s = rx_data_2mhz_n;

// =========================================================================
// FRAME PATH (Unchanged from lvds interface )
// =========================================================================

// receive frame interface, ibuf -> idelay -> iddr

  ad_data_in #(
    .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
    .IODELAY_CTRL (IODELAY_CTRL),
    .IODELAY_GROUP (IO_DELAY_GROUP),
    .REFCLK_FREQUENCY (DELAY_REFCLK_FREQUENCY)
  ) i_rx_frame (
    .rx_clk (rx_clk_in),
    .rx_data_in_p (rx_frame_in_p),
    .rx_data_in_n (rx_frame_in_n),
    .rx_data_p (rx_frame_s[1]),
    .rx_data_n (rx_frame_s[0]),
    .up_clk (up_clk),
    .up_dld (up_adc_dld[6]),
    .up_dwdata (up_adc_dwdata[34:30]),
    .up_drdata (up_adc_drdata[34:30]),
    .delay_clk (delay_clk),
    .delay_rst (delay_rst),
    .delay_locked (locked_s));


  // =========================================================================
  // TX PATH: Use standard ad_data_out modules (unchanged)
  // =========================================================================

  // transmit data interface, oddr -> obuf
  genvar i;
  generate
  for (i = 0; i < 6; i = i + 1) begin: g_tx_data
  ad_data_out #(
    .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
    .IODELAY_ENABLE (DAC_IODELAY_ENABLE),
    .IODELAY_CTRL (0),
    .IODELAY_GROUP (IO_DELAY_GROUP),
    .REFCLK_FREQUENCY (DELAY_REFCLK_FREQUENCY)
  ) i_tx_data (
    .tx_clk (l_clk),
    .tx_data_p (tx_data_1[i]),
    .tx_data_n (tx_data_0[i]),
    .tx_data_out_p (tx_data_out_p[i]),
    .tx_data_out_n (tx_data_out_n[i]),
    .up_clk (up_clk),
    .up_dld (up_dac_dld[i]),
    .up_dwdata (up_dac_dwdata[((i*5)+4):(i*5)]),
    .up_drdata (up_dac_drdata[((i*5)+4):(i*5)]),
    .delay_clk (delay_clk),
    .delay_rst (delay_rst),
    .delay_locked ());
  end
  endgenerate

  // transmit frame interface, oddr -> obufparameter   DDR_SDR_N = 1,

  ad_data_out #(
    .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
    .IODELAY_ENABLE (DAC_IODELAY_ENABLE),
    .IODELAY_CTRL (0),
    .IODELAY_GROUP (IO_DELAY_GROUP),
    .REFCLK_FREQUENCY (DELAY_REFCLK_FREQUENCY)
  ) i_tx_frame (
    .tx_clk (l_clk),
    .tx_data_p (tx_frame),
    .tx_data_n (tx_frame),
    .tx_data_out_p (tx_frame_out_p),
    .tx_data_out_n (tx_frame_out_n),
    .up_clk (up_clk),
    .up_dld (up_dac_dld[6]),
    .up_dwdata (up_dac_dwdata[34:30]),
    .up_drdata (up_dac_drdata[34:30]),
    .delay_clk (delay_clk),
    .delay_rst (delay_rst),
    .delay_locked ());

// transmit clock interface, oddr -> obuf

  ad_data_out #(
    .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
    .IODELAY_ENABLE (DAC_IODELAY_ENABLE),
    .IODELAY_CTRL (0),
    .IODELAY_GROUP (IO_DELAY_GROUP),
    .REFCLK_FREQUENCY (DELAY_REFCLK_FREQUENCY)
  ) i_tx_clk (
    .tx_clk (l_clk),
    .tx_data_p (tx_clk[1]),
    .tx_data_n (tx_clk[0]),
    .tx_data_out_p (tx_clk_out_p),
    .tx_data_out_n (tx_clk_out_n),
    .up_clk (up_clk),
    .up_dld (up_dac_dld[7]),
    .up_dwdata (up_dac_dwdata[39:35]),
    .up_drdata (up_dac_drdata[39:35]),
    .delay_clk (delay_clk),
    .delay_rst (delay_rst),
    .delay_locked ());

  // enable, oddr -> obuf

  ad_data_out #(
    .SINGLE_ENDED (1),
    .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
    .IODELAY_ENABLE (DAC_IODELAY_ENABLE),
    .IODELAY_CTRL (0),
    .IODELAY_GROUP (IO_DELAY_GROUP),
    .REFCLK_FREQUENCY (DELAY_REFCLK_FREQUENCY)
  ) i_enable (
    .tx_clk (l_clk),
    .tx_data_p (enable_int_p),
    .tx_data_n (enable_int_p),
    .tx_data_out_p (enable),
    .tx_data_out_n (),
    .up_clk (up_clk),
    .up_dld (up_dac_dld[8]),
    .up_dwdata (up_dac_dwdata[44:40]),
    .up_drdata (up_dac_drdata[44:40]),
    .delay_clk (delay_clk),
    .delay_rst (delay_rst),
    .delay_locked ());

  // txnrx, oddr -> obuf

  ad_data_out #(
    .SINGLE_ENDED (1),
    .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
    .IODELAY_ENABLE (DAC_IODELAY_ENABLE),
    .IODELAY_CTRL (0),
    .IODELAY_GROUP (IO_DELAY_GROUP),
    .REFCLK_FREQUENCY (DELAY_REFCLK_FREQUENCY)
  ) i_txnrx (
    .tx_clk (l_clk),
    .tx_data_p (txnrx_int_p),
    .tx_data_n (txnrx_int_p),
    .tx_data_out_p (txnrx),
    .tx_data_out_n (),
    .up_clk (up_clk),
    .up_dld (up_dac_dld[9]),
    .up_dwdata (up_dac_dwdata[49:45]),
    .up_drdata (up_dac_drdata[49:45]),
    .delay_clk (delay_clk),
    .delay_rst (delay_rst),
    .delay_locked ());


   //========= Moved Before PLL (exept l_clk assign ) ==========//
 /*
  // ad_data_clk.v
  generate if (USE_SSI_CLK == 1) begin

  ad_data_clk #(
    .SINGLE_ENDED (0)
  ) i_clk (
    .rst (1'd0),
    .locked (),
    .clk_in_p (rx_clk_in_p),
    .clk_in_n (rx_clk_in_n),
    .clk (rx_clk_in));

     assign l_clk = clk_4mhz;
  end else begin
    assign l_clk = clk;
  end

  endgenerate
 */

 assign l_clk = (USE_SSI_CLK == 1) ? clk_4mhz : clk;

endmodule

Parents
  • HI  

    • Check PLL/MMCM Lock Status:
      • Probe pll_locked using ILA or LEDs to confirm it's high.
      • If not, verify input clock frequency and MMCM/PLL configuration.
    • Verify ADC_RST_REGISTER propagation:
      • Use ILA to monitor ADC_RST_REGISTER and up_core_preset.
      • Ensure the reset signal is synchronized across clock domains.
    • Confirm USE_SSI_CLK is set to 1:
      • If you're using the custom clock path, ensure this parameter is correctly defined and propagated.
    • Check for stuck signals in simulation or hardware:
      • Use Vivado simulation or ILA to trace rst, pll_locked, and ADC_RST_REGISTER.

    Regards,

    SJ

  • Hello, so I solve my problème, the thing was that the adc_rst was generated through an clk=l_clk event process and this local clock was generated  y a process reset by the adc_rst.
    Now I think I have to synchronise the rx_frame signal to the l_clk domain because for now It's synchronise to rx_clk_in in ad_data_in module 

Reply
  • Hello, so I solve my problème, the thing was that the adc_rst was generated through an clk=l_clk event process and this local clock was generated  y a process reset by the adc_rst.
    Now I think I have to synchronise the rx_frame signal to the l_clk domain because for now It's synchronise to rx_clk_in in ad_data_in module 

Children
No Data