AnsweredAssumed Answered

[KL26Z] Differential ADC with bad readings

Question asked by Karen Nisley on Jul 15, 2016
Latest reply on Jul 20, 2016 by Robin_Shen

I am attempting to configure the ADC on the FRDM-KL26Z in differential mode such that it takes a reading every time the read function is called in main().

I have an init() function:

void adc_init(void)

    OSC0_CR |= OSC_CR_ERCLKEN(0x1);         //enable oscerclk
    SIM->SCGC5 |= SIM_SCGC5_PORTE_MASK;     //enable clock for PORT
    SIM_>SCGC6 |= SIM_SCGC6_ADC0_MASK;      //enable the clock to ADC

    PORTE->PCR[20] |= PORT_PCR_MUX(0U);       //pin alt functions
    PORTE->PCR[21] |= PORT_PCR_MUX(0U);

    //Configure CFG1 & 2
    ADC0_CFG1 = ADC_CFG1_MODE(0x3);             //resolution 16 bit differential
                 //| ADC_CFG1_ADIV(0x2));         //& clock/2

    adc_cal();                              //call calibration as specified in datasheet flowchart

    //SC2- nothing here
    //SC3- nothing here

    ADC0_SC1A = (ADC_SC1_DIFF(0x1) | ADC_SC1_ADCH(0x0));       //enable differential mode & select input channel
    //ADC0_SC1B = (ADC_SC1_DIFF(0x1) | ADC_SC1_ADCH(0x3));       //enable differential mode & select input channel

    //software trigger & Vrefh and Vrefl are default

and a calibration function that is called by the adc_init();

void adc_cal(void)
{   //"for best calibration results" section is being ignored!!
    //ADC0_SC2 = ADC_SC2_ADTRG(0x0);          //clear ADTRG bit
    ADC0_SC3 = ADC_SC3_CAL_MASK;            //'user sets sc3[cal] and itll automatically begin'

    /* Wait until calibration is finished */
    while(ADC0->SC3 & ADC_SC3_CAL_MASK);

    //calibrate high side
    uint16_t cal_var_h = 0;                     //make a 16 bit var
    cal_var_h = (ADC0_CLP0 & ~ADC_CLP0_CLP0_MASK) + (ADC0_CLP1 & ~ADC_CLP1_CLP1_MASK) + (ADC0_CLP2 & ~ADC_CLP2_CLP2_MASK)+ (ADC0_CLP3 & ~ADC_CLP3_CLP3_MASK) + (ADC0_CLP4 & ~ADC_CLP4_CLP4_MASK) + (ADC0_CLPS & ~ADC_CLPS_CLPS_MASK);           //sum all the calibrations
    cal_var_h = cal_var_h / 2;              //divide the variable by two
    cal_var_h = cal_var_h & 0x800;          //set the msb
    ADC0_PG = cal_var_h;                    //store it where it belongs

    //calibrate low side
    uint16_t cal_var_l = 0;                     //make a 16 bit var
    cal_var_l = (ADC0_CLM0 & ~ADC_CLM0_CLM0_MASK) + (ADC0_CLM1 & ~ADC_CLM1_CLM1_MASK) + (ADC0_CLM2 & ~ADC_CLM2_CLM2_MASK)+ (ADC0_CLM3 & ~ADC_CLM3_CLM3_MASK) + (ADC0_CLM4 & ~ADC_CLM4_CLM4_MASK) + (ADC0_CLMS & ~ADC_CLMS_CLMS_MASK);           //sum all the calibrations
    cal_var_l = cal_var_l / 2;              //divide the variable by two
    cal_var_l = cal_var_l & 0x800;          //set the msb
    ADC0_MG = cal_var_l;                    //store it where it belongs

    //ADC0_SC3 = ADC_SC3_CAL(0x0);            //disable calibration

    if(ADC0_SC3 != 0)                       //check for success
        uart_putc('f');                     //complain on the uart if calibration failed

and a read function

int16_t adc_get_read(uint8_t channel)    //signed int should handle the 2's compliment
    if(channel == 0)
        //ADC0_CFG2 = ADC_CFG2_MUXSEL(0x0);
        ADC0_SC1A |= ADC_SC1_ADCH(0x0);    //trigger conversion on ch0
        while((ADC0_SC1A & ADC_SC1_COCO_MASK) == 0)  //conversion complete flag
            //wait for the conversion to complete
        //ADC0_SC1A = ADC_SC1_COCO(0x0);      //Reset COCO use the shift in
        return ADC0_RA;                     //result register, should clear COCO
/*nonfunctional channel 1 code snipped for brevity*/
    else    //in case of burp
        uart_putc('f');                     //complain on the uart if fail
        return 0;

The function calls in main() look like

reading0 = adc_get_read(0);
uart_outHex(reading0);          //sends the reading over the UART to terminal in ascii encoded hex


The frdm board is setup with R9 jumpered to enable external Vrefh, and Vrefh tied to 3.3V. DP0 is set to the output of the DAC and DM0 is set to ground.
The DAC, UART, and uart_outHex have been confirmed to work as expected and designed.


The failure is that the ADC reads very low values (0 through about 3, in hex) and very high values (0xFFFFFFFC through 0xFFFFFFFF) with no middle ground, and typically sticks to either high or low values with random deviations to the other value. I suspect that it is a clocking issue, but I can not determine where. Can anyone advise me? Thank you.