Energy Management in Riot

Hello,

I am currently writing my thesis for my university degree. The topic is the comparison of different Low-End-IoT-Operating Systems and one of those is RIOT. One of the categories I chose to compare the different OS´s is Energy Management/Consumption. I wanted to ask if there`s a specific place in the documention where I can see how Energy Mangement is implemented by RIOT or if someone would be so kind to help me with this topic.

Greetings, Steven

Hi Steven and welcome to the community!

Power management in RIOT is done implicitly. That is, when no thread is runnable, the system will go to the lowest possible power state, however, only power saving modes that keep the RAM contents are considered.

If the application uses a peripheral, e.g. a timer running on the high frequency domain, the timer driver will block (bock = increases the reference count) of power modes that would turn off that frequency domain. The advantage is that this effectively disarms any footgun that would otherwise be there when accidentally disabling clock domains etc. that are still in use. The downside is that it may not be obvious why an app is using more power than one was hoping for. We do have some utilities for that, though, e.g. the pm command can show the current blockers (e.g. recounts).

The best practice to power saving is:

  • try to avoid using stdio over UART / USB. If this is not possible an periph_lpuart instance would be much better than an periph_uart instance. (They use the same API and looking into the doc or config would be required to check which UART_DEV() identifies the low power one.)
  • try to avoid keeping periph_timer instances active, but only use them briefly for whatever the app needs them and quickly power them down again
  • same for periph_pwm or basically any other peripheral
  • Use ztimer_msec for long running timeouts. The low frequency clock has a lot less clock drift and will be more accurate anyway, despite having a lower resolution
  • If you use ztimer_usec at all, use ztimer_ondemand to disable the underlying periph_timer when no timeout is set on ZTIMER_USEC
  • confirm that the power modes available to the app match what you expect. If not, trace down which module is using a peripheral that blocks power modes.

Finally: There also is the option of explicit power management by setting an RTC timeout and manually entering the lowest possible power mode. This allows to also make use of power modes that will not preserve RAM. When the RTC fires, RIOT will practice do a warm boot. You will have to use RTC memory, EEPROM, or backup RAM to safe data between wake up phases. This is more effort, but can yield the highest power savings. E.g. @benpicco did use this in one ultra low power app, if I recall correctly.

I hope I could help you. Feel invited to ask further questions, if something is still unclear or you have trouble to achieve the low power consumption you expected :slight_smile:

1 Like

Sorry, typing from my smartphone and hit the send button too early. I’ll finish the reply now.

Update: The reply above is now complete

1 Like

Hello Maribu,

thank you very much for your fast and detailed answer! This helps me out a lot! You might be able to help me even more, since I am currently looking into the security features that are implemented in RIOT. I know that multiple features are already implemented and supported like DTLS, but I haven´t found the information in the official RIOT documentation. Is there a list or anything like that where I can find all the security features?

Greetings, Steven

Hope I understood your question correctly. Do you mean something like this? https://doc.riot-os.org/group__net__sock__dtls.html

When it comes to security there are so many moving parts. What are you specifically looking for? Maybe describing the use-case helps as well. So we can point you in the right direction :slight_smile:

1 Like

I assume you are interested in a list of security features for some comparison between different OSes?

Security relevant features provided include:

  • availability of cryptographic building blocks using both software and hardware implementations. Check PSA for how to use hardware security features such ciphers and crytographic hashes implemented in hardware
  • a level higher e.g. libcose that provides an easy to use, space efficient and CPU efficient format for secure data exchange. (Think of COSE as JOSE, but CBOR used instead of JSON for efficiency reasons.)
  • A SUIT implementation to allow secure over-the-air updates following an open standard
  • An entropy source API (that is still a bit WIP) that can used to obtain the entropy needed to securely generate key material. In addition there also is PUF SRAM that can obtain entropy once at start-up from a cold boot and a common API to access hardware random number generators available on some MCUs
  • various dynamic runtimes such as micropython, a JavaScript Interpreter, a Web Assembly VM, and others. Those can be used to run code sandboxed despite the MCU not having any MPU/MMU
  • the ability to prevent code execution from RAM when an MPU or an PMP is available, which can thwart a number of remote code execution attacks
  • the ability to detect stack overflows using the MPU that can increase the effort needed for certain attacks
  • the ability to use Rust in RIOT for writing drivers and apps in a memory-safe language
  • DTLS as already pointed out
  • layer 2 security (think: WPA) for IEEE 802.15.4 (which still is WIP, as key management is not addressed yet)
  • An EDHOC implementation for secure key exchange suitable for IoT

Those are the parts that come to my mind, but maybe I missed one. I guess we should have a security page in the doc that would link to the individual components and briefly explain when to use which component :sweat_smile:

1 Like

Sorry I still have to ask you a few more questions. If I understand it correctly, the pm_layered module does most of the work and decides, which power saving mode is the best for the current situation. But those power saving modes are dependent on the CPU right? So not every System will go into the same mode under the same circumstances, it all depends on what modes the CPU supports. Is there still a “list” which power modes RIOT can go to? And can I explicitly set the system into a specific mode, for example to deep sleep etc.?

The power management is implemented by periph_pm independently for each MCU family, as this is (as you correctly pointed out), highly MCU depended. The pm_layered module can be used to implement the logic to figure out what is the lowest possible power mode.

A periph_pm implementation may choose to not use pm_layered for power management. E.g. I opted against this for the MSP430. Even though the high level datasheet for the MSP430 provides a list of numbered power modes, the configuration registers actually just allow disabling clock domains individually.

The pm_layered module assumes that there are levels, of power saving. E.g. the most shallow would be the disabling of the CPU, but keeping all clock domains. The next would disable the CPU and high speed clock domain, the next would disable again CPU, high speed clock domain, and additionally the low speed clock domain. Some MCUs may add additional steps in between, e.g. if there are multiple high speed clock domains, or if e.g. an SRAM cache could be disabled or whatever. If the MCU follows this model, pm_layered is a useful tool to implement the decision logic which level can be picked.

For e.g. the MSP430 it was not the perfect fit, as the low speed clock can there be disabled when it has no users, even when the high speed clock domain is still active. I guess using pm_layered there wouldn’t be too bad, as the high speed clock domain consumes a lot more power than the low speed clock domain, so if the high speed clock domain is on anyway, keeping the low speed clock domain running (even if it would be possible to disable it) will a limited impact.

So: pm_layered is not doing most of the work, but rather a lightweight and elegant utility that periph_pm implementations can use (and should use, if applicable).

Exactly.

It is up to the MCU implementation to document the power modes it offers, as this list would differ between MCUs. But I don’t think there is much documentation for it, as we focus on documenting user facing APIs. And for power management one of the design goal was to not get in the way of the users; in fact, other than reboot or powering off users will not interact with the power management subsystem at all. You could ask for a specific MCU, e.g. @aabadie will know for STM32 and FE310, @benpicco or @dylad will know for SAM MCUs, I can tell you for MSP430. I suggest for your thesis to pick, let’s say 3, MCUs that are officially and maturely supported by the different operating systems you compare. That way you will be able to get a list of supported power modes.

There is no portable API to do that, but MCU implementation are free to add custom MCU-specific APIs. The reason is that code cannot be implemented portable anyway, as “deep sleep” may have completely different meanings for different MCUs. E.g. some may keep the RAM contents (and would be able to resume when waking up), others would keep a portion of the RAM (so that app developers could allocate data to retain between sleeps there and when RIOT is booting up from a such a deep sleep resume operation based on the retained data), others do not retain any data in RAM (but may have EEPROM or a few bytes of data that can be stored in the RTC, which is however not part of the address space).

This is also a bit complex, as app developers would need to exactly know what they are doing: E.g. going explicitly to deep sleep while an UART is waiting for input (e.g. the shell, but also drivers for e.g. GPS sensors, particulate matter sensors, the DFU MP3 player, etc.) the UART would likely just be disabled and no data would be received.

E.g. @benpicco did use this approach for one app, but he certainly belongs to the “knows what they are doing” group :slight_smile: