KW36 - Low Power Support on OTAP Client Software

cancel
Showing results for 
Search instead for 
Did you mean: 

KW36 - Low Power Support on OTAP Client Software

KW36 - Low Power Support on OTAP Client Software

Introduction

This document is to guide how to modify the OTAP Client software to the Low Power module. The starting point of this document is the OTAP Client example in the FRDM-KW36 SDK v2.2.2.

 

Deep Sleep Modes

This section provides a base to understand how the developer should change between DSM1 (Deep Sleep Mode 1) and DSM3 (Deep Sleep Mode 3). The DSM6 does not need to be started by the developer, instead, the controller configures this mode automatically and returns to the latest mode after finished the radio activity.

 

DSM1

This low-power mode was designed to be used when the BLE stack is active, in other words when the LL is in advertising, scanning, or connection states. In this mode, the MCU enters LLS3 and BLE Link Layer enters deep sleep. The SoC wakes up from this mode by the on-board switches, by LPTMR timeout, or by BLE Link Layer wake-up interrupt (BLE_LL reference clock reaches wake up instance register) using LLWU module. The LPTMR timer is used to measure the time that the MCU spends in deep sleep to synchronize low-power timers at wakeup.

 

DSM3

This low-power mode was designed to be used when all stacks enabled for this platform are idle, in other words, when the LL stop advertising, scanning, or connection. In this mode, the MCU enters LLS3 and all enabled link layers remain idle. All RAM is retained. The SoC wakes up from this mode by the on-board switches, by DCDC power switch (when DCDC is in buck mode), or by LPTMR timeout using LLWU module. The LPTMR timer is also used to measure the time that MCU spends in deep sleep to synchronize low-power timers at wakeup.

 

DSM6

This low-power mode was developed to save some power while the radio is on. Its most common use case is with the radio in Rx waiting for a packet. Upon receiving the packet the radio wakes up the MCU. In this mode, the MCU enters STOP mode and the radio maintains its state. Any module capable of producing an interrupt can wake up the MCU, such as on-board switches, DCDC power switch (when DCDC is in buck mode), LPTMR timeout, Radio Interrupt, UART, and so on. The LPTMR timer is also used to measure the time that the MCU spends in deep sleep to synchronize low-power timers at wakeup.

 

For more information about DSM modes, you can inspect the “Connectivity Framework Reference Manual” chapter 3.15 Low-power library, it provides full information of Low Power modes and the usage on the NXP stack. It is available in your SDK at <FRDM-KW36 SDK root>\docs\wireless\Common.

 

Modifications on the Software

In order to add low power on the OTAP Client (switching between DSM1, DSM3, and DSM6) two files must be modified:
- app_preinclude.h
- otap_client_att.c
The following sections explain these changes.

 

app_preinclude.h

This file is intended to contain the definitions that manage the behavior of the application. To include and enable the Low Power module you must add (or modify if the macro is already defined in this file) the following preprocessor directives.

 

1. Modify the AppPoolsDetails as following.

/* Defines pools by block size and number of blocks. Must be aligned to 4 bytes.*/
#define AppPoolsDetails_c \
_block_size_ 32 _number_of_blocks_ 6 _eol_ \
_block_size_ 64 _number_of_blocks_ 4 _eol_ \
_block_size_ 88 _number_of_blocks_ 3 _eol_ \
_block_size_ 248 _number_of_blocks_ 2 _eol_ \
_block_size_ 312 _number_of_blocks_ 1 _eol_ \
_block_size_ 392 _number_of_blocks_ 1 _eol_‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

2. Set “cPWR_UsePowerDownMode” to 1 and keep the following directives in the “Framework Configuration” section as shown below.

/* Check Low Power Timer */
#define cPWR_CheckLowPowerTimers 1
/* Enable/Disable Low Power Timer */
#define gTMR_EnableLowPowerTimers 1
/* Enable/Disable PowerDown functionality in PwrLib */
#define cPWR_UsePowerDownMode 1
/* Enable/Disable BLE Link Layer DSM */
#define cPWR_BLE_LL_Enable 1
/* Default Deep Sleep Mode*/
#define cPWR_DeepSleepMode 3
/* Enable/Disable MCU Sleep During BLE Events */
#define cMCU_SleepDuringBleEvents 1
/* Default deep sleep duration in ms */
#define cPWR_DeepSleepDurationMs 30000
/* Number of slots(625us) before the wake up instant before which the hardware needs to exit from deep
sleep mode. */
#define cPWR_BLE_LL_OffsetToWakeupInstant 3
/* Enables / Disables the DCDC platform component */
#define gDCDC_Enabled_d 1
/* Default DCDC Mode used by the application */
#define APP_DCDC_MODE gDCDC_Mode_Buck_c
/* Default DCDC Battery Level Monitor interval */
#define APP_DCDC_VBAT_MONITOR_INTERVAL 600000‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

3. Add the following directives in the “BLE Stack Configuration” section. Create the “Auto Configuration” section to disable LED support whenever Low Power is enabled.

/*! *********************************************************************************
* BLE Stack Configuration
********************************************************************************** */
/* Time between the beginning of two consecutive advertising PDU's */
#define mcAdvertisingPacketInterval_c 0x02 /* 1.25 msec */
/* Offset to the first instant register. */
#define mcOffsetToFirstInstant_c 0x00 /* 625usec */
/*! *********************************************************************************
* Auto Configuration
********************************************************************************** */
/* Disable LEDs when enabling low power */
#if cPWR_UsePowerDownMode || gMWS_UseCoexistence_d
#define gLEDSupported_d 0
#endif
#if gMWS_UseCoexistence_d
#undef gKBD_KeysCount_c
#define gKBD_KeysCount_c 1
#endif‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

4. Modify the “Memory Pools Configuration” section as follows.

/* Enable RNG seed storage in Flash */
#define gRngSeedStorageAddr_d ((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR + 1024)
/* Enable XCVR calibration storage in Flash */
#define gPreserveXcvrDacTrimValue_d 1
#define gXcvrDacTrimValueSorageAddr_d ((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR + 1040)
/* Application Connection sleep mode */
#define gAppDeepSleepMode_c 1
/* Application RAM usage configuration */
#define cPWR_RamRetentionInVLLS 2 /* 32K */
/* Disable unused LowPower modes */
#define cPWR_EnableDeepSleepMode_1 1
#define cPWR_EnableDeepSleepMode_2 0
#define cPWR_EnableDeepSleepMode_3 1
#define cPWR_EnableDeepSleepMode_4 0
#define cPWR_EnableDeepSleepMode_5 0
#define cPWR_EnableDeepSleepMode_7 0
#define cPWR_EnableDeepSleepMode_8 0
/* Warm-boot sequence will use the default stack which is used by ISRs on FreeRTOS */
#define USE_WARMBOOT_SP 0‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

otap_client_att.c

This is the main source file at the application level. Here are managed all the procedures that the device performs, before, during, and after to create a connection. This allows you to get the state of the device any instant and, hence, the dedicated low power APIs that rule the application must be implemented here, in the callbacks contained in this file, for an easier switching among the low power states.

 

1. Include “PWR_Configuration.h” header in “Include” section:

#if (cPWR_UsePowerDownMode)
#include "PWR_Interface.h"
#include "PWR_Configuration.h"
#endif‍‍‍‍‍‍‍‍‍‍‍‍

2. Locate the “BleApp_Config” function. This function is executed once, after POR (Power on reset) during the device setup. Here you can change the deep sleep mode to DSM3 and allow the device to sleep using “PWR_ChangeDeepSleepMode” and “PWR_AllowDeviceToSleep” APIs. When the device has finished the initialization, it goes to sleep since all stacks are idle. See the following example.

static void BleApp_Config(void)
{
#if defined(MULTICORE_APPLICATION_CORE) && (MULTICORE_APPLICATION_CORE == 1)
if (GattDbDynamic_CreateDatabase() != gBleSuccess_c)
{
panic(0,0,0,0);
return;
}
#endif /* MULTICORE_APPLICATION_CORE */
/* Common GAP configuration */
BleConnManager_GapCommonConfig();
/* Register stack callbacks */
(void)App_RegisterGattServerCallback (BleApp_GattServerCallback);‍‍‍‍‍‍‍‍‍‍‍‍‍
mAdvState.advOn = FALSE;
/* Start services */
basServiceConfig.batteryLevel = BOARD_GetBatteryLevel();
(void)Bas_Start(&basServiceConfig);
(void)Dis_Start(&disServiceConfig);
if (OtapClient_Config() == FALSE)
{
/* An error occurred in configuring the OTAP Client */
panic(0,0,0,0);
}
/* Allocate application timer */
appTimerId = TMR_AllocateTimer();
mBatteryMeasurementTimerId = TMR_AllocateTimer();
#if (cPWR_UsePowerDownMode)
#if MULTICORE_APPLICATION_CORE
#if gErpcLowPowerApiServiceIncluded_c
PWR_ChangeBlackBoxDeepSleepMode(cPWR_DeepSleepMode);
PWR_AllowBlackBoxToSleep();
#endif
PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode);
PWR_AllowDeviceToSleep();
#else
PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode);
PWR_AllowDeviceToSleep();
#endif
#endif
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

3. Locate the “BleApp_Start” function. This function is executed just after wake up by pressing the LLWU SW3 button. This action will trigger the advertising, so, you must change the deep sleep mode to DSM1 using “PWR_ChangeDeepSleepMode” API since the BLE stack is active. See the following example.

void BleApp_Start(void)
{
Led1On();
if (mPeerDeviceId == gInvalidDeviceId_c)
{
/* Device is not connected and not advertising*/
if (!mAdvState.advOn)
{
#if gAppUseBonding_d
if (gcBondedDevices > 0)
{
mAdvState.advType = whiteListAdvState_c;
}
else
{
#endif
mAdvState.advType = advState_c;
#if gAppUseBonding_d
}
#endif
#if (cPWR_UsePowerDownMode)
#if MULTICORE_APPLICATION_CORE
#if gErpcLowPowerApiServiceIncluded_c
PWR_ChangeBlackBoxDeepSleepMode(gAppDeepSleepMode_c);
#endif
#else
PWR_ChangeDeepSleepMode(gAppDeepSleepMode_c);
#endif
#endif
BleApp_Advertise();
}
}
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

4. Locate the “BleApp_AdvertisingCallback” function. This function is executed every time the advertising state changes. Change the deep sleep mode to DSM3 when “mAdvState.advOn” is false, in other words, when the device stops advertising. If you stop the advertising either using an application timer or a user button, KW36 will go to sleep until you start advertising again (pressing LLWU SW3 button), saving power when all stacks are idle. See the following example.

static void BleApp_AdvertisingCallback (gapAdvertisingEvent_t* pAdvertisingEvent)
{
switch (pAdvertisingEvent->eventType)
{
case gAdvertisingStateChanged_c:
{
mAdvState.advOn = !mAdvState.advOn;
if(mAdvState.advOn)
{
LED_StopFlashingAllLeds();
Led1Flashing();
}
#if (cPWR_UsePowerDownMode)
else
{
#if MULTICORE_APPLICATION_CORE
#if gErpcLowPowerApiServiceIncluded_c
PWR_ChangeBlackBoxDeepSleepMode(cPWR_DeepSleepMode);
#endif
#else
PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode);
#endif
}
#endif
}
break;
case gAdvertisingCommandFailed_c:
{
Led2On();
panic(0,0,0,0);
}
break;
default:
; /* For MISRA compliance */
break;
}
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

5. Locate “BleApp_ConnectionCallback” function. It is executed every time the connection state changes. In “gConnEvtConnected_c” add the following code to change to DSM1, since the BLE stack is active.

case gConnEvtConnected_c:
{
/* Advertising stops when connected */
mAdvState.advOn = FALSE;
(void)TMR_StopTimer(appTimerId);
/* Subscribe client*/
mPeerDeviceId = peerDeviceId;
(void)Bas_Subscribe(&basServiceConfig, peerDeviceId);
(void)OtapCS_Subscribe(peerDeviceId);
OtapClient_HandleConnectionEvent (peerDeviceId);
/* Start battery measurements */
(void)TMR_StartLowPowerTimer(mBatteryMeasurementTimerId, gTmrLowPowerIntervalMillisTimer_c,
TmrSeconds(mBatteryLevelReportInterval_c), BatteryMeasurementTimerCallback, NULL);
#if (cPWR_UsePowerDownMode)
#if MULTICORE_APPLICATION_CORE
#if gErpcLowPowerApiServiceIncluded_c
PWR_ChangeBlackBoxDeepSleepMode(gAppDeepSleepMode_c);
PWR_AllowBlackBoxToSleep();
#endif
#else
PWR_ChangeDeepSleepMode(gAppDeepSleepMode_c);
PWR_AllowDeviceToSleep();
#endif
#else
/* UI */
LED_StopFlashingAllLeds();
Led1On();
#endif
}
break;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

In “gConnEvtDisconnected_c” add the following code to change to DSM3, since all stacks are idle.

case gConnEvtDisconnected_c:
{
/* Unsubscribe client */
mPeerDeviceId = gInvalidDeviceId_c;
(void)Bas_Unsubscribe(&basServiceConfig, peerDeviceId);
(void)OtapCS_Unsubscribe();
/* UI */
LED_StopFlashingAllLeds();
Led1Flashing();
Led2Flashing();
Led3Flashing();
Led4Flashing();‍‍‍‍‍‍‍‍‍‍‍‍
OtapClient_HandleDisconnectionEvent (peerDeviceId);
#if (cPWR_UsePowerDownMode)
/* Go to sleep */
#if MULTICORE_APPLICATION_CORE
#if gErpcLowPowerApiServiceIncluded_c
PWR_ChangeBlackBoxDeepSleepMode(cPWR_DeepSleepMode);
#endif
#else
PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode);
#endif
#else
/* Restart advertising*/
BleApp_Start();
#endif
}
break;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

Power Consumption Profile of OTAP Client

This section explains the behavior of the power consumption profile along the time. We can differ when DSM1 or DSM3 are used depending on the device state. If the device needs to advertise or is in connection state, it will use DSM1 because this sleep mode can predict when the device needs to handle the communication with others and wake up automatically through the BLE Link Layer wakeup interrupt. On the other hand, when no actions are in progress, it will use DSM3 and the wake up depends entirely on the LLWU SW3 button in this example. On the other hand, the DSM6 puts the MCU in STOP mode during the transmission and reception in BLE events, it does not need to be started manually, instead, the controller configures this mode automatically and returns to DSM1 mode after finished the radio activity.

 

The APIs that change the deep sleep mode to DSM1 are:

• BleApp_Start: It starts advertising.
• BleApp_ConnectionCallback – gConnEvtConnected_d: It notifies when the MCU has been connected to a peer device.

 

The APIs that change the deep sleep mode to DSM3 are:
• BleApp_Config: It takes part of the initialization procedure after POR. All tasks are idle, the device is waiting for the LLWU SW3 button to wake up and start advertising.
• BleApp_AdvertisingCallback – mAdvState is off: The device has to stopped advertising, so the MCU is idle.
• BleApp_ConnectionCallback – gConnEvtDisconnected_d: It notifies when the device has been disconnected, so the MCU is idle.

 

Please let us know any questions or comments regarding this topic.

Labels (3)
Tags (2)
Version history
Revision #:
3 of 3
Last update:
a week ago
Updated by:
 
Contributors