AnsweredAssumed Answered

Serious problem with calibration of ADC on Kinetis K60 (Urgent)

Question asked by LE Quang Huy on May 6, 2013
Latest reply on May 22, 2013 by LE Quang Huy

Hi everybody,

 

I'm facing a serious problem with calibration of ADC on Kinetis K60. I configure output mode differential 16 bits, Vdda=3,3 V, Voltage reference select Valt = 3V, bus clock  = 50 Mhz, internal clock ADCK = 50/4 = 12,5 MHz (Registers CFGx config is the same with exemple ADC_demo of Fresscale).

I use also calibration routine of this exemple:

int ADC_Cal(int Num_adc)

{

    unsigned short cal_var;

    ADC_MemMapPtr adcmap;

   

    if(Num_adc==ADC0)

    {

        adcmap = ADC0_BASE_PTR;

    }

    else if(Num_adc==ADC1)

    {

        adcmap = ADC1_BASE_PTR;

    }

   

    // Turn on the ADC0 and ADC1 clocks

    SIM_SCGC6 |= (SIM_SCGC6_ADC0_MASK );

    SIM_SCGC3 |= (SIM_SCGC3_ADC1_MASK );

   

    ADC_SC2_REG(adcmap) &=  ~ADC_SC2_ADTRG_MASK ;                     // Enable Software Conversion Trigger for Calibration Process  

    ADC_SC3_REG(adcmap) &= (~ADC_SC3_ADCO_MASK & ~ADC_SC3_AVGS_MASK); // set single conversion, clear avgs bitfield for next writing

    ADC_SC3_REG(adcmap) |= (ADC_SC3_AVGE_MASK|ADC_SC3_AVGS(AVGS_32)); // Turn averaging ON and set at max value ( 32 )

   

    ADC_CFG1_REG(adcmap)&= (~ADC_CFG1_ADIV(ADIV_4)& ~ADC_CFG1_ADICLK(ADICLK_BUS)); // Clear fADCK initiated

    ADC_CFG1_REG(adcmap)|= ADC_CFG1_ADIV(ADIV_8)|ADC_CFG1_ADICLK(ADICLK_BUS_2); // fADCK = 50/2/8

    ADC_SC2_REG(adcmap) &= ~ADC_SC2_REFSEL(REFSEL_ALT);    // Clear Vrefh initiated

    ADC_SC2_REG(adcmap) |= ADC_SC2_REFSEL(REFSEL_EXT); // Vrefh = VDDA

   

    ADC_SC3_REG(adcmap) |= ADC_SC3_CAL_MASK ;                          // Start CAL

    while ((ADC_SC1_REG(adcmap,A) & ADC_SC1_COCO_MASK ) == COCO_NOT); // Wait calibration end

   

    if ((ADC_SC3_REG(adcmap)& ADC_SC3_CALF_MASK) == CALF_FAIL )

    { 

    return 1;                                                            // Check for Calibration fail error and return

    }

    // Calculate plus-side calibration

    cal_var  = 0x00;

   

    cal_var  = ADC_CLP0_REG(adcmap);

    cal_var += ADC_CLP1_REG(adcmap);

    cal_var += ADC_CLP2_REG(adcmap);

    cal_var += ADC_CLP3_REG(adcmap);

    cal_var += ADC_CLP4_REG(adcmap);

    cal_var += ADC_CLPS_REG(adcmap);

   

    cal_var = cal_var/2;

    cal_var |= 0x8000;    // Set MSB

   

    ADC_PG_REG(adcmap) = ADC_PG_PG(cal_var);

   

   

    // Calculate minus-side calibration

    cal_var  = 0x00;

   

    cal_var  = ADC_CLM0_REG(adcmap);

    cal_var += ADC_CLM1_REG(adcmap);

    cal_var += ADC_CLM2_REG(adcmap);

    cal_var += ADC_CLM3_REG(adcmap);

    cal_var += ADC_CLM4_REG(adcmap);

    cal_var += ADC_CLMS_REG(adcmap);

 

    cal_var  = cal_var/2;

   

    cal_var |= 0x8000;     // Set MSB

   

    ADC_MG_REG(adcmap)   = ADC_MG_MG(cal_var);

   

    ADC_SC3_REG(adcmap) &= ~ADC_SC3_CAL_MASK ; /* Clear CAL bit */

   

    return 0;

}

But when i make a conversion, after eache reset, results vary greatly with a gap of 80 points(ex input DADP3 = 2,18 V, DADM3 = 0,82 V, output (before reset 15137, after reset 15050)). I tried looking values of registers ADCx_CLPD and ADCx_CLMD and write  these values in the calib function in order to these registers don't change after each reset. Therefore, output value don't vary.


How can I fix this don't write registers ADCx_CLPD and ADCx_CLMD ?

Many thanks

 

LE Quang Huy

Outcomes