I'm trying deep sleep mode on the LPC804. I have a one-time program that puts the processor to sleep (deep sleep) and when it wakes up, it turns on the LED:
#include <cr_section_macros.h>
#include "LPC804.h"
#define LED_PORT 0
#define LED_PIN 1
#define GPIO LPC_GPIO_PORT
#define SYSCON LPC_SYSCON
#define WKT LPC_WKT
#define PMU LPC_PMU
#define GPIO_INPUT(PORT, PIN) GPIO->DIR[PORT] &= ~(1 << PIN)
#define GPIO_OUTPUT(PORT, PIN) GPIO->DIR[PORT] |= (1 << PIN)
#define LED_OFF() GPIO->CLR[LED_PORT] |= (1 << LED_PIN);
#define LED_ON() GPIO->SET[LED_PORT] |= (1 << LED_PIN);
#define LED_Q() (GPIO->PIN[LED_PORT] & (1 << LED_PIN))
int main(void) {
SYSCON->SYSAHBCLKCTRL0 |= (1 << 18) | (1 << 6); // IOCON, GPIO0
SYSCON->PDRUNCFG &= ~(1 << 6); // LPOSC_PD
LPC_SYSCON->LPOSCCLKEN |= (1 << 1); // WKT
GPIO_OUTPUT(LED_PORT, LED_PIN);
LED_OFF();
// *** WKT
SYSCON->SYSAHBCLKCTRL0 |= (1 << 9); // WKT
SYSCON->PRESETCTRL0 &= ~(1 << 9);
SYSCON->PRESETCTRL0 |= (1 << 9);
NVIC_EnableIRQ(WKT_IRQn);
WKT->CTRL = (1 << 2) | (1 << 1) | (1 << 0); // CLEARCTR, ALARMFLAG, CLKSEL
WKT->COUNT = 5000000;
PMU->PCON = (1 << 0); // Deep-sleep
SYSCON->PDSLEEPCFG &= ~(1 << 6); // LPOSC_PD
SYSCON->PDAWAKECFG = SYSCON->PDRUNCFG;
SYSCON->STARTERP1 = (1 << 15); // WKT
SYSCON->MAINCLKSEL = 0; // FRO
SYSCON->MAINCLKUEN = 0;
SYSCON->MAINCLKUEN = 1;
SCB->SCR = (1 << 2); // SLEEPDEEP
__WFI();
uint32_t i;
while(1) {
LED_ON();
for (i = 0; i < 500000; i++);
LED_OFF();
for (i = 0; i < 500000; i++);
}
return 0 ;
}
void WKT_IRQHandler(void) {
WKT->CTRL |= (1 << 2); // CLEARCTR
}
I used the sleep procedure from UM11065 rev. 1.3 page 157. I have an ammeter connected to the processor to see if sleep has occurred. After running the program you can see that the current has decreased to about 33 uA, but after about a second the current increases to about 330 uA. This value is then measured all the time. I do the sleeping exactly according to the instructions, but it does not work. The processor does not wake up. Can anyone advise what the problem might be?
After a long time, I am contacting again about the power consumption of the LPC802/804 in power down mode. I used an example from the SDK and made a simplification:
/*
* Copyright 2018 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "board.h"
#include "fsl_common.h"
#include "fsl_power.h"
#include "fsl_usart.h"
#include "fsl_syscon.h"
#include "fsl_wkt.h"
#include "fsl_iocon.h"
#include <stdbool.h>
#include "fsl_pint.h"
#include "fsl_swm.h"
/*******************************************************************************
* Definitions
******************************************************************************/
//#define DEMO_ACTIVE_IN_DEEPSLEEP (kPDSLEEPCFG_DeepSleepBODActive | kPDSLEEPCFG_DeepSleepLPOscActive)
#define DEMO_ACTIVE_IN_DEEPSLEEP (kPDSLEEPCFG_DeepSleepLPOscActive)
#define DEMO_USER_WAKEUP_KEY_GPIO GPIO
#define DEMO_USER_WAKEUP_KEY_PORT BOARD_PB3_GPIO_PORT
#define DEMO_USER_WAKEUP_KEY_PIN BOARD_PB3_GPIO_PIN
#define DEMO_SYSCON_PIN_INT_SEL (4U)
#define DEMO_SYSCON_STARTER0_MASK (1U)
#define DEMO_SYSCON_STARTER1_MASK (1U << 15U)
#define DEMO_WKT_TIMEOUT_VALUE (250000U * 12U)
#define DEMO_PINT_PIN_INT0_SRC kSYSCON_GpioPort0Pin8ToPintsel
#define DEMO_WKT_CLK_FREQ (10000U)
#define DEMO_SLEEP_WAKEUP_SOURCE "\t1. PB3, wakeup key\r\n\t2. Wkt timer\r\n\t3. PB2, reset key\r\n"
#define DEMO_DEEP_SLEEP_WAKEUP_SOURCE "\t1. PB3, wakeup key\r\n\t2. Wkt timer\r\n\t3. PB2, reset key\r\n"
#define DEMO_POWER_DOWN_WAKEUP_SOURCE "\t1. PB3,wakeup key\r\n\t2. Wkt timer\r\n\t3. PB2, reset key\r\n"
#define DEMO_DEEP_POWERDOWN_WAKEUP_SOURCE "\t1. PB3,wakeup key\r\n"
#define DEMO_SLEEP_WAKEUP_SOURCE_SIZE (3U)
#define DEMO_DEEP_SLEEP_WAKEUP_SOURCE_SIZE (3U)
#define DEMO_POWER_DOWN_WAKEUP_SOURCE_SIZE (3U)
#define DEMO_DEEP_POWERDOWN_WAKEUP_SOURCE_SIZE (3U)
#define DEMO_WAKEUP_CASE_WAKEUP (0U)
#define DEMO_WAKEUP_CASE_WKT (1U)
#define DEMO_WAKEUP_CASE_RESET (2U)
#define DEMO_DEEP_POWERDOWN_RESET_ENABLE (1U)
#define POWER_DPD_ENABLE_WAKEUP_PIN POWER_DeepPowerDownWakeupSourceSelect(kPmu_Dpd_En_Pio0_8);
#define POWER_DPD_ENABLE_RESET_PIN
static power_mode_cfg_t s_CurrentPowerMode;
static uint32_t s_CurrentWakeupSource;
/*******************************************************************************
* Prototypes
******************************************************************************/
void DEMO_PreEnterLowPower(void);
void DEMO_LowPowerWakeup(void);
static power_mode_cfg_t DEMO_GetUserSelection(void);
static uint32_t DEMO_GetWakeUpSource(power_mode_cfg_t targetPowerMode);
/*******************************************************************************
* Code
******************************************************************************/
/*
* Callback function when wakeup key is pressed.
*/
static void pint_intr_callback(pint_pin_int_t pintr, uint32_t pmatch_status)
{
/* do nothing here */
}
void DEMO_InitWkt(void)
{
wkt_config_t wktConfig;
POWER_EnableLPO(true);
/*POWER_EnableLPOInDpdMode(true);*/
wktConfig.clockSource = kWKT_LowPowerClockSource;
/* Init wkt module */
WKT_Init(WKT, &wktConfig);
/* Clear Pending Interrupt */
NVIC_ClearPendingIRQ(WKT_IRQn);
/* Enable at the NVIC */
EnableIRQ(WKT_IRQn);
}
static void DEMO_InitResetPin(void)
{
SWM_SetFixedPinSelect(SWM0, kSWM_RESETN, true);
}
/*
* Setup a GPIO input pin as wakeup source.
*/
static void DEMO_InitWakeupPin(void)
{
gpio_pin_config_t gpioPinConfigStruct;
/* Set SW pin as GPIO input. */
gpioPinConfigStruct.pinDirection = kGPIO_DigitalInput;
GPIO_PinInit(DEMO_USER_WAKEUP_KEY_GPIO, DEMO_USER_WAKEUP_KEY_PORT, DEMO_USER_WAKEUP_KEY_PIN, &gpioPinConfigStruct);
SYSCON_AttachSignal(SYSCON, kPINT_PinInt0, DEMO_PINT_PIN_INT0_SRC);
/* Configure the interrupt for SW pin. */
PINT_Init(PINT);
PINT_PinInterruptConfig(PINT, kPINT_PinInt0, kPINT_PinIntEnableFallEdge, pint_intr_callback);
PINT_EnableCallback(PINT); /* Enable callbacks for PINT */
}
void DEMO_PreEnterLowPower(void)
{
/* switch main clock source to FRO18M */
POWER_DisablePD(kPDRUNCFG_PD_FRO_OUT);
POWER_DisablePD(kPDRUNCFG_PD_FRO);
CLOCK_SetMainClkSrc(kCLOCK_MainClkSrcFro);
CLOCK_SetFroOscFreq(kCLOCK_FroOscOut18M);
/*
* system osc power down
* application should decide if more part need to power down to achieve better power consumption
*/
CLOCK_DisableClock(kCLOCK_Iocon);
CLOCK_DisableClock(kCLOCK_Uart0);
}
void DEMO_LowPowerWakeup(void)
{
/* clock configurations restore */
BOARD_InitBootClocks();
CLOCK_EnableClock(kCLOCK_Iocon);
CLOCK_EnableClock(kCLOCK_Uart0);
}
void WKT_IRQHandler(void)
{
/* Clear interrupt flag.*/
WKT_ClearStatusFlags(WKT, kWKT_AlarmFlag);
WKT_StartTimer(WKT, USEC_TO_COUNT(DEMO_WKT_TIMEOUT_VALUE, DEMO_WKT_CLK_FREQ));
}
static uint32_t DEMO_GetUserInput(uint32_t maxChoice)
{
uint32_t ch = 0U;
while (1)
{
ch = GETCHAR();
if ((ch < '1') || (ch > (maxChoice + '0')))
{
continue;
}
else
{
ch = ch - '1';
break;
}
}
return ch;
}
/*!
* @brief Main function
*/
int main(void)
{
BOARD_InitBootPins();
BOARD_InitBootClocks();
BOARD_InitDebugConsole();
DEMO_InitWkt();
while (1)
{
/* Enable wakeup for wkt. */
EnableDeepSleepIRQ(WKT_IRQn);
WKT_StartTimer(WKT, USEC_TO_COUNT(DEMO_WKT_TIMEOUT_VALUE, DEMO_WKT_CLK_FREQ));
/* prepare to enter low power mode */
DEMO_PreEnterLowPower();
// POWER_EnterSleep();
// POWER_EnterDeepSleep(DEMO_ACTIVE_IN_DEEPSLEEP);
POWER_EnterPowerDown(DEMO_ACTIVE_IN_DEEPSLEEP);
/* restore the active mode configurations */
DEMO_LowPowerWakeup();
WKT_StopTimer(WKT);
}
}
static uint32_t DEMO_GetWakeUpSource(power_mode_cfg_t targetPowerMode)
{
uint32_t ch = 0U;
switch (targetPowerMode)
{
case kPmu_Sleep:
PRINTF(DEMO_SLEEP_WAKEUP_SOURCE);
ch = DEMO_GetUserInput(DEMO_SLEEP_WAKEUP_SOURCE_SIZE);
break;
case kPmu_Deep_Sleep:
PRINTF(DEMO_DEEP_SLEEP_WAKEUP_SOURCE);
ch = DEMO_GetUserInput(DEMO_DEEP_SLEEP_WAKEUP_SOURCE_SIZE);
break;
case kPmu_PowerDown:
PRINTF(DEMO_POWER_DOWN_WAKEUP_SOURCE);
ch = DEMO_GetUserInput(DEMO_POWER_DOWN_WAKEUP_SOURCE_SIZE);
break;
case kPmu_Deep_PowerDown:
PRINTF(DEMO_DEEP_POWERDOWN_WAKEUP_SOURCE);
ch = DEMO_GetUserInput(DEMO_DEEP_POWERDOWN_WAKEUP_SOURCE_SIZE);
break;
}
switch (ch)
{
case DEMO_WAKEUP_CASE_WKT:
/* Enable wakeup for wkt. */
EnableDeepSleepIRQ(WKT_IRQn);
DisableDeepSleepIRQ(PIN_INT0_IRQn);
WKT_StartTimer(WKT, USEC_TO_COUNT(DEMO_WKT_TIMEOUT_VALUE, DEMO_WKT_CLK_FREQ));
break;
case DEMO_WAKEUP_CASE_WAKEUP:
/* Enable wakeup for PinInt0. */
EnableDeepSleepIRQ(PIN_INT0_IRQn);
DisableDeepSleepIRQ(WKT_IRQn);
if (targetPowerMode == kPmu_Deep_PowerDown)
{
POWER_DPD_ENABLE_WAKEUP_PIN
}
break;
case DEMO_WAKEUP_CASE_RESET:
if (targetPowerMode == kPmu_Deep_PowerDown)
{
POWER_DPD_ENABLE_RESET_PIN
}
break;
}
return ch;
}
/*
* Get user selection from UART.
*/
static power_mode_cfg_t DEMO_GetUserSelection(void)
{
uint32_t ch = 0U;
PRINTF(
"\r\nSelect an option\r\n"
"\t1. Sleep mode\r\n"
"\t2. Deep Sleep mode\r\n"
"\t3. Power Down mode\r\n"
"\t4. Deep power down mode\r\n");
ch = DEMO_GetUserInput(4);
switch (ch)
{
case 0:
ch = kPmu_Sleep;
break;
case 1:
ch = kPmu_Deep_Sleep;
break;
case 2:
ch = kPmu_PowerDown;
break;
case 3:
ch = kPmu_Deep_PowerDown;
default:
break;
}
return (power_mode_cfg_t)ch;
}
With this setup I have a consumption of 29 uA. I would like to get to even lower consumption. Only the LPOsc is active during power-down mode. If I left the BOD active as well, the consumption went up to about 60 uA.
The datasheet states that it is possible to get down to 6 - 14 uA provided the pins are set as output with log. 0 and the pins are without pull-down and pull-up resistors. I have added the code before the DEMO_PreEnterLowPower() function:
gpio_pin_config_t pin_config = { kGPIO_DigitalOutput, 0 };
for (uint8_t i = 0; i < 31; i++)
{
if (i == 6) continue;
GPIO_PinInit(GPIO, 0, i, &pin_config);
IOCON_PinMuxSet(IOCON, i, IOCON_MODE_INACT | IOCON_HYS_EN);
}
In the loop I had to add a condition for pin number 6, because if I didn't put it, the processor would draw a nonsensical draw of approx. 23 mA. With this code I unfortunately got to about 700 uA, which is even worse than when I didn't set the pins.
Can anyone advise where I am making a mistake? Thank you.
Hello,
Could you tell me what kind of IDE you are using? Is your target an evaluation board or custom? I recommend reviewing the updated User Manual rev 1.4.
Best regards,
Pavel
I am using latest MCUXpresso. My target is custom board. I measure the MCU current between the voltage regulator and the MCU power pin. It didn't work and I tried further and further. Now I have this code where I am already solving the power down mode.
#include <cr_section_macros.h>
#include "LPC804.h"
#define LED_PIN 1
#define GPIO LPC_GPIO_PORT
#define SYSCON LPC_SYSCON
#define WKT LPC_WKT
#define PMU LPC_PMU
#define IOCON LPC_IOCON
#define GPIO_IN(x) GPIO->DIR[0] &= ~(1 << x)
#define GPIO_Q(x) (GPIO->PIN[0] & (1 << x))
#define GPIO_OUT(x) GPIO->DIR[0] |= (1 << x)
#define GPIO_LOW(x) GPIO->CLR[0] |= (1 << x)
#define GPIO_HIGH(x) GPIO->SET[0] |= (1 << x)
#define TIME 10000000
void sleepMode(void) {
uint32_t pmsk;
pmsk = __get_PRIMASK();
__disable_irq();
PMU->PCON = 0;
WKT->COUNT = TIME;
SCB->SCR &= ~(1 << 2);
__WFI();
__set_PRIMASK(pmsk);
}
void deepSleepMode(void) {
uint32_t pmsk;
pmsk = __get_PRIMASK();
__disable_irq();
PMU->PCON = (1 << 11) | (1 << | (1 << 0);
SYSCON->BODCTRL &= ~(1 << 4);
SYSCON->PDSLEEPCFG &= ~(1 << 6);
SYSCON->PDAWAKECFG = SYSCON->PDRUNCFG;
SYSCON->STARTERP1 = (1 << 15);
WKT->COUNT = TIME;
SCB->SCR = (1 << 2);
__WFI();
SCB->SCR &= ~(1 << 2);
SYSCON->BODCTRL |= (1 << 4);
__set_PRIMASK(pmsk);
}
void powerDownMode(void) {
uint32_t pmsk;
pmsk = __get_PRIMASK();
__disable_irq();
PMU->PCON = (1 << 11) | (1 << | (2 << 0);
SYSCON->BODCTRL &= ~(1 << 4);
SYSCON->PDSLEEPCFG &= ~(1 << 6);
SYSCON->PDAWAKECFG = SYSCON->PDRUNCFG;
SYSCON->STARTERP1 = (1 << 15);
WKT->COUNT = TIME;
SCB->SCR = (1 << 2);
__WFI();
SCB->SCR &= ~(1 << 2);
SYSCON->BODCTRL |= (1 << 4);
__set_PRIMASK(pmsk);
}
int main(void) {
// *** IOCON
SYSCON->SYSAHBCLKCTRL0 |= (1 << 18);
// *** GPIO
SYSCON->SYSAHBCLKCTRL0 |= (1 << 6);
GPIO_OUT(LED_PIN);
GPIO_LOW(LED_PIN);
// *** LPOSC
SYSCON->LPOSCCLKEN = (1 << 1); // WKT
SYSCON->PDRUNCFG &= ~(1 << 6);
// *** WKT
SYSCON->SYSAHBCLKCTRL0 |= (1 << 9); // WKT
SYSCON->PRESETCTRL0 &= ~(1 << 9); // Assert
SYSCON->PRESETCTRL0 |= (1 << 9); // Reset
NVIC_EnableIRQ(WKT_IRQn); // Enable interrput
WKT->CTRL = (1 << 2) | (1 << 1) | (1 << 0); // CLEARCTR, ALARMFLAG, CLKSEL
uint32_t i;
for (i = 0; i < 500000; i++);
GPIO_HIGH(LED_PIN);
for (i = 0; i < 500000; i++);
GPIO_LOW(LED_PIN);
for (i = 0; i < 500000; i++);
GPIO_HIGH(LED_PIN);
for (i = 0; i < 500000; i++);
GPIO_LOW(LED_PIN);
for (i = 0; i < 500000; i++);
GPIO_HIGH(LED_PIN);
for (i = 0; i < 500000; i++);
GPIO_LOW(LED_PIN);
for (i = 0; i < 500000; i++);
GPIO->DIR0 = 0xFFFFFFFF;
GPIO->SET0 = 0xFFFFFFFF;
GPIO_LOW(LED_PIN);
IOCON->PIO0_0 &= ~(0x3 << 3);
IOCON->PIO0_1 &= ~(0x3 << 3);
IOCON->PIO0_2 &= ~(0x3 << 3);
IOCON->PIO0_3 &= ~(0x3 << 3);
IOCON->PIO0_4 &= ~(0x3 << 3);
IOCON->PIO0_5 &= ~(0x3 << 3);
IOCON->PIO0_7 &= ~(0x3 << 3);
IOCON->PIO0_8 &= ~(0x3 << 3);
IOCON->PIO0_9 &= ~(0x3 << 3);
IOCON->PIO0_10 &= ~(0x3 << 3);
IOCON->PIO0_11 &= ~(0x3 << 3);
IOCON->PIO0_12 &= ~(0x3 << 3);
IOCON->PIO0_13 &= ~(0x3 << 3);
IOCON->PIO0_14 &= ~(0x3 << 3);
IOCON->PIO0_15 &= ~(0x3 << 3);
IOCON->PIO0_16 &= ~(0x3 << 3);
IOCON->PIO0_17 &= ~(0x3 << 3);
// IOCON->PIO0_18 &= ~(0x3 << 3);
// IOCON->PIO0_19 &= ~(0x3 << 3);
// IOCON->PIO0_20 &= ~(0x3 << 3);
// IOCON->PIO0_21 &= ~(0x3 << 3);
// IOCON->PIO0_22 &= ~(0x3 << 3);
// IOCON->PIO0_23 &= ~(0x3 << 3);
// IOCON->PIO0_24 &= ~(0x3 << 3);
// IOCON->PIO0_25 &= ~(0x3 << 3);
// IOCON->PIO0_26 &= ~(0x3 << 3);
// IOCON->PIO0_27 &= ~(0x3 << 3);
// IOCON->PIO0_28 &= ~(0x3 << 3);
// IOCON->PIO0_29 &= ~(0x3 << 3);
// IOCON->PIO0_30 &= ~(0x3 << 3);
powerDownMode();
GPIO_HIGH(LED_PIN);
while(1) {
}
return 0 ;
}
void WKT_IRQHandler(void) {
WKT->CTRL |= (1 << 2); // CLEARCTR
}
This code already works, puts the processor to sleep and wakes it up. I'm solving the problem with consumption. When I put it to sleep (power down mode), the current is around 45 uA. When I take the processor off the board, the components take a total of 2.5 uA. if the processor is supposed to consume around 10 uA in power down mode, somewhere unnecessarily "eats" 30 uA. I've tried everything, but I can't seem to get below that. What could be the problem?
Hello,
Thanks for the information, give me a chance to review your case, when I have more details I will contact you.
Best regards,
Pavel
Hello,
I replayed the example in the SDK [lpcxpresso804_power_mode_switch_lpc] and this mentioned the following.
The power consumption data for Sleep mode can reach 0.4mA.
The power consumption data for Deep Sleep mode can reach 100uA.
The power consumption data for Power Down mode can reach 9uA. If want to reach 6uA, please disable LPOsc.
The power consumption data for Deep Power Down mode can reach 0.15uA.
I confirmed the data in the multimeter and the datasheet have the same data. Table 12. Static characteristics, supply pins take in count the following.
I recommend using the example of the SDK.
Best regards,
Pavel