LowPower
Low Power reference user guide
This Readme file describes the connectivity software architecture and provides the general low power enablement user guide.
1- Connectivity Low Power SW architecture
The connectivity low power software architecture is composed of various components. These are described from the lower layer to the application layer:
The SDK power manager in component/power_manager. This component provides the basic low power framework. It is not specific to the connectivity but generic across devices. it covers:
gather the low power constraints for upper layer and take the decision on the best suitable low power state the device is allowed to go to fullfill the constraints.
call the low power entry and exit function callbacks
call the appropriate SW routines to switch the device into the suitable low power state
Connectivity Low power module in the connectivity framework. This module is composed of:
The low power service called PWR inside framework/LowPower (this folder), This module is generic to all connectivity devices.
The platform lowpower: fwk_platform_lowpower.[ch] located in framework\platform\<platform_name>. These files are a collection of low power routines functions for the PWR module and upper layer. These are specific to the device.
Both PWR and platform lowpower files are detailed in section below.
Low power Application modules, it consists of 3 parts:
Application initialization file app_services_init.c where the application initializes the low power framework, see next section ‘Demo example for typical usage of low power framework’
Application Idle task from application to call the main low power entry function PWR_EnterLowPower() to switch the device into lowpower. This function is application specific, one example is given in the section 1.3.3
Low power board files : board_lp.[ch] located in board/lowpower. These files implement the low power entry and exit functions related to the application and board. Customers shall modify these files for their own needs. Example code is given for the connectivity applications.
User guide is provided in section 1.3 below.
Note : Linker script may also be impacted for power down mode support in order to provide an RAM area for ROM warm boot (depends on the platform) and application warmboot stack
The Low power central and master reference design applications provide an example of Low power implementation for BLE. Customer can also refer to the associated document ‘low power connectivity reference design user guide’.
1.1 - SDK power manager
This module provides the main low power functionalities such as:
Decide the best low-power mode dependent on the constraints set by upper layers by using PWR_SetLowPowerModeConstraints() API function.
Handle the sequences to enter and exit low-power mode.
Enable and configure wake up sources, call the application callbacks on low power entry/exit sequences.
The SDK power manager provides the capability for application and all components to receive low power constraints to the power. The Application does not set the low-power mode the device shall go into. When going to low power, the SDK power manager selects the best low-power mode that fits all the constraints.
As an example, if the low power constraint set from Application is Power Down mode, and no other constraint is set, the SDK power manager selects Power down mode, the next time the device enters low power. However, if a new constraint is set by another component, such as the SecLib module that operates Hardware encryption, the SecLib module would select WFI as additional low power constraint. Also, the SDK power manager selects this last low-power mode until the constraint is released by the SecLib module. It then reselects Power Down mode for further low power entry modes.
1.2 - PWR Low power module
The PWR module in the connectivity framework provides additional services for the connectivity stacks and applications on top of the SDK power manager.
It also provides a simple API for Connectivity Stack and Connectivity applications.
However, more advanced features such as configuring the wake-up sources are only accessible from the SDK Power Manager API.
In addition to the SDK Power Manager, the PWR module uses the software resources from lower level drivers but is independent of the platform used.
1.2.1 - Functional description
Initialization of the PWR module should be done through PWR_Init() function. This is mainly to initialize the SDK power manager and the platform for low power. It also registers PWR low power entry/exit callback PWR_LowpowerCb() to the SDK power manager. This function will be called back when entering and exiting low power to perform mandatory save/restore operations for connectivity stacks. The application can perform extra optional save/restore operations in the board_lp file where it can register to the SDK Power Manager its own callback. This is usually used to handle optional peripherals such as serial interfaces, GPIOs, and so on.The main entry function is PWR_EnterLowPower(). It should be called from Idle task when no SW activity is required. The maximum duration for lowpower is given as argument timeoutUs in useconds. This function will check the next Hardware event in the connectivity stack, typically the next Radio activity. A wakeup timer is programmed if the timeoutUs value is shorter than the next radio event timing. Passing a timeout of 0us will be interpreted as no timeout on the application side.
On device wakeup from low power state, the function will return the time duration the device has been in low power state.
Two APi are provided to set and release low power state constraints : PWR_SetLowPowerModeConstraint() and PWR_ReleaseLowPowerModeConstraint(). These are helper functions. User can use directly the SDK power manager if needed.
The PWR module also provides some API to be set as callbacks into other components to prevent from going to low power state. It can be used in following examples :
If a DMA is running, the module in charge of the DMA would need to set a constraint to avoid the system from going to a low power state when the RAM and system bus are no longer available.
If transfer is going on a peripheral, the drivers shall set a constraint to forbid low power mode.
If encryption is on going through an Hardware accelerator, the HW accelerator and the required ressources (clocks, etc), shall be kept active also by setting a constraints.
1.2.2 - Tickless mode support
This module also provides some routines functions PWR_SysticksPreProcess() and PWR_SysticksPostProcess() from PWR_systicks.c in order to support the tickless mode when using FreeRTOS. The tickless mode is the capability to suspend the periodic system ticks from FreeRTOS and keep timebase tracking using another low power counter. In this implementation, the Timer Manager and time_stamp component are used for this purpose.
Idle task shall call these functions PWR_SysticksPreProcess() and PWR_SysticksPostProcess() before and after the call to the main low power entry function PWR_EnterLowPower().
Refer to framework/LowPower/PWR_systicks.c file or section 2.1 below for more information.
1.3 - Low power platform submodule
Low power platform module file fwk_platform_lowpower.c provides the necessary helper functions to support low power device initialization, device entry, and exit routines. These are platform and device specific. Typically, the PWR module uses the low power platform submodule for all low power specific routines.
The low power platform submodule is documented in the Connectivity Framework Reference Manual document and in the Connectivity Framework API document.
1.4 - Low power board files
Low power board files board_lp.[ch] are both application and board specific. Users should update this file to add new functions to include new used peripherals that require low power support. In the current SDK package, only Serial Manager over UART and button (IO toggle wake up source) are supported and demonstrated in the Bluetooth LE demo application.
Other peripherals that require specific action on low power entry and restore on low power exit should be added to low power board files. For more details, refer to section Low power board file update
2 - Low power Application user guide
This section provides a user guide to enable Low power on a connectivity application, It gives example of typical implementation for the initialization, Idle task function and low power entry/exit functions.
2.1 - Application Project updates
It is recommended to reuse the low-power peripheral/central reference design application projects as a start. This ensures that everything is in place for the low-power optimization feature. Then, application files may be added to one of the two projects.
However, users can start directly from the application project and implement low power in it, by performing the steps described in the following sections.
2.1.1 - SDK Power Manager
Most of the Low power functionality is implemented in the SDK Power Manager. The files to add into the project SDK power_manager module are listed in the figure below:
You need to use the files located in the folder that match your device.
2.1.2 - PWR connectivity framework module
PWR.c PWR_Interface.h shall be added to your application projects :
Optionally, in order to support Systick less mode, PWR_systicks.c or PWR_systicks_bm.c could also be added.
The include path to add is: middleware/wireless/framework/LowPower
2.1.3 -Low power platform submodule
Low power platform files can be found in the ‘Platform’ module in the connectivity framework:
2.1.4 - Low power board files
These files are located in the same folder that the other board files board.[ch]. Hence, it is not required to add any new include path at compiler command line.
2.1.5 - Application RTOS Idle hook and tickeless hook functions
See section 2.4.3 Idle task implementation example
2.2 - Low power and wake up sources Initialization
Low power initialization and configuration are performed in APP_ServiceInitLowpower()function. This is called from APP_InitServices() function called from the main() function so all is already set up when calling the main application entry point, typically BluetoothLEHost_AppInit() function in the Bluetooth LE demo applications.
The default Low Power mode configured in APP_InitServices() is Deep Sleep mode. In Bluetooth LE, (or any other stack technology), Deep Sleep mode fits for all use cases. For instance, for Bluetooth LE states: Advertising, Connected, Scanning states. This mode already performs a very good level of power saving and likely, this is not required to optimize more if the device is powered from external supply.
APP_ServiceInitLowpower() function performs the following initialization and configuration:
Initialize the Connectivity framework Low power module PWR_Init(), this function initialized the SDK power manager.
Configure the wakeup sources such as serial manager wake up source for UART, or button for IO wake up configuration. These are typical wakeup sources used in the connectivity application. Developer may want to add additional wake up sources here specific for the application.
Note : The low power timer wakeup source and wakeup from Radio domain are directly enabled from the Connectivity framework Low power module PWR as it is mandatory for the connectivity stack. If your application supports other peripherals (such as i2c, spi, and others) that require wake sources from low power, developer should add additional wake up sources setting in this function APP_ServiceInitLowpower(). The complete list of wakeup sources are available from the SDK power manager component, see file fsl_pm_board.h in component/boards/<device_name>/.
Initialize and register the Low power board file used to register and implement low power entry and exit callback function used for peripheral. This is done by calling the BOARD_LowPowerInit() function.
Register low power Enter and exit critical function to driver component to enable / disable low power when the Hardware is active. Example is given for serial manager that needs to disable low power when the TX ring buffer contains data so the device does not enter low power until the buffer is empty.
Finally, APP_ServiceInitLowpower() function configures the Deep Sleep mode as the default low power constraint for the application. It is recommended to keep this level of low power constraint during all the connectivity stack initialization.
Example of low power framework initialization can be found in app_services_init.c file. Below is some code example for initializing the low power framework and wake up sources:
static void APP_ServiceInitLowpower(void)
{
PWR_ReturnStatus_t status = PWR_Success;
/* It is required to initialize PWR module so the application
* can call PWR API during its init (wake up sources...) */
PWR_Init();
/* Initialize board_lp module, likely to register the enter/exit
* low power callback to Power Manager */
BOARD_LowPowerInit();
/* Set Deep Sleep constraint by default (works for All application)
* Application will be allowed to release the Deep Sleep constraint
* and set a deepest lowpower mode constraint such as Power down if it needs
* more optimization */
status = PWR_SetLowPowerModeConstraint(PWR_DeepSleep);
assert(status == PWR_Success);
#if (defined(gAppButtonCnt_c) && (gAppButtonCnt_c > 0))
/* Init and enable button0 as wake up source
* BOARD_WAKEUP_SOURCE_BUTTON0 can be customized based on board configuration
* On EVK we use the SW2 mapped to GPIOD */
PM_InitWakeupSource(&button0WakeUpSource, BOARD_WAKEUP_SOURCE_BUTTON0, NULL, true);
#endif
#if (gAppButtonCnt_c > 1)
/* Init and enable button1 as wake up source
* BOARD_WAKEUP_SOURCE_BUTTON1 can be customized based on board configuration
* On EVK we use the SW3 mapped to PTC6 */
PM_InitWakeupSource(&button1WakeUpSource, BOARD_WAKEUP_SOURCE_BUTTON1, NULL, true);
#endif
#if (defined(gAppUseSerialManager_c) && (gAppUseSerialManager_c > 0))
#if defined(gAppLpuart0WakeUpSourceEnable_d) && (gAppLpuart0WakeUpSourceEnable_d > 0)
/* To be able to wake up from LPUART0, we need to keep the FRO6M running
* also, we need to keep the WAKE domain is SLEEP.
* We can't put the WAKE domain in DEEP SLEEP because the LPUART0 is not mapped
* to the WUU as wake up source */
(void)PM_SetConstraints(PM_LP_STATE_NO_CONSTRAINT, APP_LPUART0_WAKEUP_CONSTRAINTS);
#endif
/* Register PWR functions into SerialManager module in order to disable device lowpower
during SerialManager processing. Typically, allow only WFI instruction when
uart data are processed by serail manager */
SerialManager_SetLowpowerCriticalCb(&gSerMgr_LowpowerCriticalCBs);
#endif
#if defined(gAppUseSensors_d) && (gAppUseSensors_d > 0)
Sensors_SetLowpowerCriticalCb(&app_LowpowerSensorsCriticalCBs);
#endif
(void)status;
}
2.3 - low power entry/exit sequences : board files updates
Board Files that handles low-power are board_lp.[ch] files.
Low power board files implement the low-power callbacks of the peripherals to be notified when entering or exiting Low Power mode. This module also registers these low-power callbacks to the SDK Power Manager component to get the notifications when the device is about to enter low-power or exit Low Power mode. The Low-power callbacks are registered from BOARD_LowPowerInit() function. This function is called from app_services_init.c file after PWR module initialization.
The low power callback functions can be categorized in two groups:
Entry Low power call back functions: These are usually used to prepare the peripherals to enter low-power. For example, they can be used for flushing FIFOs, switching off some clocks, and reconfiguring pin mux to avoid leakage on pins. In case of Power Down mode, these functions could be used to save the Hardware peripheral context.
Exit Low power call back functions: These are typically used to restore the peripherals to functionality. Therefore, they perform the reverse of what is done by the entry callback functions: restoring the pin mux, re-enabling the clock, in case of Power Down mode, restoring the Hardware peripheral context, and so on.
Note that distinction can be done between clock gating mode (Deep Sleep mode), and power gated mode (Power down mode) when entering and exiting Low Power mode. The BOARD_EnterLowPowerCb() and BOARD_ExitLowPowerCb() functions provide the code to call the various peripheral entry and exit functions to go and exit Deep Sleep mode: serial manager, button, debug console, and others.
However, the processing to save and restore the Hardware peripheral is implemented in different functions BOARD_EnterPowerDownCb() and BOARD_ExitPowerDownCb(). These two functions should be called when exiting power gated modes of the power domain. These two should implement specific code for such case (likely the complete reinitialization of each peripheral). In order to know the Low Power mode that the wake up domain, or main domain has been entered, the low-power platform API PLATFORM_GetLowpowerMode() can be called.
Note : BOARD_ExitPowerDownCb() is called before BOARD_ExitLowPowerCb() as it is generally required to restore the Hardware peripheral contexts before reconfiguring the pin mux to avoid any signal glitches on the pads
Also, It is important to know whether the location of the Hardware peripheral is in the main domain or wake up domain. The two power domains can go into different power modes with the limitation that the wakeup domain cannot go to a deepest Low Power mode than the main domain. Depending on the constraint set on SDK power manager, the wake up domain could remain in active while the main domain can go to deep sleep or power down modes. In this case, the peripherals in the wake up domain does not required to be restored, as explained in the section Power Down. Likely, only pin mux reconfiguration is required in this case.
example Low power entry and exit functions shall be registered to the SDK power manager so these functions will be called when the device will enter and exit low power mode. This is done by BOARD_LowPowerInit() typically called from application source code in app_services_init.c file
static pm_notify_element_t boardLpNotifyGroup = {
.notifyCallback = BOARD_LowpowerCb,
.data = NULL,
};
void BOARD_LowPowerInit(void)
{
status_t status;
status = PM_RegisterNotify(kPM_NotifyGroup2, &boardLpNotifyGroup);
assert(status == kStatus_Success);
(void)status;
}
BOARD_LowpowerCb() callback function will handle both the entry and exit sequences. An argument is passed to the function to indicate the lowpower state the device enter/exit. Typical implementation is given below. Customer shall make sure to differentiate low power entry and exit, and the various low power states.
Typically, nothing is expected to be done if low power state is WFI or Sleep mode. These modes are some light low power states and the system can be woken up by interrupt trigger.
In Deep sleep mode, the clock tree and source clocks are off, the system needs to be woken up from an event from the WUU module.
In Power down mode, some peripherals are likely to be powered off, context save and restore may need to be done in these functions.
static status_t BOARD_LowpowerCb(pm_event_type_t eventType, uint8_t powerState, void *data)
{
status_t ret = kStatus_Success;
if (powerState < PLATFORM_DEEP_SLEEP_STATE)
{
/* Nothing to do when entering WFI or Sleep low power state
NVIC fully functionnal to trigger upcoming interrupts */
}
else
{
if (eventType == kPM_EventEnteringSleep)
{
BOARD_EnterLowPowerCb();
if (powerState >= PLATFORM_POWER_DOWN_STATE)
{
/* Power gated low power modes often require extra specific
* entry/exit low power procedures, those should be implemented
* in the following BOARD API */
BOARD_EnterPowerDownCb();
}
}
else
{
/* Check if Main power domain domain really went to Power down,
* powerState variable is just an indication, Lowpower mode could have been skipped by an immediate wakeup
*/
PLATFORM_PowerDomainState_t main_pd_state = PLATFORM_NO_LOWPOWER;
PLATFORM_status_t status;
status = PLATFORM_GetLowpowerMode(PLATFORM_MainDomain, &main_pd_state);
assert(status == PLATFORM_Successful);
(void)status;
if (main_pd_state == PLATFORM_POWER_DOWN_MODE)
{
/* Process wake up from power down mode on Main domain
* Note that Wake up domain has not been in power down mode */
BOARD_ExitPowerDownCb();
}
BOARD_ExitLowPowerCb();
}
}
return ret;
}
2.4 - Low power constraint updates and optimization
Except for the board file update as seen in previous section, the application does not need any other changes for low-power support in Deep Sleep mode. It shall work as if no low-power is supported. However, If more aggressive power saving is required, this constraint can be changed in your application in order to further reduce the power consumption in Low Power mode.
2.4.1 - Changing the Default Application low power constraint after firmware initialization
The Low power reference design applications (central or peripheral) provides demonstration on how to change the Application low power constraint. In the Application main entry point BluetoothLEHost_AppInit(), Deep Sleep mode is configured by default from APP_ServiceInitLowpower() function.
Note : It is recommended to keep Deep Sleep mode as default during all the stack initialization phase until BluetoothLEHost_Initialized() and BleApp_StartInit() functions are called. In case of Bonded device with privacy, it is recommended to wait for gControllerPrivacyStateChanged_c event to be called.
BleApp_LowpowerInit() function provides an example of code on how to release the default Deep sleep low-power constraint and set a new constraint such as Power down mode for the application. This deeper low-power mode is used when no Bluetooth LE activity is on going, and if no other higher Low-power constraint is set by another components or layer. For instance, if some serial transmission is on going by the serial manager, or if the SecLib module has on going activity on the HW crypto accelerator, the low-power mode could less deep.
static void BleApp_LowpowerInit(void)
{
#if defined(gAppLowpowerEnabled_d) && (gAppLowpowerEnabled_d>0)
PWR_ReturnStatus_t status;
/*
* Optionally, Allow now Deepest lowpower mode constraint given by gAPP_LowPowerConstraintInNoBleActivity_c
* rather than DeepSleep mode.
* Deep Sleep mode constraint has been set in APP_InitServices(), this is fine
* to keep this constraint for typical lowpower application but we want the
* lowpower reference design application to be more agressive in term of power saving.
* To apply a lower lowpower mode than Deep Sleep mode, we need to
* - 1) First, release the Deep sleep mode constraint previously set by default in app_services_init()
* - 2) Apply new lowpower constraint when No BLE activity
* In the various BLE states (advertising, scanning, connected mode), a new Lowpower
* mode constraint will be applied depending of Application Compilation macro set in app_preinclude.h :
* gAppPowerDownInAdvertising, gAppPowerDownInConnected, gAppPowerDownInScanning
*/
/* 1) Release the Deep sleep mode constraint previously set by default in app_services_init() */
status = PWR_ReleaseLowPowerModeConstraint(PWR_DeepSleep);
assert(status == PWR_Success);
(void)status;
/* 2) Apply new Lowpower mode constraint gAppLowPowerConstraintInNoBleActivity_c *
* The BleAppStart() call above has already set up the new lowpower constraint
* when Advertising request has been sent to controller */
BleApp_SetLowPowerModeConstraint(gAppLowPowerConstraintInNoBleActivity_c);
#endif
}
2.4.2 - Changing the Application lowest low power constraint during application execution
In the various application use cases, (in the various Bluetooth LE activity states, advertising, connected, scanning), some lower low-power constraint can be set, as Power down for advertising, Deep Sleep for connected, or Scanning. Customer can change the level of Low Power mode in the various use case mainly depending of the time duration the device is supposed to remain in low-power. The longer the time that the device remains in low power, the higher the benefit for a deeper Low Power mode such as Power down mode. However, please note that the wake up from power down mode takes significantly more time than deep sleep as ROM code is re executed and the hardware logic needs to be restored. Sections Deep Sleep and Power Down provide some guidance on when to use Deep Sleep mode or Power Down modes respectively.
In the low power reference design applications, four application compilations macros are defined to adjust the low-power mode into advertising, scanning, connected, or no Bluetooth LE activity. Other use cases can be added as desired. For instance, If application needs to run a DMA transfer, or if application needs to wakeup regularly to process data from external device, it may be useful to set WFI constraint (in case of DMA transfer), or Deep Sleep constraint (in case of regular wake up to process external data), rather than power down or a even lower low-power mode.
The 4 application compilation macros can be found in app_preinclude.h file of the project. See app_preinclude.h for low power reference design peripheral application :
/*! Lowpower Constraint setting for various BLE states (Advertising, Scanning, connected mode)
The value shall map with the type defintion PWR_LowpowerMode_t in PWR_Interface.h
0 : no LowPower, WFI only
1 : Reserved
2 : Deep Sleep
3 : Power Down
4 : Deep Power Down
Note that if a Ble State is configured to Power Down mode, please make sure
gLowpowerPowerDownEnable_d variable is set to 1 in Linker Script
The PowerDown mode will allow lowest power consumption but the wakeup time is longer
and the first 16K in SRAM is reserved to ROM code (this section will be corrupted on
each power down wakeup so only temporary data could be stored there.)
Power down feature not supported. */
#define gAppLowPowerConstraintInAdvertising_c 3
/* Scanning not supported on peripheral */
//#define gAppLowPowerConstraintInScanning_c 2
#define gAppLowPowerConstraintInConnected_c 2
#define gAppLowPowerConstraintInNoBleActivity_c 4
In lowpower_central.c lowpower_preripheral.c files, the application sets and releases the low power constraint from BleApp_SetLowPowerModeConstraint() and BleApp_ReleaseLowPowerModeConstraint() functions. These functions are called with the macro value passed as argument.
Important Note : Setting the application low power constraint shall be done on new Bluetooth LE state request so the new constraint is applied immediately, while the application low-power mode constraint shall be released when the Bluetooth LE state is exited. For example, setting the new low power constraint for Advertising shall be done when the application requests advertising to start. Releasing the low power constraint shall be done in the advertising stop callback (advertising has been stopped).
After releasing the low power constraint, the previous low power constraint, (likely the one that has been set during firmware initialization in APP_ServiceInitLowpower() function, or the updated low power constraint in BleApp_StartInit() function) applies again.
2.4.3 - Idle task implementation example
2.4.3.1 Tickless mode support and Low power entry function
Idle task configuration from FreeRTOS shall be enabled by configUSE_TICKLESS_IDLE in FreeRTOSConfig.h. This will have the effect to have vPortSuppressTicksAndSleep() called from Idle task created by FreeRTOS. Here is a typical implementation of this function:
void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)
{
bool abortIdle = false;
uint64_t actualIdleTimeUs, expectedIdleTimeUs;
/* The OSA_InterruptDisable() API will prevent us to wakeup so we use
* OSA_DisableIRQGlobal() */
OSA_DisableIRQGlobal();
/* Disable and prepare systicks for low power */
abortIdle = PWR_SysticksPreProcess((uint32_t)xExpectedIdleTime, &expectedIdleTimeUs);
if (abortIdle == false)
{
/* Enter low power with a maximal timeout */
actualIdleTimeUs = PWR_EnterLowPower(expectedIdleTimeUs);
/* Re enable systicks and compensate systick timebase */
PWR_SysticksPostProcess(expectedIdleTimeUs, actualIdleTimeUs);
}
/* Exit from critical section */
OSA_EnableIRQGlobal();
}
2.4.3.2 Connectivity background tasks and Idle hook function example
Some process needs to be run in background before going into low power. This is the case for writing in NVM, or firmware update OTA to be writen in Flash. If so, configUSE_IDLE_HOOK shall be enabled in FreeRTOSCOnfig.h so vApplicationIdleHook() will be called prior to vPortSuppressTicksAndSleep(). Typical implementation of vApplicationIdleHook() function can be found here :
void vApplicationIdleHook(void)
{
/* call some background tasks required by connectivity */
#if ((gAppUseNvm_d) || \
(defined gAppOtaASyncFlashTransactions_c && (gAppOtaASyncFlashTransactions_c > 0)))
if (PLATFORM_CheckNextBleConnectivityActivity() == true)
{
BluetoothLEHost_ProcessIdleTask();
}
#endif
}
PLATFORM_CheckNextBleConnectivityActivity() function implemented in low power platform file fwk_platform_lowpower.c typically checks the next connectivity event and returns true if there’s enough time to perform time consuming tasks such as flash erase/write operations (can be defined by the compile macro depending on the platform).
2. Low power features
2.1 - FreeRTOS systicks
Low power module in framework supports the systick generation for FreeRTOS. Systicks in FreeRTOS are most of the time not required in the Bluetooth LE demos applications because the framework already supports timers by the timer manager component, so the application can use the timers from this module. The systicks in FreeRTOS are useful for all internal timer service provided by FreeRTOS (through OSA) like OSA_TimeDelay(), OSA_TimeGetMsec(), OSA_EventWait(). When systicks are enabled, an interrupt (systick interrupt) is triggered and executed on a periodic basis. In order to save power, periodic systick interrupts are undesirable and thus disabled when going to low-power mode. This feature is called low power FreeRTOS tickless mode. When entering the low power state, the system ticks shall be disabled and switch to a low power timer. On wake-up, the module retrieves the time passed in low power and compensate the ticks count accordingly. This feature does not apply on bare metal scheduler.
On FreeRTOS, the vPortSuppressTicksAndSleep() function implemented in the app_low_power.c file will be called when going to idle. FreeRTOS will give to this function the xExpectedIdleTime, time in tick periods before a task is due to be moved into the Ready state. This function will manage the systicks (disable/enable) through PWR_SysticksPreProcess() and PWR_SysticksPostProcess() calls. Then, when calling PWR_EnterLowPower(), a time out duration in micro seconds will be given and the function will set a timer before entering low power. In addition, this function will return the low power period duration, used to compensate the ticks count.
In our example low power reference design peripheral application, an OSA_EventWait() has been added to demonstrate the tickless mode feature. You can adjust the timeout with the gAppTaskWaitTimeout_ms_c flag in the app_preinclude.h file, its value in our demo is 8000ms. So 8 seconds after stopping any activity we will wake up from low power. If the flag is not defined in the application its value will be osaWaitForever_c and there will be no OS wake up.
2.2 - Selective RAM bank retention
To optimize the consumption in low power, the linker script specific function PLATFORM_GetDefaultRamBanksRetained() is implemented. This function obtains the RAM banks that need to be retained when the device goes in low power, in order to set them with PLATFORM_SetRamBanksRetained() function. The RAM banks that are not needed are set in power off state, when the device goes in low power mode.
The function PLATFORM_GetDefaultRamBanksRetained() is linker script specific. Hence, it cannot be adapted for a different application. If these functions are called from board_lp.c, it is possible to give to PLATFORM_SetRamBanksRetained() a different bank_mask adapted to your specific application.
In deep power down, this feature does not have any impact because in this power mode, all RAM banks are already powered off.
3 - Low power modes overview
PWR module API provides the capability to set low power mode constraints from various components or from the application. These constraints are provided to the SDK power manager. Upper layer (all Application code, connectivity stacks, etc.) can call directly the SDK Power Manger if it requires more advanced tuning. The PWR API can be found in PWR_Interface.h.
Note : ‘Upper layer’ signifies all layers, applications, components, or modules that are above the connectivity framework in the Software architecture.
Note : Each power domain has its own Low Power mode capability. The Low Power modes described below are for the main domain and it is supposed that the wake up domain goes to the same Low Power mode. This is not always true as the wake up domain that contains some wake up peripheral can go a lower Low Power mode state than the main domain so the peripherals in the wake up domain can remain operational when the main domain is in Low Power mode (deep sleep or power down modes). In this case, the context of the Hardware peripheral located in the wake up domain does not need to be saved and restored as for the peripherals located in the main domain
3.1 Wait for Interrupt (WFI)
Definition
In the Wait for Interrupt (WFI) state, the CPU core is powered on, but is in an idle mode with the clock turned OFF.
Wake up time and typical use case
The wakeup time from this Low Power mode is insignificant because the Fast clock from FRO is still running.
This Low Power mode is mainly used when there is an hardware activity while the Software runs the Idle task. This allows the code execution to be temporarily suspende, thus reducing a bit the power consumption of the device by switching off the processor clock. When an interrupt fires, the processor clock is instantaneously restored to process the Interrupt Service Routine (ISR).
Usage
In order to prevent the software from programming the device to go to a lower Low Power mode (such as Deep Sleep, Power Down mode or Deep Power Down mode), the component responsible for the hardware drivers shall call PWR_SetLowPowerModeConstraint(PWR_WFI) function. When the Hardware activity is completed, the component shall release the constraint by calling PWR_ReleaseLowPowerModeConstraint(PWR_WFI).
Alternatively, the component can call PWR_LowPowerEnterCritical() and then PWR_LowPowerExitCritical() functions.
For fine tuning of the Low Power mode allowing more power saving, the component can call directly the SDK power manager API with PM_SetConstraints() function using the appropriate Low Power mode and low power constraint. However, this is reserved for more advanced user that knows the device very well. It is not recommended to do so.
The PWR module has no external dependencies, so the low-power entry and exit callback functions must be defined by the user for each peripheral that has specific low power constraints It is consequently convenient to register to the component the low power callbacks structure that is used for entering and exit low power critical sections. In Bluetooth LE, you can take the example in the app_conn.c file as shown here :
#if defined(gAppLowpowerEnabled_d) && (gAppLowpowerEnabled_d>0)
static const Seclib_LowpowerCriticalCBs_t app_LowpowerCriticalCBs =
{
.SeclibEnterLowpowerCriticalFunc = &PWR_LowPowerEnterCritical,
.SeclibExitLowpowerCriticalFunc = &PWR_LowPowerExitCritical,
};
#endif
void BluetoothLEHost_Init(..)
{
...
/* Cryptographic hardware initialization */
SecLib_Init();
#if defined(gAppLowpowerEnabled_d) && (gAppLowpowerEnabled_d>0)
/* Register PWR functions into SecLib module in order to disable device lowpower
during Seclib processing. Typically, allow only WFI instruction when
commands (key generation, encryption) are processed by Seclib */
SecLib_SetLowpowerCriticalCb(&app_LowpowerCriticalCBs);
#endif
...
}
Limitations
No limitation when using the WFI mode.
3.2 Sleep mode
Sleep mode is similar to WFI low power mode but with some additional clock gating. The Sleep mode is device specific, please consult the Hardware reference manuel of the device for more information.
3.2 Deep Sleep mode
Definition
In Deep Sleep mode, the fast clock is turned off, and the CPU along with the main power domain are placed into a retention state, with the voltage being scaled down to support state retention only. Because no high frequency clock is running, the voltage applied on the power domain can be reduced to reduce leakage on the hardware logic. This reduces the overall power consumption in the Deep Sleep mode. When waking up from Deep sleep mode, the core voltage is increased back to nominal voltage and the fast clock (FRO) is turned back on, the peripheral in this domain can be reused as normal.
To same more additional power, Some unused RAM banks can be powered off. this prevents from having current leakage and consequently, allow to reduce even more the power consumption in Deep SLeep mode. This is achieved by calling PLATFORM_SetRamBanksRetained() from low power entry function from board_lp.c file.
Usage
All firmware is able to implement Deep Sleep mode transparently to the application thanks to the PWR module, low power platform submodule and low power board file. This is described in the section Low-power implementation.
When entering this mode, it is recommended to turn the output pins into input mode, or high impedance to reduce leakage on the pads. This is typically done in pin_mux.c file, called from board.c file and executed from the low power callback in board_lp.c file. As an example, the TX line of the UART peripheral can be turned to disabled so it prevents the current from being drawn by the pad in Low Power mode.
Wake up time and typical use case
The wake up time is very fast, it takes mostly the time for the Fast FRO to start up again (couple of hundreds of microseconds) so this mode is a very good balance between power consumption in low-power mode and wake up latency and shall be used extensively in most of the use cases of the application.
Limitations
In Deep Sleep mode, the clock is disabled to the CPU and the main peripheral domain, so peripheral activity (for example, an on-going DMA transfer) is not possible in Deep Sleep mode.
3.3 Power Down mode
Definition
In Power Down mode, both the clock, and power are shut off to the CPU and the main peripheral domain. SRAM is retained, but register values are lost. The SDK power manager handles the restore of the processor registers and dependencies such as interrupt controller and similar ones transparently from the application.
Usage
The application, with the help of the low power board files, saves and restores the peripherals that were located in the power domain during the entry and exit of the power down mode. This is done from low power board_lp files in the entry/exit low power callbacks. Example is given for the serial manager and debug console in board_lp.c file in function BOARD_ExitPowerDownCb().
If the device contains a dedicated wake up power domain where some wake up peripherals are located, if this wake up domain is not turned into power down mode but only Deep sleep mode or active mode, this peripheral does not need for a save and restore on low power entry/exit. For instance, on KW45, This is basically achieved when enabling the wakeup source of the peripheral PWR_EnableWakeUpSource() from APP_ServiceInitLowpower() function. Alternatively, this can be directly achieved by setting the constraint to the SDK power manager by calling PM_SetConstraints(), (use APP_LPUART0_WAKEUP_CONSTRAINTS for wakeup from UART constraint).
On exit from low power, The low power state of power domain can be retrieved by Platform API PLATFORM_GetLowpowerMode(). This API shall be called from low power exit callback function only.
As for Deep Sleep mode, software shall configure the output pins into input or high impedance during the Low Power mode to avoid leakage on the pads.
Wake up time and typical use case
The wake up time is significantly longer than wake up time from Deep Sleep (from several hundreds of micro-seconds to a couple of milliseconds depending on the platform). On some platform, it can takes longer, for instance, if ROM code is implemented and perform authentication checks for security and hardware logic in power domain needs to be restored (case for KW45). However, After ROM code execution, the SDK power manager resumes the Idle task execution from where it left before entering low-power mode. Hence, the wakeup time from this mode is still significantly lower that the initialization time from a power on reset or any other reset.
Depending on the wakeup time of the platform and the low power time duration, This mode is recommended when no Software activity is expected to happen for the next several seconds. In Bluetooth LE, this mode is preferred in advertising or without Bluetooth LE activity. However, in scanning or connected mode, Regular wakes up happens regularly for instance to retrieve HCI message responses from the Link layer, the Deep Sleep mode is rather recommended.
Limitations
In addition to the Deep Sleep limitation (no Hardware processing on going when going to Power down mode) and the significant increase of the wake time, the Power Down mode requires the ROM code to execute and this last uses significant amount of memory in SRAM.
Typically, The first SRAM bank (16 KBytes) is used by the ROM code during execution so the Application firmware can use this section of SRAM for storing bss, rw data, or stacks. Only temporary data could be stored here and this location is overwritten on every Power Down exit sequence.
In order to avoid placing firmware data section (bss, rw, etc.) in the first SRAM bank, the linker script variable gLowpowerPowerDownEnable_d should be set to 1. Setting the linker script variable to avoid placing firmware data section in the first SRAM bank, The effect of setting this flag is to prevent the firmware from using the first 16 KB in SRAM.
Note : This setting is ONLY required if the application implements Power Down mode. If Application uses other low-power mode, this is not required.
3.4 Deep Power-down mode
Definition
In Deep Power Down mode, the SRAM is not retained. This power mode is the lowest disponible, it is exited through reset sequence.
Usage
In addition to the Power Down limitation, the Deep Power Down mode shut down all memory in SRAM. Because it is exited through reset sequence the wake time is also longer.
Wake up time and typical use case
As this low-power mode is exited through the reset sequence, the wake up time is longer than any other mode. In Bluetooth LE, this mode is possible in no Bluetooth LE activity, and is preferred if we know that there will be no Bluetooth LE activity before a several amount of time.
Limitations
All memory in SRAM will be shut down in deep power down, the main limitation in going in this low-power mode is that the context will not be saved.