propose a Low Power Modes API that is intuitive, hardware/device agnostic as possible, camelCase and easy to remember.
This issue is related to these issues pertaining to different low power modes:
| API | What it does |
| :-- | :-- |
| WiFi.enableEco() | Turns Eco mode on with a 500ms[1] throughput delay by default |
| WiFi.enableEco(10) | Turns Eco mode on with a throughput delay of 10 milliseconds (drops to low power mode 10 milliseconds after TX/RX), pass a 0 for no throughput delay. |
| WiFi.disableEco() | Turns Eco mode off, resets any currently set throughput delay |
| WiFi.ecoEnabled() | Return if Eco mode is on, off or on with throughput delay |
| Cellular.enableEco() | Turns Eco mode on |
| Cellular.disableEco() | Turns Eco mode off |
| Cellular.ecoEnabled() | Return if Eco mode is enabled |
| System.enableEco() | Put system in Eco mode, until System.disableEco() is called. |
| System.enableEco(60) | Put system in Eco mode for 60 seconds or until System.disableEco() is called, code can still execute, limited peripherals |
| System.disableEco() | Put system back in full power operation mode |
| System.ecoEnabled() | Return if Eco mode is enabled |
| Future API | What it does |
| :-- | :-- |
| System.setSpeed(clockSpeed) | Sets the system clockSpeed, e.g. CLOCK_SPEED_120MHZ |
| System.enablePeripheral(systemPeripheral) | Enable the systemPeripheral, e.g. PERIPHERAL_SPI. Only takes effect if System.ecoEnabled() is true |
| System.disablePeripheral(systemPeripheral) | Disable the systemPeripheral, e.g. PERIPHERAL_SPI. Only takes effect if System.ecoEnabled() is true |
| System.setConfig(SystemConfig& profile) | Change the default configuration used in System.enableEco() to enable/disable other |
| System.getConfig(SystemConfig& profile) | Retreive the currently set system configuration |
[1] 500ms subject to change. This will be based on typical roundtrip TCP message times with an additional factor of padding to ensure maximum throughput speed by default.
There is no Network.enableEco() proposed because the operation of each Eco mode for each device type may behave a bit differently as follows:
Behind the scenes, WiFi Eco mode has a unique concept of an optional throughput delay which keeps the system in high speed operation after the transmission is complete, for the duration of the delay. This is useful if responses are expected and full performance is desired. After delay, the WiFi will be set back in Eco mode automatically. There is a minimum delay associated with exiting Eco mode automatically when transmissions begin again, but it's negligible as it's less than 1ms (_double check this value_).
Behind the scenes, Cellular Eco mode (enabled) will automatically enter and exit a low power state when the modem is used for communication using UPSV=3. A 20ms delay is automatically applied before each new AT command sent to the modem when Eco mode is enabled. This delay is required to allow the modem to transition from idle mode to active mode. After the command is processed the modem will automatically re-enter idle mode. This will slow down the operation of the modem a bit during all system commands as well (about _add percentage here_), with the benefit of improved power efficiency.
Cellular Eco mode (disabled) will stop forcing the modem into idle mode after the current AT command is processed. It will also remove the 20ms delay imposed on the system to resume from idle to active mode. When Eco mode is disabled, the electron will still be able to enter a low power state automatically after approx 10 seconds of being idle. Asynchronously received data can still cause the modem to enter active mode again. This is the current operation of the system.
Behind the scenes, System Eco mode drops the STM32 processor clock speed to _XX_ MHz and disables all peripherals except (_name the peripherals required for simple timing and GPIO_). Code continues to execute in this mode at a slower pace based on the system clock speed. Some commands are not functional when the clock speed is this low (_provide a table of available commands_).
Completeness:
For System.setSpeed() how about making it a fuller description, System.setClockSpeed() since we also have clock speed on other APIs, e.g. SPI.
What's the difference between System.disableEco() and System.run()?
In the future API for system config, it might be useful to return the configs that correspond to Eco mode and regular mode, so that the developer can use these as a starting point and then tweak.
Oops that System.run() was a straggler from before this was unified with Eco ... I replaced it will System.disableEco().
I specifically decided on System.setSpeed() over System.setClockSpeed() for the fact that it is the same as an existing API Wire.setSpeed(). That way when you are are trying to configure the clock speed of either System or Wire it is the same. However I just noticed we also have SPI.setClockSpeed() which throws a wrench into things. I would vote to make them all the same so our brains have less nuances to store :)
I'd prefer .setSpeed() as it is shorter, i.e. more succinct. However SPI has other .setClockDivider() and .setClockDividerReference() which seems like we'd be making that API weird if we made them .setDivider() and .setDividerReference(). Also Arduino has SPI.setClockDivider() so it appears that we should make them all .setClockSpeed() despite the longer name.
Wire.setSpeed() as Wire.setClockSpeed() if you agree that we should unite them. We can depreciate the Wire.setSpeed() with a warning explaining to use Wire.setClockSpeed() for the future. Just check this box :)I was thinking System.getConfig(SystemConfig& profile) would return the default Eco profile by reference assuming you haven't used .setConfig() already to change it. But it would be weird to have to use .setConfig() to reset the profile back to the default of Eco just to get the profile. Since we will have to have a profile for default Eco anyway to be able to reset things (either on fresh boot or by user demand), maybe it would be appropriate to just define one as static const struct SystemConfig SYSTEM_CONFIG_DEFAULT = { clockSpeed, peripheralList }; and then users could just do this to use the default profile System.setConfig(SYSTEM_CONFIG_DEFAULT);
It might also be worth discussing if the profile is persistent in flash memory or not. Because I could see this mode being toggled very quickly and often, I think it should stay in RAM instead of FLASH memory so there's no concern of flash wear. And should that be backup system RAM or normal user RAM? If not in backup RAM it would require user code to always set the profile on boot, but that could be a good thing as well because then any reset (power loss, software, hardware, OTA update, USB descriptor, etc..) would put the system back in a known state. Also for Safe Mode this would be important to be in a full power state to connect back to the Cloud.
I'm not sure we need to be ruthlessly consistent about this. But if we do, my take is to only deprecate Wire.setSpeed() if it's also deprecated in the Arduino SDK since that's our baseline.
The system config has the potential to cover different types of config that have different persistence needs. We already have System.set()/System.get() for feature flags - should these be rolled into the config API too? I believe we should, and then there are cases where some settings are persisted to flash, others to backup RAM while others are only stored in RAM. This is why I feel system config should be nothing more than a data-driven way to call all our other APIs, so that each API can document it's persistence characteristics, and what it does. To put another way, I feel there should be no setting in the system config that you cannot also set via some other API System.setXXXX(), and the API is the source of truth, behavior and documentation for that setting.
The preset configurations for run/eco etc.. are best fetched via an API rather than as a static data. This is because they come from the system. Also an API gives is more flexibility and implementation choices. We can get this simply by adding an optional parameter to System.getConfig();
SystemConfig config;
System.getConfig(config); // retrieve the current config
System.getConfig(config, ECO); // retrieve the ECO config
System.getConfig(config, DEFAULT); // power on config
The Wire library for Arduino doesn't have a speed configuration. It must be 100kHz and that's all, so I think we can unite our API without any repercussions from the Arduino base. We still may deviate over time if Arduino adds new APIs for models with more functionality.
Good points about System.setConfig(). Here's a summary:
I think we may only chose to include APIs in System.setConfig() that build what we deem as a System profile (related to system features, settings and peripherals) so that it doesn't get unwieldy to support.
FYI I use the following to set the CPU speed:
void setCPUspeed(unsigned short speed) {
if (speed == 30) {
// CPU @ 30MHz (saves ~19mA @ 5v)
RCC_PCLK1Config(RCC_HCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_HCLKConfig(RCC_SYSCLK_Div4);
} else if (speed == 60) {
// CPU @ 60MHz (saves ~13mA @ 5v)
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_HCLKConfig(RCC_SYSCLK_Div2);
} else {
// Default to 120MHz
RCC_PCLK1Config(RCC_HCLK_Div4);
RCC_PCLK2Config(RCC_HCLK_Div2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
}
SystemCoreClockUpdate();
SysTick_Configuration();
}
Everything seem to work 100% and I've been running projects at 30MHz without any issues.
Most helpful comment
FYI I use the following to set the CPU speed:
Everything seem to work 100% and I've been running projects at 30MHz without any issues.