Jump to content
43oh

Sleep mode during a fixed duration ?


Recommended Posts

The standard Energia delay() function spends most of its time in LPM0.  If you want lower than that you need to set up a timer running off either the optional Crystal or the VLO clock. 

 

As an example for long low power delays, you could do something like the following:

 

#include <Energia.h>

volatile unsigned long delaycounter;

void StartTimer()
{
    //To use the VLO, Use the following:

    BCSCTL1 &= ~DIVA_3;      // ACLK without divider - nominally 12kHz
    BCSCTL3 = (LFXT1S_2);    // Source ACLK from VLO
    TA1CCTL0 = CCIE;         //  CCR0 interupt activated
    TA1CCR0=11999;           // 12000 ticks is nominally 1 second
    TA1CTL = TASSEL_1 | ID_0 | MC_1; // Clock for TIMER = ACLK, No division, up mode

  //Alternatively to use the Crystal for more accuracy use the Following
/*
    P2SEL |= (BIT6 | BIT7); // Reset P2_6 & P2_7
    BCSCTL1 &= ~DIVA_3;     // ACLK without divider - 32768kHz
    BCSCTL3 = (LFXT1S_0 | XCAP_3);// Source ACLK from XTal
    TA1CCTL0 = CCIE;             //  CCR0 interupt activated
    TA1CCR0=4096-1;      // we are dividing clock by 8, so 4096 ticks = 1 second
    TA1CTL = TASSEL_1 | ID_3 | MC_1; // Clock for TIMER = ACLK, By 8 division, up mode
*/

}

void StopTimer()
{
  TA1CTL|=TACLR;
}

//Set Up the Interrupt routine...
__attribute__((interrupt(TIMER1_A0_VECTOR)))
void timer_isr (void)
{
        ++delaycounter;         //increment our seconds counter
        __bic_status_register_on_exit(LPM3_bits); //exit at full power.
}

//And here is our delay function...
//this will create delays of up to approx 136 years
//with 1 second resolution.
void longdelay(unsigned long delayseconds)
{
  delaycounter=0;
  StartTimer();                     //start our timer up
  while (delaycounter<delayseconds)  //while we haven't reached our count...
    __bis_status_register(LPM3_bits+GIE); //switch back to LPM3.
  StopTimer();                       //times up, stop our timers.
};

void setup()
{
  Serial.begin(9600);
};

void loop()
{
  Serial.println("10 seconds mostly in LPM0 with traditional delay...");
  delay(10000);
  Serial.println("10 seconds in LPM3 with longdelay...");
  longdelay(10);
};    

 

When I tested this, I was getting about 1300uA (1.3mA) during the traditional delay(). This dropped to about 25uA when it was in the longdelay function.

Link to post
Share on other sites
  • 1 month later...

Yes, timers and interrupts can work together, with a few restrictions.

 

If you use the delay function above, when the interrupt finishes execution the delay will continue from where it left off. If this is not what you require (ie you want the delay to run for 8 seconds OR until a button is pushed, whichever comes first), you could modify the while clause to check for a change in a variable, then set the variable in your ISR. Remember to declare the variable as "volatile". There is a limitation with this approach, and it stems from the Energia library. The Energia library doesn't reset the low power mode when a pin interrupt exits. Consequently with the above code, your interrupt will run then the processor would go back to sleep until the timer wakes it up again. This means it could be up to a second before the delay exits. Personally I think the Energia interrupt dispatcher should have a call to _bic_status_register_on_exit(LPM4_bits) before it exits, so that it can wake the processor from all sleep modes, and I have modified my WInterrupts.c file to include this.

Link to post
Share on other sites
  • 2 months later...

Hello. I have a problem with timers. I would like to use the longdelay function above, but I use 2452 chip, not the 2553 and if I try to compile it, energia says "TIMER1_A0_VECTOR was not declared in ths scope"... Could someone rewrite the code to work with MSP430G2452? Thank you

Link to post
Share on other sites

Hi @@hawwwran, modifying this to suit the 2452 is pretty straightforward. Firstly, in StartTimer & StopTimer, change all the registers that start with TA1 to TA0, eg TA1CCTL0 becomes TA0CCTL0. Then change the interrupt routine to TIMER0_A0_VECTOR.

 

There are a couple of caveats with this though. The 2452 only has 1 timer, which is also used for serial & analogwrite. The above routine will mess up the timers these routines use, so serial & analogwrite will stop working. This is less of an issue with the 2553 which uses hardware serial. On the 2553, the only conflict is using analogwrite with the pins that use the 2nd timer.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...