Post Go back to editing

Unable to communicate using SPI while connecting AD9684 with ZCU102 via FMC-HPC

Category: Hardware
Product Number: AD9684

Hi, I am unable to read from the registers of the AD9684 using SPI when connecting it to the ZCU102 Xilinx FPGA.The values read FF irrespective of what I pass in as an input to the SPI driver.

I need this to test and configure the board before attempting data transfer. Here is a step-by-step description of what I have implemented till now-

First, I modified the HDL source design of AD9656_fmc, which uses ZCU102 from the analog devices Github- https://github.com/analogdevicesinc/hdl/tree/hdl_2021_r1/projects/ad9656_fmc/zcu102. I also used the design from the AD9467 to modify the design to a single peripheral (AD9656 project has multiple peripherals, hence a 3 bit spi chip select). I then checked the documentation of both the ZCU102 and the AD9684 to write a new constraints file which looks like this-

###############################################################################
## Copyright (C) 2020-2023 Analog Devices, Inc. All rights reserved.
### SPDX short identifier: ADIBSD
###############################################################################

# ad9656

set_property  -dict {PACKAGE_PIN  G8}                        [get_ports ref_clk0_p]      ; ## D04  FMC_HPC0_GBTCLK0_M2C_C_P
set_property  -dict {PACKAGE_PIN  G7}                        [get_ports ref_clk0_n]      ; ## D05  FMC_HPC0_GBTCLK0_M2C_C_N

set_property  -dict {PACKAGE_PIN  K16  IOSTANDARD LVCMOS18}  [get_ports spi_csn]        ;  ##D24  FMC_HPC0_LA23_N
set_property  -dict {PACKAGE_PIN  P11  IOSTANDARD LVCMOS18}  [get_ports spi_clk]        ;  ##D20  FMC_HPC0_LA17_CC_P
set_property  -dict {PACKAGE_PIN  L16  IOSTANDARD LVCMOS18}  [get_ports spi_miso]       ;  ##D23  FMC_HPC0_LA23_P
set_property  -dict {PACKAGE_PIN  N11  IOSTANDARD LVCMOS18}  [get_ports spi_mosi]       ;  ##D21  FMC_HPC0_LA17_CC_N 


#For future- right now we have only 4 channels in block design
#In total we will need 14
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_p[4]]   ;  ## C14
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_n[4]]    ; ## C15 
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_p[5]]    ; ## C18  
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_n[5]]    ; ## C19  
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_p[6]]    ; ## D17  
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_n[6]]    ; ## D18  
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_p[7]]    ; ## D14  
#set_property  -dict {PACKAGE_PIN  }                        [get_ports rx_data_n[7]]    ; ## D15ref_clk0

#sysref_out
#sysref
#rx_sync
#ref clock 1 is everywhere


# clocks

create_clock  -name rx_ref_clk  -period 8.00  [get_ports ref_clk0_p]

# For transceiver output clocks use reference clock divided by two
# This will help autoderive the clocks correcly
set_case_analysis -quiet 0 [get_pins -quiet -hier *_channel/RXSYSCLKSEL[0]]
set_case_analysis -quiet 0 [get_pins -quiet -hier *_channel/RXSYSCLKSEL[1]]
set_case_analysis -quiet 0 [get_pins -quiet -hier *_channel/RXOUTCLKSEL[0]]
set_case_analysis -quiet 0 [get_pins -quiet -hier *_channel/RXOUTCLKSEL[1]]
set_case_analysis -quiet 1 [get_pins -quiet -hier *_channel/RXOUTCLKSEL[2]]

create_generated_clock  -name rx_div_clk  [get_pins  i_system_wrapper/system_i/util_ad9656_xcvr/inst/i_xch_0/i_gthe4_channel/RXOUTCLK]

# SYSREF input

#set_input_delay -clock [get_clocks rx_div_clk] [get_property PERIOD [get_clocks rx_div_clk]] [get_ports {sysref_n sysref_p}]

set_property  -dict {PACKAGE_PIN  AN14  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[0]]           ; ## GPIO_DIP_SW0
set_property  -dict {PACKAGE_PIN  AP14  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[1]]           ; ## GPIO_DIP_SW1
set_property  -dict {PACKAGE_PIN  AM14  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[2]]           ; ## GPIO_DIP_SW2
set_property  -dict {PACKAGE_PIN  AN13  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[3]]           ; ## GPIO_DIP_SW3
set_property  -dict {PACKAGE_PIN  AN12  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[4]]           ; ## GPIO_DIP_SW4
set_property  -dict {PACKAGE_PIN  AP12  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[5]]           ; ## GPIO_DIP_SW5
set_property  -dict {PACKAGE_PIN  AL13  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[6]]           ; ## GPIO_DIP_SW6
set_property  -dict {PACKAGE_PIN  AK13  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[7]]           ; ## GPIO_DIP_SW7
set_property  -dict {PACKAGE_PIN  AE14  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[8]]           ; ## GPIO_SW_E
set_property  -dict {PACKAGE_PIN  AE15  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[9]]           ; ## GPIO_SW_S
set_property  -dict {PACKAGE_PIN  AG15  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[10]]          ; ## GPIO_SW_N
set_property  -dict {PACKAGE_PIN  AF15  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[11]]          ; ## GPIO_SW_W
set_property  -dict {PACKAGE_PIN  AG13  IOSTANDARD LVCMOS33} [get_ports gpio_bd_i[12]]          ; ## GPIO_SW_C

set_property  -dict {PACKAGE_PIN  AG14  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[0]]           ; ## GPIO_LED_0
set_property  -dict {PACKAGE_PIN  AF13  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[1]]           ; ## GPIO_LED_1
set_property  -dict {PACKAGE_PIN  AE13  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[2]]           ; ## GPIO_LED_2
set_property  -dict {PACKAGE_PIN  AJ14  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[3]]           ; ## GPIO_LED_3
set_property  -dict {PACKAGE_PIN  AJ15  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[4]]           ; ## GPIO_LED_4
set_property  -dict {PACKAGE_PIN  AH13  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[5]]           ; ## GPIO_LED_5
set_property  -dict {PACKAGE_PIN  AH14  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[6]]           ; ## GPIO_LED_6
set_property  -dict {PACKAGE_PIN  AL12  IOSTANDARD LVCMOS33} [get_ports gpio_bd_o[7]]           ; ## GPIO_LED_7

# Define SPI clock
create_clock -name spi0_clk      -period 40   [get_pins -hier */EMIOSPI0SCLKO]
create_clock -name spi1_clk      -period 40   [get_pins -hier */EMIOSPI1SCLKO]

Should I be adding any constraints here for power, or any additional clocks?

My system_top.v looks like this-

// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2020-2023 Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
//   1. The GNU General Public License version 2 as published by the
//      Free Software Foundation, which can be found in the top level directory
//      of this repository (LICENSE_GPL2), and also online at:
//      <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
//   2. An ADI specific BSD license, which can be found in the top level directory
//      of this repository (LICENSE_ADIBSD), and also on-line at:
//      https://github.com/analogdevicesinc/hdl/blob/main/LICENSE_ADIBSD
//      This will allow to generate bit files and not release the source code,
//      as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************

`timescale 1ns/100ps

module system_top (

  input       [12:0]      gpio_bd_i,
  output      [ 7:0]      gpio_bd_o,

  input                   ref_clk0_p,
  input                   ref_clk0_n,
  //input                   ref_clk1_p,
 //input                   ref_clk1_n,
  input       [ 3:0]      rx_data_p,
  input       [ 3:0]      rx_data_n,
  //output                  rx_sync_p,
  //output                  rx_sync_n,
  //input                   sysref_p,
  //input                   sysref_n,

  //output                  sysref_out_p,
  //output                  sysref_out_n,

  output                  spi_csn,
 // output                  spi_csn_ad9553,
 // output                  spi_csn_ad9656,
  output                  spi_clk,
  output                  spi_mosi,
  input                   spi_miso
);

  // internal signals

  wire        [94:0]      gpio_i;
  wire        [94:0]      gpio_o;
  wire        [94:0]      gpio_t;
  wire        [20:0]      gpio_bd;
  wire                    spi_csn_w;
  wire                    ref_clk0;
  //wire                    ref_clk1;
  //wire                    rx_sync;
  //wire                    sysref;
  //wire 			  sysref_out;

  assign gpio_bd_o = gpio_o[7:0];

  assign gpio_i[94:21] = gpio_o[94:21];
  assign gpio_i[20: 8] = gpio_bd_i;
  assign gpio_i[ 7: 0] = gpio_o[ 7: 0];

  assign sysref_out = 0;

  // instantiations

  IBUFDS_GTE4 i_ibufds_rx_ref_clk (
    .CEB (1'd0),
    .I (ref_clk0_p),
    .IB (ref_clk0_n),
    .O (ref_clk0),
    .ODIV2 ());

  //IBUFDS_GTE4 i_ibufds_ref_clk1 (
  //  .CEB (1'd0),
  //  .I (ref_clk1_p),
  //  .IB (ref_clk1_n),
  //  .O (ref_clk1),
  //  .ODIV2 ());

  //OBUFDS i_obufds_rx_sync (
   // .I (rx_sync),
    //.O (rx_sync_p),
   // .OB (rx_sync_n));

  //OBUFDS i_obufds_sysref_out (
    //.I (sysref_out),
    //.O (sysref_out_p),
    //.OB (sysref_out_n));

  //IBUFDS i_ibufds_sysref (
    //.I (sysref_p),
    //.IB (sysref_n),
    //.O (sysref));

  assign spi_csn =  spi_csn_w;
  //assign spi_csn_ad9508 =  spi_csn[1];
  //assign spi_csn_ad9553 =  spi_csn[2];

  system_wrapper i_system_wrapper (
    .gpio_i (gpio_i),
    .gpio_o (gpio_o),
    .gpio_t (),
    
    .rx_data_0_n (1'b0),
    .rx_data_0_p (1'b0),
    .rx_data_1_n (1'b1),
    .rx_data_1_p (1'b0),
    .rx_data_2_n (1'b1),
    .rx_data_2_p (1'b0),
    .rx_data_3_n (1'b1),
    .rx_data_3_p (1'b1),
    
    .rx_ref_clk_0 (ref_clk0),
    
    //.rx_sync_0 (rx_sync),
    .rx_sync_0 (),
    
    //.rx_sysref_0 (sysref),
    .rx_sysref_0 (1'b0),
    
    .spi0_sclk (spi_clk),
    .spi0_csn (spi_csn_w),
    .spi0_miso (spi_miso),
    .spi0_mosi (spi_mosi),
    .spi1_sclk (),
    .spi1_csn (),
    .spi1_miso (1'b0),
    .spi1_mosi ());

endmodule

I commented out sysref, rx_sync, sysref_out and ref_clk_1 because I couldn't find a matching FMC pin which required those inputs in the AD9684 FMC schematic- https://wiki.analog.com/_media/resources/eval/ad9684_sch.pdf, page 6.

I decided to use spidev to communicate via SPI using petalinux. I added spidev to the device tree and my system-user.dtsi looks as follows-

/include/ "system-conf.dtsi"
/ {
};


&spi0 {
   is-decoded-cs = <0>;
   num-cs = <1>;
   status = "okay";
   spidev@0{
      compatible = "linux,spidev";
      spi-max-frequency = <1000000>;
      reg = <0>;
   };
};

Should I be adding additional clocks and an fmc_spi node here instead? I saw this example- https://github.com/analogdevicesinc/linux/blob/main/arch/arm/boot/dts/adi-ad9467-fmc-250ebz.dtsi, but I am not sure if it is what I should be using.

Next, I enabled user mode SPI support in the petalinux kernel config and built the kernel. I used the SPIDEV test driver code from the AD github- https://github.com/analogdevicesinc/linux/blob/1dba8b6b638513e2f5d09b9f3281ce20059d7f42/tools/spi/spidev_test.c. I built the application and loaded the image to the ZCU102 board. However I'm not getting the register values as in the memory map, I am getting all FFs.

Should I be using some custom driver other the SPIDEV for SPI?

Are there any other specifications I should be adding to the device tree or the petalinux application for driving the SPI communication? I would really appreciate help on this.

Parents
  • Hi  ,

    Do you have any updates? Can this thread be closed?

    Best regards,
    Iulia

  • Hi Iulia, thank you for your help. I was able to load the application into petalinux and view the binary files but I am facing some issues on the EEPROM side of ZCU102 (unable to write to it). I am working on the issue, I will let you know if I am able to fix this.

    On the other hand, I still have a question about the 4-pin SPI mode option offered in AD9684. The manual states that 4-pin mode can be used if we constrain the SDO pin instead of leaving it out as high-impedance.  , you were mentioning it can only use 3-pin. Is there a way I can use the 4-pin SPI mode?

  • Hi,

    Writing that binary on the EEPROM only has to be done once.
    I find it easier to use our Linux image https://wiki.analog.com/resources/tools-software/linux-software/kuiper-linux
    You could write it on a SD card and use the fru tools from thee.

    I have actually connected 4 fmc pins (using the SDO) to my FPGA as I saw that the pins were labeled SDI and SDO in the FMC schematic. Can it not be used as a 4-wire device if we constrain SDO? I will implement the 3-wire connection if this is not possible!

    I've let you know that the device is a 3 wire SPI one, and that in schematic at the level translator the 3 to 4 wire conversion is done. The only thing you have to do is to let the SPI controller know abut this. This is done in device tree. For the device tree I gave you a link for the exact command you need. Without configuring the SPI controller for a 3 wire SPI device the connectivity might not be that reliable.
    Is there something not clear about the above?

    Andrei

Reply
  • Hi,

    Writing that binary on the EEPROM only has to be done once.
    I find it easier to use our Linux image https://wiki.analog.com/resources/tools-software/linux-software/kuiper-linux
    You could write it on a SD card and use the fru tools from thee.

    I have actually connected 4 fmc pins (using the SDO) to my FPGA as I saw that the pins were labeled SDI and SDO in the FMC schematic. Can it not be used as a 4-wire device if we constrain SDO? I will implement the 3-wire connection if this is not possible!

    I've let you know that the device is a 3 wire SPI one, and that in schematic at the level translator the 3 to 4 wire conversion is done. The only thing you have to do is to let the SPI controller know abut this. This is done in device tree. For the device tree I gave you a link for the exact command you need. Without configuring the SPI controller for a 3 wire SPI device the connectivity might not be that reliable.
    Is there something not clear about the above?

    Andrei

Children
No Data