Skip to content

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

Merged
merged 2 commits into from
Jul 23, 2024

Conversation

projectgus
Copy link
Contributor

@projectgus projectgus commented Jun 25, 2024

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 tunning time.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.

Copy link

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +8 +0.001% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS

@dpgeorge

This comment was marked as outdated.

@projectgus

This comment was marked as outdated.

@projectgus projectgus force-pushed the bugfix/rp2_machine_idle branch from 5edcfaa to 4bc14ee Compare July 5, 2024 06:48
@projectgus projectgus added the bug label Jul 5, 2024
@projectgus projectgus force-pushed the bugfix/rp2_machine_idle branch 3 times, most recently from 3079deb to 42d0b28 Compare July 5, 2024 07:13
Copy link

codecov bot commented Jul 5, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.43%. Comparing base (e1ecc23) to head (ba98533).

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.
📢 Have feedback on the report? Share it here.

@projectgus
Copy link
Contributor Author

This PR is ready now but depends on #15398 for correct behaviour.

@projectgus projectgus force-pushed the bugfix/rp2_machine_idle branch from 42d0b28 to 657fd48 Compare July 5, 2024 07:20
@projectgus projectgus marked this pull request as ready for review July 5, 2024 07:20
@projectgus projectgus changed the title WIP: rp2,docs: Stop machine.idle() blocking indefinitely, update docs. rp2,docs: Stop machine.idle() blocking indefinitely, update docs. Jul 5, 2024
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>
@projectgus projectgus force-pushed the bugfix/rp2_machine_idle branch from 657fd48 to ba98533 Compare July 23, 2024 06:50
@projectgus
Copy link
Contributor Author

@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.

@dpgeorge dpgeorge merged commit ba98533 into micropython:master Jul 23, 2024
29 checks passed
@dpgeorge
Copy link
Member

Thanks! I tested it and the test works well (on rp2, and also stm32 just for my interest).

@projectgus projectgus deleted the bugfix/rp2_machine_idle branch November 1, 2024 05:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants