Post Go back to editing

AD9081 Multichip syncronization API

Category: Software
Product Number: AD9081
Software Version: Petalinux

Hi All,

I'm developing a custom application for multichip syncronization with AD9081. I follow the specifications indicated in: 

"">www.analog.com/.../power-up-phase-determinism-using-multichip-synchronization.html" Fig.2 and  the following instructions in UG-1578:

  

My code is the following:

/*!
	* @brief     Standalone Linux Application
	*
	* @copyright copyright(c) 2018 analog devices, inc. all rights reserved.
	*            This software is proprietary to Analog Devices, Inc. and its
	*            licensor. By using this software you agree to the terms of the
	*            associated analog devices software license agreement.
*/

/*!
	* @addtogroup __ADI_AD9081_APP__
	* @{
*/

/*============= I N C L U D E S ============*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "adi_ad9081.h"
#include "adi_ad9081_config.h"
#include "adi_ad9081_hal.h"
#include "adi_hmc7043.h"
#include "adi_adf4371.h"
#include "pl.h"
#include "NCO_settings.h"
#include "fw_settings.h"
#include "uc_settings.h"


/*============= D A T A ====================*/

#define STAGE1    (1<<0)
#define STAGE2    (1<<1)
#define STAGE3    (1<<2)
#define STAGE4    (1<<3)
#define SYNC_MS_GPIO_NUM 0
#define TRIGGER_SRC 0
#define EXTRA_LFMC_NUM 0
#define MS_SYNC_ENB 1
#define MXFE_NUMBER 4

/*============= C O D E ====================*/
/**
	* div_s64_rem - signed 64bit divide with 32bit divisor with remainder
*/
static inline int64_t div_s64_rem(int64_t dividend, int32_t divisor, int32_t *remainder)
{
	*remainder = dividend % divisor;
	return dividend / divisor;
}


/**
	* div_s64 - signed 64bit divide with 32bit divisor
*/
static inline int64_t div_s64(int64_t dividend, int32_t divisor)
{
	int32_t remainder;
	return div_s64_rem(dividend, divisor, &remainder);
}

int32_t adi_ad9081_adc_nco_sync(adi_ad9081_device_t *device,
	uint8_t trigger_src,
uint8_t extra_lmfc_num)
{
	int err;
	
	AD9081_NULL_POINTER_RETURN(device);
	AD9081_LOG_FUNC();
	
	err = adi_ad9081_hal_bf_set(device, REG_MAIN_AUTO_CLK_GATING_ADDR, 0x00000400, 7);
	AD9081_ERROR_RETURN(err);
	
	err = adi_ad9081_adc_ddc_coarse_sync_enable_set(device,
	AD9081_ADC_CDDC_ALL, 1);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_adc_ddc_coarse_sync_next_set(device,
	AD9081_ADC_CDDC_ALL, 1);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_adc_ddc_coarse_trig_nco_reset_enable_set(
	device, AD9081_ADC_CDDC_ALL, 0);
	AD9081_ERROR_RETURN(err);
	
	err = adi_ad9081_adc_ddc_fine_sync_enable_set(device,
	AD9081_ADC_FDDC_ALL, 1);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_adc_ddc_fine_sync_next_set(device, AD9081_ADC_FDDC_ALL,
	1);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_adc_ddc_fine_trig_nco_reset_enable_set(
	device, AD9081_ADC_FDDC_ALL, 0);
	AD9081_ERROR_RETURN(err);
	
	err = adi_ad9081_device_nco_sync_mode_set(device, 0);
	AD9081_ERROR_RETURN(err);
	
	err = adi_ad9081_device_nco_sync_sysref_mode_set(device, trigger_src);
	AD9081_ERROR_RETURN(err);
	
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_device_nco_sync_extra_lmfc_num_set(device,
	extra_lmfc_num);
	AD9081_ERROR_RETURN(err);
	
	err = adi_ad9081_adc_ddc_coarse_sync_next_set(device,
	AD9081_ADC_CDDC_ALL, 0);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_adc_ddc_fine_sync_next_set(device, AD9081_ADC_FDDC_ALL,
	0);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_adc_ddc_coarse_sync_next_set(device,
	AD9081_ADC_CDDC_ALL, 1);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_adc_ddc_fine_sync_next_set(device, AD9081_ADC_FDDC_ALL,
	1);
	AD9081_ERROR_RETURN(err);
	
	err = adi_ad9081_device_nco_sync_reset_via_sysref_set(device, 0);
	AD9081_ERROR_RETURN(err);
	err = adi_ad9081_device_nco_sync_reset_via_sysref_set(device, 1);
	AD9081_ERROR_RETURN(err);
	
	return API_CMS_ERROR_OK;
}

int adi_ad9081_device_gpio_set_highz(adi_ad9081_device_t *device, uint8_t gpio_index)
{
	int err;
	
	AD9081_NULL_POINTER_RETURN(device);
	AD9081_LOG_FUNC();
	AD9081_INVALID_PARAM_RETURN(gpio_index > 5);
	
	if ((gpio_index & 1) == 0) {
		err = adi_ad9081_hal_bf_set(device,
		REG_GPIO_CFG0_ADDR + (gpio_index >> 1), 0x0400, 0);
		AD9081_ERROR_RETURN(err);
		} else {
		err = adi_ad9081_hal_bf_set(device,
		REG_GPIO_CFG0_ADDR + (gpio_index >> 1), 0x0404, 0);
		AD9081_ERROR_RETURN(err);
	}
	
	return API_CMS_ERROR_OK;
}
	
int32_t adi_ad9081_jesd_sysref_monitor_phase_get(adi_ad9081_device_t *device,
uint16_t *sysref_phase)
{
	int32_t err;
	uint8_t phase0_val;
	uint8_t phase1_val;
	
	AD9081_NULL_POINTER_RETURN(device);
	AD9081_NULL_POINTER_RETURN(sysref_phase);
	AD9081_LOG_FUNC();
	
	/* Write strobe to trigger a value update */
	err = adi_ad9081_hal_bf_set(device, REG_SYSREF_PHASE0_ADDR, 0x800,
	0x00);
	
	err = adi_ad9081_hal_bf_get(device, REG_SYSREF_PHASE0_ADDR, 0x800,
	&phase0_val, sizeof(uint8_t));
	err = adi_ad9081_hal_bf_get(device, REG_SYSREF_PHASE1_ADDR, 0x400,
	&phase1_val, sizeof(uint8_t));
	
	*sysref_phase = (phase1_val << 8) + phase0_val;
	
	AD9081_ERROR_RETURN(err);
	
	return API_CMS_ERROR_OK;
}
	
int32_t ad9081_multichip_sync(adi_ad9081_device_t *device, uint8_t isMaster) {
	
	int32_t err;
    uint32_t sysref_average_cnt_exp = 4; /*exp of sysref average count 2^4 = 16*/
	
	
	/* ONESHOT SYNC */
	printf ("*******************************\n");
	printf ("***** STAGE1 ONESHOT SYNC *****\n");
	printf ("*******************************\n");
		
	/*Force a digital reset of the jesd link*/
	err =  adi_ad9081_hal_bf_set(device, REG_FORCE_LINK_RESET_REG_ADDR, BF_FORCE_LINK_DIGITAL_RESET_INFO, 0); /* not paged */
	
	if (err != API_CMS_ERROR_OK)
	{
		printf ("ad9081_jesd_tx_link_dig_reset: error %d\n",err); 
		return err;
	}
	printf ("ad9081_jesd_tx_link_dig_reset DONE\n");
	
	pl_wait_us(NULL,4000);			
	
	/* JESD OneShot Sync */
	
	/*Enable SYSREF Averaging Mode*/
	err = adi_ad9081_hal_bf_set(device, REG_SYNC_DEBUG0_ADDR, BF_AVRG_FLOW_EN_INFO, 1);
	if (err != API_CMS_ERROR_OK)
	{
		printf ("REG_SYNC_DEBUG0_ADDR: error %d\n",err); 
		return err;
	} 
	printf ("Enable Bit for SYSREF AVERAGED\n");
	
	/* Sets how many SYSREF pulses are averaged before one shot synchronization or monitoring. The number of SYSREF pulses to be averaged is calculated by 2^N . When set to 0, SYSREF will be in sampled mode and no averaging is done. This bit field must be set prior to enabling one shot mode. */ 
	
	err = adi_ad9081_hal_bf_set(device, REG_SYSREF_AVERAGE_ADDR, BF_SYSREF_AVERAGE_INFO, BF_SYSREF_AVERAGE(sysref_average_cnt_exp));  
	if (err != API_CMS_ERROR_OK)
	{
		printf ("SYSREF_AVERAGE SET: error %d\n",err); 
		return err;
	}  
	printf ("SYSREF_AVERAGE SET\n");
	
	err = adi_ad9081_jesd_oneshot_sync(device); 
	if (err != API_CMS_ERROR_OK)
	{
		printf ("adi_ad9081_jesd_oneshot_sync: error %d\n",err); 
		return err;
	}
	printf ("adi_ad9081_jesd_oneshot_sync done\n");			
	
	err = adi_ad9081_hal_bf_set(device, REG_SYNC_DEBUG0_ADDR, BF_AVRG_FLOW_EN_INFO, 0);
	if (err != API_CMS_ERROR_OK)
	{
		printf ("REG_SYSREF_AVERAGE_ADDR: error %d\n",err); 
		return err;
	}  
	printf ("Disable Bit for SYSREF AVERAGED \n");
	
	err = adi_ad9081_hal_bf_set(device, REG_SYSREF_AVERAGE_ADDR, BF_SYSREF_AVERAGE_INFO, BF_SYSREF_AVERAGE(0));
	if (err != API_CMS_ERROR_OK)
	{
		printf ("SYSREF_AVERAGE SET: error %d\n",err); 
		return err;
	}  
	printf ("SYSREF_AVERAGE SET 0\n");
	
	/*OCCORRE INSERIRE L'ABILITAZIONE DELLA RICHIUSURA DEL GPIO0. POI VEDIAMO COME FARE.
		if (phy->ms_sync_en_gpio)
	gpiod_set_value(phy->ms_sync_en_gpio, 1);*/
	
	/* We need to make sure the master-slave master GPIO is enabled before we move on */
	err = adi_ad9081_device_nco_sync_gpio_set(device, SYNC_MS_GPIO_NUM, 1);
	if (err != API_CMS_ERROR_OK)
	{
		printf ("adi_ad9081_device_nco_sync_gpio_set SET: error %d\n",err); 
		return err;
	}  
	printf ("adi_ad9081_device_nco_sync_gpio_set DONE\n");
	
	
	
	printf ("\n");
	
	/* NCO SYNC */
	printf ("*******************************\n");
	printf ("******* STAGE2 NCO SYNC *******\n");
	printf ("*******************************\n");		
	
	/* NCO Sync */
	
	err = adi_ad9081_device_nco_sync_pre(device);
	if (err != API_CMS_ERROR_OK)
	{
		printf ("adi_ad9081_device_nco_sync_pre: error %d\n",err); 
		return err;
	}  
	printf ("adi_ad9081_device_nco_sync_pre DONE\n");
	
	#if MS_SYNC_ENB 
		
		err = adi_ad9081_adc_nco_master_slave_sync(device, isMaster, 1, SYNC_MS_GPIO_NUM, EXTRA_LFMC_NUM);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("adi_ad9081_adc_nco_master_slave_sync master: error %d\n",err);
			return err;
		}
		printf("adi_ad9081_adc_nco_master_slave_sync master set DONE\n");

	#else
		err =adi_ad9081_adc_nco_sync(device, 0, 0);
		if (err!= API_CMS_ERROR_OK)
		{
			printf("adi_ad9081_adc_nco_sync: error %d\n",err); 
			return err;
		}
		printf ("adi_ad9081_adc_nco_sync DONE \n");
	#endif		
		
		
	printf ("\n");
	/* Post NCO Master Slave */
	printf ("********************************\n");
	printf ("* STAGE3 Post NCO Master Slave *\n");
	printf ("********************************\n");	
	/* Do some post-settings for nco sync.*/
	
	err =adi_ad9081_device_nco_sync_post(device);
	if (err!= API_CMS_ERROR_OK)
	{
		printf("adi_ad9081_device_nco_sync_post: error %d\n",err); 
		return err;
	}
	printf ("adi_ad9081_device_nco_sync_post DONE \n");	
	
	/* Put GPIO in HighZ*/
	
	err =adi_ad9081_device_gpio_set_highz(device, SYNC_MS_GPIO_NUM);
	if (err!= API_CMS_ERROR_OK)
	{
		printf("adi_ad9081_device_gpio_set_highz: error %d\n",err); 
		return err;
	}
	printf ("adi_ad9081_device_gpio_set_highz DONE \n");
	/*Force a digital reset of the jesd link*/
	err =  adi_ad9081_hal_bf_set(device, REG_FORCE_LINK_RESET_REG_ADDR, BF_FORCE_LINK_DIGITAL_RESET_INFO, 0); /* not paged */
	
	if (err != API_CMS_ERROR_OK)
	{
		printf ("ad9081_jesd_tx_link_dig_reset: error %d\n",err); 
		return err;
	}
	printf ("ad9081_jesd_tx_link_dig_reset DONE\n");
	printf ("\n");
	pl_wait_us(NULL,4000);	

	AD9081_ERROR_RETURN(err);
	
	return API_CMS_ERROR_OK;
}

int32_t adf4371_phase_adjust(adi_adf4371_device_t *device) {
	int32_t reg10Val;
	uint8_t ADF4371_PhaseAdjust;
	uint32_t phaseWord;
	int32_t err;
	
	ADF4371_PhaseAdjust = 90;
	while (ADF4371_PhaseAdjust>0){
		if (ADF4371_PhaseAdjust>360){
			phaseWord = round(359.99997*16777216/360);
			ADF4371_PhaseAdjust = ADF4371_PhaseAdjust - 360;
		}
		else
		{
			phaseWord = round(ADF4371_PhaseAdjust*16777216/360);
			ADF4371_PhaseAdjust = 0;
		}
		
		/*Turn On Sigma-Delta*/
		err = adf4371_spi_reg_set(device, 0x2B, 0x04);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Turn On Sigma-Delta: error %d\n",err); 
			return err;
		}
		printf("Turn On Sigma-Delta\n");
		
		/*Turn Off Autocalibration*/
		err = adf4371_spi_reg_set(device, 0x12, 0x00);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Turn Off Autocalibration: error %d\n",err); 
			return err;
		}				
		printf("Turn Off Autocalibration\n");
		
		/*Turn On Phase Adjust*/
		err = adf4371_spi_reg_set(device, 0x1A, 0x40);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Turn Off Autocalibration: error %d\n",err); 
			return err;
		}				
		printf("Turn On Phase Adjust\n");
		
		/*Adjusting PLL phaseword 5_6*/
		err = adf4371_spi_reg_set(device, 0x1B, phaseWord & 0x0000FF);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Adjusting PLL: reg 0x1B: error %d\n",err); 
			return err;
		}				
		printf("Adjusting PLL: reg 0x1B\n");
		
		/*Adjusting PLL phaseword 3_4*/
		err = adf4371_spi_reg_set(device, 0x1C, phaseWord & 0x00FF00);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Adjusting PLL: reg 0x1C: error %d\n",err); 
			return err;
		}				
		printf("Adjusting PLL: reg 0x1C\n");	
		
		/*Adjusting PLL phaseword 1_2*/
		err = adf4371_spi_reg_set(device, 0x1D, phaseWord & 0xFF0000);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Adjusting PLL: reg 0x1D: error %d\n",err); 
			return err;
		}				
		printf("Adjusting PLL: reg 0x1D\n");
		
		/*Read register 10*/
		err = adf4371_spi_reg_get(device, 0x10, &reg10Val);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Reading register 10 ADF4371: error %d\n",err); 
			return err;
		}					
		/*Write register 10*/
		err = adf4371_spi_reg_set(device, 0x10, reg10Val);
		if (err!=API_CMS_ERROR_OK)
		{
			printf("Writing register 10 ADF4371: error %d\n",err); 
			return err;
		}			
		printf("Register 10 ADF4371 updated\n");
		
	}

	AD9081_ERROR_RETURN(err);
	
	return API_CMS_ERROR_OK;
}

uint32_t sumSysref(uint16_t sysref_phase[], uint32_t item) {
	uint32_t i;
	uint32_t sum;
	
	sum=0;
	for (i=0;i<item;i++) {
		sum+=sysref_phase[i];
	}
	
	return sum;
}


int32_t main(int argc, char *argv[])
{
    int32_t err;
	int32_t i;
	uint8_t isMaster;
	
    uint32_t mxfeEnabledTmp;
	uint8_t mxfeEnabled[MXFE_NUMBER];
    int32_t stageType;
	int32_t stageTmp;
	int32_t revisionC = 1;
    uint8_t rev[3];
	uint16_t sysref_phase[MXFE_NUMBER];
	uint8_t numTimesForOneShotSync;
	
    if (argc > 1) 
	{
		
		stageTmp = atoi(argv[1]);
		
		if (stageTmp==0) stageType = STAGE1;
		if (stageTmp==1) stageType = STAGE2;
		if (stageTmp==2) stageType = STAGE3;
		if (stageTmp==3) stageType = STAGE4;
		
		sscanf (argv[2],"0x%x",&mxfeEnabledTmp);	
		for (i=0;i<MXFE_NUMBER;i++)
		{
			if (mxfeEnabledTmp&(1<<i)) {
				mxfeEnabled[i] = 1;
				} else {
				mxfeEnabled[i] = 0;
			}
		}
		
	}
	else
	{
        printf("stage is mandatory\n");
        printf("\n");
        printf("Usage: mcs [stage] [mxfe Enabled]\n");
        printf("\n");
        printf(" [stage]: mandatory\n");
        printf("    0: Stage1: OneShot SYNC \n");
        printf("    1: Stage2: NCO Master Slave \n");
        printf("    2: Stage3: Post NCO Master Slave\n");
		printf("    3: Stage4: SYSREF-LEMC Phase Adjustment\n");
        printf(" [mxfe Enabled]: optional\n");
		
        printf("\n");
        return API_CMS_ERROR_OK;
	}
    
    if (stageTmp > 0) 
	{
        printf("\n");
        printf("Running stage: ");
		if (stageType&STAGE1) printf ("OneShot SYNC ");
		if (stageType&STAGE2) printf ("NCO MASTER SLAVE ");
		if (stageType&STAGE3) printf ("POST NCO MASTER SLAVE ");
		if (stageType&STAGE4) printf ("SYSREF-LEMC Phase Adjustment ");
        printf("\n");		
	} 
	
    /* connect to platform */
	adi_ad9081_device_t ad9081_dev[MXFE_NUMBER] = {
		{
			.hal_info = {
				.sdo = SPI_SDO,
				.msb = SPI_MSB_FIRST,
				.addr_inc = SPI_ADDR_INC_AUTO,
				.log_write = pl_log_write,
				.delay_us = pl_wait_us,
				.spi_xfer = pl_spi_xfer_ad9081,
				.reset_pin_ctrl = pl_hw_rst_pin_ctrl_ad9081,
			},
			.serdes_info = {
				.ser_settings = { /* ad9081 jtx */
					.lane_settings = {
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
					},
					.invert_mask = 0x00,
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
					//					.lane_mapping = { { 3, 2, 1, 0, 7, 6, 5, 4 }, { 3, 2, 1, 0, 7, 6, 5, 4 } }, 
				},
				.des_settings = { /* ad9081 jrx */
					.boost_mask = 0xff,
					.invert_mask = 0x00,
					.ctle_filter = { 2, 2, 2, 2, 2, 2, 2, 2 },
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
					//					.lane_mapping = { { 3, 2, 1, 0, 7, 6, 5, 4 }, { 3, 2, 1, 0, 7, 6, 5, 4 } }, 
				}
			}
		},
		{
			.hal_info = {
				.sdo = SPI_SDO,
				.msb = SPI_MSB_FIRST,
				.addr_inc = SPI_ADDR_INC_AUTO,
				.log_write = pl_log_write,
				.delay_us = pl_wait_us,
				.spi_xfer = pl_spi_xfer_ad9081,
				.reset_pin_ctrl = pl_hw_rst_pin_ctrl_ad9081,
			},
			.serdes_info = {
				.ser_settings = { /* ad9081 jtx */
					.lane_settings = {
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
					},
					.invert_mask = 0x00,
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
				},
				.des_settings = { /* ad9081 jrx */
					.boost_mask = 0xff,
					.invert_mask = 0x00,
					.ctle_filter = { 2, 2, 2, 2, 2, 2, 2, 2 },
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
				}
			}
		},
		{
			.hal_info = {
				.sdo = SPI_SDO,
				.msb = SPI_MSB_FIRST,
				.addr_inc = SPI_ADDR_INC_AUTO,
				.log_write = pl_log_write,
				.delay_us = pl_wait_us,
				.spi_xfer = pl_spi_xfer_ad9081,
				.reset_pin_ctrl = pl_hw_rst_pin_ctrl_ad9081,
			},
			.serdes_info = {
				.ser_settings = { /* ad9081 jtx */
					.lane_settings = {
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
					},
					.invert_mask = 0x00,
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
				},
				.des_settings = { /* ad9081 jrx */
					.boost_mask = 0xff,
					.invert_mask = 0x00,
					.ctle_filter = { 2, 2, 2, 2, 2, 2, 2, 2 },
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
				}
			}
		},
		{
			.hal_info = {
				.sdo = SPI_SDO,
				.msb = SPI_MSB_FIRST,
				.addr_inc = SPI_ADDR_INC_AUTO,
				.log_write = pl_log_write,
				.delay_us = pl_wait_us,
				.spi_xfer = pl_spi_xfer_ad9081,
				.reset_pin_ctrl = pl_hw_rst_pin_ctrl_ad9081,
			},
			.serdes_info = {
				.ser_settings = { /* ad9081 jtx */
					.lane_settings = {
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
						{.swing_setting = AD9081_SER_SWING_850, .pre_emp_setting = AD9081_SER_PRE_EMP_0DB, .post_emp_setting = AD9081_SER_POST_EMP_0DB},
					},
					.invert_mask = 0x00,
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
				},
				.des_settings = { /* ad9081 jrx */
					.boost_mask = 0xff,
					.invert_mask = 0x00,
					.ctle_filter = { 2, 2, 2, 2, 2, 2, 2, 2 },
					/* in the array set id of LOGICAL line of link0, link1 */
					.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }, 
				}
			}
		}
	};
	
    adi_hmc7043_device_t hmc7043_dev = {
        .hal_info = {
            .spi_xfer = pl_spi_xfer_hmc7043,
            .delay_us = pl_wait_us,
            .log_write = pl_log_write,
		}
	};
	
    adi_adf4371_device_t adf4371_dev[MXFE_NUMBER] = {
        { 
			.hal_info = {
				.spi_xfer = pl_spi_xfer_adf4371,
				.delay_us = pl_wait_us,
				.log_write = pl_log_write,
			}
		},
        { 
			.hal_info = {
				.spi_xfer = pl_spi_xfer_adf4371,
				.delay_us = pl_wait_us,
				.log_write = pl_log_write,
			}
		},
        { 
			.hal_info = {
				.spi_xfer = pl_spi_xfer_adf4371,
				.delay_us = pl_wait_us,
				.log_write = pl_log_write,
			}
		},
        { 
			.hal_info = {
				.spi_xfer = pl_spi_xfer_adf4371,
				.delay_us = pl_wait_us,
				.log_write = pl_log_write,
			}
		}
	};
	
    system_device_t system_dev = {
        .hal_info = {
		}
	};
	
	
	pl_hw_open("log_mcs");;
	
	/* create user data */
	
	for (i=0;i<MXFE_NUMBER;i++) {
		if (err = pl_user_data_create_ad9081(&ad9081_dev[i], MXFE_SPI_BASE_ADDRESS, MXFE_SPI_BASE_ADDRESS, i), err != API_CMS_ERROR_OK)
		return err;
	}
	
	for (i=0;i<MXFE_NUMBER;i++) {
		if (err = pl_user_data_create_adf4371(&adf4371_dev[i], ADF4371_SPI_BASE_ADDRESS, ADF4371_CS_BASE_ADDRESS, i), err != API_CMS_ERROR_OK)
		return err;
	}
	
	if (err = pl_user_data_create_hmc7043(&hmc7043_dev, HMC7043_SPI_BASE_ADDRESS, 0), err != API_CMS_ERROR_OK)
	return err;
	
	if (err = pl_user_data_create_system(&system_dev, CLK_CTRL_BASE_ADDRESS, MXFE_EN_BASE_ADDRESS, MXFE_CTRL_BASE_ADDRESS, SYSTEM_CTRL_BASE_ADDRESS, HMC425A_CTRL_BASE_ADDRESS), err != API_CMS_ERROR_OK)
	return err;
	
	/* show api version */
	if (err = adi_ad9081_device_api_revision_get(&ad9081_dev[0], &rev[0], &rev[1], &rev[2]), err != API_CMS_ERROR_OK)
	return err;
	printf("AD9081 API v%d.%d.%d\n", rev[0], rev[1], rev[2]);
	
	printf ("\n");
	
	for (i=0;i<MXFE_NUMBER;i++) {
		if (!mxfeEnabled[i]) sysref_phase[i]=0;
		else sysref_phase[i]=1;
	}
	numTimesForOneShotSync = 0;
	
	while(sumSysref(sysref_phase, MXFE_NUMBER)>0) {
		for (i=0;i<MXFE_NUMBER;i++) {
			if (!mxfeEnabled[i]) continue;
			
			if (i==MXFE_NUMBER-1) isMaster=1;
			else isMaster=0;
			
			printf ("\n");
			printf ("MxFE#%d\n",i); 
			printf ("*********************************\n");
			printf ("*STAGE4 SYSREF-LEMC Phase adjust*\n");
			printf ("*********************************\n");
			
			/* MCS */
			err =ad9081_multichip_sync(&ad9081_dev[i], isMaster);
			if (err!=API_CMS_ERROR_OK)
			{
				printf("ad9081_multichip_sync: error %d\n",err); 
				return err;
			}
			printf("ad9081_multichip_sync\n");
			
		}
		
		for (i=0;i<MXFE_NUMBER;i++) {
			if (!mxfeEnabled[i]) continue;
			
			/* Monitor SYSREF-LEMC PHASE*/
			err =adi_ad9081_jesd_sysref_monitor_phase_get(&ad9081_dev[i], &sysref_phase[i]);
			if (err!=API_CMS_ERROR_OK)
			{
				printf("adi_ad9081_jesd_sysref_monitor_phase_get: error %d\n",err); 
				return err;
			}
			printf("Sysref-LEMC Phase = %d\n",sysref_phase[i]);
		}
		
		
		if (sumSysref(sysref_phase, MXFE_NUMBER)==0){
		
			for (i=0;i<MXFE_NUMBER;i++) {
				if (!mxfeEnabled[i]) continue;
				
				/*Check one more time to confirm*/
				err =adi_ad9081_jesd_sysref_monitor_phase_get(&ad9081_dev[i], &sysref_phase[i]);
				if (err!=API_CMS_ERROR_OK)
				{
					printf("adi_ad9081_jesd_sysref_monitor_phase_get: error %d\n",err); 
					return err;
				}
				printf("Sysref-LEMC Phase = %d\n",sysref_phase[i]);
			}
		}
		else {
			for (i=0;i<MXFE_NUMBER;i++) {
				if (!mxfeEnabled[i]) continue;
				
				if (sysref_phase[i]!=0)
				
				/*SYSREF->LEMC Phase Is Not Stable, Adjust PLL/Synthesizer To Compensate*/
				printf ("Adjusting Sysref-LEMC Phase of MxFE#%d\n",i);
				printf("Sysref-LEMC Phase before allignment = %d\n",sysref_phase[i]);
				
				adf4371_phase_adjust(&adf4371_dev[i]);
				printf("PLL %d Phase Adjusted By 90 Degrees\n",i);
			}
		}
		
		numTimesForOneShotSync++;
		printf("Num times for one shot sync: %d\n",numTimesForOneShotSync);
	}

	/* free resource and close platform */
	for (i=0;i<MXFE_NUMBER;i++) {
		if (err = pl_user_data_free(&ad9081_dev[i].hal_info.user_data), err != API_CMS_ERROR_OK)
		return err;
	}
	for (i=0;i<MXFE_NUMBER;i++) {
		if (err = pl_user_data_free(&adf4371_dev[i].hal_info.user_data), err != API_CMS_ERROR_OK)
		return err;
	}
	if (err = pl_user_data_free(&hmc7043_dev.hal_info.user_data), err != API_CMS_ERROR_OK)
		return err;
	if (err = pl_user_data_free(&system_dev.hal_info.user_data), err != API_CMS_ERROR_OK)
		return err;

	printf ("\n");


	pl_hw_close();

	printf ("Exit application\n");
	printf("\n");

	return API_CMS_ERROR_OK;
}


I'm not able to reach a stable phase between SYSREF-LEMC signals. I'm reaching a min value of sysref-lemc and after is manifested a slip to a max value. I've missed something in my code?  

Can someone provide me a document that describes the One shot sync procedure? 

Thank you so much! 

Best regards.



Adding more infos
[edited by: LGChiriac at 2:16 PM (GMT -5) on 22 Nov 2022]