rp2: Stop machine.idle() blocking indefinitely.

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>
This commit is contained in:
Angus Gratton 2024-06-25 15:30:02 +10:00
parent 81daba31c5
commit ba98533454
3 changed files with 38 additions and 1 deletions

View File

@ -103,7 +103,7 @@ static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args) {
}
static void mp_machine_idle(void) {
__wfe();
MICROPY_INTERNAL_WFE(1);
}
static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args) {

View File

@ -0,0 +1,36 @@
import machine
import time
# Verify that machine.idle() resumes execution within 0.1 and 1.1ms (should be
# 1ms max but allowing for some overhead).
#
# (A minimum sleep time for machine.idle() isn't specified but in a system like
# this with no active interrupts then we should expect some idle time before
# resuming. If it's consistently resuming immediately then that indicates a bug
# is preventing proper idle.)
#
# This test doesn't contain any rp2-specific code, but rp2 is currently the only
# tickless port - which is what led to the bug this is a regression test for.
# Some other ports (unix, esp32) have idle behaviour that resumes immediately on
# a quiet system, so this test is also less useful for those.
#
# Verification uses the average idle time, as individual iterations will always
# have outliers due to interrupts, scheduler, etc.
ITERATIONS = 500
total = 0
for _ in range(ITERATIONS):
before = time.ticks_us()
machine.idle()
total += time.ticks_diff(time.ticks_us(), before)
total /= 1000 # us to ms
average = total / ITERATIONS
# print(f"Total {total}ms average {average}ms") # uncomment for debug
if 0.1 < average < 1.1:
print("PASS")
else:
print(f"Total {total}ms average {average}ms, out of spec")

View File

@ -0,0 +1 @@
PASS