Low Power Modes with embOS-Ultra

From SEGGER Wiki
Jump to: navigation, search

This wiki article describes and shows an example on how to use low power modes with embOS-Ultra.

Requirements

This wiki article requires basic understanding of how embOS-Ultra works. If you are not familiar with embOS-Ultra, please have a look into the generic embOS-Ultra manual.

Introduction

In contrast to embOS' support for the Tickless Mode, embOS-Ultra is by default running without a periodic system tick. The system tick is automatically configured to occur when a timeout of a task or software timer expires. If there is no timeout, the timer is configured to generate a system tick after the maximal period of the timer.

The best case situation is an application that runs into OS_Idle(), enters a low power mode and returns from the low power mode when the next system tick occurs. However, many clocks and peripherals are not powered during low power modes and it might be that the used hardware counter and timer stop working when a low power mode is entered. In this case, different hardware counter and timer must be used which continue counting during low power modes. In this case, a hardware counter and timer must be chosen which can be used while the processor is in a low power mode.

Example

Download

Example project: STM32L073_STM32L073Z_Eval_embOS_Ultra_LowPowerExample.zip

Configuration and used timers

The example is written for the STM32L073Z-EVAL. All required changes for using a low power mode with embOS-Ultra were applied to RTOSInit_STM32L0xx.c.

The RTOSInit_STM32L0xx.c contains two macros, USE_LOW_POWER_TIMER and ENTER_LOW_POWER_MODE, which can be used to select the used timers and whether the application shall enter the processor's stop mode. If USE_LOW_POWER_TIMER is set to 0, the application uses TIM3 as the continuous timer and the Cortex-M SysTick for generating interrupts. If USE_LOW_POWER_TIMER is set to 1, the application uses the low power timer LPTIM1 as the continuous timer as well as for generating interrupts. If ENTER_LOW_POWER_MODE is set to 1, the processor's stop mode is entered in OS_Idle(), which is the second deepest low power mode of the STM32L073.

Any combination of these macros can be used together. However, if USE_LOW_POWER_TIMER is set to 0 and ENTER_LOW_POWER_MODE is set to 1, the application will not work properly, since the clocks used by TIM3 and SysTick are not powered during stop mode. LPTIM1, on the other hand, uses the LSI low power clock which stays powered during the used stop mode. The disadvantage of using the LPTIM1 with the LSI is that it has a lower resolution than the SysTick and TIM3, because the LSI runs with only 37 kHz. Also, with 37 kHz the maximum time that can be spent in the stop mode is ~1.7 seconds. Decreasing the LPTIM1 clock by using a prescaler increases the time that can be spent in stop mode without interruption, but also decreases the resolution. If the application returns after ~1.7 seconds from the stop mode and there is no task or software timer ready for execution, the scheduler updates the current time before the counter overflows and calls OS_Idle() again where the application will enter the stop mode again.

Entering low power mode

When there is no task ready for execution, embOS-Ultra calls the function OS_Idle(). Within OS_Idle() a low power mode can be entered until the next interrupt occurs. Since entering and leaving the stop mode takes some time, OS_Idle() checks how many cycles are left until the next timer interrupt occurs. Since the stop mode only works with the low power timer LPTIM1, this step is done only when LPTIM1 is used. If the next timer interrupts occurs in less than 1ms, the low power mode is not entered. This step is optional and depends on the requirements of the application.

Next, we disable all interrupts and enter the processor's stop mode by calling HAL_PWR_EnterSTOPMode(). As soon as an interrupt occurs an event is generated which wakes the processor up. Since interrupts are still disabled, the processor continues execution in OS_Idle() where the processor clock is set to 32 MHz again. After configuring the clocks, interrupts are enabled again and the interrupt that woke up the processor is executed.

 1 void OS_Idle(void) {  // Idle loop: No task is ready to execute
 2   while (1) {
 3 #if (ENTER_LOW_POWER_MODE == 1)
 4     //
 5     // Enter low power mode.
 6     // Disable interrupts, so that the application continues execution in
 7     // OS_Idle() after the processor woke up due to an interrupt event in
 8     // order to configure the processor clock to 32 MHz again.
 9     //
10 #if (USE_LOW_POWER_TIMER == 1)
11     OS_U16 CyclesLeft;
12 
13     //
14     // Enter low power mode only if at least 1ms is spent in OS_Idle().
15     //
16     CyclesLeft = (OS_U16)(LPTIM1->CMP - LPTIM1->CNT);
17     if (CyclesLeft >= (LPTIM_CLOCK_FREQUENCY / 1000))
18 #endif
19     {
20       OS_INT_DisableAll();
21       HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
22       SetSysClock();
23       OS_INT_EnableAll();
24     }
25 #endif
26   }
27 }