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