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: -----
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]