Deep sleep support for RP2 port
This entry in the documentation suggests that there is support for deep sleep in the current MicroPython release. However, as far as I can see there isn't? At least, there doesn't seem to be a machine.DEEPSLEEP_RESET present in the current build.
Looking at https://ghubcoder.github.io/posts/deep-sleeping-the-pico-micropython/ it looks like adding this capability to the rp2 port is fairly easy, and there is an out of date — and looks to be unmaintained — fork at https://github.com/ghubcoder/micropython-pico-deepsleep.
Any plans to add support for DEEP SLEEP to the RP2 machine class?
rp2,docs: Stop machine.idle() blocking indefinitely, update docs.
Summary
Updates rp2 port to always resume from idle within 1ms max.
When rp2 port went tickless the behaviour of machine.idle() changed as there is no longer a tick interrupt to wake it up every millisecond. On a quiet system without interrupts it can now block indefinitely. No other port does this.
A lot of existing code (i.e. micropython-lib lps22h, lcd160cr sensor drivers, lora sync_modem driver, usb-device-hid) calls machine.idle() inside a tight loop that is polling some condition. This reduces the power usage compared to constantly looping, but can be faster than calling a sleep function. However there's not always an interrupt before the condition they are polling for, so it's difficult to restructure this code if machine.idle() doesn't have any upper limit on execution time.
Also changes the machine module documentation to explain the new behaviour and recommended usage. I believe all ports will pause for at most 1ms now, and suggest this is good behaviour to stick with.
This fix depends on #15398 for correct behaviour, and that PR should be merged before this.
Testing
Tested on rp2 PICO and PICO_W:
- Added a unit test to verify the
machine.idle()wakeup time. This test fails on master (30ms average wakeup time on PICO-W, never completes on PICO). The test also fails in this branch without the linked PR (average wakeup time of 0.02ms). Passes after this branch is rebased with the WFE fix. - Ran
while True: machine.idle()and verified power consumption was approximately the same as tunningtime.sleep(10). This is also depends on the linked PR with the WFE fix.
Trade-offs and Alternatives
- Keeping the current behaviour of "machine.idle() blocks indefinitely on some ports" rules out a lot of use cases, and the power consumption is only very marginally less. Lightsleep is always going to be a better fit for long idle periods, and saves much more power.
- Could add an optional
machine.idle(sleep_ms=1)argument but it's hard to come up with a use case to justify the extra complexity. This isn't a sleep function so an interrupt can resume execution at any time, and looping with 1ms periods has basically the same power consumption as looping with 1000ms idle periods.
This work was funded through GitHub Sponsors.