MSPM0C1104: Low power optimization - ADC pulls current high

Part Number: MSPM0C1104

I tried optimizing the power consumption of my device and can get as low as ~4.5uA on my custom hardware in STANDBY1. When requesting a short ADC measurement. however, my current consumption jumps to over 1mA. I did narrow it down to a snippet where I shortly initialise my ADC and start the conversion, then after the conversion stop it again.

This is roughly what my low power mode initialisation does.

DL_TimerA_stopCounter(PWM_INST);
DL_TimerA_disablePower(PWM_INST);

DL_I2C_disableController(I2C_0_INST);
DL_I2C_disablePower(I2C_0_INST);

DL_VREF_disableInternalRef(VREF);
DL_VREF_disablePower(VREF);
DL_ADC12_disableConversions(ADC12_INST);
DL_ADC12_disablePower(ADC12_INST);

delay_cycles(POWER_STARTUP_DELAY);

 

This is my problematic code. Inserting a delay_cycles with ~300us or more wait time fixes the issue.

void adc_off(void) {
    DL_VREF_disableInternalRef(VREF);
    DL_VREF_disablePower(VREF);
    DL_ADC12_disableConversions(ADC12_INST);
    DL_ADC12_disablePower(ADC12_INST);
    delay_cycles(POWER_STARTUP_DELAY);
}

void adc_on(void){
    DL_VREF_enablePower(VREF);
    DL_VREF_enableInternalRef(VREF);
    DL_ADC12_enablePower(ADC12_INST);
    DL_ADC12_setStartAddress(ADC12_INST, DL_ADC12_SEQ_START_ADDR_00); // manual repeat of ADC sequence
    DL_ADC12_enableConversions(ADC12_INST);
    DL_ADC12_startConversion(ADC12_INST);
    delay_cycles(POWER_STARTUP_DELAY);
}

void my_conversion(void) {
    adc_on();
    while (interrupt_received == false) {;}
    delay_cycles(24*100*3); // fixes issue
    adc_off();
}

Why exactly could this occur? Why does a delay annul this issue? Why 300us? The time seems quite long to me for a 24MHz device.

When I remove the while loop and the delay, the issue also doesn't occur (no optimization). In that case, however, I assume that the registers have not been processed before turning ADC off again.

CTL0 = 0x05000000
CTL1 = 0x00010000
CTL2 = 0x03000000

  • Hello RH,

    I want to check some details about this issue:

    • It is normal that the current up when CPU and ADC is involved in to do conversion and calculation, etc.
    • The current you measured is the instantaneous value or the average value in a long time?
    • I think you use ADC interrupt to receive the ADC conversion result, right? So you need CPU involved in this process.
    • It is very strange that after you add a time delay, the power consumption down, because in the time length you do the time delay, the CPU is wake and ADC is also powered up. So I can't understand why the power consumption actually decreased.

    BR,

    Janz Bai

  • Hello Janz Bai,

    The 1mA current stays for an indefinite period of time but may be resolved with new ADC measurements it seems.
    Yes, I am using ADC interrupts to notify my task of new available data.

    I actually might have found a clue. It might be that I am disabling the ADC while a measurement is running. But would the ADC power down not resolve this? My ADC conversion runs for about 100us.

    Best Regards,

    RH

  • I should add that my ADC conversion runs as a sequence with 4 total conversions.

    Adding stopConversion() at the top of my adc_off() function did nothing.

  • Hello RH,

    Could you please help to explain what is the meaning of "I am disabling the ADC while a measurement is running"?

    You can try to reset whole ADC module before enter STANDBY mode, and then re-initialize ADC again after exit from STANDBY mode 

    And by the way, could you please show the ADC interrupt handle part code to me too? I want to check the interrupt handler setting when you use sequence

    BR,

    Janz Bai

  • Hello Janz Bai,

    by disabling the ADC I mean the adc_off function I posted initially. I am starting the measurement, wait for the interrupt to notify me that my measurement is done, then call adc_off. This could potentially happen during the measurement of the second measurement in the sequence.

    volatile interrupt_received = false;
    
    void ADC12_INST_IRQHandler(void)
    {
        switch (DL_ADC12_getPendingInterrupt(ADC12_INST))
        {
        case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
            interrupt_received = true;
            adc_data_flags |= 0x1;
            break;
        case DL_ADC12_IIDX_MEM1_RESULT_LOADED:
            adc_data_flags |= 0x2;
            break;
        case DL_ADC12_IIDX_MEM2_RESULT_LOADED:
            adc_data_flags |= 0x4;
            break;
        case DL_ADC12_IIDX_MEM3_RESULT_LOADED:
            adc_data_flags |= 0x8;
            DL_ADC12_stopConversion(ADC12_INST);
            DL_ADC12_setStartAddress(ADC12_INST, DL_ADC12_SEQ_START_ADDR_00); // manual repeat of ADC sequence
            break;
        default:
            break;
        }
    }

    12-bit ADC, no averaging, measuring on channel 2 of the SOT-16 (DYY) package. Using ULPCLK at 24MHz, 24 clock divider. Software triggers, internal VRef at 1.4V. 

    Best Regards