ADRV9029
Recommended for New Designs
The ADRV9029 is a highly integrated, radio frequency (RF) agile transceiver offering four independently controlled transmitters, dedicated observation...
Datasheet
ADRV9029 on Analog.com
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: -----