From ba98533454eef5ab5783039f9929351c8f54d005 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 25 Jun 2024 15:30:02 +1000 Subject: [PATCH] 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 --- ports/rp2/modmachine.c | 2 +- tests/ports/rp2/rp2_machine_idle.py | 36 +++++++++++++++++++++++++ tests/ports/rp2/rp2_machine_idle.py.exp | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/ports/rp2/rp2_machine_idle.py create mode 100644 tests/ports/rp2/rp2_machine_idle.py.exp diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c index 2cc79369f614..229000cc1797 100644 --- a/ports/rp2/modmachine.c +++ b/ports/rp2/modmachine.c @@ -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) { diff --git a/tests/ports/rp2/rp2_machine_idle.py b/tests/ports/rp2/rp2_machine_idle.py new file mode 100644 index 000000000000..f9c28284782f --- /dev/null +++ b/tests/ports/rp2/rp2_machine_idle.py @@ -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") diff --git a/tests/ports/rp2/rp2_machine_idle.py.exp b/tests/ports/rp2/rp2_machine_idle.py.exp new file mode 100644 index 000000000000..7ef22e9a431a --- /dev/null +++ b/tests/ports/rp2/rp2_machine_idle.py.exp @@ -0,0 +1 @@ +PASS