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.