Jump to content
energia

Building low power into Energia

Recommended Posts

Hi,

 

I like a lot the idea of having LPM available into Energia, from a beginner's point of view, what I miss the most is a LPM-aware delay() function, based on 32KHz chrystal, if available, this allows for RTC implementations.

Share this post


Link to post
Share on other sites

Hi,

 

I like a lot the idea of having LPM available into Energia, from a beginner's point of view, what I miss the most is a LPM-aware delay() function, based on 32KHz chrystal, if available, this allows for RTC implementations.

:shock:

You're going to do an RTC using a delay instead of an interval?!! Bear with me for a second, say I delay for 1000ms (1 second) then increment the second counter by 1, then check to increment minute, then hours and then send this information to my LCD screen. When I enter the 1000ms delay again I'm (for example) 1002ms in real time. Ergo; you're going to go off by 0.2% or almost 3 minutes a day!

If I want to do something really time related, I use an interval, so I fire my timer once a second. Then instead of adding these 2ms to my second, they are inside my second (get eaten off of the period I'm in low power).

Share this post


Link to post
Share on other sites

:shock:

You're going to do an RTC using a delay instead of an interval?!! Bear with me for a second, say I delay for 1000ms (1 second) then increment the second counter by 1, then check to increment minute, then hours and then send this information to my LCD screen. When I enter the 1000ms delay again I'm (for example) 1002ms in real time. Ergo; you're going to go off by 0.2% or almost 3 minutes a day!

If I want to do something really time related, I use an interval, so I fire my timer once a second. Then instead of adding these 2ms to my second, they are inside my second (get eaten off of the period I'm in low power).

 

Well, no, sorry, I mixed up things, I was thinking about misllis(), I meant that with current millis implementation, the millis stop counting in LPM, I would also like to have a millis() which still counts (from the chrystal) when in LPM.

 

So, to summarize, I would like to see a LPM-delay and a LPM millis, I tend to use millis for debounching push buttons, if I go to sleep in the loop and attach an interrupt to a pin, currently I cannot use millis to debounce because it stops counting when sleeping.

 

I would implement an RTC with an interrupt, but I usually get an external DS1388 to have battery backup.

Share this post


Link to post
Share on other sites

I've had a little bit of a play, and have made up a few libraries for basic LPM support. These libraries are based on the Energia core files, but take advantage of the fact that the Energia linker gives a higher priority to libraries than to the core, consequently if you add these libraries to your sketch, they will be used seamlessly instead of the core files.  The advantage of doing it this way, is that unless you add the library to your sketch, the standard core files are used, so there's no compatibility issues resulting from modifying the standard core.  I have also designed the routines so that they maintain total compatibility with the existing Energia framework.  Although I don't expect any insidious bugs, the code isn't thoroughly debugged, so if you do choose to use it, it is at your risk.  I have only tested on the 2553 & 2452 - perhaps someone with a 2231 or 5529 could test and modify if they feel so inclined.

 

My replacement libraries are:

LPMinterrupts - replaces the core Winterrupts.c.  The inbuilt pin handler now clears LPM bits on exit, so you can go to LPM4 and have your program wake up after a pin interrupt occurs.  Also I've added a couple of functions "waitForAnyPin" and "waitForPin" that allow you to pause execution at a set low power mode until a pin interrupt occurs, with an optional timeout.

 

crystalWDT - replaces the basic timer core in wiring.c with a version that uses the 32.768 crystal instead of SMCLK. This reduces the resolution of millis & delay, but allows the use of LPM3 timed delays. I have enhanced the delay function to take an optional parameter specifying the low power mode.  In addition I have also added a seconds() function which gives the number of seconds since startup. It takes about 136 years for seconds() to roll over, compared to approx 50 days for millis().

 

VLOclockWDT - replaces the core wiring.c with a version that uses the internal VLO clock. Again this allows the use of LPM3 timed delays but the VLO clock has poorer resolution and is not nearly as accurate as the standard SMCLK.  I didn't bother with a seconds() function here, as I don't believe the low accuracy of the VLO clock would make it useful.

 

I have also attached a couple of basic sketches to demonstrate the functions in the libraries.  When I tested I found the following power consumption in the delay and waitForPin functions:

 

LPM0 - 735uA

LPM3 - 9uA

LPM4 - <1uA (my meter read 0)

 

These are just an idea that I'm throwing out into the open for people to look at, criticise, praise, use or delete as they desire. I'm not suggesting that it be the method ultimately used in Energia (although I'd be very flattered if it is).

 

 

EDIT: Apparently some people are having trouble opening the zip - if it doesn't work, try the version attached a couple of posts down.

lpm.zip

Share this post


Link to post
Share on other sites

@@grahamf72

the library file format from the zip file folders are not in the proper Arduino/Energia file/folder format?

aka examples files and header files...

running the test files fails compile due to Energia not finding the header files? 

I am using ver 10 on windows /xp/sp3 on a 2553

Share this post


Link to post
Share on other sites

@@MSP430Andy

Sorry, no they are just a quick zip up from my library & sketch folders. You will need to manually add the LPMinterrupts, CrystalWDT & VLOclockWDT folders into your library path, and add the two samples into your sketches folder. Once they are in your libraries folder, Energia should be able to find the headers - you will need to restart Energia if it was running when you copied them into the libraries folder.

 

I also haven't bothered making a keywords.txt to go with them. These were just a quick knock up for testing (and also because The VLO part will be handy for something else I'm working on), that I'm throwing out for comment. Depending what feedback I get, I may redo them as a traditional library with examples, keywords.txt etc. I'm away from my PC for a while now though, so it will probably be a few days before I can rezip it as a fully-fledged library.

 

 

Sent from my iPad using Tapatalk

Share this post


Link to post
Share on other sites

This may be better suited for the Stellarisiti /Tiva C forum but it would be good to also think about the Tiva capabilities when discussing low power enhancements. It would be nice if some of the enhanced functionality could be shared with the Tiva C.  The Tiva C has lots of timers and even a RTC.  Here's a quote from the TI site.

 

Tiva C Series MCUs also have a number of clock and power domains that can be gated as needed to manage power. When the DSP or floating-point units are not needed, for example, or if any of the peripheralswill be idle, power and/or clocking to those modules can be shut down in order to optimize power consump-tion. Tiva C Series devices provide sleep, deep-sleep and hibernate (HIB) modes to save power when minimalfunctionality is required. In the hibernate mode, power to the entire chip is cut off except to the HIB block,leaving the MCU in a state where it can be brought back to life when the need arises. The HIB block includesa 32-kHz oscillator circuit, a supporting real-time clock (RTC) module, a battery monitor circuit and sixteen32-bit words of backup battery SRAM. This minimalist implementation allows the power consumption to be reduced, in hibernate (HIB) mode, to as little as 1.6

Share this post


Link to post
Share on other sites

I took a while but I finally got around to spend a couple of days looking at low power modes using the awesome feedback in this thread. The key of course is to not break any existing API's. That led to the introduction of a sleep() API. It's not fully baked yet but I have some interesting numbers below.

 

1: Empty loop: 5.3 mA

2: loop with delay(10): 800 uA

 

That's pretty low power already if your code spends most of it's time in delay(). The new sleep API improves the current consumption significantly. Right now it uses the 32k crystal only but the idea is to fall back on the VLO if there is no XTAL. This will basically be done by looking at the oscillator fault bit. Sleep goes down to LPM3. You might ask, why not put LPM3 mode in delay(). This was the plan initially but it would potentially break to many Sketches if the user would not be aware of the change in behavior.

 

3: loop with sleep(10): 30 uA

This set WDT to wakeup every 2 milliseconds and hence the resolution is 2 milliseconds.

4: loop with sleepSeconds(1): 1.3 uA measured with a FLUKE multimeter so I am positive that this is pretty accurate.

This sets WDT to wakeup every 1 second. 

 

You can also call delay with > 1000. It will call sleepSeconds() for the whole seconds and the sleep() for the remainder. The full seconds will draw 1.3 uA and the remainder 30 uA.

 

To give some color to what this means in terms of battery live. I have an Anaren 900MHz wireless BoosterPack transmitting sensor data every 10 sec. The time it takes to transmit and the current draw associated with it can be neglected vs the time spend in LMP3. To take worse case let's say we consume 2.5 uA on average. With a CR2032 coin cell battery with a capacity of 225mA the sensor node can operate for 63000 hours or 2625 days or roughly 7 years :-) The battery live was calculated using the "battery life calculator" up on the Digikey website. This calculator already takes in account external factors that can affect battery life by applying a 0.7 multiplication.

 

There is still plenty of room for improvement but I think this is pretty interesting already.

Once sleep is implemented for all boards I will look at attachInterrupt() as suggested in this thread.

 

Thanks for all the help and feedback!

 

Robert

Share this post


Link to post
Share on other sites

I just finished the first version of low power implementation. 2 new functions were introduced: sleep(uint32_t milliseconds) and sleepSeconds(uint32_t seconds).

sleep() has a resolution of 2 ms while sleepSeconds() has a resolution of 250ms. So calling sleep(1) will actually get you 2 ms. calling sleepSeconds(1) will get you 1.25 seconds. sleep() will go to LPM3 2ms at the time while sleepSeconds() will go to LPM3 250ms at the time. For this reason sleepSeconds() is a lot more efficient. sleep() depending on the MSP430 will get you between 15uA for the FR5969 and 25uA for the G/F5-Series. sleepSecond on the other hand will get you between 700nA for the FR5969 and 2uA for the G/F5-Series. If you would like to give this a try then replace the flowing files in your Energia installation. Make sure that you create a backup of your original files first.

Replace: hardware/msp430/cores/msp430/Energia.h with https://raw.githubusercontent.com/energia/Energia/master/hardware/msp430/cores/msp430/Energia.h

 
Below is an example Sketch for the G-Series that spends most of it's time in LPM3 and briefly flashes the green LED every x seconds/milliseconds.

/* 
 * To reduce power consumption all unused pins should be set as output low.
 * Setting pins as output can potentiall cause conflicsts.
 * Therefor this below functions set all pins to input pulldown as a good alternative.
 */
void setInputLow(uint8_t port, uint8_t pins) {
  volatile uint8_t *out;
  volatile uint8_t *ren;

  /* Get the output register */
  out = portOutputRegister(port);
  /* Get the internal resistor pull up/down register */
  ren = portRenRegister(port);
  
  /* If the port is not a port then return */
  if(out == NOT_A_PORT || ren == NOT_A_PORT) return;
  
  /* Enable the internal pull up/down resistors */
  *ren |= pins;
  /* Clear output register bits to select pull down */
  *out &= ~pins;  
}

void setup() { 
  /* IMPORTANT: Set all unused pins to input low to reduce power consumption. 
   * The XTAL bits, P2.6/7 on the G-series and P5.4/5 on the F5529 and PJ4/5 on the FR5969
   * should NOT be set as input low since this significantly increases current draw and
   * the crystal will fail to start. 
   * The example below shows the pin settings for the G2553.
   * P1.6 is the Green LED and P2.6/7 are the the Crystal pins. */
   
  setInputLow(1, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT7);
  setInputLow(2, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5);
//  setInputLow(3, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
//  setInputLow(4, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
//  setInputLow(5, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
//  setInputLow(6, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
//  setInputLow(7, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
//  setInputLow(8, BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
  
  /* Set the GREEN_LED as OUTPUT */
  pinMode(GREEN_LED, OUTPUT);
}

void loop() {

  /* Briefly flash the RED LED every x seconds */
  digitalWrite(GREEN_LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(10);
  digitalWrite(GREEN_LED, LOW);    // turn the LED off by making the voltage LOW
  delay(10); 

  /* Sleep for 2 seconds. Around 1.5 uA of current */
  sleepSeconds(2);
  /* Sleep for 500 ms. Around 25 uA current */
//  sleep(500);
}

Share this post


Link to post
Share on other sites

Great work !

 

I think it was the best solution to adopt.

 

Just a remark : reading your code, I see that if there isn't a crystal, timeout will take 2 sec, so 2 sec lost at starting, right ? Is it possible, if we know that there is no crystal, to skip this step and directly configure VLO ? 

Share this post


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...