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.

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

  • Hello RH,

    Let me check your code, and I will reply to you tomorrow (China time)

    BR,

    Janz Bai

  • Hello Janz Bai,

    I'm still awaiting your answer. Did you find anything?

    Best Regards

  • Hello R H,

    Sorry for the late response. I have checked your code. If you want to let ADC work normally, you need put this code "interrupt_received = true;" into the ADC interrupt case DL_ADC12_IIDX_MEM3_RESULT_LOADED: because if you want to disable ADC, you need for all the memory 0~3 is ready. But in your original code, you put the  "interrupt_received = true;" in the case DL_ADC12_IIDX_MEM0_RESULT_LOADED: and you use 

     while (interrupt_received == false) {;} in you code, this will cause that when the memory 0 is ready, you will disable ADC, then cause issue, because you use 
    memory 0~3 in your code. But after you add the time delay, it will give enough time to let ADC complete the conversion of memory 1~3, then there will be no issue.


    Best Regards,
    Janz Bai


  • Hello Janz Bai,

    I want to only do the first ADC conversion. Why can I not stop the conversion with DL_ADC12_disableConversions(ADC12_INST) or DL_ADC12_stopConversion( ADC12_INST) without this issue? 

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

    According to the low power optimization guide this is the correct sequence.

    Best Regards,

    RH

  • Hello RH,

    You can use the DL_ADC12_disableConversions(ADC12_INST) or DL_ADC12_stopConversion( ADC12_INST)  to stop the ADC conversion, this is not the key point of this issue. I have helped you analysis the possible root cause in my last time response. In your application, you used the memory 0~memory 3 to store your conversion result, but you put the flag interrupt_received = true; in the memory0 load interrupt, it will cause "when memory 0 load, the intterupt_recieved will be true, then in your original code (with out time delay) like below figure, CPU will operate adc_off() directly soon which includes the ADC disable conversion. As I said, all of these occurs when memory 0 load, but at the same time, memory 1~memory 3 maybe not ready, that is the reason why you face the ADC usage issue. 

    And if you add the time delay in the my_conversion(), it will give time to let memory 1~memory 3 ready, then adc_off() operates, ADC runs correctly.

    That is the reason why I ask you can put the  flag interrupt_received = true in the memory 3 load intterupt. 

    Can you understanding now? If you have any questions about my explanation, feel free to let me know.

    BR,

    Janz Bai

  • Hello Janz Bai,

    I understand that if I put the interrupt_received = true statement into memory 3 load interrupt, I will not require the delay anymore.
    The problem is that I wish to only do the conversion of memory 1 in this specific case. But if I stop the conversion after memory 0 load, the current consumption stays at 1mA where it should be <10uA. 

    What I do not understand is why stopping the conversion and powering down the ADC and VREF does not stop the power flow to the ADC.

    Kind Regards,

    RH