[LPC804] Deep sleep mode

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

[LPC804] Deep sleep mode

1,365 Views
masterboy
Contributor III

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?

0 Kudos
5 Replies

621 Views
masterboy
Contributor III

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.

0 Kudos

1,354 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

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

0 Kudos

1,322 Views
masterboy
Contributor III

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?

0 Kudos

1,315 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

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

0 Kudos

1,280 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

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.

  • IDD measurements were performed with all pins configured as GPIO outputs driven LOW and pull-up resistors disabled.

I recommend using the example of the SDK.

Best regards,
Pavel

 

0 Kudos