# Tickless Idle on STM32L4 Nucleo and low power modes question

**URL:** <https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489>\
**Category:** Kernel\
**Created:** [May 3, 2021, 2:41am UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489 "2021-05-03T02:41:29Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Fahrenkrog](https://avatars.discourse-cdn.com/v4/letter/f/f0a364/32.png) [@Fahrenkrog](https://forums.freertos.org/u/Fahrenkrog)\
**Post date:** [May 3, 2021, 2:41am UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/1 "2021-05-03T02:41:29Z")

</div>

Hi all,  
I’ve been actively using FreeRTOS for the last few months in various projects, and we’re very happy with the results.

At the moment I’m working on an STM32L4 nucleo board, and I have a few questions regarding low power modes and FreeRTOS. Some questions may actually be STM32 related, but I’ll take my chances here anyway!

I’ve set configUSE\_TICKLESS\_IDLE to 1 in this project. My understanding is the scheduler will try to go to sleep whenever the expected idle time is more than configEXPECTED\_IDLE\_TIME\_BEFORE\_SLEEP (2). Now, the application works as follows:

- There is one task that calls vTaskDelay(250), which is an LED toggle.
- All other tasks start either with xStreamBufferReceive(…) or ulTaskNotifyTake(…) in different shapes and sizes as they are all interrupt based (USB comms, UART, etc).

Can I expect FreeRTOS to actually enter:

```
traceLOW_POWER_IDLE_BEGIN();
portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
traceLOW_POWER_IDLE_END();

```

?

Here’s another question on the same system. I’d like to put the system on sleep for an indefinite amount of time, and be woken up either by push button (GPIO) interrupt or the RTC alarm. When the system wakes up, it would call a system reset, it doesn’t really care for how long it was asleep.

There is a system task which wakes up with xTaskNotifyWait(…), within that task, the system gets deinitialised like this:

```
vTaskSuspendAll();
vPortRaiseBASEPRI();

HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFE); ///< Enters sleep mode here
HAL_NVIC_SystemReset();

```

That puts the system to sleep until the button is pushed and it restarts. RTC values are kept. So far so good.

If I change the stop mode entry to \_WFI and enable the GPIO pin as interrupt instead of event:  
vTaskSuspendAll();  
vPortRaiseBASEPRI();  
HAL\_PWREx\_EnterSTOP2Mode(PWR\_STOPENTRY\_WFI); ///\< Enters sleep mode here  
HAL\_NVIC\_SystemReset();

The system goes to sleep but fails to wake up when I push the button!

Below, I remove vPortRaiseBASEPRI():

```
vTaskSuspendAll();
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); ///< Enters sleep mode here
HAL_NVIC_SystemReset();

```

And the system jumps from the enter power mode to reset, starting again.

The GPIO button interrupt is set to 7. if I add this line:

```
vTaskSuspendAll();
vPortSetBASEPRI(7);
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); ///< Enters sleep mode here
HAL_NVIC_SystemReset();

```

Same as before, the system goes directly to reset. Same thing if I add  
HAL\_SuspendTick();  
after suspending the tasks.

My guess is there is an interrupt running configured by FreeRTOS which wakes the system up immediately after going to sleep in stop mode.

How would I go deactivating only those interrupts used by FreeRTOS and not the ones I need, the GPIO interrupt and the RTC interrupt?

Alternatively, I could disable all interrupts and just wake up on events, but for the sake of understanding, I’d like to get both methods to work.

Many thanks in advance!

Cheers,

Alberto

---

<div class="post-metadata">

**Author:** ![jefftenney](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/jefftenney/32/1314_2.png) [@jefftenney](https://forums.freertos.org/u/jefftenney)\
**Post date:** [May 3, 2021, 3:36am UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/2 "2021-05-03T03:36:03Z")

</div>

Hi Alberto,

> [@Fahrenkrog](#):
>
> Can I expect FreeRTOS to actually enter: …

Yes.

> [@Fahrenkrog](#):
>
> The system goes to sleep but fails to wake up when I push the button!

On CM4, interrupts masked with BASEPRI cannot wake the CPU from WFI sleep. But the corresponding event can still wake the system from WFE sleep.

> [@Fahrenkrog](#):
>
> I’d like to put the system on sleep for an indefinite amount of time, and be woken up either by push button (GPIO) interrupt or the RTC alarm.

Since you’re already using tickless idle, you could implement `configPRE_SLEEP_PROCESSING()` and use it to induce STOP2. When that macro executes, FreeRTOS has already temporarily suspended its tick interrupt (not to be confused with the HAL tick). You’ll want `configPRE_SLEEP_PROCESSING()` to induce STOP2 conditionally, only when application conditions require STOP2 instead of normal tickless idle. Using that macro, you’ll be able to implement with WFI or WFE just as you said. Also, as you said, it’s good to watch out for the HAL tick as it will also wake you unnecessarily from tickless idle. You can stop the HAL tick, or you can override the HAL tick functions to use the FreeRTOS tick (a little more advanced).

---

<div class="post-metadata">

**Author:** ![Fahrenkrog](https://avatars.discourse-cdn.com/v4/letter/f/f0a364/32.png) [@Fahrenkrog](https://forums.freertos.org/u/Fahrenkrog)\
**Post date:** [May 6, 2021, 11:09pm UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/3 "2021-05-06T23:09:50Z")

</div>

Hi Jeff,

Thanks for your reply, I will give the config\_PRE\_SLEEP\_PROCESSING() macro a try.

> [@jefftenney](#):
>
> On CM4, interrupts masked with BASEPRI cannot wake the CPU from WFI sleep. But the corresponding event can still wake the system from WFE sleep.

I found the information to this a bit confusing, so, does

```auto
vPortSetBASEPRI(7)

```

effectively “disable” the higher priority (lower number) interrupts (0 to 7)? In that case, wouldn’t a prio-8 interrupt get through? Or is it the other way around.

Cheers,

Alberto

---

<div class="post-metadata">

**Author:** ![richard-damon](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/richard-damon/32/38_2.png) [@richard-damon](https://forums.freertos.org/u/richard-damon)\
**Post date:** [May 7, 2021, 12:52am UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/4 "2021-05-07T00:52:27Z")

</div>

Just the opposite. vPortSetBASEPRI(7) disables priority numbers 7 and higher, leaving priority 0-6 (the higher priorities) enabled.

It acts like you are currently in a priority 7 interrupt.

---

<div class="post-metadata">

**Author:** ![jefftenney](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/jefftenney/32/1314_2.png) [@jefftenney](https://forums.freertos.org/u/jefftenney)\
**Post date:** [May 7, 2021, 3:00am UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/5 "2021-05-07T03:00:30Z")

</div>

It’s just as Richard says above.

> [@Fahrenkrog](#):
>
> I found the information [on BASEPRI] a bit confusing

That’s for sure. ARM really did a number on Cortex M interrupt priorities, and NVIC settings too. It’s very easy to get confused. But I think FreeRTOS does a nice job of abstracting it for application developers and of catching related configuration errors.

---

<div class="post-metadata">

**Author:** ![richard-damon](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/richard-damon/32/38_2.png) [@richard-damon](https://forums.freertos.org/u/richard-damon)\
**Post date:** [May 7, 2021, 3:06pm UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/6 "2021-05-07T15:06:10Z")

</div>

Low numbers being High Priority isn’t really that strange. After all, don’t you do your #1 priority thing before working on #10? It is more of a language issue.

The fact that the priority number is a variable number of bits (depending on the exact machine) makes some sense as a generic core, as most machines DON’T need 256 interrupt priority levels, and saving hardware costs by reducing bits makes sense. Putting them in the Upper bits also make sense, it says a priority register value of 255 is always the lowest, 128 is the middle and 1 is the highest, thus configurations that don’t require exact knowledge are portable. The system intentionally allows lower bits to be written to even if they don’t read back.

---

<div class="post-metadata">

**Author:** ![jefftenney](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/jefftenney/32/1314_2.png) [@jefftenney](https://forums.freertos.org/u/jefftenney)\
**Post date:** [May 7, 2021, 4:10pm UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/7 "2021-05-07T16:10:50Z")

</div>

> [@Fahrenkrog](#):
>
> `vPortSetBASEPRI(7)`

Should be

`vPortSetBASEPRI( 7 << (8 - configPRIO_BITS) );`

if you want leave priorities 0 through 6 unmasked.

---

<div class="post-metadata">

**Author:** ![Fahrenkrog](https://avatars.discourse-cdn.com/v4/letter/f/f0a364/32.png) [@Fahrenkrog](https://forums.freertos.org/u/Fahrenkrog)\
**Post date:** [May 9, 2021, 11:33pm UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/8 "2021-05-09T23:33:09Z")

</div>

So, for my understanding, does that mean that

```auto
vPortSetBASEPRI(7);

```

leaves interrupts 0-6 enabled, and

```auto
vPortSetBASEPRI(7 << (8 - configPRIO_BITS))

```

disabled?

When you say “0 to 6 unmasked” that means to me that interrupts 0-6 are active. I mean, that’s what it sounds like to me (as in non-maskable interrupt).

Cheers,

Alberto

---

<div class="post-metadata">

**Author:** ![richard-damon](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/richard-damon/32/38_2.png) [@richard-damon](https://forums.freertos.org/u/richard-damon)\
**Post date:** [May 10, 2021, 12:18am UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/9 "2021-05-10T00:18:37Z")

</div>

First, I needed to double check which numbering vPortSetBASEPRI uses, and it wants the upshifted version of the priority, so for the typical machine with configPRIO\_BITS of 4, calling it with a value of 6 is the same as calling it with a value of 0, as only the upper 4 bits are used.

When using a configPRIO\_BITS value for the priority, you need to shift it with a call like vPortSetBASEPRI(n \<\< (8-configPRIO\_BITS))

When you do that, it sets the ‘current’ interrupt priority that that value, and interrupts with that value or larger (higher number, lower priority) will be blocked. Interrupts with smaller values (lower number, higher priority) will still be able to interrupt the system.

---

<div class="post-metadata">

**Author:** ![jefftenney](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/jefftenney/32/1314_2.png) [@jefftenney](https://forums.freertos.org/u/jefftenney)\
**Post date:** [May 10, 2021, 4:56am UTC](https://forums.freertos.org/t/tickless-idle-on-stm32l4-nucleo-and-low-power-modes-question/12489/10 "2021-05-10T04:56:11Z")

</div>

Just adding to what Richard said –

```auto
     BASEPRI in STM32L4 (4 priority bits):

+---+--...--+---+---+---+---+---+---+---+---+---+
| X | ... | X | P | P | P | P | X | X | X | X |
+---+--...--+---+---+---+---+---+---+---+---+---+
 31 8 7 6 5 4 3 2 1 0

```

Field [P] can hold a number from 0 through 15.

To set [P] = 7, the CPU must write BASEPRI = (7 \<\< 4). With [P] = 7, all interrupts at priorities 7 through 15 are masked. (And they cannot wake the MCU from WFI sleep.)

If the CPU writes BASEPRI = 7, [P] ends up set to 0. Note that [P] = 0 is a special case. It does _not_ mask all interrupts at priorities 0 through 15. Instead, it masks no interrupts at all. This special case is needed because all other values of [P] mask at least some interrupts, and we need some way not to mask any interrupts. So zero does that for us.
