summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAngus Gratton <angus@redyak.com.au>2024-06-25 15:30:02 +1000
committerAngus Gratton <angus@redyak.com.au>2024-07-23 16:46:27 +1000
commitba98533454eef5ab5783039f9929351c8f54d005 (patch)
tree5527d67b243f4b919e1f0a1bcee43e90c2743eb7
parent81daba31c5f7541986b4cc1b12d2cf9c41e025e1 (diff)
downloadmicropython-ba98533454eef5ab5783039f9929351c8f54d005.tar.gz
micropython-ba98533454eef5ab5783039f9929351c8f54d005.zip
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>
-rw-r--r--ports/rp2/modmachine.c2
-rw-r--r--tests/ports/rp2/rp2_machine_idle.py36
-rw-r--r--tests/ports/rp2/rp2_machine_idle.py.exp1
3 files changed, 38 insertions, 1 deletions
diff --git a/ports/rp2/modmachine.c b/ports/rp2/modmachine.c
index 2cc79369f6..229000cc17 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 0000000000..f9c2828478
--- /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 0000000000..7ef22e9a43
--- /dev/null
+++ b/tests/ports/rp2/rp2_machine_idle.py.exp
@@ -0,0 +1 @@
+PASS