Post Go back to editing

How to Configure DPD correctly?

Hello, 

I have a ton of questions to ask about DPD configuration on the ADRV9025 chip. I am trying to configure DPD without the PA connected between the Tx-ORx path solely for testing purposes. I have gone through all the steps required in setting up DPD but there seems to be no signal in the ORx path. The  dpdErrorCode I get shifts between 0x3405 and 0x340E. 

My setup is as follows:

I am running a 2T-2R-2ORx setup utilizing TX3/TX2, RX3/RX2, and ORX3/ORX1. With this setup, I am running DPD on the TX2, connecting the output of the TX2 via a splitter to the ORX1 port and a spectrum analyzer (So as to monitor the TX2-ORX1 path).

For the DPD Tracking Cal Bring up Sequence, I followed the following steps. Note that I have supplied only the necessary snippets to avoid cluttering up this page:

1a. Program the device and run initial calibrations 

1b. Run TxQEC initial calibration after chip initialization (for some reason, the programming failed when I tried to run the tx_qec init cal as part of the POSTMCS during initialization, see code snippet)

recoveryAct = adi_init_tx_cals_run( adrv9025Device, 
                                    ADI_ADRV9025_TX2,  
                                    ( ADI_ADRV9025_TX_QEC_INIT | ADI_ADRV9025_INTERNAL_PATH_DELAY | ADI_ADRV9025_TX_LO_LEAKAGE_INTERNAL )                                        
                                ) ;

2. Disabled ORX channels mapped TX2 to ORX1 and called the adi_adrv9025_RadioCtrlCfgSet function, setting all control modes to SPI (see code snippet)

printf("*** Disabling ORx Channels ***\n") ;
recoveryAct = adi_adrv9025_RxTxEnableSet ( adrv9025Device, 0x06, 0x06 ) ;

rxChannelMaskGet = 0 ;
txChannelMaskGet = 0 ;
usleep(1) ;
recoveryAct = adi_adrv9025_RxTxEnableGet(adrv9025Device, &rxChannelMaskGet, &txChannelMaskGet) ;

recoveryAct = adi_adrv9025_TxToOrxMappingSet(device,ADI_ADRV9025_ORX1, ADI_ADRV9025_TX2);

adrv9025PostMcsInitInst.radioCtrlInit.radioCtrlModeCfg.orxRadioCtrlModeCfg.orxEnableMode = ADI_ADRV9025_ORX_EN_SPI_MODE; //ADI_ADRV9025_ORX_EN_SINGLE_CH_2PIN_MODE;
adrv9025PostMcsInitInst.radioCtrlInit.radioCtrlModeCfg.rxRadioCtrlModeCfg.rxEnableMode = ADI_ADRV9025_RX_EN_SPI_MODE ; //ADI_ADRV9025_RX_EN_PIN_MODE;
adrv9025PostMcsInitInst.radioCtrlInit.radioCtrlModeCfg.txRadioCtrlModeCfg.txEnableMode = ADI_ADRV9025_TX_EN_SPI_MODE ;//ADI_ADRV9025_TX_EN_PIN_MODE;
recoveryAct = adi_adrv9025_RadioCtrlCfgSet(adrv9025Device, &adrv9025PostMcsInitInst.radioCtrlInit.radioCtrlModeCfg);
	

3. Adjusted ORX1 gain, using gain index of 0xFF (see code snippet)

rx_gain.gainIndex       = 0xFF ;
rx_gain.rxChannelMask   = ADI_ADRV9025_ORX1 ;
    
recoveryAct = adi_adrv9025_RxGainSet  (device, &rx_gain, 1);

4. Run the external path delay for TX2 (see code snippet)

adrv9025PostMcsInitInst.initCals.calMask 		= 0x00200000; //external path delay
adrv9025PostMcsInitInst.initCals.channelMask 	= ADI_ADRV9025_TX2 ;
adrv9025PostMcsInitInst.initCals.warmBoot		= 0 ;
recoveryAct = adi_adrv9025_InitCalsRun(device, &adrv9025PostMcsInitInst.initCals);

recoveryAct = adi_adrv9025_InitCalsWait(device, 60000, &initCalsError);

5. Run the Tx external LOL init cals (see code snippet)

adrv9025PostMcsInitInst.initCals.calMask        = 0x00000800; //external LOL
adrv9025PostMcsInitInst.initCals.channelMask 	= ADI_ADRV9025_TX2 ;
adrv9025PostMcsInitInst.initCals.warmBoot		= 0 ;

recoveryAct = adi_adrv9025_InitCalsRun(device, &adrv9025PostMcsInitInst.initCals);

recoveryAct = adi_adrv9025_InitCalsWait(device, 60000, &initCalsError);

6. Configured the CFR settings (adi_adrv9025_CfrCtrlConfigSet,  adi_adrv9025_CfrCorrectionPulseWrite_v2, adi_adrv9025_CfrEnableSet, adi_adrv9025_CfrHardClipperConfigSet, see code snippet)

7. Run the CFR Init Cals (with 60s wait time passed to the adi_adrv9025_InitCalsWait function)

8. Loaded the PA model (see code snippet)

dpdModelConfigInst.txChannelMask = ADI_ADRV9025_TX2 ; 
dpdModelConfigInst.dpdNumFeatures = 22;

char* dpd_model = "/media/sddata/defaultDpdModel.txt"  ;
FILE *fp = fopen(dpd_model, "r");

for(int n = 0; n <dpdModelConfigInst.dpdNumFeatures ; n++)
{
    fscanf(fp, "%d %d %d %d %f %f",
    	&dpdModelConfigInst.dpdFeatures[n].i,
    	&dpdModelConfigInst.dpdFeatures[n].j,
    	&dpdModelConfigInst.dpdFeatures[n].k,
    	&dpdModelConfigInst.dpdFeatures[n].lut,
    	&dpdModelConfigInst.dpdFeatures[n].coeffReal,
    	&dpdModelConfigInst.dpdFeatures[n].coeffImaginary);
    
    printf("\n%d %d %d %d %f %f\n",
    	dpdModelConfigInst.dpdFeatures[n].i,
    	dpdModelConfigInst.dpdFeatures[n].j,
    	dpdModelConfigInst.dpdFeatures[n].k,
    	dpdModelConfigInst.dpdFeatures[n].lut,
    	dpdModelConfigInst.dpdFeatures[n].coeffReal,
    	dpdModelConfigInst.dpdFeatures[n].coeffImaginary);
}
adi_adrv9025_TxChannels_e tx_channels ;
fclose(fp);
recoveryAct = adi_adrv9025_DpdModelConfigSet(adrv9025Device, &dpdModelConfigInst);

--- My DPD MODEL ---

   0  0  0   0       0            0
   0  0  1   0       0            0
   0  0  2   0       0            0
   0  0  3   0       0            0
   0  0  4   0       0            0
   0  0  5   0       0            0
   1  1  1   2       0            0
   1  1  2   2       0            0
   1  1  3   2       0            0
   1  1  4   2       0            0
   1  1  5   2       0            0
   0  1  0   8       0            0
   0  1  1   8       0            0
   0  1  2   8       0            0
   0  1  3   8       0            0
   0  1  4   8       0            0
   0  1  5   8       0            0
   2  2  1  26       0            0
   2  2  2  26       0            0
   2  2  3  26       0            0
   2  2  4  26       0            0
   2  2  5  26       0            0

9. Asserted DPD Reset  (ADI_ADRV9025_DPD_RESET_FULL, see code snippet)

recoveryAct = adi_adrv9025_DpdReset(adrv9025Device, ADI_ADRV9025_TX2, ADI_ADRV9025_DPD_RESET_FULL);
if (recoveryAct != ADI_COMMON_ACT_NO_ACTION)
{
    printf("ERROR: : %s:%u has failed.\n", __func__, __LINE__);
    return recoveryAct;
}

10. Run DPD Tracking configuration (see code snippet)

int32_t MThreshold_dBFS                 = -21; 
int16_t DpdLowPowerThreshold_dBFS       = -36;
int16_t DpdLowPowerThresholdORx_dBFS    = -36;

int32_t temp                            = pow(10,(MThreshold_dBFS/20.0))*FULL_SCALE_CODE;
int32_t dpdMThreshold_val               = pow(temp,2);
int16_t minAvgSignalLevel_val           = pow(10,(DpdLowPowerThreshold_dBFS/20.0))*FULL_SCALE_CODE;
int16_t minAvgSignalLevelOrx_val        = pow(10,(DpdLowPowerThresholdORx_dBFS/20.0))*FULL_SCALE_CODE;

dpdTrackingConfigInst.txChannelMask                             = ADI_ADRV9025_TX2; 
dpdTrackingConfigInst.minAvgSignalLevel                         = minAvgSignalLevel_val;
dpdTrackingConfigInst.minAvgSignalLevelOrx                      = minAvgSignalLevelOrx_val;
dpdTrackingConfigInst.dpdMThreshold                             = temp ;
dpdTrackingConfigInst.dpdPeakSearchWindowSize                   = 65536;
dpdTrackingConfigInst.dpdIndirectRegularizationValue            = 30;
dpdTrackingConfigInst.dpdDirectRegularizationValue              = 30; 
dpdTrackingConfigInst.dpdSamples                                = 16384;
dpdTrackingConfigInst.dpdUpdateMode                             = ADI_ADRV9025_DPD_TRACKING_UPDATE_MODE_0;
dpdTrackingConfigInst.dpdIndirectRegularizationLowPowerValue    = 20;
dpdTrackingConfigInst.dpdFilterSel                              = 0; 
dpdTrackingConfigInst.enableDirectLearning                      = 0;
dpdTrackingConfigInst.dpdMu                                     = 50;

recoveryAct = adi_adrv9025_DpdTrackingConfigSet(adrv9025Device, &dpdTrackingConfigInst);

11. Setup closed-loop gain control configurations (for monitoring purposes. See code snippet)

adi_adrv9025_ClgcConfig_t clgc_config   ;
clgc_config.clgcEnableGainControl   = 0 ;
clgc_config.txChannelMask           = ADI_ADRV9025_TX2 ;

recoveryAct = adrv9025_ClgcConfigSet( adrv9025Device, &clgc_config, 1) ;

12. Enabled TX QEC and TX LOL tracking Calibrations (See code snippet)

recoveryAct = adi_adrv9025_TrackingCalsEnableSet (  adrv9025Device, 
                                                        ( ADI_ADRV9025_TRACK_TX2_QEC | ADI_ADRV9025_TRACK_TX2_LOL ), 
                                                        ADI_ADRV9025_TRACKING_CAL_ENABLE
                                                    );

13. Enabled DPD Tracking Calibration (See code snippet)

adi_adrv9025_TrackingCalsEnableSet (device, ADI_ADRV9025_TRACK_TX2_DPD, ADI_ADRV9025_TRACKING_CAL_ENABLE);

14. Enabled CLGC Tracking Calibration  (See code snippet)

recoveryAct = adi_adrv9025_TrackingCalsEnableSet (  adrv9025Device, 
                                                        ADI_ADRV9025_TRACK_TX2_CLGC, 
                                                        ADI_ADRV9025_TRACKING_CAL_ENABLE
                                                    );

15.  Started monitoring DPD tracking calibration (See code snippet)

//Wait for some time before getting the status
sleep(20);


adi_adrv9025_DpdStatus_t dpdStatus;
int32_t recoveryAction = 0;
recoveryAction = adi_adrv9025_DpdStatusGet (device, txChannel, &dpdStatus);

printf ("dpdErrorCode		:0x%x\n",dpdStatus.dpdErrorCode);
printf ("dpdPercentComplete	:%d\n",dpdStatus.dpdPercentComplete);
printf ("dpdPerformanceMetric	:%d\n",dpdStatus.dpdPerformanceMetric);
printf ("dpdIterCount		:%d\n",dpdStatus.dpdIterCount);
printf ("dpdUpdateCount		:%d\n",dpdStatus.dpdUpdateCount);

printf ("dpdSyncStatus		:%d\n",dpdStatus.dpdSyncStatus);


float meanTu = dpdStatus.dpdStatistics.dpdMeanTuPower;
float peakTu = dpdStatus.dpdStatistics.dpdPeakTuPower;
float meanTx = dpdStatus.dpdStatistics.dpdMeanTxPower;
float peakTx = dpdStatus.dpdStatistics.dpdPeakTxPower;
float meanOrx = dpdStatus.dpdStatistics.dpdMeanOrxPower;
float peakOrx = dpdStatus.dpdStatistics.dpdPeakOrxPower;

printf ("dpdModelTable		:%d\n",dpdStatus.dpdModelTable);


printf ("dpdMeanTuPower		:%f\n",20*log10(sqrt(meanTu) / 32768));
printf ("dpdPeakTuPower		:%f\n",(20*log10(sqrt(peakTu) / 32768)));
printf ("dpdMeanTxPower		:%f\n",(20*log10(sqrt(meanTx) / 32768)));
printf ("dpdPeakTxPower		:%f\n",20*log10(sqrt(peakTx) / 32768));
printf ("dpdMeanOrxPower		:%f\n",20*log10(sqrt(meanOrx) / 32768));
printf ("dpdPeakOrxPower		:%f\n",20*log10(sqrt(peakOrx) / 32768));
printf ("dpdDirectEvm		:%f\n",dpdStatus.dpdStatistics.dpdDirectEvm);
printf ("dpdIndirectEvm		:%f\n",dpdStatus.dpdStatistics.dpdIndirectEvm);
printf ("dpdSelectError		:%f\n",dpdStatus.dpdStatistics.dpdSelectError);
printf ("dpdIndirectError	:%f\n",dpdStatus.dpdStatistics.dpdIndirectError);
printf ("dpdErrorStatus0 (metrics:actions): X:X	:%d:%d\n",	dpdStatus.dpdErrorStatus0.dpdMetricsMask,
						    dpdStatus.dpdErrorStatus0.dpdActionMask);

printf ("dpdErrorStatus1 (metrics:actions)		:%d:%d\n", 	dpdStatus.dpdErrorStatus1.dpdMetricsMask,
							dpdStatus.dpdErrorStatus1.dpdActionMask);
printf ("dpdPersistentErrorStatus0 (metrics:actions)	:%d:%d\n", 	dpdStatus.dpdPersistentErrorStatus0.dpdMetricsMask,
							dpdStatus.dpdPersistentErrorStatus0.dpdActionMask);
printf ("dpdPersistentErrorStatus1 (metrics:actions)	:%d:%d\n", 	dpdStatus.dpdPersistentErrorStatus1.dpdMetricsMask,
							dpdStatus.dpdPersistentErrorStatus1.dpdActionMask);
printf ("reservedPM		:%d\n",dpdStatus.reservedPM);
printf ("reservedTP		:%d\n",dpdStatus.reservedTP);
printf ("reservedPR		:%d\n",dpdStatus.reservedPR);

16. Started monitoring CLGC status (See code snippet)

recoveryAct = adi_adrv9025_ClgcStatusGet(   adrv9025Device  ,
                                                ADI_ADRV9025_TX2,
                                                &clgc_status
                                            );

printf("******** CLGC Monitoring ****************\n")  ;
printf ("clgc_status.clgcLoopGain           : %f\n", clgc_status.clgcLoopGain) ;
printf ("clgc_status.clgcTxRmsPower           : %f\n", clgc_status.clgcTxRmsPower) ;
printf ("clgc_status.clgcOrxRmsPower           : %f\n", clgc_status.clgcOrxRmsPower) ;
printf ("clgc_status.activeTxAttenIndex           : 0x%x\n", clgc_status.activeTxAttenIndex) ;
printf ("clgc_status.activeOrxGainIndex           : 0x%x\n", clgc_status.activeOrxGainIndex) ;

---- And, here's the output of the above code: ----- 

*** Tx2 DPD Status ***
***************************************
Retrieving DPD status
dpdErrorCode :0x3405
dpdPercentComplete :0
dpdPerformanceMetric :0
dpdIterCount :18
dpdUpdateCount :0
dpdSyncStatus :4
dpdModelTable :0
dpdMeanTuPower :-14.280720
dpdPeakTuPower :-3.605944
dpdMeanTxPower :-inf
dpdPeakTxPower :-inf
dpdMeanOrxPower :-58.033522
dpdPeakOrxPower :-49.337814
dpdDirectEvm :4.338248
dpdIndirectEvm :nan
dpdSelectError :0.000000
dpdIndirectError :0.000000
dpdErrorStatus0 (metrics:actions): X:X :0:0
dpdErrorStatus1 (metrics:actions) :0:0
dpdPersistentErrorStatus0 (metrics:actions) :0:0
dpdPersistentErrorStatus1 (metrics:actions) :0:0
reservedPM :0
reservedTP :40249683
reservedPR :40249683
***************************************

*** Running Monitor CLGC tracking Calibration Status ***
******** CLGC Monitoring ****************
clgc_status.clgcLoopGain : 0.000000
clgc_status.clgcTxRmsPower : 0.000000
clgc_status.clgcOrxRmsPower : 0.000000
clgc_status.activeTxAttenIndex : 0x0
clgc_status.activeOrxGainIndex : 0x0
---------------- End of output ----------------------------
 
I am not sure what I am doing wrong here. Could it be because I have not connected a PA yet? 

Edit Notes

One thing to add is that after asserting reset, the signal on the TX2-ORX1 path dies and never comes back up. Could it be that I am not performing reset correctly? 
[edited by: AlexAntwi at 2:44 AM (GMT -5) on 12 Nov 2021]
Parents Reply
  • Hello

    I am using a splitter at the TX output. The splitter has two outputs. One part is connected to the ORX port and the other, I connected it to a spectrum analyzer for monitoring the TX-ORX signal. After programming the chip and enabling Tx and writing the data, I am able to see the data on this path I just described. After I assert reset, this signal dies. and all I see is a low-power single-tone signal in the spectrum analyzer. The other path where I am not running DPD is constantly showing the data on the spectrum analyzer. So, unless I did not get you well, I am sending a signal from TX. 

    And, I followed all the steps from the document in the link you shared. Could it be that I used the wrong parameters? Kindly check my code snippets for me, please. 

Children
No Data

Before You Switch


Switching languages will make ADI Explorer unavailable. Resume your session by switching back to English and reopening ADI Explorer.