Hello Team, srimoyi
We are using Kuiper Linux drivers for ZCU102 with Fmcomms8. We are able to change LO using iio_attr and sysfs. For this test, phases for the 2 chips are getting maintained in multiple powerons with +/- 2.5 degree changes from poweron to poweron. The time taken for this is around 400ms for each chip.
When we wrote a shell script for the FHM. Hopping seems to be there but the phases are changing with each poweron as well as each run. This shell script takes around 50ms for each chip to hop between frequencies.
Next we used the python script mentioned in the following forum post:
IIO Usage: Multi-Chip Sync (MCS) in Frequency Hopping (FHM) Mode using GPIO pin trigger - Q&A - Design Support ADRV9008-1/ADRV9008-2/ADRV9009 - EngineerZone (analog.com)
Since we are using ZCU102 instead of ZU11EG, I modified the code as below:
# Copyright (C) 2019 Analog Devices, Inc. # # SPDX short identifier: ADIBSD import time import adi import matplotlib.pyplot as plt import numpy as np from scipy import signal import random def measure_phase(chan0, chan1): errorV = np.angle(chan0 * np.conj(chan1)) * 180 / np.pi error = np.mean(errorV) return error # Plot config plot_time_domain = False # Use FHM fhm = True # Create radio sdr = adi.adrv9009_zu11eg_fmcomms8 (uri="ip:10.0.0.206") #changed IP and also used adrv900_zu11eg_fmcomms8 instead of adrv9009_zu11eg sdr._rxadc.set_kernel_buffers_count(1) #devices are named as chip_c and chip_d so changed the names in the below properties # Configure properties sdr.rx_enabled_channels = [0, 1, 2, 3] sdr.tx_enabled_channels = [0, 1] sdr.trx_lo_chip_c = 2000000000 sdr.trx_lo_chip_d = 2000000000 sdr.tx_hardwaregain_chan0_chip_c = -10 sdr.tx_hardwaregain_chan1_chip_c = -10 sdr.tx_hardwaregain_chan0_chip_d = -10 sdr.tx_hardwaregain_chan1_chip_d = -10 sdr.gain_control_mode_chan0_chip_c = "slow_attack" sdr.gain_control_mode_chan1_chip_c = "slow_attack" sdr.gain_control_mode_chan0_chip_d = "slow_attack" sdr.gain_control_mode_chan1_chip_d = "slow_attack" sdr.rx_buffer_size = 2 ** 14 if fhm: # setr devicetree power up TRX lo frequency for all devices sdr.set_trx_lo_frequency = 2500000000 # Setup FHM print("setting up FHM Chip A") print("Setting FHM trigger to SPI") sdr._ctrl_c.debug_attrs["adi,fhm-mode-fhm-trigger-mode"].value = "1" print("Setting FHM init frequency") sdr._ctrl_c.debug_attrs["adi,fhm-mode-fhm-init-frequency_hz"].value = "2450000000" print("Setting FHM Min frequency") sdr._ctrl_c.debug_attrs["adi,fhm-config-fhm-min-freq_mhz"].value = "200" print("Setting FHM Max frequency") sdr._ctrl_c.debug_attrs["adi,fhm-config-fhm-max-freq_mhz"].value = "6000" print("Set MCS+FHM") sdr._ctrl_c.debug_attrs["adi,fhm-mode-enable-mcs-sync"].value = "1" sdr._ctrl_c.debug_attrs["adi,fhm-config-fhm-gpio-pin"].value = "8" print("setting up FHM Chip B") print("Setting FHM trigger to SPI") sdr._ctrl_d.debug_attrs["adi,fhm-mode-fhm-trigger-mode"].value = "1" print("Setting FHM init frequency") sdr._ctrl_d.debug_attrs["adi,fhm-mode-fhm-init-frequency_hz"].value = "245000000" print("Setting FHM Min frequency") sdr._ctrl_d.debug_attrs["adi,fhm-config-fhm-min-freq_mhz"].value = "200" print("Setting FHM Max frequency") sdr._ctrl_d.debug_attrs["adi,fhm-config-fhm-max-freq_mhz"].value = "5000" print("Set MCS+FHM") sdr._ctrl_d.debug_attrs["adi,fhm-mode-enable-mcs-sync"].value = "1" sdr._ctrl_d.debug_attrs["adi,fhm-config-fhm-gpio-pin"].value = "8" #print("Syncing") # this will renitialize both ADRV9009s from reset and sync them together using the jesd204-fsm #sdr.jesd204_fsm_ctrl = "1" #trying to enable this function throws an exception so checked the property using iio_attr -d iio:device3 and #iio_attr -d iio:device4, this property already set to 1 #print("Done syncing") print("FH Mode Enable", sdr.frequency_hopping_mode_en_chip_c) sdr.frequency_hopping_mode_en_chip_c = 1 print("FH Mode Enable", sdr.frequency_hopping_mode_en_chip_c) print("FH Mode Enable Chip B", sdr.frequency_hopping_mode_en_chip_d) sdr.frequency_hopping_mode_en_chip_d = 1 print("FH Mode Enable Chip B", sdr.frequency_hopping_mode_en_chip_d) print("Setting first frequency") nextLO = 3000000000 sdr.frequency_hopping_mode_chip_c = nextLO sdr.frequency_hopping_mode_chip_d = nextLO sdr.dds_single_tone(500000, 0.8) # Collect data M = 150 N = 1 p1 = np.zeros(M) p2 = np.zeros(M) p1v = np.zeros(M) p2v = np.zeros(M) for k in range(M): pf1 = np.zeros(N) pf2 = np.zeros(N) #hopping between 2 static LOs first next_freq_lj = 3000000000 #random.randrange(200000000, 5999000000, 10) #if k % 5 == 0: next_freq_sj = 2000000000 #random.randrange(2000000000, 2001000000, 10000) if True: ############################ start_time_lo = time.time(); print(f"start time: {start_time_lo * 1e6} microseconds") print("RUN #", k) print("Off tune to ", nextLO) tobemovedto = sdr.frequency_hopping_mode_chip_c # Tell LO to move and set next frequency sdr.frequency_hopping_mode_chip_c = next_freq_sj sdr.frequency_hopping_mode_chip_d = next_freq_sj nextLO = sdr.frequency_hopping_mode_chip_c print("Current LO", tobemovedto) time.sleep(0.0001) ############################ print("Tune back to", nextLO) tobemovedto = sdr.frequency_hopping_mode_chip_c # Tell LO to move and set next frequency sdr.frequency_hopping_mode_chip_c = next_freq_lj sdr.frequency_hopping_mode_chip_d = next_freq_lj nextLO = sdr.frequency_hopping_mode_chip_c print("Current LO", tobemovedto) time.sleep(0.0001) ############################ print("FH Mode Enable", sdr.frequency_hopping_mode_en_chip_c) print("FH Mode Enable Chip B", sdr.frequency_hopping_mode_en_chip_d) end_time_lo = time.time() print(f"end time: {end_time_lo * 1e6} microseconds") total_time=int((end_time_lo - start_time_lo) * 1e6) print("total time:",total_time) else: if fhm: sdr.frequency_hopping_mode_chip_c = next_freq_sj sdr.frequency_hopping_mode_chip_d = next_freq_sj sdr.frequency_hopping_mode_chip_c = next_freq_lj sdr.frequency_hopping_mode_chip_d = next_freq_lj else: sdr.trx_lo_chip_c = next_freq_sj sdr.trx_lo_chip_d = next_freq_sj # Flush #for r in range(N): #x = sdr.rx() for r in range(N): x = sdr.rx() pf1[r] = measure_phase(x[0], x[1]) pf2[r] = measure_phase(x[0], x[2]) if plot_time_domain: plt.clf() plt.plot(np.real(x[0][:1000])) plt.plot(np.real(x[1][:1000])) plt.plot(np.real(x[2][:1000])) plt.show() plt.draw() plt.pause(2) p1[k] = np.mean(pf1) p2[k] = np.mean(pf2) p1v[k] = np.var(pf1) p2v[k] = np.var(pf2) print("Phases", p1[k], p2[k]) print("Variances", p1v[k], p2v[k]) print("\n") plt.clf() x = np.array(range(0, k + 1)) plt.errorbar(x, p1[x], yerr=p1v[x], label="Channel 0/1)") plt.errorbar(x, p2[x], yerr=p2v[x], label="Channel 0/2") plt.xlim([-1, x[-1] + 1]) plt.xlabel("Measurement Index") plt.ylabel("Phase Difference (Degrees)") plt.legend() plt.draw() plt.pause(0.05) plt.show()
In adrv_zu11eg_fmcomms8.py file located in usr/local/lib/python3.9/dist-packages/adi we also changed some few lines for frequency hopping mode for making it compatible to our board as below:
def mcs_chips(self): """mcs_chips: MCS Synchronize all four transceivers """ try: _ = self.jesd204_fsm_ctrl # We're JESD204-fsm enabled - do nothing except: # noqa: E722 # Turn off continuous SYSREF, and enable GPI SYSREF request # self._clock_chip_carrier.reg_write(0x5A, 0) commented since only fmc clock is present self._clock_chip_fmc.reg_write(0x5A, 0) #self._ctrl and self._ctrl_b removed in below loop since only fmcomms8 is present chips = [self._ctrl_c, self._ctrl_d] for i in range(12): for chip in chips: try: self._set_iio_dev_attr_str("multichip_sync", i, chip) except OSError: pass @property def frequency_hopping_mode_chip_c(self): """frequency_hopping_mode_chip_c: Set Frequency Hopping Mode""" return self._get_iio_attr( "TRX_LO", "frequency_hopping_mode", True, self._ctrl_c ) @frequency_hopping_mode_chip_c.setter def frequency_hopping_mode_chip_c(self, value): self._set_iio_attr( "TRX_LO", "frequency_hopping_mode", True, value, self._ctrl_c ) @property def frequency_hopping_mode_en_chip_c(self): """frequency_hopping_mode_en: Enable Frequency Hopping Mode""" return self._get_iio_attr( "TRX_LO", "frequency_hopping_mode_enable", True, self._ctrl_c ) @frequency_hopping_mode_en_chip_c.setter def frequency_hopping_mode_en_chip_c(self, value): self._set_iio_attr( "TRX_LO", "frequency_hopping_mode_enable", True, value, self._ctrl_c ) @property def frequency_hopping_mode_chip_d(self): """frequency_hopping_mode_chip_d: Set Frequency Hopping Mode""" return self._get_iio_attr( "TRX_LO", "frequency_hopping_mode", True, self._ctrl_d ) @frequency_hopping_mode_chip_d.setter def frequency_hopping_mode_chip_d(self, value): self._set_iio_attr( "TRX_LO", "frequency_hopping_mode", True, value, self._ctrl_d ) @property def frequency_hopping_mode_en_chip_d(self): """frequency_hopping_mode_en: Enable Frequency Hopping Mode""" return self._get_iio_attr( "TRX_LO", "frequency_hopping_mode_enable", True, self._ctrl_d ) @frequency_hopping_mode_en_chip_d.setter def frequency_hopping_mode_en_chip_d(self, value): self._set_iio_attr( "TRX_LO", "frequency_hopping_mode_enable", True, value, self._ctrl_d )
In the same file we had to comment 4 recievers and 4 transceivers out of 8. since we have only 2 chips.
After these particular changes, we are able to get frequency hopping mode and get phases maintained around +/- 2.5 degrees in different power-cycles. But the issue is that it takes around 400ms for both chips combined in the GPIO mode to switch from 1 LO to another using the above python script. This time should be around 70us as stated in the ADRV9009 datasheet. Our questions are as below
What could be done to reduce the time for switching and getting constant phases in different powerons?
Why do we get exception when we try to set sdr.jesd204_fsm_ctrl = "1" when using the python script?
Thank you in advance for your time and support.
Regards
Meghraj
.
[edited by: MeghrajT at 5:22 AM (GMT -5) on 15 Nov 2023]