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

Discussion in 'Embedded Systems and Microcontrollers' started by bug13, Jan 21, 2016.

  1. bug13

    Thread Starter Well-Known Member

    Feb 13, 2012
    1,208
    38
    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 (Text):
    1. // Timer A0 interrupt service routine
    2. #pragma vector=TIMER0_A0_VECTOR
    3. __interrupt void Timer_A (void)
    4. {
    5.     // reset ADC10 to save power
    6.     // ADC10CTL0 = 0;
    7.     // ADC10CTL1 = 0;
    8.    
    9.     // other stuff, removed for easy reading
    10.  
    11.     // check voltage
    12.     {
    13.         static unsigned int counter = 0;
    14.         counter++;
    15.         if (counter == 60)                    // every count is 100ms, 60 counts is about 6 seconds
    16.         {
    17.             counter = 0;                    // reset counter
    18.             ADC10CTL0 |= SREF_1;            // VR+ = VREF+, VR- = VSS
    19.             ADC10CTL0 |= ADC10SHT_2;        // sample and hold time = 16 x ADC10CLK
    20.             ADC10CTL0 |= REFON;                // reference on
    21.             ADC10CTL0 |= ADC10ON;            // ADC10 on
    22.             ADC10CTL0 |= ADC10IE;            // interrupt enable
    23.             __delay_cycles(30);                // wait ~30us for Vref to stablise
    24.             ADC10CTL1 |= INCH_11;            // input = (Vcc - Vss)/2
    25.             ADC10CTL0 |= ENC;                // ADC10 enable
    26.             ADC10CTL0 |= ADC10SC;            // start conversion
    27.         }
    28.     }
    29. }
    30.  
    31. // ADC10 interrupt service routine
    32. #pragma vector = ADC10_VECTOR
    33. __interrupt void ADC10_ISR(void)
    34. {
    35.     if (ADC10MEM < 852)            // 852 ~= 2.5V
    36.         TMP_ENGAGED();            // engage temper alarm
    37.     else if (ADC10MEM > 886)    // 886 ~= 2.6V
    38.         TMP_DIS_ENGAGED();        // disengage temper alarm
    39.     // the following two lines reset ADC10, turning it off
    40.     ADC10CTL0 = 0;            
    41.     ADC10CTL1 = 0;
    42. }
    but if I move move the code that turn off ADC10 to the timer A interrupt, it works, current draws reduce to ~10uA.

    Code (Text):
    1. // Timer A0 interrupt service routine
    2. #pragma vector=TIMER0_A0_VECTOR
    3. __interrupt void Timer_A (void)
    4. {
    5.     // reset ADC10 to save power
    6.     ADC10CTL0 = 0;
    7.     ADC10CTL1 = 0;
    8.    
    9.     // other stuff, removed for easy reading
    10.  
    11.     // check voltage
    12.     {
    13.         static unsigned int counter = 0;
    14.         counter++;
    15.         if (counter == 60)                    // every count is 100ms, 600 counts is about 1 minutes
    16.         {
    17.             counter = 0;                    // reset counter
    18.             ADC10CTL0 |= SREF_1;            // VR+ = VREF+, VR- = VSS
    19.             ADC10CTL0 |= ADC10SHT_2;        // sample and hold time = 16 x ADC10CLK
    20.             ADC10CTL0 |= REFON;                // reference on
    21.             ADC10CTL0 |= ADC10ON;            // ADC10 on
    22.             ADC10CTL0 |= ADC10IE;            // interrupt enable
    23.             __delay_cycles(30);                // wait ~30us for Vref to stablise
    24.             ADC10CTL1 |= INCH_11;            // input = (Vcc - Vss)/2
    25.             ADC10CTL0 |= ENC;                // ADC10 enable
    26.             ADC10CTL0 |= ADC10SC;            // start conversion
    27.         }
    28.     }
    29. }
    30.  
    31. // ADC10 interrupt service routine
    32. #pragma vector = ADC10_VECTOR
    33. __interrupt void ADC10_ISR(void)
    34. {
    35.     if (ADC10MEM < 852)            // 852 ~= 2.5V
    36.         TMP_ENGAGED();            // engage temper alarm
    37.     else if (ADC10MEM > 886)    // 886 ~= 2.6V
    38.         TMP_DIS_ENGAGED();        // disengage temper alarm
    39. }
    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
     
  2. sailorjoe

    Member

    Jun 4, 2013
    361
    63
    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.
     
  3. bug13

    Thread Starter Well-Known Member

    Feb 13, 2012
    1,208
    38
    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 (Text):
    1. // ADC10 interrupt service routine
    2. #pragma vector = ADC10_VECTOR
    3. __interrupt void ADC10_ISR(void)
    4. {
    5.     if (ADC10MEM < 852)            // 852 ~= 2.5V
    6.         TMP_ENGAGED();            // engage temper alarm
    7.     else if (ADC10MEM > 886)    // 886 ~= 2.6V
    8.         TMP_DIS_ENGAGED();    // disengage temper alarm
    9.     while(ADC10CTL1 & ADC10BUSY);   // wait for ADC to finish conversion
    10.     ADC10CTL0 = 0;                                 // shut down ADC10
    11.     ADC10CTL1 = 1;                                 // shut down ADC10
    12. }
     
  4. bug13

    Thread Starter Well-Known Member

    Feb 13, 2012
    1,208
    38
    sailorjoe likes this.
Loading...