AnsweredAssumed Answered

KV31 ADC Calibration

Question asked by Shawn Mason on Mar 1, 2017
Latest reply on Apr 7, 2017 by Jorge Antonio Alcala Vazquez

Hi,

We've run into a performance limit on our application when using an uncalibrated ADC.  However, we've seen issues when attempting to perform the internal Kinetis calibration.  Device is a MKV31F512.

1)  The major problem is that when running the initialization code below for both ADC0 and ADC1, the ADC1 calibration always returns with 0 values.  I've tried different combinations of COCO and CAL flags but the results are always the same.  The only way I can get a result appear is to breakpoint on the line "tmp32 = ADC1->CLP0 + ADC1->CLP1 + ADC1->CLP2 + ADC1->CLP3 + ADC1->CLP4 + ADC1->CLPS;".  The input bus clock to the ADC modules is 24 MHz.

2)  Minor issue is that occasionally the calibration occasionally gives outlier results.  The offset goes to -1 in these cases.  I've used the breakpoint method above to gather ADC1 data.  I've read you need to run the calibration 20 times and apply a median filter but it appears some thing isn't correct in the hardware.

 

Any ideas on how to properly poll the calibration status and ensure the ADC1 calibration completes correctly?

 

Shawn

 

 

 

void InitADC(void)
{
uint32_t tmp32 = 0x00000000;

ADC0->CFG1 &= ~(ADC_CFG1_ADLPC_MASK | ADC_CFG1_ADLSMP_MASK | ADC_CFG1_ADICLK_MASK | ADC_CFG1_ADIV_MASK| ADC_CFG1_MODE_MASK);
ADC0->CFG1 |= (ADC_CFG1_ADIV(3U) | ADC_CFG1_MODE(1U));
ADC0->CFG2 &= ~(ADC_CFG2_MUXSEL_MASK | ADC_CFG2_ADACKEN_MASK | ADC_CFG2_ADLSTS_MASK | ADC_CFG2_ADHSC_MASK);
ADC0->CFG2 |= (ADC_CFG2_ADHSC_MASK);
ADC0->SC2 &= ~(ADC_SC2_ADTRG_MASK | ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK |
ADC_SC2_DMAEN_MASK | ADC_SC2_REFSEL_MASK);
ADC0->SC3 &= ~(ADC_SC3_ADCO_MASK | ADC_SC3_AVGE_MASK | ADC_SC3_AVGS_MASK);
ADC0->SC3 |= (ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(0x3));
ADC0->SC1[0] &= ~(ADC_SC1_COCO_MASK | ADC_SC1_AIEN_MASK | ADC_SC1_ADCH_MASK);
ADC0->SC1[0] |= (ADC_SC1_DIFF_MASK | ADC_SC1_ADCH(0x00));
ADC0->SC1[1] |= (ADC_SC1_DIFF_MASK | ADC_SC1_ADCH_MASK);

ADC1->CFG1 &= ~(ADC_CFG1_ADLPC_MASK | ADC_CFG1_ADLSMP_MASK | ADC_CFG1_ADICLK_MASK | ADC_CFG1_ADIV_MASK| ADC_CFG1_MODE_MASK);
ADC1->CFG1 |= (ADC_CFG1_ADIV(3U) | ADC_CFG1_MODE(1U));
ADC1->CFG2 &= ~(ADC_CFG2_MUXSEL_MASK | ADC_CFG2_ADACKEN_MASK | ADC_CFG2_ADLSTS_MASK);
ADC1->CFG2 |= (ADC_CFG2_ADHSC_MASK);
ADC1->SC2 &= ~(ADC_SC2_ADTRG_MASK | ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK |
ADC_SC2_DMAEN_MASK | ADC_SC2_REFSEL_MASK);
ADC1->SC3 &= ~(ADC_SC3_ADCO_MASK | ADC_SC3_AVGE_MASK | ADC_SC3_AVGS_MASK);
ADC1->SC3 |= (ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(0x3));
ADC1->SC1[0] &= ~(ADC_SC1_COCO_MASK | ADC_SC1_AIEN_MASK | ADC_SC1_ADCH_MASK);
ADC1->SC1[0] |= (ADC_SC1_DIFF_MASK | ADC_SC1_ADCH(0x00));
ADC1->SC1[1] |= (ADC_SC1_DIFF_MASK | ADC_SC1_ADCH_MASK);

#ifdef ADC_CAL
ADC0->SC3 |= (ADC_SC3_CAL_MASK | ADC_SC3_CALF_MASK);

while (((ADC0->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK) & ((ADC0->SC3 & ADC_SC3_CAL_MASK) == ADC_SC3_CAL_MASK))
{
if ((ADC0->SC3 & ADC_SC3_CALF_MASK) == ADC_SC3_CALF_MASK)
{
break;
}
}
tmp32 = ADC0->R[0];

if ((ADC0->SC3 & ADC_SC3_CALF_MASK) != ADC_SC3_CALF_MASK)
{
tmp32 = ADC0->CLP0 + ADC0->CLP1 + ADC0->CLP2 + ADC0->CLP3 + ADC0->CLP4 + ADC0->CLPS;
tmp32 = 0x8000U | (tmp32 >> 1U);
ADC0->PG = tmp32;

tmp32 = ADC0->CLM0 + ADC0->CLM1 + ADC0->CLM2 + ADC0->CLM3 + ADC0->CLM4 + ADC0->CLMS;
tmp32 = 0x8000U | (tmp32 >> 1U);
ADC0->MG = tmp32;
}

ADC1->SC3 |= (ADC_SC3_CAL_MASK | ADC_SC3_CALF_MASK);

while (((ADC1->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK) & ((ADC0->SC3 & ADC_SC3_CAL_MASK) == ADC_SC3_CAL_MASK))
{
if ((ADC1->SC3 & ADC_SC3_CALF_MASK) == ADC_SC3_CALF_MASK)
{
break;
}
}
tmp32 = ADC1->R[0];

if ((ADC1->SC3 & ADC_SC3_CALF_MASK) != ADC_SC3_CALF_MASK)
{
tmp32 = ADC1->CLP0 + ADC1->CLP1 + ADC1->CLP2 + ADC1->CLP3 + ADC1->CLP4 + ADC1->CLPS;
tmp32 = 0x8000U | (tmp32 >> 1U);
ADC1->PG = tmp32;

tmp32 = ADC1->CLM0 + ADC1->CLM1 + ADC1->CLM2 + ADC1->CLM3 + ADC1->CLM4 + ADC1->CLMS;
tmp32 = 0x8000U | (tmp32 >> 1U);
ADC1->MG = tmp32;
}
#else
ADC0->OFS = 0x00000000;
ADC0->PG = 0x82D2;
ADC0->MG = 0x82D2;
ADC0->CLPD = 0xE;
ADC0->CLPS = 0x2E;
ADC0->CLP4 = 0x2C8;
ADC0->CLP3 = 0x16D;
ADC0->CLP2 = 0xB7;
ADC0->CLP1 = 0x5C;
ADC0->CLP0 = 0x2E;
ADC0->CLMD = 0xE;
ADC0->CLMS = 0x2E;
ADC0->CLM4 = 0x2C8;
ADC0->CLM3 = 0x16D;
ADC0->CLM2 = 0xB7;
ADC0->CLM1 = 0x5C;
ADC0->CLM0 = 0x2E;

ADC1->OFS = 0x00000000;
ADC1->PG = 0x82C8;
ADC1->MG = 0x82D0;
ADC1->CLPD = 0xD;
ADC1->CLPS = 0x2E;
ADC1->CLP4 = 0x2BF;
ADC1->CLP3 = 0x166;
ADC1->CLP2 = 0xB6;
ADC1->CLP1 = 0x5B;
ADC1->CLP0 = 0x2D;
ADC1->CLMD = 0xF;
ADC1->CLMS = 0x2E;
ADC1->CLM4 = 0x2C5;
ADC1->CLM3 = 0x16B;
ADC1->CLM2 = 0xB7;
ADC1->CLM1 = 0x5D;
ADC1->CLM0 = 0x2E;
#endif

ADC0->CFG1 &= ~(ADC_CFG1_ADIV_MASK);
ADC0->CFG1 |= ADC_CFG1_ADIV(0U);
ADC0->SC3 &= ~(ADC_SC3_AVGS_MASK | ADC_SC3_AVGE_MASK);
ADC0->SC2 |= (ADC_SC2_ADTRG_MASK | ADC_SC2_DMAEN_MASK);

ADC1->CFG1 &= ~(ADC_CFG1_ADIV_MASK);
ADC1->CFG1 |= ADC_CFG1_ADIV(0U);
ADC1->SC3 &= ~(ADC_SC3_AVGS_MASK | ADC_SC3_AVGE_MASK);
ADC1->SC2 |= (ADC_SC2_ADTRG_MASK | ADC_SC2_DMAEN_MASK);

}

Outcomes