msp430, adc10, exceed current draw, can't turn off

Thread Starter

bug13

Joined Feb 13, 2012
1,863
Hi guys

I am using msp430g2452, my timer A fire every 100ms and start ADC10 reading every 6 seconds. The ADC result is handle in ADC10 interrupt. What I found is I CANNOT turn off the ADC10 (mainly the internal Vref) in ADC10 interrupt to save power. But I CAN turn off ADC10 with the same code in my Timer A interrupt.

The following codes use more current, ~180uA, gussing ADC10 is not turn off.

Code:
// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    // reset ADC10 to save power
    // ADC10CTL0 = 0;
    // ADC10CTL1 = 0;
   
    // other stuff, removed for easy reading

    // check voltage
    {
        static unsigned int counter = 0;
        counter++;
        if (counter == 60)                    // every count is 100ms, 60 counts is about 6 seconds
        {
            counter = 0;                    // reset counter
            ADC10CTL0 |= SREF_1;            // VR+ = VREF+, VR- = VSS
            ADC10CTL0 |= ADC10SHT_2;        // sample and hold time = 16 x ADC10CLK
            ADC10CTL0 |= REFON;                // reference on
            ADC10CTL0 |= ADC10ON;            // ADC10 on
            ADC10CTL0 |= ADC10IE;            // interrupt enable
            __delay_cycles(30);                // wait ~30us for Vref to stablise
            ADC10CTL1 |= INCH_11;            // input = (Vcc - Vss)/2
            ADC10CTL0 |= ENC;                // ADC10 enable
            ADC10CTL0 |= ADC10SC;            // start conversion
        }
    }
}

// ADC10 interrupt service routine
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    if (ADC10MEM < 852)            // 852 ~= 2.5V
        TMP_ENGAGED();            // engage temper alarm
    else if (ADC10MEM > 886)    // 886 ~= 2.6V
        TMP_DIS_ENGAGED();        // disengage temper alarm
    // the following two lines reset ADC10, turning it off
    ADC10CTL0 = 0;            
    ADC10CTL1 = 0;
}
but if I move move the code that turn off ADC10 to the timer A interrupt, it works, current draws reduce to ~10uA.

Code:
// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    // reset ADC10 to save power
    ADC10CTL0 = 0;
    ADC10CTL1 = 0;
   
    // other stuff, removed for easy reading

    // check voltage
    {
        static unsigned int counter = 0;
        counter++;
        if (counter == 60)                    // every count is 100ms, 600 counts is about 1 minutes
        {
            counter = 0;                    // reset counter
            ADC10CTL0 |= SREF_1;            // VR+ = VREF+, VR- = VSS
            ADC10CTL0 |= ADC10SHT_2;        // sample and hold time = 16 x ADC10CLK
            ADC10CTL0 |= REFON;                // reference on
            ADC10CTL0 |= ADC10ON;            // ADC10 on
            ADC10CTL0 |= ADC10IE;            // interrupt enable
            __delay_cycles(30);                // wait ~30us for Vref to stablise
            ADC10CTL1 |= INCH_11;            // input = (Vcc - Vss)/2
            ADC10CTL0 |= ENC;                // ADC10 enable
            ADC10CTL0 |= ADC10SC;            // start conversion
        }
    }
}

// ADC10 interrupt service routine
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    if (ADC10MEM < 852)            // 852 ~= 2.5V
        TMP_ENGAGED();            // engage temper alarm
    else if (ADC10MEM > 886)    // 886 ~= 2.6V
        TMP_DIS_ENGAGED();        // disengage temper alarm
}
If I turn off the ADC10 in my timer interrupt, it can have a delay between 0-100ms, and I want to minimize the current draw of my application, so how can I turn off the ADC10 properly ASAP after it done reading?



Thanks guys

James
 

sailorjoe

Joined Jun 4, 2013
363
Control register 1 has ADC10BUSY. In your first example, you could take a look and see what the value of ADC10BUSY is before you try to shut down the ADC10 to conserve power. Maybe the ADC is still busy for some reason (I don't know why), so the shutdown doesn't work, but 4 usec later, it would work.
 

Thread Starter

bug13

Joined Feb 13, 2012
1,863
Control register 1 has ADC10BUSY. In your first example, you could take a look and see what the value of ADC10BUSY is before you try to shut down the ADC10 to conserve power. Maybe the ADC is still busy for some reason (I don't know why), so the shutdown doesn't work, but 4 usec later, it would work.
Hi SailorJoe

I have tried polling the ADC10BUSY bit before I shut it down in my ADC10 interrupt, still can't get it to shut down properly. Here is how I do it:
Code:
// ADC10 interrupt service routine
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    if (ADC10MEM < 852)            // 852 ~= 2.5V
        TMP_ENGAGED();            // engage temper alarm
    else if (ADC10MEM > 886)    // 886 ~= 2.6V
        TMP_DIS_ENGAGED();    // disengage temper alarm
    while(ADC10CTL1 & ADC10BUSY);   // wait for ADC to finish conversion
    ADC10CTL0 = 0;                                 // shut down ADC10
    ADC10CTL1 = 1;                                 // shut down ADC10
}
 
Top