This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/LAUNCHXL-F280049C: ADC Zero Offset Calibration

Part Number: LAUNCHXL-F280049C

Tool/software: Code Composer Studio

according to 28004X datasheet, zero offset for ADC module is needed, but there is no AdcOffsetCalibrate() function corresponding to 28004X. So i coded the ADCzeroOffsetCalibration below. During debug, program stuck in 

        while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0)
        IntFlag = (HWREGH(ADCA_BASE + ADC_O_INTFLG) & ADC_INTFLG_ADCINT1);
        while (IntFlag == 0)
        {}  

I found that ADCINTOVF was always set 1. And I can not find the root cause, could you please give some advice, thanks.

void ADCzeroOffsetCalibration(void)
{
    uint16_t index, SampleSize, Mean, IntFlag;
    uint32_t Sum;
    index       = 0;            //initialize index to 0
    SampleSize  = 256;          //set sample size to 256 (**NOTE: Sample size must be multiples of 2^x where is an integer >= 4)
    Sum         = 0;            //set sum to 0
    Mean        = 999;          //initialize mean to known value
    IntFlag     = 0;
    EALLOW;
    //an artificial offset to account for negative offset
    HWREGH(ADCA_BASE + ADC_O_OFFTRIM) = 0x70U;
    EDIS;
    // Configure SOC0 of ADCA to convert pin A13 with a sample window of 7
    // SYSCLK cycles. The EPWM1SOCA signal will be the trigger.
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER4, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER5, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER6, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER7, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER8, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER9, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER10, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER11, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER12, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER13, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER14, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER15, ADC_TRIGGER_EPWM1_SOCA,
                 ADC_CH_ADCIN13, 7);
    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER2);
    ADC_disableContinuousMode(ADCA_BASE, ADC_INT_NUMBER1);
    ADC_disableContinuousMode(ADCA_BASE, ADC_INT_NUMBER2);
    ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
    //EOC6 triggers ADCINT1
    ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER6);
    //EOC14 triggers ADCINT2
    ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER2, ADC_SOC_NUMBER14);
    //this need be reset after calibration finished
    EALLOW;
    HWREGH(ADCA_BASE + ADC_O_INTSOCSEL1) = (HWREGH(ADCA_BASE + ADC_O_INTSOCSEL1) & ~ 0xFFFF) | 0xAAAA;
    HWREGH(ADCA_BASE + ADC_O_INTSOCSEL2) = (HWREGH(ADCA_BASE + ADC_O_INTSOCSEL2) & ~ 0xFFFF) | 0x5555;
    EDIS;
    DEVICE_DELAY_US(1000);
    // Force Start SOC0-7 to begin ping-pong sampling
    EALLOW;
    HWREGH(ADCA_BASE + ADC_O_SOCFRC1) |= (HWREGH(ADCA_BASE + ADC_O_SOCFRC1) & ~ 0xFFFF)| 0x00FF;
    EDIS;
    while( index < SampleSize )
    {
        //Wait for ADCINT1 to trigger, then add ADCRESULT0-7 registers to sum
        while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0)
        IntFlag = (HWREGH(ADCA_BASE + ADC_O_INTFLG) & ADC_INTFLG_ADCINT1);
        while (IntFlag == 0)
        {}  //program stuck, because INTFLG is 0
        ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER2);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER3);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER4);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER5);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER6);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER7);
        //Wait for ADCINT2 to trigger, then add ADCRESULT8-15 registers to sum
//        while (AdcRegs.ADCINTFLG.bit.ADCINT2 == 0)
        IntFlag = (HWREGH(ADCA_BASE + ADC_O_INTFLG) & ADC_INTFLG_ADCINT2);
        while (IntFlag == 0)
        {}
        ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER2);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER8);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER9);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER10);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER11);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER12);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER13);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER14);
        Sum += ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER15);
        index+=16;
    } // end data collection
    ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
    ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER2);
    Mean = Sum / SampleSize;    //Calculate average ADC sample value
    HWREGH(ADCA_BASE + ADC_O_OFFTRIM) = 0x70U - Mean;
    HWREGH(ADCB_BASE + ADC_O_OFFTRIM) = 0x70U - Mean;
    HWREGH(ADCC_BASE + ADC_O_OFFTRIM) = 0x70U - Mean;
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER2, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER3, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER4, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER5, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER6, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER7, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER8, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER9, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER10, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER11, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER12, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER13, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER14, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER15, ADC_INT_SOC_TRIGGER_NONE);
}

  • Hi,

    This post isn't very helpful for us to respond to. There is not much that we can respond too since there is very little information.

    Also, please do not post large amounts of code like this on the forum.

    What specific behavior are you observing? What are you wishing to accomplish?

    sal

  • thanks for your suggestion, and i update the question, please review.

  • Hi,

    An ADC expert will respond to this thread. 

    Thank you for your patience.

    sal

  • Hi Yamazaky,

    Self-calibration of offset error (one-time or periodic) is not required for this device.  Where do you see this requirement in the datasheet?

    Certainly you can re-calibrate the offset error, if desired.  

    In your code you are getting an overflow because you have disabled continuous mode but you aren't clearing the ADCINT flag.

    If you want to sample using the continuous ping-pong method, you might want to start with the continuous ADC example for bitfields for the F2837x device.  You can instead use the ePWM or SW triggered method that are demonstrated in the F28004x examples - these should work fine for offset re-calibration - just point the SOC to the internal VREFLO connection and use the same strategy for artificially adjusting the offset trim before sampling.   

  • Hi Devin, 

    Thanks for your guidance. You can find self-calibration in Technical Reference Manual part 13.1.12.1--ADC Zero Offset Calibration.

    I want to realize calibration by ping-pong sampling, but the cycle only executed once. I coded this program referred to 2806x AdcOffsetSelfCal() in example, where the ADC continuous mode was disabled. So whether the continuous mode should be disabled?

    And I will check f2837x ping-pong sampling.

  • Hi Yamazaky,

    The F2806x code should also be a usable starting point; the F28004x ADC is different, but the HW wrapper is reasonably similar. 

    Is the F2806x code you are starting with driver-lib or bit-field based?  One thing that can happen with ping-ping sampling is the ADC can sample faster than the CPU can collect the results.  To determine if this is happening, add a statement before your spin-wait on the ADCINT flag to determine if the flag is already set.  Something along the lines of:

    if(1 == AdcaRegs.ADCINTFLG.bit.ADCINT1){
        //sampling fail; the flag should not be set before entering the spin-wait loop
    }
    while (0 == AdcaRegs.ADCINTFLG.bit.ADCINT1);
    //...collect samples indicated by ADCINT1 completion...

    I'm also not sure about this sequence:

            while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0)
            IntFlag = (HWREGH(ADCA_BASE + ADC_O_INTFLG) & ADC_INTFLG_ADCINT1);
            while (IntFlag == 0)

    I think it will work, but only because of the first spin-wait loop.  The second while loop doesn't really make sense since IntFlag will never update inside the loop.  

  • Hi Devin, 

    I am glad to tell you that my problem had been resolved according your suggestion about the f2837x. Difference is trigger SOCs every time enter the While-Loop

    by software, but in the 2806x the ping-pong sampling use SOCx to trigger the another SOCx. And the F2806x code you are starting with bit-field based.