The purpose of this trivial sample is to better understand how to write power efficient code in Toit. Warning, as is, it is not power efficient.

For a device to be able to operate without a battery change for a year, requires careful consideration of the power consumption of sensors, peripherals, power supply, processor and radio used. Modern processors, with a multitude of subsystems, have various sleep states with some combination of features and power. The ESP32 has 4 sleep modes and leverages an ultra-low-power coprocessor (ULP), that "remains powered on during the Deep-sleep mode of the main SoC. Hence, the developer can store in the RTC memory a program for the ULP coprocessor to access peripheral devices, internal sensors and RTC registers during deep sleep. This is useful for designing applications where the CPU needs to be woken up by an external event, or timer, or a combination of these, while maintaining minimal power consumption."

In Toit, the VM orchestrates the running of tasks (fibers in other languages). Features are provided in the standard library, which may be applicable to writing power efficient code.

This sample reads a switch, that a user could press. How might you do this?

  • sit in a loop, testing pin.get … great on latency, awful otherwise
  • sit in a loop, testing and sleep --ms= … can you accept the input latency introduced by the sleep interval? (the less you wakeup the processor, the more power you save)
  • sit in a loop, blocked on pin.wait_for … looks good! (The developer communicates their intent to the VM, that you can yield/sleep here, so long as you wake when something happens)

In the sample code, once the task wakes, it then ‘debounces’ the switch action (see the references in the code README if not familiar with switch bounce) and generates an event. In a more complex application, upon waking, some more extensive computation or measurement might be run, before again sleeping.

A prototype was wired as:

schematic

and is pictured below:

breadboard

Without user interaction, the only power drawn is by the ESP32 module. In the code, there is no communication to the cloud or console and the Max offline: 5m was used, so that the device was only checking in infrequently. The firmware was v1.2.0-pre.158+df5fbcda7. A Nordic Semiconductor Power Profiler Kit II (PPK II) was used in Source meter mode, to monitor power consumption.

Even without owning a PPK II, it is possible to inspect the results of this experiment. Download the application nRF Connect for Desktop, install the Power Profiler feature and when the Power Profile opens, select the Load button to load the data collected

The power consumption is worse than expected, sitting around 55mA. In a previous post the data acquisition application was run periodically, as defined in the main.yaml file. Between executions, current dropped to 6.3mA. In this sample where user interaction is required, the application is launched at boot in the main.yaml, and relies upon the implementation of pin.wait_for to conserve power.

screenshot

(Note in the trace, at the 0:17, 1:09 and 2:35 mark, you can see “bumps” in the current floor, as the button was pressed 3 times and the LED lit, at just less than 2mA)

This post is a starting point to understand power consumption in an interactive application and usage of pin.wait_for.
(All errors in coding are mine and not derived from a Toit tutorial).