Hi, I'm using the PWR_MGMT SDK 17.0.2 demo code on my nRF52 DK.
Q1) After enabling parameters in the sdk_config.h, the nRF52 DK could enter the Power Off Mode if I press the button manually (LED4 will turn on as the indication). However, by using Scheduler, nRF52 DK cannot automatically enter Power Off Mode after 5 seconds period.
Here is the PuTTY information when Schedular timeout is triggerred:
<info> pwr_mgmt: Shutdown request 0 <info> pwr_mgmt: Shutdown started. Type 0 <info> pwr_mgmt: SysOff handler 0x00003A85 => blocking
Here is my sdk_config.h
// <e> NRF_PWR_MGMT_ENABLED - nrf_pwr_mgmt - Power management module //========================================================== #ifndef NRF_PWR_MGMT_ENABLED #define NRF_PWR_MGMT_ENABLED 1 #endif // <e> NRF_PWR_MGMT_CONFIG_DEBUG_PIN_ENABLED - Enables pin debug in the module. // <i> Selected pin will be set when CPU is in sleep mode. //========================================================== // Set a GPIO (LED) on/off when the CPU is active/asleep, so that we could track of when the CPU is active or asleep. #ifndef NRF_PWR_MGMT_CONFIG_DEBUG_PIN_ENABLED #define NRF_PWR_MGMT_CONFIG_DEBUG_PIN_ENABLED 1 #endif // <o> NRF_PWR_MGMT_SLEEP_DEBUG_PIN - Pin number // <0=> 0 (P0.0) // <1=> 1 (P0.1) // <2=> 2 (P0.2) // <3=> 3 (P0.3) // <4=> 4 (P0.4) // <5=> 5 (P0.5) // <6=> 6 (P0.6) // <7=> 7 (P0.7) // <8=> 8 (P0.8) // <9=> 9 (P0.9) // <10=> 10 (P0.10) // <11=> 11 (P0.11) // <12=> 12 (P0.12) // <13=> 13 (P0.13) // <14=> 14 (P0.14) // <15=> 15 (P0.15) // <16=> 16 (P0.16) // <17=> 17 (P0.17) // <18=> 18 (P0.18) // <19=> 19 (P0.19) // <20=> 20 (P0.20) // <21=> 21 (P0.21) // <22=> 22 (P0.22) // <23=> 23 (P0.23) // <24=> 24 (P0.24) // <25=> 25 (P0.25) // <26=> 26 (P0.26) // <27=> 27 (P0.27) // <28=> 28 (P0.28) // <29=> 29 (P0.29) // <30=> 30 (P0.30) // <31=> 31 (P0.31) // <4294967295=> Not connected // We could select the debug pin = LED pin to debug (i.e. display) the sleep mode ON/OFF (For nRF52 DK, LED1/2/3/4 coresponds to P0.17/18/19/20) // Since the LEDs on nRF52DK are active low, that means the LED will be turned ON when CPU is active. LED will be OFF when CPU is asleep. #ifndef NRF_PWR_MGMT_SLEEP_DEBUG_PIN #define NRF_PWR_MGMT_SLEEP_DEBUG_PIN 20 #endif // </e> // <q> NRF_PWR_MGMT_CONFIG_CPU_USAGE_MONITOR_ENABLED - Enables CPU usage monitor. // <i> Module will trace percentage of CPU usage in one second intervals. // This feature is used with the Logger Module to trace and log CPU usage (0% to 100%), and display through RTT/UART every 1 second. #ifndef NRF_PWR_MGMT_CONFIG_CPU_USAGE_MONITOR_ENABLED #define NRF_PWR_MGMT_CONFIG_CPU_USAGE_MONITOR_ENABLED 1 #endif // <e> NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED - Enable standby timeout. //========================================================== // Allow us to configure an auto-sleep after a period of inactivity (Note: requires the RTC to be configured) #ifndef NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED #define NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED 1 #endif // <o> NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_S - Standby timeout (in seconds). // <i> Shutdown procedure will begin no earlier than after this number of seconds. #ifndef NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_S #define NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_S 5 #endif // </e> // <q> NRF_PWR_MGMT_CONFIG_FPU_SUPPORT_ENABLED - Enables FPU event cleaning. // To handle "sleep" or "exit sleep" when the Floating Point Unit (FPU) of the SoC is used #ifndef NRF_PWR_MGMT_CONFIG_FPU_SUPPORT_ENABLED #define NRF_PWR_MGMT_CONFIG_FPU_SUPPORT_ENABLED 1 #endif // <q> NRF_PWR_MGMT_CONFIG_AUTO_SHUTDOWN_RETRY - Blocked shutdown procedure will be retried every second. #ifndef NRF_PWR_MGMT_CONFIG_AUTO_SHUTDOWN_RETRY #define NRF_PWR_MGMT_CONFIG_AUTO_SHUTDOWN_RETRY 1 #endif // <q> NRF_PWR_MGMT_CONFIG_USE_SCHEDULER - Module will use @ref app_scheduler. // #ifndef NRF_PWR_MGMT_CONFIG_USE_SCHEDULER #define NRF_PWR_MGMT_CONFIG_USE_SCHEDULER 1 #endif // <o> NRF_PWR_MGMT_CONFIG_HANDLER_PRIORITY_COUNT - The number of priorities for module handlers. // <i> The number of stages of the shutdown process. #ifndef NRF_PWR_MGMT_CONFIG_HANDLER_PRIORITY_COUNT #define NRF_PWR_MGMT_CONFIG_HANDLER_PRIORITY_COUNT 3 #endif // </e> // <q> NRF_SECTION_ITER_ENABLED - nrf_section_iter - Section iterator #ifndef NRF_SECTION_ITER_ENABLED #define NRF_SECTION_ITER_ENABLED 1 #endif
Here is my main.c:
#include <stdbool.h>
#include <stdint.h>
#include "boards.h"
#include "bsp.h"
#include "bsp_nfc.h"
#include "app_timer.h"
#include "nordic_common.h"
#include "app_error.h"
#include "nrf_drv_clock.h"
#include "nrf_pwr_mgmt.h" // Power management library
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#if NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
#include "app_scheduler.h"
#define APP_SCHED_MAX_EVENT_SIZE 0 /**< Maximum size of scheduler events. */
#define APP_SCHED_QUEUE_SIZE 4 /**< Maximum number of events in the scheduler queue. */
#endif // NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
#define BTN_ID_READY 0 /**< ID of the button used to change the readiness to sleep. */
#define BTN_ID_SLEEP 1 /**< ID of the button used to put the application into sleep/system OFF mode. */
#define BTN_ID_WAKEUP 1 /**< ID of the button used to wake up the application. */
#define BTN_ID_RESET 2 /**< ID of the button used to reset the application. */
static volatile bool m_stay_in_sysoff; /**< True if the application should stay in system OFF mode. */
static volatile bool m_is_ready; /**< True if the application is ready to enter sleep/system OFF mode. */
static volatile bool m_sysoff_started; /**< True if the application started sleep preparation. */
/**@brief Handler for shutdown preparation.
*/
bool shutdown_handler(nrf_pwr_mgmt_evt_t event)
{
uint32_t err_code;
if (m_is_ready == false)
{
m_sysoff_started = true;
return false;
}
switch (event)
{
case NRF_PWR_MGMT_EVT_PREPARE_SYSOFF:
NRF_LOG_INFO("NRF_PWR_MGMT_EVT_PREPARE_SYSOFF");
/**@brief Function for disabling all buttons.
*
* @details After calling this function, no buttons will generate events when pressed, and
* no buttons will be able to wake the system up from sleep mode.
*
* @retval NRF_SUCCESS If the buttons were successfully disabled.
* @retval NRF_ERROR_NOT_SUPPORTED If the board has no buttons or BSP_SIMPLE is defined.
* @return A propagated error.
*/
err_code = bsp_buttons_disable();
APP_ERROR_CHECK(err_code);
break;
case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP:
NRF_LOG_INFO("NRF_PWR_MGMT_EVT_PREPARE_WAKEUP");
err_code = bsp_buttons_disable();
// Suppress NRF_ERROR_NOT_SUPPORTED return code.
UNUSED_VARIABLE(err_code);
/**@brief Function for enabling wakeup from SYSTEM OFF for given button.
*
* @details After calling this function, button can be used to wake up the chip.
* This function should only be called immediately before going into sleep.
*
* @param[in] button_idx Index of the button.
*
* @retval NRF_SUCCESS If the button was successfully enabled.
* @retval NRF_ERROR_NOT_SUPPORTED If the board has no buttons or BSP_SIMPLE is defined.
*/
err_code = bsp_wakeup_button_enable(BTN_ID_WAKEUP);
// Suppress NRF_ERROR_NOT_SUPPORTED return code.
UNUSED_VARIABLE(err_code);
err_code = bsp_nfc_sleep_mode_prepare();
// Suppress NRF_ERROR_NOT_SUPPORTED return code.
UNUSED_VARIABLE(err_code);
break;
case NRF_PWR_MGMT_EVT_PREPARE_DFU:
NRF_LOG_ERROR("Entering DFU is not supported by this example.");
APP_ERROR_HANDLER(NRF_ERROR_API_NOT_IMPLEMENTED);
break;
case NRF_PWR_MGMT_EVT_PREPARE_RESET:
NRF_LOG_INFO("NRF_PWR_MGMT_EVT_PREPARE_RESET");
break;
}
err_code = app_timer_stop_all();
APP_ERROR_CHECK(err_code);
return true;
}
/**@brief Register application shutdown handler with priority 0. */
/**@brief Macro for registering a shutdown handler to be called before entering system off sleep mode.
* It's very useful for doing application-level housekeeping before netering System off sleep mode.
* Modules that want to get events
* from this module must register the handler using this macro.
*
* @details This macro places the handler in a section named "pwr_mgmt_data".
*
* @param[in] _handler Event handler (@ref nrf_pwr_mgmt_shutdown_handler_t).
* @param[in] _priority Priority of the given handler.
*/
NRF_PWR_MGMT_HANDLER_REGISTER(shutdown_handler, 0);
/**@brief Function for handling BSP events.
*/
static void bsp_evt_handler(bsp_event_t evt)
{
#if NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED
/*
*@brief Function for indicating activity.
*
* @details Call this function whenever doing something that constitutes "activity".
* For example, whenever sending data, call this function to indicate that the application
* is active and should not disconnect any ongoing communication links.
* This API is only applicable when NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED is enabled.
*
* It is called to reset the counter and hence prevent the automatic sleep.
*/
nrf_pwr_mgmt_feed();
NRF_LOG_INFO("bsp_evt_handler: Power management fed");
#endif // NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED
switch (evt)
{
// BSP_EVENT_KEY_0 = Default event of the push action of BSP_BUTTON_0 (only if this button is present)
case BSP_EVENT_KEY_0:
if (m_is_ready)
{
m_is_ready = false;
NRF_LOG_INFO("System is not ready for shutdown");
}
else
{
m_is_ready = true;
NRF_LOG_INFO("System is ready for shutdown");
}
if (m_sysoff_started && m_is_ready)
{
/**@brief Function for shutting down the system.
* @param[in] shutdown_type Type of operation.
* @details All callbacks will be executed prior to shutdown.
*/
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_CONTINUE);
}
break;
// BSP_EVENT_SYSOFF = The device should enter system off mode (without wakeup)
case BSP_EVENT_SYSOFF:
m_stay_in_sysoff = true;
break;
// BSP_EVENT_SLEEP = The device should enter sleep mode
case BSP_EVENT_SLEEP:
if (m_stay_in_sysoff)
{
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_STAY_IN_SYSOFF);
}
else
{
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
}
break;
// BSP_EVENT_RESET = The device should reset
case BSP_EVENT_RESET:
nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_RESET);
break;
default:
return; // no implementation needed
}
}
/**@brief Function for initializing low-frequency clock.
In this example, LFCLK is used for
*/
static void lfclk_config(void)
{
/**
* @brief Function for initializing the nrf_drv_clock module.
*
* After initialization, the module is in power off state (clocks are not requested).
*
* @retval NRF_SUCCESS If the procedure was successful.
* @retval NRF_ERROR_MODULE_ALREADY_INITIALIZED If the driver was already initialized.
*/
ret_code_t err_code = nrf_drv_clock_init();
APP_ERROR_CHECK(err_code);
/**
* @brief Function for requesting the LFCLK.
*
* The low-frequency clock can be requested by different modules
* or contexts. The driver ensures that the clock will be started only when it is requested
* the first time. If the clock is not ready but it was already started, the handler item that is
* provided as an input parameter is added to the list of handlers that will be notified
* when the clock is started. If the clock is already enabled, user callback is called from the
* current context.
*
* The first request will start the selected LFCLK source. If an event handler is
* provided, it will be called once the LFCLK is started. If the LFCLK was already started at this
* time, the event handler will be called from the context of this function. Additionally,
* the @ref nrf_drv_clock_lfclk_is_running function can be polled to check if the clock has started.
*
* @note When a SoftDevice is enabled, the LFCLK is always running and the driver cannot control it.
*
* @note The handler item provided by the user cannot be an automatic variable.
*
* @param[in] p_handler_item A pointer to the event handler structure.
*/
nrf_drv_clock_lfclk_request(NULL);
}
/**
@brief Function for initializing the BSP module.
#define BTN_ID_READY 0 //< ID of the button used to change the readiness to sleep
#define BTN_ID_SLEEP 1 //< ID of the button used to put the application into sleep/system OFF mode
#define BTN_ID_WAKEUP 1 //< ID of the button used to wake up the application
#define BTN_ID_RESET 2 //< ID of the button used to reset the application
*/
static void bsp_configuration()
{
uint32_t err_code;
/**@brief Function for initializing BSP.
*
* @details The function initializes the board support package to allow state indication and
* button reaction. Default events are assigned to buttons.
* @note Before calling this function, you must initiate the following required modules:
* - @ref app_timer for LED support
* - @ref app_gpiote for button support
*
* @param[in] type Type of peripherals used.
* @param[in] callback Function to be called when button press/event is detected.
*
* @retval NRF_SUCCESS If the BSP module was successfully initialized.
* @retval NRF_ERROR_INVALID_STATE If the application timer module has not been initialized.
* @retval NRF_ERROR_NO_MEM If the maximum number of timers has already been reached.
* @retval NRF_ERROR_INVALID_PARAM If GPIOTE has too many users.
* @retval NRF_ERROR_INVALID_STATE If button or GPIOTE has not been initialized.
*/
err_code = bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler);
APP_ERROR_CHECK(err_code);
/**@brief Function for assigning a specific event to a button.
*
* @details This function allows redefinition of standard events assigned to buttons.
* To unassign events, provide the event @ref BSP_EVENT_NOTHING.
*
* @param[in] button Button ID to be redefined.
* @param[in] action Button action to assign event to.
* @param[in] event Event to be assigned to button.
*
* @retval NRF_SUCCESS If the event was successfully assigned to button.
* @retval NRF_ERROR_INVALID_PARAM If the button ID or button action was invalid.
*/
// When press button 1 for 2000 ms (long press), the device should enter system off mode (without wakeup)
err_code = bsp_event_to_button_action_assign(BTN_ID_SLEEP,
BSP_BUTTON_ACTION_LONG_PUSH,
BSP_EVENT_SYSOFF);
APP_ERROR_CHECK(err_code);
// When release button 1, The device should enter sleep mode.
err_code = bsp_event_to_button_action_assign(BTN_ID_SLEEP,
BSP_BUTTON_ACTION_RELEASE,
BSP_EVENT_SLEEP);
APP_ERROR_CHECK(err_code);
//-----------------------------------------
// When press button 0, assign this event to an action to prevent the action from generating an event (disable the action)
err_code = bsp_event_to_button_action_assign(BTN_ID_READY,
BSP_BUTTON_ACTION_PUSH,
BSP_EVENT_NOTHING);
APP_ERROR_CHECK(err_code);
// When release button 0, Default event of the push action of BSP_BUTTON_0 (only if this button is present)
err_code = bsp_event_to_button_action_assign(BTN_ID_READY,
BSP_BUTTON_ACTION_RELEASE,
BSP_EVENT_KEY_0);
APP_ERROR_CHECK(err_code);
//-----------------------------------------
// When release button 2, The device should reset
err_code = bsp_event_to_button_action_assign(BTN_ID_RESET,
BSP_BUTTON_ACTION_RELEASE,
BSP_EVENT_RESET);
APP_ERROR_CHECK(err_code);
}
/**
* @brief Function for application main entry.
*/
int main(void)
{
APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
NRF_LOG_DEFAULT_BACKENDS_INIT();
NRF_LOG_INFO("Power Management example");
// Cnfigure and initialize the LFCLK
// We need a LFCLK for NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_S feature
// If use SoftDevice, this step is NOT needed because the SoftDevice already tuen on the LFCLK
lfclk_config();
uint32_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
#if NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
/**@brief Macro for initializing the event scheduler.
*
* @details It will also handle dimensioning and allocation of the memory buffer required by the
* scheduler, making sure the buffer is correctly aligned.
*
* @param[in] EVENT_SIZE Maximum size of events to be passed through the scheduler.
* @param[in] QUEUE_SIZE Number of entries in scheduler queue (i.e. the maximum number of events
* that can be scheduled for execution).
*
* @note Since this macro allocates a buffer, it must only be called once (it is OK to call it
* several times as long as it is from the same location, e.g. to do a reinitialization).
*/
APP_SCHED_INIT(APP_SCHED_MAX_EVENT_SIZE, APP_SCHED_QUEUE_SIZE);
#endif // NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
bsp_configuration();
// Initilize the power management library
ret_code_t ret_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(ret_code);
while (true)
{
#if NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
app_sched_execute();
#endif // NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
/**@brief Macro for processing a single log entry from a queue of deferred logs.
*
* You can call this macro from the main context or from the error handler to process
* log entries one by one.
*
* @note If logs are not deferred, this call has no use and is defined as 'false'.
*
* @retval true There are more logs to process in the buffer.
* @retval false No more logs in the buffer.
*
* If there is no deferred log to print, enter system on sleep mode.
*/
if (NRF_LOG_PROCESS() == false)
{
// Function for running power management. Should run in the main loop.
// Enter system on sleep mode
// It makes sure that entering and existing sleep in safe and error-free whether SoftDevicce is used or not.
nrf_pwr_mgmt_run();
}
}
}
Q2) The PuTTY shows the message:
<info> pwr_mgmt: Shutdown request 0
<info> pwr_mgmt: Shutdown started. Type 0
<info> pwr_mgmt: SysOff handler 0x00003A85 => blocking
What does 0x00003A85 and blocking mean?
What does the 1st and 2nd 0 mean? I only found nrf_pwr_mgmt_shutdown_t shutdown_type and nrf_pwr_mgmt_evt_t m_pwr_mgmt_evt has the following definition


Thanks in advance!
