Enables lower power Sleep and power down modes for LPC11U24 systems than the mbed API supports directly.

Dependents:   mBuDice SleepyCounting

Provides a clean method to put the mBuino into various power save modes while minimizing power draw. This code is specifically for the mBuino, for other LPC11U24 based systems use this version.

When the mBuino was released the mbed library Sleep() and DeepSleep() commands causes the system to crash, even if fixed in a later release of the library the mBed API doesn't allow access to the lowest power modes that you need when running from a watch battery. Hence this library.

When commanded to sleep the system will pause in a power saving state until it receives an interrupt at which point things carry on as before.

The basic use is

#include "mBuinoSleep.h"

main() {
mBuinoSleep(PowerDown);
}

In order to shut off the LEDs the library will create a BusOut object called LEDs containing all 7 mBuino LEDs in order. When entering sleep mode the LEDs will be turned off, when waking the previous state will be restored. Within your code you can set the state of all 7 LEDs by setting the value of LEDs directly e.g. LEDs = 0x7f would turn them all on. LEDs=0x2A would turn LEDs 2,4 and 6 on. See BusOut for more details.

Similarly a DigitalIn called progMode is created on port pin 0_3 in order to disable the internal pullup on this pin (required to reduce power consumption).

If either of these cause a problem in your code then use the mBuino_Sleep_Minimal library which has the same sleep code but without any IO control. If doing this ensure you disable the pullup and turn off the LEDs in your code.

Finally if you add the line

sleep_CleanShutdown = true;

to your code anywhere before entering sleep mode then the system clock will be switched from the PLL to the IRC before entering DeepSleep or PowerDown and switched back after waking up. This is recommended by the CPU user manual in order to avoid clock glitches but in practice doesn't seem necessary. The down side to doing this is that any code in the interrupt routine that wakes the system up again will run at the IRC frequency not the normal clock frequency.

The supported sleep modes are:

  • Sleep - About a 50% power saving. All timers run as normal.
  • DeepSleep - Power consumption in the 350uA region (a few weeks or so on a watch battery). All timers are disabled, only external interrupts can wake the system.
  • DeepSleepWD - As DeepSleep but also keeping the Watch Dog timer powered up. Tiny increase in power (4uA) but the watchdog wakeup library can be used to wake the system on a timer.
  • PowerDown - Power consumption in the 3uA region (Battery life in the decades range, in practice battery life will be determined by other factors). Similar to DeepSleep but takes a few ms longer to wake up.
  • PowerDownWD - PowerDown but with the watch dog timer running resulting in a power consumption of 7uA.
  • DeepPowerDown - Sub uA power consumption but can only wake from the reset or wakeup pin (which also causes a reset).

In DeepSleep or PowerDown modes it is NOT is possible to use a normal Ticker or Timeout to wake up from sleep mode. To wake up on a timer use the modes ending in WD and use this library to configure the watchdog. See this program for an example.

An IO interrupt (i.e. anything triggered by a pin that is defined as an InterruptIn) will wake the system up from all sleep modes other than DeepPowerDown.

NOTES:

DO NOT enter sleep mode from within an interrupt (that includes Timers, Tickers, Timeouts etc...) unless your wakeup interrupt is higher priority (this is not the mbed default, if you aren't sure or don't know what I'm talking about then it isn't). If you do this you will never wake up.

DeepPowerDown requires an external pullup on the wakeup pin, without this the system will wake up as soon as it enters power down. On the mBuino this resistor is not there, you need to add it. For other platforms check the schematic.

All deepsleep and powerdown modes currently disable the brownout detection circuit. Keeping this powered would add about 50uA to the power consumption. If for some reason you need this circuit active then this would require a minor change to the library, specifically the value programmed into PDSLEEPCFG around line 40.

Committer:
AndyA
Date:
Sun Sep 28 09:16:33 2014 +0000
Revision:
7:bcb4ed255791
Parent:
6:23973d4b6b34
Fix stupid typo;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AndyA 0:a03325b9f702 1 #include "mBuinoSleep.h"
AndyA 0:a03325b9f702 2
AndyA 1:542283bfadf6 3
AndyA 0:a03325b9f702 4 BusOut LEDs(LED1, LED2, LED3, LED4, LED5, LED6, LED7);
AndyA 0:a03325b9f702 5
AndyA 4:c3f400cbe2fe 6 DigitalIn progMode(P0_3,PullNone);
AndyA 1:542283bfadf6 7
AndyA 1:542283bfadf6 8 bool sleep_CleanShutdown = false;
AndyA 0:a03325b9f702 9
AndyA 0:a03325b9f702 10 void mBuinoSleep(enum sleepMode_t mode)
AndyA 0:a03325b9f702 11 {
AndyA 0:a03325b9f702 12
AndyA 1:542283bfadf6 13 uint8_t oldLEDState = LEDs;
AndyA 0:a03325b9f702 14 LEDs = 0;
AndyA 0:a03325b9f702 15
AndyA 1:542283bfadf6 16 progMode.mode(PullNone);
AndyA 0:a03325b9f702 17
AndyA 3:a3fd27c4a161 18 if ((mode == DeepPowerDown) && (LPC_PMU->PCON & 0x08)) // bit 3 high blocks deep power down.
AndyA 3:a3fd27c4a161 19 mode = PowerDown;
AndyA 3:a3fd27c4a161 20
AndyA 0:a03325b9f702 21 switch (mode) {
AndyA 0:a03325b9f702 22 default:
AndyA 0:a03325b9f702 23 case Sleep:
AndyA 0:a03325b9f702 24 LPC_PMU->PCON = 0x0;
AndyA 0:a03325b9f702 25 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
AndyA 0:a03325b9f702 26 __WFI();
AndyA 0:a03325b9f702 27 break;
AndyA 0:a03325b9f702 28
AndyA 0:a03325b9f702 29 case DeepSleep:
AndyA 6:23973d4b6b34 30 case PowerDown:
AndyA 6:23973d4b6b34 31 case PowerDownWD:
AndyA 6:23973d4b6b34 32 case DeepSleepWD:
AndyA 6:23973d4b6b34 33 {
AndyA 7:bcb4ed255791 34 if ((mode == PowerDown) || (mode == PowerDownWD))
AndyA 0:a03325b9f702 35 LPC_PMU->PCON = 0x2;
AndyA 0:a03325b9f702 36 else
AndyA 0:a03325b9f702 37 LPC_PMU->PCON = 0x1;
AndyA 0:a03325b9f702 38
AndyA 0:a03325b9f702 39 LPC_SYSCON->PDSLEEPCFG |= 0x7f; // shut off everything we can.
AndyA 6:23973d4b6b34 40
AndyA 6:23973d4b6b34 41 if ((mode == DeepSleepWD) || (mode == PowerDownWD))
AndyA 6:23973d4b6b34 42 LPC_SYSCON->PDSLEEPCFG &= ~(1<<6);
AndyA 6:23973d4b6b34 43
AndyA 0:a03325b9f702 44 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
AndyA 0:a03325b9f702 45
AndyA 0:a03325b9f702 46 bool IRCPowered = (LPC_SYSCON->PDRUNCFG & 0x01); // only used for cleen shutdown but defined here for scope reasons.
AndyA 0:a03325b9f702 47 if (!IRCPowered)
AndyA 0:a03325b9f702 48 LPC_SYSCON->PDRUNCFG &= 0xfffffffe; // power up the IRC
AndyA 0:a03325b9f702 49
AndyA 2:9586ea22ab1b 50 if(sleep_CleanShutdown) {
AndyA 2:9586ea22ab1b 51 LPC_SYSCON->MAINCLKSEL = 0x00; // switch to IRC to avoid glitches
AndyA 2:9586ea22ab1b 52 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
AndyA 2:9586ea22ab1b 53 LPC_SYSCON->MAINCLKUEN = 0x00; /* Toggle Update Register */
AndyA 2:9586ea22ab1b 54 LPC_SYSCON->MAINCLKUEN = 0x01;
AndyA 2:9586ea22ab1b 55 while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated */
AndyA 2:9586ea22ab1b 56 }
AndyA 0:a03325b9f702 57
AndyA 0:a03325b9f702 58 LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG; // switch on everything that is currently on when we wake up.
AndyA 0:a03325b9f702 59 __WFI();
AndyA 0:a03325b9f702 60
AndyA 2:9586ea22ab1b 61 if(sleep_CleanShutdown) {
AndyA 2:9586ea22ab1b 62 LPC_SYSCON->MAINCLKSEL = 0x03; // switch to PLL output
AndyA 2:9586ea22ab1b 63 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
AndyA 2:9586ea22ab1b 64 LPC_SYSCON->MAINCLKUEN = 0x00; /* Toggle Update Register */
AndyA 2:9586ea22ab1b 65 LPC_SYSCON->MAINCLKUEN = 0x01;
AndyA 2:9586ea22ab1b 66 while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated */
AndyA 2:9586ea22ab1b 67 }
AndyA 0:a03325b9f702 68
AndyA 0:a03325b9f702 69 if (!IRCPowered)
AndyA 0:a03325b9f702 70 LPC_SYSCON->PDRUNCFG |= 0x01; // power down the IRC if it was off before
AndyA 0:a03325b9f702 71 }
AndyA 0:a03325b9f702 72 break;
AndyA 3:a3fd27c4a161 73 case DeepPowerDown:
AndyA 3:a3fd27c4a161 74 LPC_PMU->PCON = 0x3;
AndyA 3:a3fd27c4a161 75 LPC_SYSCON->PDSLEEPCFG |= 0x7f; // shut off everything we can.
AndyA 3:a3fd27c4a161 76 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
AndyA 3:a3fd27c4a161 77 __WFI();
AndyA 0:a03325b9f702 78 }
AndyA 1:542283bfadf6 79 LEDs = oldLEDState;
AndyA 0:a03325b9f702 80 }