Using Energy Modes with Bluetooth Stack#

Introduction#

This document discusses different energy modes available on EFR32 devices and demonstrates when and how to switch between energy modes while using Silicon Labs Bluetooth Stack. It also provides guidelines to save the most energy while ensuring that the stack is working.

EFR32 devices are designed for energy saving. Energy Management Unit (EMU) ensures that only actively needed peripherals are running and consuming current. For example, while waiting for an external signal or for the result of an A/D conversion, all clocks can be stopped (except ultra-low frequency clock) and all clocked peripherals can be shut down to save energy, but the device still stays in a state from which it can be woken up quickly.

Silicon Labs Bluetooth stack is designed so that it efficiently uses EMU. If configured properly, the stack puts the device into Deep Sleep mode and wakes it up only when needed, such as in communications windows or when a task is pending. This ensures minimal current consumption.

However, applications over the stack can have different needs regarding energy modes. For example, while waiting for an USART transaction, the processor can be shut down, but the device cannot be put into Deep Sleep mode. This is why it is important to understand how the stack handles energy modes.

Energy Modes of EFR32#

EFR32 devices support a number of energy modes ranging from EM0 Active to EM4 Shutoff. EM0 Active mode provides the highest number of features, enabling the CPU, Radio, and peripherals with the highest clock frequency. EM4 Shutoff Mode provides the lowest power state, allowing the part to return to EM0 Active on a wakeup condition. In between modes different peripherals are enabled/disabled providing a highly scalable energy profiling possibility. Figure 1 shows different peripherals of an EFR32 device with the lowest energy modes in which they are active. For example, the Low Energy UART runs in EM0, EM1, and EM2 energy modes.

Note that the peripherals and their energy mode needs are highly dependent on the specific device.

Peripherals of an EFR32 DevicePeripherals of an EFR32 Device

For more information about energy modes, see the Reference Manual of your device and AN0007 – Energy Modes.

Silicon Labs Bluetooth Stack needs the following peripherals to work:

  • RAM memory – always needed for data retention

  • RTCC – always needed for sleep timing

  • LDMA – used for handling BGAPI commands in NCP mode

  • UART – used for receiving/transmitting BGAPI commands/responses in NCP mode

  • PROTIMER – used for protocol timing when receiving/transmitting packets

  • RADIO – used for receiving/transmitting packets

RAM and RTCC are always needed while running the stack. RAM retains application data and RTCC ensures the working of soft timers and that the device will be woken up in time when a communication window opens and packets have to be received/transmitted. RAM needs EM3 or higher to work, while RTCC needs EM0/EM1/EM2 or EM4H to work from LFXO/LFRCO (ULFRCO is not supported by stack). This means that the device can be put, at most, into EM2 Deep Sleep mode to keep the stack working if higher energy modes are not needed.

EM0 Active mode is needed while tasks are running on the processor and/or radio is receiving/transmitting. EM1 Sleep mode is needed if there are no tasks running and no radio communication, but some peripheral is active that needs EM1 Sleep mode (e.g., USART, see Figure 1). In any other use case, the device can go into EM2 Deep Sleep mode.

The stack is designed to switch between EM0 Active and EM2 Deep Sleep modes if Deep Sleep is enabled and between EM0 Active and EM1 Sleep modes if Deep Sleep is disabled.

Enabling EM2 Deep Sleep in the Stack#

Silicon Labs Bluetooth stack can be configured by either putting the device into EM1 Sleep mode or into EM2 Deep Sleep mode when EM0 Active mode is not needed. If sleep mode is not configured, EM1 is used by default.

To enable Deep Sleep in a C project, add this line to the gecko_configuration structure, which will be passed to gecko_init():

.sleep.flags = SLEEP_FLAGS_DEEP_SLEEP_ENABLE;

To disable Deep Sleep mode, set the sleep flags to 0:

.sleep.flags = 0;

Important: Bluetooth connections need at least 500 ppm timing accuracy. If LFRCO is used as a sleep clock (e.g., because a 32 kHz crystal is not connected), deep sleep mode has to be disabled because LFRCO cannot meet the accuracy. PLFRCO (available on some devices) may be used as sleep clock, as it is more accurate, but in this case the sleep_clock_accuracy has to be set to 500 ppm instead of the default 100 ppm, which can only be achieved with LFXO.

.bluetooth.sleep_clock_accuracy = 500,

In the SoC – Empty Software Examples provided with Silicon Labs Bluetooth SDK, Deep Sleep is enabled by default (if LFXO is present).

The stack puts the device into EM1 Sleep or into EM2 Deep Sleep mode every time the processor is not needed and starts a timer to wake it up when needed, for example when a communication window opens or a task is pending.

The default template of a Bluetooth stack based application looks like the following:

while(1)
{
    evt = gecko_wait_event();

    switch(BGLIB_MSG_ID(evt->header))
    {
          //handling of different stack events
    }
}

The function gecko_wait_event() automatically puts the device into EM1 Sleep / EM2 Deep Sleep mode after all tasks are done, and sets a timer to wake it up when needed. The function returns only when a stack event (e.g., connection established event) is raised. After this, the application can handle the event and perform other tasks.

To learn more about how to handle the main loop, see Scheduling application tasks while running BLE stack.

Wake Up from EM1/EM2 by Application#

Sometimes the application needs to run even if there is no Bluetooth event, for example to periodically poll the state of some peripheral.

The device can be woken up by the application in two ways, as follows:

  • Setting up a software timer in the stack with gecko_cmd_hardware_set_soft_timer(). This will wake up the device when the timer expires, generate a stack event (evt_hardware_soft_timer), and return from gecko_wait_event().

  • Setting up any interrupt and triggering an external stack event from the interrupt handler with gecko_external_signal(signal). Now the interrupt wakes up the device and forces the stack to raise a new event (evt_system_external_event). A new event is raised and gecko_wait_event() returns.

For more information about the soft timer see the API Reference Manual. For more details about gecko_external_signal(), see Silicon Labs Bluetooth C Application Developer's Guide.

Temporarily Disable EM2 Deep Sleep Mode#

The Deep Sleep enable bit in the stack configuration cannot be dynamically changed. In other words, after Deep Sleep is enabled/disabled, it cannot be withdrawn. However, there are two ways to temporarily disable going into EM2 Deep Sleep mode:

  • in SoC mode you can use the sleep driver

  • in NCP mode you can use the wake up pin.

With sleep driver the EM2 Deep sleep mode can be disabled (/blocked) temporarily by using SLEEP_SleepBlockBegin(sleepEM2). To Re-enable EM2 Deep Sleep mode, use SLEEP_SleepBlockEnd(sleepEM2). While EM2 is disabled (/blocked), the stack will switch between EM0 and EM1 temporarily.

To access these functions, sleep.c and sleep.h has to be added to your project, and sleep.h has to be included in your source file. sleep.c and sleep.h are added to Bluetooth projects by default because they are need by the stack (except if you are using an old stack version, where sleep.c is precompiled in the stack).

Note that multiple issuing of SLEEP_SleepBlockBegin() requires multiple issuing of SLEEP_Sleep_BlockEnd(). Every SLEEP_SleepBlockBegin() increases the corresponding counter and every SLEEP_SleepBlockEnd() decreases it.

In NCP mode, a wake up pin can be defined to disable EM2 Deep Sleep mode temporarily. While driving this pin high (or low, depending on the configuration), going into EM2 mode will be blocked. For more information about configuring the wake up pin, see AN1042: Using the Silicon Labs Bluetooth® Stack in Network Co-Processor Mode.

Temporary blocking of EM2 Deep Sleep can be useful, for example, when USART is used for a limited time. Deep Sleep has to be disabled to get the USART controller work and to receive messages. However, when not needed any more, Deep Sleep can be re-enabled to save energy.

Putting Device into EM3 Stop Mode#

The Bluetooth stack does not work in EM3 Stop mode. However, if there are no connections alive and no advertisement/scanning is needed for a while, the device can be put into EM3 stop mode to save energy.

Since EM3 mode is blocked by default, this can be done by calling SLEEP_SleepBlockEnd(sleepEM3). The next call of SLEEP_Sleep() in the stack will put the device into EM3 mode, or application can call SLEEP_Sleep() directly. The device can be woken up by any interrupt. Call SLEEP_SleepBlockBegin(sleepEM3) within the interrupt handler to let the stack work again normally.

Note, however, that while EM2 Deep Sleep mode means a huge energy saving compared to EM1 Sleep mode, in EM3 Stop mode the current consumption drops only with around tenth of microamperes compared to EM2 Deep Sleep mode. See the Data Sheet of your device.

Putting Device into EM4 Hibernate / EM4 Shutoff Mode#

If the application does not need to be operation for a while, the device can be put into EM4 mode, the lowest possible energy mode. In this mode, nearly everything is shut down and the current consumption is around hundred nanoamperes. However, to wake up the device from this state, you need to reset the device. That is, no data is retained from the previous state and the stack is reinitialized.

EM4 Hibernate and EM4 Shutoff are two types of EM4 modes. The most important difference is that RTCC can run in EM4 Hibernate mode, while it cannot run in EM4 Shutoff mode. Also, there is a 128 byte RAM retention possibility in EM4 Hibernate mode. To switch between EM Hibernate and EM4 shutoff use the following initialization:

  EMU_EM4Init_TypeDef init_EM4 = EMU_EM4INIT_DEFAULT;
  init_EM4.em4State = emuEM4Hibernate;   OR   init_EM4.em4State = emuEM4Shutoff;
  EMU_EM4Init( &init_EM4 );

For detailed information about EM4 initialization, see https://siliconlabs.github.io/Gecko_SDK_Doc/efr32bg1/html/structEMU__EM4Init__TypeDef.html.

To put the device into EM4 mode, use the function SLEEP_ForceSleepInEM4().

Be aware that, if the device goes EM4 very soon after reset, it may be hard to get attached to the target using debugger and you can easily lock yourself out. If you got locked out, start Simplicity Commander (C:\SiliconLabs\SimplicityStudio\v4\developer\adapter_packs\commander\commander.exe), connect to the Adapter, select Flash tab, and click "Unlock debug access".

Running RTCC in EM4 Hibernate Mode#

In EM4 Hibernate mode, RTCC can run continuously.

  • If RTCC is running from LFXO add the following to the EM4 initialization: int_EM4.retainLfxo = 1;˛

  • If RTCC is running from LFRCO add the following to the EM4 initialization: int_EM4.retainLfrco = 1;

  • If RTCC is running from ULFRCO add the following to the EM4 initialization: int_EM4.retainUlfrco = 1;

To avoid the reset of the RTCC timer upon wake up from EM4, set the reset mode to LIMITED:

  RMU_ResetControl(rmuResetSys,rmuResetModeLimited);
  RMU_ResetControl(rmuResetPin,rmuResetModeLimited);

In normal operation, when the Bluetooth stack runs, the RTCC runs from LFXO or LFRCO.

Wake up from EM4 Hibernate / EM4 Shutoff Mode#

The device can wake up from EM4 mode, as follows:

  • Driving low the reset pin

  • State change of some dedicated pins

  • Cryotimer interrupt

Pins dedicated for EM4 wake up are listed in EFR32BG1 Blue Gecko Bluetooth Smart SoC Family Data Sheet. To enable EM4 wake up on these pins, use the following template:

  GPIO_PinModeSet(gpioPortF, 7, gpioModeInputPullFilter, 1);
  GPIO_EM4EnablePinWakeup( GPIO_EXTILEVEL_EM4WU1, _GPIO_EXTILEVEL_EM4WU1_DEFAULT );
  GPIO_IntClear(_GPIO_IFC_EM4WU_MASK | _GPIO_IFC_EXT_MASK);
  NVIC_ClearPendingIRQ(GPIO_ODD_IRQn);
  NVIC_EnableIRQ(GPIO_ODD_IRQn);
  NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
  NVIC_EnableIRQ(GPIO_EVEN_IRQn);

Cryotimer can also be used to wake up the device. For example, to wake up the device 4 seconds after putting it into EM4 mode, use the following initialization:

  cryoInit.enable = false;
  cryoInit.em4Wakeup = true;
  cryoInit.osc = cryotimerOscLFXO;
  cryoInit.period = cryotimerPeriod_128k;
  CRYOTIMER_Init(&cryoInit);
  CRYOTIMER_IntEnable(1);
  CRYOTIMER_IntClear(1);
  NVIC_ClearPendingIRQ(CRYOTIMER_IRQn);
  NVIC_EnableIRQ(CRYOTIMER_IRQn);
  //…
  CRYOTIMER_Enable(1);
  SLEEP_ForceSleepInEM4();

In this example, the Cryotimer runs from LFXO (remember to set int_EM4.retainLfxo = 1). LFXO has a 32 kHz clock, consequently 128 k period will result in overflow in 4 seconds. Remember to define the IRQ handler for Cryotimer:

void CRYOTIMER_IRQHandler(void)
{
  CRYOTIMER_IntClear(1);
}

To differentiate EM4 wake up from other reset causes (e.g., power on reset, Watchdog reset) the following statement can be used:

#if defined(RMU_RSTCAUSE_EM4WURST)
  if ((RMU_ResetCauseGet() & RMU_RSTCAUSE_EM4WURST) == 1)
#elif defined(RMU_RSTCAUSE_EM4RST)
  if ((RMU_ResetCauseGet() & RMU_RSTCAUSE_EM4RST) == 1)
#endif
  { /*EM4 wake up*/ } else { /*other reset cause*/ }

Example#

This guide has a related code example here: Using energy modes with Bluetooth stack