KL27z Microcontroller put in sleep mode and I2C wakeup

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

KL27z Microcontroller put in sleep mode and I2C wakeup

5,581 Views
Ravikumar1
Contributor II

Hi,

I want to put the microcontroller (KL27Z) in sleep mode, Is I2C (interrupt) can wakeup microcontroller from sleep mode ?

If yes, please tell me the steps/ configuration sequence for sleep and wakeup .

 

Thanks,

Ravikumar

0 Kudos
19 Replies

5,572 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

Did you test the example power management from the SDK? Could you tell me if you are using an evaluation board? and Could you tell me the full name part of your MCU? I will check if the I2C has capability to do a wake up.

Best regards,
Pavel

0 Kudos

5,568 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

I confirm in the Reference Manual chapter [ 7.3 Power modes] you can use this modes, Normal Wait - via WFI, VLPW (Very Low-Power Wait) -via WFI, this mode supports the interrupt recovery. Only need to configurate the I2C with the interrupt, in the SDK you can find an example of I2C and you can try to add to the other example and test it.

Best regards,
Pavel

0 Kudos

5,564 Views
Ravikumar1
Contributor II

Hi @Pavel_Hernandez 

Actually I gone through the example code and I see the power manager.c file.  In this file we have one function SMC_SetPowerModeWait(SMC) this will put the micro in Normal Wait mode. But my doubt is How I2C will wake up micro from sleep.

will you please share me the configuration/ steps for wakeup using I2C.

Regards,

Ravikumar.

0 Kudos

5,558 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

Let me get one KL27Z, and when I have more details I will share to you my results.

Best regards,
Pavel

0 Kudos

5,553 Views
Ravikumar1
Contributor II

Hi @Pavel_Hernandez 

 

Actually, I try with the power_manager.c from SDK file, we have functions for different sleep modes like,

SMC_SetPowerModeWait(SMC);

SMC_SetPowerModeVlpw(SMC);

SMC_SetPowerModeVlps(SMC); etc..

 

I am using these functions one by one and testing the current drawn while sleep mode and its drawn 10mA -12mA. Before sleep mode its like 15-17 mA, So its reduced only 5mA. But In datasheet mentioned its should be in uA.  

will you please tell me what is the mistake I have done.

And in the functions using the below register to change the power mode but I couldn't find in the register related to power mode. will you please tell me where is the register in the data sheet

SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;

 

 

Regards,

Ravikumar.

0 Kudos

5,539 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

How are you doing the measure? I made some probes with option B from the example.
Pavel_Hernandez_0-1661382837468.png

Then I add the I2C with the interrupt and has a good result.

Spoiler
/*
 * Copyright (c) 2015, Freescale Semiconductor, Inc.
 * Copyright 2016-2019 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_common.h"
#include "fsl_smc.h"
#include "fsl_llwu.h"
#include "fsl_rcm.h"
#include "fsl_lptmr.h"
#include "fsl_port.h"
#include "fsl_debug_console.h"
#include "power_manager.h"
#include "fsl_notifier.h"

#include "pin_mux.h"
#include "peripherals.h"
#include "board.h"
#include "fsl_lpuart.h"
#include "fsl_pmc.h"
#include <string.h>
#include "fsl_i2c.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define APP_DEBUG_UART_BAUDRATE 9600 /* Debug console baud rate. */

/* Default debug console clock source. */
#define APP_DEBUG_UART_DEFAULT_CLKSRC_NAME kCLOCK_McgPeriphClk /* MCGPCLK. */
#define APP_DEBUG_UART_DEFAULT_CLKSRC      0x01

/* Debug console clock source in VLPR mode. */
#define APP_DEBUG_UART_VLPR_CLKSRC_NAME kCLOCK_McgInternalRefClk /* MCGIRCLK. */
#define APP_DEBUG_UART_VLPR_CLKSRC      0x03

#define APP_LLWU            DEMO_LLWU_PERIPHERAL
#define APP_LLWU_IRQHANDLER DEMO_LLWU_IRQHANDLER

#define APP_LPTMR            DEMO_LPTMR_PERIPHERAL
#define APP_LPTMR_IRQHANDLER DEMO_LPTMR_IRQHANDLER

#define LLWU_LPTMR_IDX       0U /* LLWU_M0IF */
#define LLWU_WAKEUP_PIN_IDX  6U /* LLWU_P6 */
#define LLWU_WAKEUP_PIN_TYPE kLLWU_ExternalPinFallingEdge

#define APP_WAKEUP_BUTTON_GPIO        BOARD_SW3_GPIO
#define APP_WAKEUP_BUTTON_PORT        BOARD_SW3_PORT
#define APP_WAKEUP_BUTTON_GPIO_PIN    BOARD_SW3_GPIO_PIN
#define APP_WAKEUP_BUTTON_IRQ         BOARD_SW3_IRQ
#define APP_WAKEUP_BUTTON_IRQ_HANDLER BOARD_SW3_IRQ_HANDLER
#define APP_WAKEUP_BUTTON_NAME        BOARD_SW3_NAME
#define APP_WAKEUP_BUTTON_IRQ_TYPE    kPORT_InterruptFallingEdge

/* Debug console RX pin: PORTA1 MUX: 2 */
#define DEBUG_CONSOLE_RX_PORT   PORTA
#define DEBUG_CONSOLE_RX_GPIO   GPIOA
#define DEBUG_CONSOLE_RX_PIN    1U
#define DEBUG_CONSOLE_RX_PINMUX kPORT_MuxAlt2
/* Debug console TX pin: PORTA2 MUX: 2 */
#define DEBUG_CONSOLE_TX_PORT   PORTA
#define DEBUG_CONSOLE_TX_GPIO   GPIOA
#define DEBUG_CONSOLE_TX_PIN    2U
#define DEBUG_CONSOLE_TX_PINMUX kPORT_MuxAlt2
#define CORE_CLK_FREQ           CLOCK_GetFreq(kCLOCK_CoreSysClk)
/* I2C source clock */
#define EXAMPLE_I2C_SLAVE_BASEADDR I2C0
#define I2C_SLAVE_CLK_SRC          I2C0_CLK_SRC
#define I2C_SLAVE_CLK_FREQ         CLOCK_GetFreq(I2C0_CLK_SRC)

#define I2C_MASTER_SLAVE_ADDR_7BIT 0x7EU
#define I2C_DATA_LENGTH            34U
/*******************************************************************************
 * Prototypes
 ******************************************************************************/
static void i2c_slave_callback(I2C_Type *base, i2c_slave_transfer_t *xfer, void *userData);
/*
 * Set the clock configuration for RUN mode from VLPR mode.
 */
extern void APP_SetClockRunFromVlpr(void);

/*
 * Set the clock configuration for VLPR mode.
 */
extern void APP_SetClockVlpr(void);

/*
 * Power mode switch callback.
 */
status_t callback0(notifier_notification_block_t *notify, void *dataPtr);

/*******************************************************************************
 * Variables
 ******************************************************************************/
static uint8_t s_wakeupTimeout;            /* Wakeup timeout. (Unit: Second) */
static app_wakeup_source_t s_wakeupSource; /* Wakeup source.                 */
uint8_t g_slave_buff[I2C_DATA_LENGTH];
i2c_slave_handle_t g_s_handle;
volatile bool g_SlaveCompletionFlag = false;
i2c_slave_config_t slaveConfig;

/*******************************************************************************
 * Code
 ******************************************************************************/
static void APP_InitDebugConsole(void)
{
    uint32_t uartClkSrcFreq;
    CLOCK_SetLpuart0Clock(APP_DEBUG_UART_DEFAULT_CLKSRC);
    uartClkSrcFreq = CLOCK_GetFreq(APP_DEBUG_UART_DEFAULT_CLKSRC_NAME);
    DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE, APP_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq);
}

static void APP_InitDebugConsole_InVLPR(void)
{
    uint32_t uartClkSrcFreq;
    CLOCK_SetLpuart0Clock(APP_DEBUG_UART_VLPR_CLKSRC);
    uartClkSrcFreq = CLOCK_GetFreq(APP_DEBUG_UART_VLPR_CLKSRC_NAME);
    DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE, APP_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq);
}


status_t callback0(notifier_notification_block_t *notify, void *dataPtr)
{
    user_callback_data_t *userData     = (user_callback_data_t *)dataPtr;
    status_t ret                       = kStatus_Fail;
    app_power_mode_t targetMode        = ((power_user_config_t *)notify->targetConfig)->mode;
    smc_power_state_t originPowerState = userData->originPowerState;
    smc_power_state_t powerState;

    switch (notify->notifyType)
    {
        case kNOTIFIER_NotifyBefore:
            userData->beforeNotificationCounter++;
            /* Wait for debug console output finished. */
            while (
                !(kLPUART_TransmissionCompleteFlag & LPUART_GetStatusFlags((LPUART_Type *)BOARD_DEBUG_UART_BASEADDR)))
            {
            }
            DbgConsole_Deinit();

            if ((kAPP_PowerModeRun != targetMode) && (kAPP_PowerModeVlpr != targetMode))
            {
                /*
                 * Set pin for current leakage.
                 * Debug console RX pin: Set to pinmux to disable.
                 * Debug console TX pin: Don't need to change.
                 */
                PORT_SetPinMux(DEBUG_CONSOLE_RX_PORT, DEBUG_CONSOLE_RX_PIN, kPORT_PinDisabledOrAnalog);
            }

            ret = kStatus_Success;
            break;
        case kNOTIFIER_NotifyRecover:
            break;
        case kNOTIFIER_CallbackAfter:
            userData->afterNotificationCounter++;
            powerState = SMC_GetPowerModeState(SMC);

            /*
             * For some other platforms, if enter LLS mode from VLPR mode, when wakeup, the
             * power mode is VLPR. But for some platforms, if enter LLS mode from VLPR mode,
             * when wakeup, the power mode is RUN. In this case, the clock setting is still
             * VLPR mode setting, so change to RUN mode setting here.
             */
            if ((kSMC_PowerStateVlpr == originPowerState) && (kSMC_PowerStateRun == powerState))
            {
                APP_SetClockRunFromVlpr();
            }

            if ((kAPP_PowerModeRun != targetMode) && (kAPP_PowerModeVlpr != targetMode))
            {
                /*
                 * Debug console RX pin is set to disable for current leakage, nee to re-configure pinmux.
                 * Debug console TX pin: Don't need to change.
                 */
                PORT_SetPinMux(DEBUG_CONSOLE_RX_PORT, DEBUG_CONSOLE_RX_PIN, DEBUG_CONSOLE_RX_PINMUX);
            }

            /* Set debug console clock source. */
            if (kSMC_PowerStateVlpr == powerState)
            {
                APP_InitDebugConsole_InVLPR();
            }
            else
            {
                APP_InitDebugConsole();
            }

            ret = kStatus_Success;
            break;
        default:
            break;
    }
    return ret;
}

/*!
 * @brief LLWU interrupt handler.
 */
void APP_LLWU_IRQHANDLER(void)
{
    /* If wakeup by LPTMR. */
    if (LLWU_GetInternalWakeupModuleFlag(APP_LLWU, LLWU_LPTMR_IDX))
    {
        /* Disable lptmr as a wakeup source, so that lptmr's IRQ Handler will be executed when reset from VLLSx mode. */
        LLWU_EnableInternalModuleInterruptWakup(APP_LLWU, LLWU_LPTMR_IDX, false);
    }
    /* If wakeup by external pin. */
    if (LLWU_GetExternalWakeupPinFlag(APP_LLWU, LLWU_WAKEUP_PIN_IDX))
    {
        /* Disable WAKEUP pin as a wakeup source, so that WAKEUP pin's IRQ Handler will be executed when reset from
         * VLLSx mode. */
        LLWU_ClearExternalWakeupPinFlag(APP_LLWU, LLWU_WAKEUP_PIN_IDX);
    }
}

/*!
 * @brief LPTMR0 interrupt handler.
 */
void APP_LPTMR_IRQHANDLER(void)
{
    if (kLPTMR_TimerInterruptEnable & LPTMR_GetEnabledInterrupts(APP_LPTMR))
    {
        LPTMR_DisableInterrupts(APP_LPTMR, kLPTMR_TimerInterruptEnable);
        LPTMR_ClearStatusFlags(APP_LPTMR, kLPTMR_TimerCompareFlag);
        LPTMR_StopTimer(APP_LPTMR);
    }
}

/*!
 * @brief button interrupt handler.
 */
void APP_WAKEUP_BUTTON_IRQ_HANDLER(void)
{
    if ((1U << APP_WAKEUP_BUTTON_GPIO_PIN) & PORT_GetPinsInterruptFlags(APP_WAKEUP_BUTTON_PORT))
    {
        /* Disable interrupt. */
        PORT_SetPinInterruptConfig(APP_WAKEUP_BUTTON_PORT, APP_WAKEUP_BUTTON_GPIO_PIN, kPORT_InterruptOrDMADisabled);
        PORT_ClearPinsInterruptFlags(APP_WAKEUP_BUTTON_PORT, (1U << APP_WAKEUP_BUTTON_GPIO_PIN));
    }
}

/*!
 * @brief Get input from user to obtain wakeup timeout
 */
static uint8_t APP_GetWakeupTimeout(void)
{
    uint8_t timeout;

    while (1)
    {
        PRINTF("Select the wake up timeout in seconds.\r\n");
        PRINTF("The allowed range is 1s ~ 9s.\r\n");
        PRINTF("Eg. enter 5 to wake up in 5 seconds.\r\n");
        PRINTF("\r\nWaiting for input timeout value...\r\n\r\n");

        timeout = GETCHAR();
        PRINTF("%c\r\n", timeout);
        if ((timeout > '0') && (timeout <= '9'))
        {
            return timeout - '0';
        }
        PRINTF("Wrong value!\r\n");
    }
}

/*!
 * @brief Get wakeup source by user input.
 */
static app_wakeup_source_t APP_GetWakeupSource(void)
{
    uint8_t ch;

    while (1)
    {
        PRINTF("Select the wake up source:\r\n");
        PRINTF("Press T for LPTMR - Low Power Timer\r\n");
        PRINTF("Press S for switch/button %s. \r\n", APP_WAKEUP_BUTTON_NAME);

        PRINTF("\r\nWaiting for key press..\r\n\r\n");

        ch = GETCHAR();

        if ((ch >= 'a') && (ch <= 'z'))
        {
            ch -= 'a' - 'A';
        }

        if (ch == 'T')
        {
            return kAPP_WakeupSourceLptmr;
        }
        else if (ch == 'S')
        {
            return kAPP_WakeupSourcePin;
        }
        else
        {
            PRINTF("Wrong value!\r\n");
        }
    }
}

/*! @brief Get wakeup timeout and wakeup source. */
void APP_GetWakeupConfig(app_power_mode_t targetMode)
{
    /* Get wakeup source by user input. */
    if (targetMode == kAPP_PowerModeVlls0)
    {
        /* In VLLS0 mode, the LPO is disabled, LPTMR could not work. */
        PRINTF("Not support LPTMR wakeup because LPO is disabled in VLLS0 mode.\r\n");
        s_wakeupSource = kAPP_WakeupSourcePin;
    }
    else
    {
        /* Get wakeup source by user input. */
        s_wakeupSource = APP_GetWakeupSource();
    }

    if (kAPP_WakeupSourceLptmr == s_wakeupSource)
    {
        /* Wakeup source is LPTMR, user should input wakeup timeout value. */
        s_wakeupTimeout = APP_GetWakeupTimeout();
        PRINTF("Will wakeup in %d seconds.\r\n", s_wakeupTimeout);
    }
    else
    {
        PRINTF("Press %s to wake up.\r\n", APP_WAKEUP_BUTTON_NAME);
    }
}

/*! @brief Set wakeup timeout and wakeup source. */
void APP_SetWakeupConfig(app_power_mode_t targetMode)
{
    /* Set LPTMR timeout value. */
    if (kAPP_WakeupSourceLptmr == s_wakeupSource)
    {
        LPTMR_SetTimerPeriod(APP_LPTMR, (LPO_CLK_FREQ * s_wakeupTimeout) - 1U);
        LPTMR_StartTimer(APP_LPTMR);
    }

    /* Set the wakeup module. */
    if (kAPP_WakeupSourceLptmr == s_wakeupSource)
    {
        LPTMR_EnableInterrupts(APP_LPTMR, kLPTMR_TimerInterruptEnable);
    }
    else
    {
//        PORT_SetPinInterruptConfig(APP_WAKEUP_BUTTON_PORT, APP_WAKEUP_BUTTON_GPIO_PIN, APP_WAKEUP_BUTTON_IRQ_TYPE);
        I2C_SlaveTransferCreateHandle(EXAMPLE_I2C_SLAVE_BASEADDR, &g_s_handle, i2c_slave_callback, NULL);
    }

    /* If targetMode is VLLS/LLS, setup LLWU. */
    if ((kAPP_PowerModeWait != targetMode) && (kAPP_PowerModeVlpw != targetMode) &&
        (kAPP_PowerModeVlps != targetMode) && (kAPP_PowerModeStop != targetMode))
    {
        if (kAPP_WakeupSourceLptmr == s_wakeupSource)
        {
            LLWU_EnableInternalModuleInterruptWakup(APP_LLWU, LLWU_LPTMR_IDX, true);
        }
        else
        {
            LLWU_SetExternalWakeupPinMode(APP_LLWU, LLWU_WAKEUP_PIN_IDX, LLWU_WAKEUP_PIN_TYPE);
        }
        NVIC_EnableIRQ(LLWU_IRQn);
    }
}

/*! @brief Show current power mode. */
void APP_ShowPowerMode(smc_power_state_t currentPowerState)
{
    switch (currentPowerState)
    {
        case kSMC_PowerStateRun:
            PRINTF("    Power mode: RUN\r\n");
            break;
        case kSMC_PowerStateVlpr:
            PRINTF("    Power mode: VLPR\r\n");
            break;
        default:
            PRINTF("    Power mode wrong\r\n");
            break;
    }
}

/*!
 * @brief check whether could switch to target power mode from current mode.
 * Return true if could switch, return false if could not switch.
 */
bool APP_CheckPowerMode(smc_power_state_t currentPowerState, app_power_mode_t targetPowerMode)
{
    bool modeValid = true;

    /*
     * Check wether the mode change is allowed.
     *
     * 1. If current mode is HSRUN mode, the target mode must be RUN mode.
     * 2. If current mode is RUN mode, the target mode must not be VLPW mode.
     * 3. If current mode is VLPR mode, the target mode must not be HSRUN/WAIT/STOP mode.
     * 4. If already in the target mode, don't need to change.
     */
    switch (currentPowerState)
    {
        case kSMC_PowerStateRun:
            if (kAPP_PowerModeVlpw == targetPowerMode)
            {
                PRINTF("Could not enter VLPW mode from RUN mode.\r\n");
                modeValid = false;
            }
            break;

        case kSMC_PowerStateVlpr:
            if ((kAPP_PowerModeWait == targetPowerMode) || (kAPP_PowerModeStop == targetPowerMode))
            {
                PRINTF("Could not enter HSRUN/STOP/WAIT modes from VLPR mode.\r\n");
                modeValid = false;
            }
            break;
        default:
            PRINTF("Wrong power state.\r\n");
            modeValid = false;
            break;
    }

    if (!modeValid)
    {
        return false;
    }

    /* Don't need to change power mode if current mode is already the target mode. */
    if (((kAPP_PowerModeRun == targetPowerMode) && (kSMC_PowerStateRun == currentPowerState)) ||
        ((kAPP_PowerModeVlpr == targetPowerMode) && (kSMC_PowerStateVlpr == currentPowerState)))
    {
        PRINTF("Already in the target power mode.\r\n");
        return false;
    }

    return true;
}

/*!
 * @brief Power mode switch.
 * This function is used to register the notifier_handle_t struct's member userFunction.
 */
status_t APP_PowerModeSwitch(notifier_user_config_t *targetConfig, void *userData)
{
    smc_power_state_t currentPowerMode;         /* Local variable with current power mode */
    app_power_mode_t targetPowerMode;           /* Local variable with target power mode name*/
    power_user_config_t *targetPowerModeConfig; /* Local variable with target power mode configuration */

    smc_power_mode_lls_config_t lls_config; /* Local variable for lls configuration */

    smc_power_mode_vlls_config_t vlls_config; /* Local variable for vlls configuration */

    targetPowerModeConfig = (power_user_config_t *)targetConfig;
    currentPowerMode      = SMC_GetPowerModeState(SMC);
    targetPowerMode       = targetPowerModeConfig->mode;

    switch (targetPowerMode)
    {
        case kAPP_PowerModeVlpr:
            APP_SetClockVlpr();
            SMC_SetPowerModeVlpr(SMC);
            while (kSMC_PowerStateVlpr != SMC_GetPowerModeState(SMC))
            {
            }
            break;

        case kAPP_PowerModeRun:

            /* Power mode change. */
            SMC_SetPowerModeRun(SMC);
            while (kSMC_PowerStateRun != SMC_GetPowerModeState(SMC))
            {
            }

            /* If enter RUN from VLPR, change clock after the power mode change. */
            if (kSMC_PowerStateVlpr == currentPowerMode)
            {
                APP_SetClockRunFromVlpr();
            }
            break;

        /* For wait modes. */
        case kAPP_PowerModeWait:
            SMC_PreEnterWaitModes();
            SMC_SetPowerModeWait(SMC);
            SMC_PostExitWaitModes();
            break;
        case kAPP_PowerModeVlpw:
            SMC_PreEnterWaitModes();
            SMC_SetPowerModeVlpw(SMC);
            SMC_PostExitWaitModes();
            break;

        /* For stop modes. */
        case kAPP_PowerModeStop:
            SMC_PreEnterStopModes();
            SMC_SetPowerModeStop(SMC, kSMC_PartialStop);
            SMC_PostExitStopModes();
            break;

        case kAPP_PowerModeVlps:
            SMC_PreEnterStopModes();
            SMC_SetPowerModeVlps(SMC);
            SMC_PostExitStopModes();
            break;

        case kAPP_PowerModeLls:
            lls_config.enableLpoClock = targetPowerModeConfig->enableLpoClock;
            SMC_PreEnterStopModes();
            SMC_SetPowerModeLls(SMC, &lls_config);
            SMC_PostExitStopModes();
            break;

        case kAPP_PowerModeVlls0:
        case kAPP_PowerModeVlls1:
        case kAPP_PowerModeVlls3:
            if (targetPowerMode == kAPP_PowerModeVlls3)
            {
                vlls_config.subMode = kSMC_StopSub3;
            }
            else if (targetPowerMode == kAPP_PowerModeVlls0)
            {
                vlls_config.subMode = kSMC_StopSub0;
            }
            else
            {
                vlls_config.subMode = kSMC_StopSub1;
            }
            vlls_config.enablePorDetectInVlls0 = targetPowerModeConfig->enablePorDetectInVlls0;
            vlls_config.enableLpoClock         = targetPowerModeConfig->enableLpoClock;
            SMC_PreEnterStopModes();
            SMC_SetPowerModeVlls(SMC, &vlls_config);
            SMC_PostExitStopModes();
            break;
        default:
            PRINTF("Wrong value");
            break;
    }
    return kStatus_Success;
}

/*!
 * @brief main demo function.
 */
int main(void)
{
    uint32_t freq = 0;
    uint8_t ch;
    uint8_t targetConfigIndex;
    notifier_handle_t powerModeHandle;
    smc_power_state_t currentPowerState;
    app_power_mode_t targetPowerMode;
    bool needSetWakeup; /* Flag of whether or not need to set wakeup. */

    /*Power mode configurations*/
    power_user_config_t vlprConfig = {
        kAPP_PowerModeVlpr,

        true,

        true,
    };

    power_user_config_t vlpwConfig  = vlprConfig;
    power_user_config_t vlls1Config = vlprConfig;
    power_user_config_t vlls3Config = vlprConfig;
    power_user_config_t vlpsConfig  = vlprConfig;
    power_user_config_t waitConfig  = vlprConfig;
    power_user_config_t stopConfig  = vlprConfig;
    power_user_config_t runConfig   = vlprConfig;

    power_user_config_t llsConfig = vlprConfig;

    power_user_config_t vlls0Config = vlprConfig;

    /* Initializes array of pointers to power mode configurations */
    notifier_user_config_t *powerConfigs[] = {
        &runConfig,   &waitConfig, &stopConfig, &vlprConfig, &vlpwConfig, &vlpsConfig, &llsConfig,

        &vlls0Config,

        &vlls1Config,

        &vlls3Config,

    };

    /* User callback data0 */
    user_callback_data_t callbackData0;

    /* Initializes callback configuration structure */
    notifier_callback_config_t callbackCfg0 = {callback0, kNOTIFIER_CallbackBeforeAfter, (void *)&callbackData0};

    /* Initializes array of callback configurations */
    notifier_callback_config_t callbacks[] = {callbackCfg0};

    memset(&callbackData0, 0, sizeof(user_callback_data_t));

    /* Initializes configuration structures */
    vlpwConfig.mode  = kAPP_PowerModeVlpw;
    vlls1Config.mode = kAPP_PowerModeVlls1;
    vlls3Config.mode = kAPP_PowerModeVlls3;
    vlpsConfig.mode  = kAPP_PowerModeVlps;
    waitConfig.mode  = kAPP_PowerModeWait;
    stopConfig.mode  = kAPP_PowerModeStop;
    runConfig.mode   = kAPP_PowerModeRun;

    llsConfig.mode = kAPP_PowerModeLls;

    vlls0Config.mode = kAPP_PowerModeVlls0;

    /* Create Notifier Handle */
    NOTIFIER_CreateHandle(&powerModeHandle, powerConfigs, ARRAY_SIZE(powerConfigs), callbacks, 1U, APP_PowerModeSwitch, NULL);

    /* Must configure pins before PMC_ClearPeriphIOIsolationFlag */
    BOARD_InitPins();

    /* Power related. */
    SMC_SetPowerModeProtection(SMC, kSMC_AllowPowerModeAll);
    if (kRCM_SourceWakeup & RCM_GetPreviousResetSources(RCM)) /* Wakeup from VLLS. */
    {
        PMC_ClearPeriphIOIsolationFlag(PMC);
        NVIC_ClearPendingIRQ(LLWU_IRQn);
    }

    BOARD_InitBootClocks();
    APP_InitDebugConsole();
    BOARD_InitBootPeripherals();

    NVIC_EnableIRQ(I2C0_IRQn);

    /* Wakeup from VLLS. */
    if (kRCM_SourceWakeup & RCM_GetPreviousResetSources(RCM))
    {
        PRINTF("\r\nMCU wakeup from VLLS modes...\r\n");
    }

    /*1.Set up i2c slave first*/
	/*
	 * slaveConfig->addressingMode = kI2C_Address7bit;
	 * slaveConfig->enableGeneralCall = false;
	 * slaveConfig->enableWakeUp = false;
	 * slaveConfig->enableBaudRateCtl = false;
	 * slaveConfig->enableSlave = true;
	 */
	I2C_SlaveGetDefaultConfig(&slaveConfig);

	slaveConfig.addressingMode = kI2C_Address7bit;
	slaveConfig.slaveAddress   = I2C_MASTER_SLAVE_ADDR_7BIT;
	slaveConfig.upperAddress   = 0; /*  not used for this example */

	I2C_SlaveInit(EXAMPLE_I2C_SLAVE_BASEADDR, &slaveConfig, I2C_SLAVE_CLK_FREQ);

	for (uint32_t i = 0U; i < I2C_DATA_LENGTH; i++)
	{
		g_slave_buff[i] = 0;
	}

	memset(&g_s_handle, 0, sizeof(g_s_handle));

    while (1)
    {
        currentPowerState = SMC_GetPowerModeState(SMC);

        freq = CLOCK_GetFreq(kCLOCK_CoreSysClk);

        PRINTF("\r\n####################  Power Manager Demo ####################\n\r\n");
        PRINTF("    Core Clock = %dHz \r\n", freq);

        APP_ShowPowerMode(currentPowerState);

        PRINTF("\r\nSelect the desired operation \n\r\n");
        PRINTF("Press  %c for enter: RUN      - Normal RUN mode\r\n", kAPP_PowerModeRun);
        PRINTF("Press  %c for enter: WAIT     - Wait mode\r\n", kAPP_PowerModeWait);
        PRINTF("Press  %c for enter: STOP     - Stop mode\r\n", kAPP_PowerModeStop);
        PRINTF("Press  %c for enter: VLPR     - Very Low Power Run mode\r\n", kAPP_PowerModeVlpr);
        PRINTF("Press  %c for enter: VLPW     - Very Low Power Wait mode\r\n", kAPP_PowerModeVlpw);
        PRINTF("Press  %c for enter: VLPS     - Very Low Power Stop mode\r\n", kAPP_PowerModeVlps);
        PRINTF("Press  %c for enter: LLS/LLS3 - Low Leakage Stop mode\r\n", kAPP_PowerModeLls);

        PRINTF("Press  %c for enter: VLLS0    - Very Low Leakage Stop 0 mode\r\n", kAPP_PowerModeVlls0);

        PRINTF("Press  %c for enter: VLLS1    - Very Low Leakage Stop 1 mode\r\n", kAPP_PowerModeVlls1);

        PRINTF("Press  %c for enter: VLLS3    - Very Low Leakage Stop 3 mode\r\n", kAPP_PowerModeVlls3);

        PRINTF("\r\nWaiting for power mode select..\r\n\r\n");

        /* Wait for user response */
        ch = GETCHAR();

        if ((ch >= 'a') && (ch <= 'z'))
        {
            ch -= 'a' - 'A';
        }

        targetPowerMode = (app_power_mode_t)ch;

        if ((targetPowerMode > kAPP_PowerModeMin) && (targetPowerMode < kAPP_PowerModeMax))
        {
            /* If could not set the target power mode, loop continue. */
            if (!APP_CheckPowerMode(currentPowerState, targetPowerMode))
            {
                continue;
            }

            /* If target mode is RUN/VLPR/HSRUN, don't need to set wakeup source. */
            if ((kAPP_PowerModeRun == targetPowerMode) || (kAPP_PowerModeVlpr == targetPowerMode))
            {
                needSetWakeup = false;
            }
            else
            {
                needSetWakeup = true;
            }

            if (needSetWakeup)
            {
                APP_GetWakeupConfig(targetPowerMode);
                APP_SetWakeupConfig(targetPowerMode);
            }

            callbackData0.originPowerState = currentPowerState;
            targetConfigIndex              = targetPowerMode - kAPP_PowerModeMin - 1;
            NOTIFIER_SwitchConfig(&powerModeHandle, targetConfigIndex, kNOTIFIER_PolicyAgreement);
//**//
            /* Set up slave transfer. */
			I2C_SlaveTransferNonBlocking(EXAMPLE_I2C_SLAVE_BASEADDR, &g_s_handle, kI2C_SlaveCompletionEvent | kI2C_SlaveAddressMatchEvent);

			/*  wait for transfer completed. */
			while (!g_SlaveCompletionFlag)
			{
			}
			g_SlaveCompletionFlag = false;

			PRINTF("Slave received data :");
			for (uint32_t i = 0U; i < g_slave_buff[1]; i++)
			{
				if (i % 8 == 0)
				{
					PRINTF("\r\n");
				}
				PRINTF("0x%2x  ", g_slave_buff[2 + i]);
			}
			PRINTF("\r\n\r\n");

			/* Wait for master receive completed.*/
			while (!g_SlaveCompletionFlag)
			{
			}
			g_SlaveCompletionFlag = false;

			PRINTF("\r\nEnd of I2C example .\r\n");

        }
    }
}

static void i2c_slave_callback(I2C_Type *base, i2c_slave_transfer_t *xfer, void *userData)
{
    switch (xfer->event)
    {
        /*  Address match event */
        case kI2C_SlaveAddressMatchEvent:
            xfer->data     = NULL;
            xfer->dataSize = 0;
            break;
        /*  Transmit request */
        case kI2C_SlaveTransmitEvent:
            /*  Update information for transmit process */
            xfer->data     = &g_slave_buff[2];
            xfer->dataSize = g_slave_buff[1];
            break;

        /*  Receive request */
        case kI2C_SlaveReceiveEvent:
            /*  Update information for received process */
            xfer->data     = g_slave_buff;
            xfer->dataSize = I2C_DATA_LENGTH;
            break;

        /*  Transfer done */
        case kI2C_SlaveCompletionEvent:
            g_SlaveCompletionFlag = true;
            xfer->data            = NULL;
            xfer->dataSize        = 0;
            break;

        default:
            g_SlaveCompletionFlag = false;
            break;
    }
}

 Best regards,
Pavel

0 Kudos

5,534 Views
Ravikumar1
Contributor II

Hi @Pavel_Hernandez 

First of all thanks for the reply,

Actually I used power_manager demo code from SDK-FRDM-KL27Z and I tested with all the power mode options present in the code. by using UART to send the character like below shows A,B,C etc.. 

Press A for enter: RUN - Normal RUN mode
Press B for enter: Wait - Wait mode
Press C for enter: Stop - Stop mode
Press D for enter: VLPR - Very Low Power Run mode
Press E for enter: VLPW - Very Low Power Wait mode
Press F for enter: VLPS - Very Low Power Stop mode
Press G for enter: LLS - Low Leakage Stop mode
Press H for enter: VLLS0 - Very Low Leakage Stop 0 mode
Press I for enter: VLLS1 - Very Low Leakage Stop 1 mode
Press J for enter: VLLS3 - Very Low Leakage Stop 3 mode

 

I connected FRDM-KL27Z board with UART pins (J1-2 for UART0-Rx, J1-4 for UART0-Tx)  and Power supply pins (J3-8 for 3.3V ang J3-12 for GND). In between power supply I connected ammeter/ multimeter with series. I got current drawn results like shown below,

RUN - Normal RUN mode ------>  16.98 mA
Wait - Wait mode ----->  12.81 mA
Stop - Stop mode ----->  9.99 mA
VLPR - Very Low Power Run mode  ------->  10.65 mA    
VLPW - Very Low Power Wait mode  ------>  9.90 mA
VLPS - Very Low Power Stop mode  ------->  9.88 mA
LLS - Low Leakage Stop mode  ------------->  9.89mA
VLLS0 - Very Low Leakage Stop 0 mode ---->Not support LPTMR Wakeup
VLLS1 - Very Low Leakage Stop 1 mode ---->9.88 mA
VLLS3 - Very Low Leakage Stop 3 mode ---->9.80 mA

Actually expected results in micro amps but we got in milli amps, could you please tell me the reason and help me to resolve this issue.

 

And you mentioned that you got good result, how much current drawn did you get.

 

Regards,

Ravikumar.

0 Kudos

5,528 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

Thanks for being clear, I think you are misunderstanding the power saver mode, this mode only affects the MCU part, I only do not understand how you are measuring the amp with the pins [J3-8 for 3.3V and J3-12 for GND], the best way to get the data corresponding to the Datasheet.

Pavel_Hernandez_0-1661465773684.png

In the schematic of the KL27 you can use the J17, but you need to remove the resistor R2 and R1.

Pavel_Hernandez_1-1661466170522.png

But maybe other components are connected to the same rail and the Amp values could be near to the datasheet. If you need more information please let me know.

Best regards,
Pavel

 

 

 

0 Kudos

5,463 Views
Ravikumar1
Contributor II

Hi @Pavel_Hernandez

 

Thanks for the reply,

Actually now I am enter DEEP_SLEEP mode (Normal Stop mode) and wake up by I2C slave interrupt. after I2C interrupt I can see only 1 byte instead of 2 bytes. After/ 2nd time I can see 2 bytes.

here, 36 77-- I am using for sleep_cmd and

41 B4 using for wakeup_cmd from I2C 

Ravikumar1_1-1662496548763.png

 

And also If I want put micro again in sleep mode It will not go to Sleep mode. It will go only one time to sleep mode. Could you please tell me what I missed.

Regards

Ravikumar. 

0 Kudos

5,457 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

I suggest reviewing the state of the register from I2C after and before for if something is missing in the configuration in the IDE with help of the peripherals view.

Pavel_Hernandez_0-1662504314265.png

For get in again to the power save mode needs repeat the same steps at the first time, there are some applications notes maybe could help you.
Power Management for Kinetis L Family (nxp.com)  AN5088
Using Low Power modes on Kinetis family - AN4470 [you can find this in google].

Best regards,
Pavel

 

 

0 Kudos

5,411 Views
Ravikumar1
Contributor II

Hi @Pavel_Hernandez 

 

Thanks for the reply,

Now I can put micro in sleep and it will wakeup when I2C interrupt occurred.

Here the micro will wakeup both write and read interrupt is occurred. But I want to wake up only when write event / interrupt. 

But here I found both cases (write and read) the status register set write bit only, not set for read bit will you please tell me the reason for this and give me some solution.

Regards,

Ravikumar.

 

0 Kudos

5,400 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

I think this is not possible because the I2C NVIC will detect the start, I suggest in your code send the device to low power if the R/W bit is R, I do not know how is your final application.

Pavel_Hernandez_0-1663083382229.png

Unfortunately, that interrupt flag is not available, I apologize if this information is not helpful.

Best regards,
Pavel

0 Kudos

5,389 Views
Ravikumar1
Contributor II

Hi @Pavel_Hernandez 

Thanks for reply,

Actually after entering the sleep I send read/ write through I2C. But I got only "status 0", means I can wakeup when I2Cslave address matched but read/ write status is always come with write (0) only even if I send read event also.

So is there any pre configuration do I need to set before entering sleep mode for getting read/ write status.

Thanks and Regards,

Ravikumar.

0 Kudos

5,378 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

I review the information in the reference manual, unfortunately, the matching address is the only wakeup method, I was wrong.

Pavel_Hernandez_0-1663192078591.png

Best regards,
Pavel

 

0 Kudos

5,370 Views
Ravikumar1
Contributor II

Hi @Pavel_Hernandez 

Thanks for reply,

Yes, the matching address is the only wakeup method, I tried that way only however, 

we can wakeup from sleep 2 ways like write some data (cmd) to slave or read some data from slave.

And it will  wakeup when I2Cslave address matched but read/write status is always come with write (0), even if I send read event. So how will we find the read or write status.

means After sleep first read/ write, can we get status of read/ write along with address. because I can wake up the micro when matching the slave address but not get status bit of read/write it always give "0" only. 

Is there any pre configuration do I need to set before entering sleep mode for getting read/ write status ?

Thanks and Regards,

Ravikumar.

0 Kudos

5,359 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

Could you share the project? What kind of power saver are you finally using? 

Is there any pre-configuration do I need to set before entering sleep mode for getting read/ write status?
Let me review more information and when I have more details I will contact you.

Best regards,
Pavel

0 Kudos

5,268 Views
Ravikumar1
Contributor II

@Pavel_Hernandez 

Actually I read the KL27 Sub-Family Reference Manual and in this document pg no: 642 & 643

session 36.5.8 Address matching wake-up there is one note is like:

For the SRW bit to function properly, it only supports Address
+Write to wake up by I2C address matching. Before entering
the next low power mode, Address+Write must be sent to
change the SRW status.

 

In the above note what is the meaning for below line,

Before entering the next low power mode, Address+Write must be sent to change the SRW status.

 

Means do I need to do any configuration before entering to the next power mode, actually I configure I2C as a slave. 

I share the reference document for your reference:

Regards,

Ravikumar.

0 Kudos

5,353 Views
Ravikumar1
Contributor II

Hi  

 

Actually I am using Normal Stop - via WFI

even if I use WAIT mode I can't get any interrupt from I2C.

I can not share project in public domain I can share the I2C configuration files  for sleep mode.

 

you can see the file for entry the sleep mode calling below function

void Setup_LowPowerMode_Entry(void)

and initialization of I2C for sleepmode in this function I2C_SlaveInit(BOARD_I2C_SLAVE_INSTANCE).

and we setup i2c for wakeup 

/*! Initialize i2c slave */
I2C_DRV_SlaveInit(BOARD_I2C_SLAVE_INSTANCE, &i2cuserConfig, &slave);

uint8_t tmpReg;

I2C_Type * base = g_i2cBase[instance];
tmpReg = base->C1;
tmpReg &= ~I2C_C1_WUEN_MASK;
base->C1 = tmpReg | I2C_C1_WUEN(enableWakeUp) | I2C_C1_IICEN(enableSlave);

//! Enable I2C0 Interrupt in the NVIC
NVIC_EnableIRQ(I2C0_IRQn);

 

after that I called below functions for  Normal Stop mode.

SMC_PreEnterStopModes();
SMC_SetPowerModeStop(SMC, kSMC_PartialStop);
SMC_PostExitStopModes();

I will share the files for reference:

 

 

Regards,

Ravikumar.

 

0 Kudos

5,227 Views
Pavel_Hernandez
NXP TechSupport
NXP TechSupport

Hello,

Thanks for sending your information, I apologize for not understanding you, so the reference you sent from the reference manual is on page 642 mention.

After I2C address matching wake-up, the master must wait a
time long enough for the slave ISR to finish running and resend
start or repeat start signals

This suggests you need to send a command to get out of the Low power mode then the master must wait for the slave to recover then the master needs to send again a command or repeat the start, so that means you do not need any additional configuration.

Edit: I forgot the other part... 

Before entering the next low power mode, Address+Write must be sent to
change the SRW status.

That's for the MCU when the wake-up recovery from the last state, the last state is waiting or sleep not reset, and the register has the last status.

Best regards,
Pavel

0 Kudos