Using Energy Modes with Bluetooth Stack

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac ‎02-22-2017 11:08 AM - edited ‎05-09-2017 04:18 AM

This article presents the different energy modes available on EFR32 devices and demonstrates when and how to switch between energy modes while using Silicon Labs Bluetooth Stack. Guidelines are provided how to save the most energy while ensuring the working of the stack.

 

Introduction

 

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 effectively uses EMU. If configured properly, the stacks puts the device into Deep Sleep mode and wakes it up only when it is needed: in communications windows or when a task is to be done. This ensures minimal current consumption.

 

However, applications over the stack can have different needs regarding energy modes. For example when 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 amount 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 presents the different peripherals of an EFR32 device with the lowest energy modes in which they are active. For example, the Low Energy Timer runs in EM0, EM1 and EM2 energy modes.

 

2017-02-21_13h30_11.png

 

For more details about energy modes see AN0007 – Energy Modes and EFR32xG1 Wireless Gecko Reference Manual.

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 is always needed while running the stack. RAM retains application data and RTCC ensures that the device will be woken up 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 LFCLK. This means that the device can be put at most into EM2 Deep Sleep mode to maintain working of the stack, if there is no need for higher energy modes.

 

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 case the device can go into EM2 Deep Sleep mode.

 

The stack is designed so, that it switches between EM0 Active and EM2 Deep Sleep modes if Deep Sleep is enabled and it switches between EM0 Active and EM1 Sleep modes if Deep Sleep is disabled.

 

Enabling EM2 Deep Sleep in the Stack

 

Regarding sleep policy Silicon Labs Bluetooth stack can be configured in two ways: putting the device into EM1 Sleep mode or into EM2 Deep Sleep mode, while EM0 Active mode is not needed. If sleep mode is not configured, EM1 is used. To enable EM2 Deep Sleep in BGScript add this line to the hardware.xml configuration file:

<sleep enable=”true” />

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

config.sleep.flags=SLEEP_FLAGS_DEEP_SLEEP_ENABLE;

In the software examples provided with Silicon Labs Bluetooth SDK Deep Sleep is enabled by default (except NCP empty target).

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: when a communication window opens or a task is to be done.

The default template of a Bluetooth stack based application looks like this

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 task is 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 do other tasks.

 

Wake Up from EM1/EM2 by Application

 

Sometimes the application need 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:

  • 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 details about soft timer see Bluetooth Smart Software API Reference Manual. For more details about gecko_external_signal() see UG136: 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. That is once Deep Sleep is enabled/disabled, it cannot be withdrawn. However, there are two ways to temporarily disable going to EM2 Deep Sleep mode: using sleep driver or using 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). If EM2 is disabled (/blocked), then the stack will switch between EM0 and EM1 temporarily.

 

To access these functions sleep.h has to be included in your source file! sleep.c is already precompiled with the stack, hence it has not to be added to the project!

 

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.

 

A wake up pin can also be defined to disable EM2 Deep Sleep mode temporarily. When driving this pin high (or low, depending on configuration), going EM2 mode will be blocked within the stack. To set up a pin as wake up pin in BGScript, add the following line to hardware.xml:

<wake_up port="F" pin="6" state="up" />

To configure pin as wake up pin in C projects, follow the following configuration sample:

/* Gecko configuration parameters (see gecko_configuration.h) */ 
static const gecko_configuration_t config = {
.config_flags=0,
.bluetooth.max_connections=MAX_CONNECTIONS,
.bluetooth.heap=bluetooth_stack_heap,
.bluetooth.heap_size=sizeof(bluetooth_stack_heap),
.gattdb=&bg_gattdb_data,
.ota.flags=0,
.ota.device_name_len=3,
.ota.device_name_ptr="OTA",
#ifdef FEATURE_PTI_SUPPORT
.pti = &ptiInit,
#endif
.usarts[1]= {
.flags=USART_FLAGS_ENABLED|USART_FLAGS_BGAPI|USART_FLAGS_NO_HW_INIT,
},
.sleep.flags = SLEEP_FLAGS_ENABLE_WAKEUP_PIN | SLEEP_FLAGS_ACTIVE_HIGH | SLEEP_FLAGS_DEEP_SLEEP_ENABLE,
.sleep.port = 5, // port F
.sleep.pin = 6,
.gpio_exti.EXTIPSELL=0x05000000, // EXTIPSEL6 = 5 = port F
.gpio_exti.EXTIPSELH=0,
.gpio_exti.EXTIRISE=0x40,
.gpio_exti.EXTIFALL=0x40,
.gpio_exti.IEN=0x40,
};
/* configure wakeup pin (PF6) */
GPIO_PinModeSet(gpioPortF, 6, gpioModeInput, 0);

 

Temporary disabling of EM2 Deep Sleep can be useful for example when USART is used for a limited time. Deep Sleep has to be disabled in order to get the USART controller work and be able 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 some tenth of microamperes compared to EM2 Deep Sleep mode. See EFR32BG1 Blue Gecko Bluetooth Smart SoC Family Data Sheet.

 

Putting Device into EM4 Hibernate / EM4 Shutoff Mode

 

If the application does not need any 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 some hundred nanoamperes. However, to wake up the device from this state a reset is needed. That is no data is retained from the previous state, and the stack is reinitialized!

There are 2 types of EM4 mode: EM4 Hibernate and EM4 Shutoff. 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 description 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);

 

Wake up from EM4 Hibernate / EM4 Shutoff mode

 

The device can wake up from EM4 mode on

  • 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. E.g. if you want to wake up the device 4 seconds after putting 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 (do not forget to set int_EM4.retainLfxo = 1). LFXO has a 32kHz clock, consequently 128k period will result in overflow in 4 seconds. Do not forget 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

 

Implement the following project so that it requires as little energy as possible:

  1. After resetting the device a number has to be read in from UART between 0 and 9. Let it be n.
  2. If n=0, the device can go to sleep, and needs to wake up only on reset. Go to step 1.
  3. If n>0, an iBeacon type advertisement has to be broadcasted for n seconds.
  4. When ready, the device can go sleep, but when a new character – any character – is received on UART, it has to wake up, and read in a number (n) again. Go to 2.

First let us consider the required energy modes.

  1. In the first step UART controller has to work continuously. This means that at least EM1 Sleep mode is needed.
  2. If n=0, the device can go sleep. Since there is no operation needed, and a reset will wake up the device, the device can be put into EM4 Shutoff
  3. If n>0, the device starts broadcasting. However, there is no operation needed between sending two packets, only RTCC has to run, which ensures wake-up in time, and is counting the elapsed time since start. RTCC needs EM2 Deep Sleep, hence the device can be put into EM2 Deep Sleep mode between two packets.
  4. When all packets is sent out, there is no need for stack operation and the device can be put into EM3 Stop If an interrupt is set for the transition of the Rx pin, the device can be woken up with any incoming UART signal, and the next received character can be read in.

Find attached the project that implements this functionality using the functions discussed in this article. If you profile the project with Energy Profiler, you should observe the following:

2017-01-20_15h15_48.png

 

 

Comments
by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-05-2017 10:48 AM

Does anything need to be done diffently to configure a wakeup pin in a C project using SDK 2.3.1? 

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac
on ‎05-08-2017 04:28 AM

 

No, it should be the same. Can you get it work with an earlier version and you cannot with 2.3.1?

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-08-2017 11:24 AM

 I have not tried with an earlier SDK.

 

There is a discrepancy between this arcticle and AN1042.  AN1042 says that the call below is needed.  Is this true?

/* configure wakeup pin (PF6) */
GPIO_PinModeSet(gpioPortF, 6, gpioModeInput, 0);

 

Also, I'm working with the WSTK. As I understand it, after configuring the wakeup pin as shown in this article, pressing and releasing PB0 should trigger gecko_evt_system_awake.  Is this understanding correct?

 

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac
on ‎05-09-2017 04:16 AM

 

I see your problem. Indeed, wake up pin has to be configured as input (GPIO_PinModeSet(gpioPortF, 6, gpioModeInput, 0)). This article dealt only with the stack configuration and not with pin modes. But I can add it.

 

Yes, pressing and releasing PB0 will trigger a gecko_evt_system_awake event.

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> alexandros300
on ‎05-12-2017 12:12 PM

So I am using this to develop a simple low energy alternating advertisement, where it advertises, then enters sleep, and wakes up again (EM0 to EM2). I am trying to attempt this using a soft timer; I have used SLEEP_SleepBlockEnd(sleepEM2), and explicity called SLEEP_Sleep() to make sure it enters sleep state when hitting that part of the state. I check that the returned state is EM2 (as it is enabled in the config), and it shows it is. My energy usage is still around 3mA rather than uA when in that mode. Are there any other aspects of configuration that could be affecting this? (note I am newer to this type of development). I am using a 250 ms on/off interval and a BGM121 with the WSTK dev kit

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac
on ‎05-15-2017 06:00 AM

 

Hi,

Do you want to wake up the device only while it sends out advertisement or for a longer period?

In the former case you can simply allow deep sleep mode (see Enabling EM2 Deep Sleep in the Stack), and it will automatically switch between EM0 and EM2. It puts the device in EM2 and wake up only for the time while it sends out advertisement.

In the latter case you should also enable deep sleep mode in the config first. Then you can temporarily disable EM2. But it does not work in the other way: disabling deep sleep by default, then enabling EM2 temporarily is not the right way to do.

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> elafargue
on ‎08-31-2017 05:47 PM

I am trying to use this example on a BGM111 in C mode, but starting with the empty_soc project, a lot of the configuration fields are missing in 

the gecko_configuration_t struct - I am probably missing something obvious ?

 

Question: how can I configure a wake-up pin as described in this article with the C SDK on the BGM111 ?

 

Thanks!

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> elafargue
on ‎08-31-2017 06:49 PM
Following up on my previous post: it looks like this example only work on SDK 2.3, not 2.4 . Is there a way to enable wake up pins on 2.4 like on 2.3 ?
by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac
on ‎09-01-2017 03:58 AM

Hi, you are right this was written for v2.3.x

 

To migrate it to 2.4.x you can use these instructions: http://community.silabs.com/t5/Bluetooth-Wi-Fi-Knowledge-Base/Migrating-Simplicity-Studio-projects-f...

 

The wake-up pin configuration also changed. It's not configurable any more via the gecko configuration structure. You have to define an external interrupt on the wake up pin, and use SLEEP_SleepBlockBegin(sleepEM2) and SLEEP_SleepBlockEnd(sleepEM2) to wake up the device.

Take a look at the "NCP target - Empty" example of SDK v2.4.x where this is implemented.

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> elafargue
on ‎09-01-2017 09:38 AM

Thank you @arkalvac, this is the info I needed!