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.

TMS320F280049C: TM4C1294 ADC offset adjustment

Guru 55913 points
Part Number: EK-TM4C1294XL
Other Parts Discussed in Thread: TMS320F280049C,

Is it possible to run software ADC offset calibration using several input channels?

ADC offset adjust is factory calibrated tms320f280049c MCU but can be updated for temperature changes or other reasons. I recently debugged that routine and made work with motor SDK after the ADC interrupts were configured. The reason for abandoning they had not configured ADC's prior to calling calibration and lumped 7 SOC configurations into the ADC's configure call. Obviously that was a mistake. 

Below is the code to do 12 bit SAR calibration on the 3x ADC's via looping the 3 base addresses. Notice the ADC uses SOC1-16 (start of conversion) as an individual sequencer step. If only it had an ARM Cortex CPU  and NVIC as the interrupt structure is a bit outdated.

void HAL_runADCZeroOffsetCalibration(const uint32_t base)
{
    uint16_t adcOffsetMean;
    uint32_t adcSum;
    uint16_t index, sampleSize;

    //Interrupt_enable(INT_ADCA1); //Added
    //Interrupt_enable(INT_ADCB1); //Added
    //Interrupt_enable(INT_ADCC1); //Added

    // enable the cpu interrupt 2 for ADC interrupts
    //Interrupt_enableInCPU(INTERRUPT_CPU_INT2); //Added


    // Adc Zero Offset Calibration
    // This is not typically necessary
    // to achieve datasheet specified performance
    // A13 is VREFALO MCU pin 27
    ADC_setupSOC(base, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);
    ADC_setupSOC(base, ADC_SOC_NUMBER1, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);
    ADC_setupSOC(base, ADC_SOC_NUMBER2, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);
    ADC_setupSOC(base, ADC_SOC_NUMBER3, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);
    ADC_setupSOC(base, ADC_SOC_NUMBER4, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);
    ADC_setupSOC(base, ADC_SOC_NUMBER5, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);
    ADC_setupSOC(base, ADC_SOC_NUMBER6, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);
    ADC_setupSOC(base, ADC_SOC_NUMBER7, ADC_TRIGGER_SW_ONLY,
                 ADC_CH_ADCIN13, 10);

    EALLOW;
    HWREGH(base + ADC_O_OFFTRIM) = 112; //96
    EDIS;

    //
    // Set SOC1 to set the interrupt 2 flag. Enable the interrupt and make
    // sure its flag is cleared.
    //
    ADC_setInterruptSource(base, ADC_INT_NUMBER1, ADC_SOC_NUMBER7);
    ADC_enableInterrupt(base, ADC_INT_NUMBER1);
    ADC_clearInterruptStatus(base, ADC_INT_NUMBER1);

    adcOffsetMean = 0;
    adcSum = 0;
    index = 0;
    sampleSize = 512;

    while(index < sampleSize)
    {
        ADC_forceSOC(base, ADC_SOC_NUMBER0);
        ADC_forceSOC(base, ADC_SOC_NUMBER1);
        ADC_forceSOC(base, ADC_SOC_NUMBER2);
        ADC_forceSOC(base, ADC_SOC_NUMBER3);
        ADC_forceSOC(base, ADC_SOC_NUMBER4);
        ADC_forceSOC(base, ADC_SOC_NUMBER5);
        ADC_forceSOC(base, ADC_SOC_NUMBER6);
        ADC_forceSOC(base, ADC_SOC_NUMBER7);

        SysCtl_delay(2000);

        while(ADC_getInterruptStatus(base, ADC_INT_NUMBER1) == false)
        {
        	//SysCtl_delay(50);//delay
        }

        SysCtl_delay(100);

        adcSum += ADC_readResult(base, ADC_SOC_NUMBER0);
        adcSum += ADC_readResult(base, ADC_SOC_NUMBER1);
        adcSum += ADC_readResult(base, ADC_SOC_NUMBER2);
        adcSum += ADC_readResult(base, ADC_SOC_NUMBER3);
        adcSum += ADC_readResult(base, ADC_SOC_NUMBER4);
        adcSum += ADC_readResult(base, ADC_SOC_NUMBER5);
        adcSum += ADC_readResult(base, ADC_SOC_NUMBER6);
        adcSum += ADC_readResult(base, ADC_SOC_NUMBER7);

        index += 8;

        ADC_clearInterruptStatus(base, ADC_INT_NUMBER1);
    }

    ADC_clearInterruptStatus(base, ADC_INT_NUMBER1);

    //Calculate average ADC sample value
    adcOffsetMean = adcSum / 32; //sampleSize

    // delay to allow ADCs to power up
    SysCtl_delay(100U);

    EALLOW;
    HWREGH(base + ADC_O_OFFTRIM) = 112 - adcOffsetMean; //96
    EDIS;
    //ADC_setOffTrim(base, 96-adcOffsetMean);

    // delay to allow ADCs to power up
    SysCtl_delay(100U);

    return;
}