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.