Jump to content
energia

Building low power into Energia

Recommended Posts

The only way to know if there is a XTAL present is to try and start it and check the fault flag. The 32kHz XTAL, according to the datasheet, can take 1 sec to startup for some MSP430's. I still have a question outstanding with the MSP430 folks to confirm this. Hence this is the reason it tries for 2 sec. I could give the user a define that they can set in the Sketch to indicate that there is no XTAL present and that would allow the code to skip over the XTAL testing all together.

Share this post


Link to post
Share on other sites

Quick idea/solution for "interrupting" the sleep in the middle from an attachInterrupt() ISR:

 

1. wiring.c change:

        while(sleeping && (millis() - start <= seconds * 1000))
                /* Wait for WDT interrupt in LPM3 */
                __bis_status_register(LPM3_bits+GIE);

as the conditional in both functions

 

2. WInterrupts.c change:

__attribute__((interrupt(PORT1_VECTOR)))
void Port_1(void)
{
        uint8_t i, is_sleeping = sleeping;
        for(i = 0; i < 8; i++) {
                if((P1IFG & BV(i)) && intFuncP1[i]) {
                        intFuncP1[i]();
                        if(intChangeVectP1 & BV(i)) {
                                P1IES ^= BV(i);
                                P1IFG = ((P1IN & BV(i)) == (P1IES & BV(i))) ? \
                                        (P1IFG & ~BV(i)) : P1IFG;
                        } else {
                                P1IFG &= ~BV(i);
                        }
                }
        }
        if (sleeping != is_sleeping)
                __bic_SR_register_on_exit(LPM3_bits);
}

Just added the "sleeping" check... similar change was added for PORT2_VECTOR too.

 

3. Energia.h support:

void delay(uint32_t milliseconds);
void sleep(uint32_t milliseconds);
void sleepSeconds(uint32_t seconds);
extern volatile uint8_t sleeping;
#define sleepAbort() { sleeping = false; }

Just exposed the "sleeping" variable and sleepAbort() sets it to false.

 

Example sketch that can be interrupted on the MSP430G2 launchpad with the P1.3 pushbutton:

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  
  pinMode(PUSH2, INPUT_PULLUP);
  while (digitalRead(PUSH2))
    delay(50); // wait for user press before writing anything to UART due to linux ACM bug
  
  Serial.println("Begin:");
  attachInterrupt(PUSH2, myISR, FALLING);
}

void loop()
{
  // put your main code here, to run repeatedly:
  Serial.print("millis: "); Serial.println(millis());
  Serial.flush();
  sleepSeconds(1);
}

void myISR()
{
  sleepAbort();
}

I'd say that "sleepAbort()" should be at the very end of the ISR simply to ensure the WDT ISR increments millis/micros correctly, since it tests that "sleeping" variable to determine how far to increment them.

 

Output:

Begin:
millis: 517
millis: 1901
millis: 3278
millis: 4655
millis: 4667
millis: 4680
millis: 4692
millis: 4704
millis: 4716
millis: 4729
millis: 4741
millis: 6118
millis: 7495
millis: 8872
millis: 10249
millis: 11626
millis: 11640
millis: 11653
millis: 11666
millis: 11680
millis: 11693
millis: 11706
millis: 13084
millis: 14462
millis: 15840

(note all the rapid-fire short increments around 11626-11706, 4655-4741 where I pressed the button)

Share this post


Link to post
Share on other sites

I am currently working on a low power mailbox sensor which notifies me when I recieve (snail) mail and when it is picked up. (I live in an appartment and my mailbox is in the central staircase)

 

I've implement the changes from both Robert and Spirillis to enable low-power interrupts. This is the code:

#include <x10rf.h> //https://github.com/p2baron/x10rf
#define intpin1     P1_2 // Sensor on the outer lid <- used by mailman to deliver mail
#define intpin2     P1_3 // Sensor on the inner lid <- used by me to pickup mail
#define txpin       P2_7 // Signal pin for 433Mhz module
#define txvcc       P2_6 // VCC oun for the 433Mhz module
#define reps           4 // Number of times the RF message should be send.	

x10rf myx10 = x10rf(txpin,0,reps);

void setup()
{
  for(uint8_t i;i<20;i++) pinMode(i, INPUT_PULLDOWN); // Put all Pins in INPUT_PULLDOWN (see http://forum.43oh.com/topic/4984-low-power-mode-first-sketch/)
  myx10.begin();
  pinMode(intpin1,INPUT_PULLUP);
  pinMode(intpin2,INPUT_PULLUP);
  pinMode(txvcc,OUTPUT);
  digitalWrite(intpin1, HIGH);
  digitalWrite(txvcc, LOW);
  attachInterrupt(intpin1, igotmail, CHANGE);
  attachInterrupt(intpin2, pickedupmail, CHANGE);
}
void loop()
{ 
  sleepSeconds(200);
}
void igotmail()
{
  uint8_t _state = digitalRead(intpin1);
  digitalWrite(txvcc, HIGH);
  if (_state == 0) {
    myx10.x10Security(3,0x04); // Send status alarm
  }
  sleep(10);
  digitalWrite(txvcc, LOW);
  sleepAbort();
}

void pickedupmail()
{
  uint8_t _state = digitalRead(intpin2);
  digitalWrite(txvcc, HIGH);
  if (_state == 0) {
    myx10.x10Security(3,0x84); // Send status normal
  }
  sleep(10);
  digitalWrite(txvcc, LOW);
  sleepAbort();
}

My question is: Do I need to sleep in the main loop? And can I use "sleep" in the interrupt routines?

 

 

 

 

Share this post


Link to post
Share on other sites

very nice!

did some measurements, on a naked G2553, 3.5V supply,

film cap as decoupling:

sleep(200)    10uA

sleep(2000)  0.5uA, same as sleepSeconds

 

impressive! 

 

did I miss something, does the sleep function go into lower

power mode for longer times?

Share this post


Link to post
Share on other sites

very nice!

did some measurements, on a naked G2553, 3.5V supply,

film cap as decoupling:

sleep(200)    10uA

sleep(2000)  0.5uA, same as sleepSeconds

 

impressive! 

 

did I miss something, does the sleep function go into lower

power mode for longer times?

I think sleepSeconds() is what goes into LPM for longer times.  sleep() in theory uses more power b/c it has to wake up & check more often.

Share this post


Link to post
Share on other sites

@@p2baron you brought up a good point and it made me think of extending the sleep API's with a sleep that takes no parameters. This function will put the MSP430 to sleep indefinitely. You would do an attachInterrupt() to the pin you want to wakeup from and exit sleep in your attachInterrupt() callback.

 

What do you think? Would this work?

 

Robert

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×