-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
rp2,docs: Stop machine.idle() blocking indefinitely, update docs. #15345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rp2,docs: Stop machine.idle() blocking indefinitely, update docs. #15345
Conversation
Code size report:
|
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
5edcfaa
to
4bc14ee
Compare
3079deb
to
42d0b28
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #15345 +/- ##
=======================================
Coverage 98.43% 98.43%
=======================================
Files 161 161
Lines 21275 21275
=======================================
Hits 20942 20942
Misses 333 333 ☔ View full report in Codecov by Sentry. |
This PR is ready now but depends on #15398 for correct behaviour. |
42d0b28
to
657fd48
Compare
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 on a tickless port 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. This commit specifies an upper limit of 1ms before machine.idle() resumes execution. This is already the case for all ports except rp2. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
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 it would now block indefinitely. No other port does this. See parent commit for justification of why this change is useful. Also adds a test case that fails without this change. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
657fd48
to
ba98533
Compare
@dpgeorge Rebased to pick up the WFE fix, and split into two commits. I ended up making the new test rp2-only for now as there are several ports it won't pass on. |
Thanks! I tested it and the test works well (on rp2, and also stm32 just for my interest). |
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 ifmachine.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:
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.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
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.