Skip to content

On RP2350 time.sleep_ms is a busy wait loop #16562

Closed

Description

@cpottle9

Port, board and/or hardware

rp2 on RPI PICO2

MicroPython version

MicroPython v1.24.0-dirty on 2025-01-09; Raspberry Pi Pico2 with RP2350
Also on latest version v1.25.preview commit 495ce91 and 1.24.1

Reproduction

To get some insight on the problem I added some debug code to mp_hal_delay_us() in mphalport.c.

here is a diff of my changes:

git diff mphalport.c
diff --git a/ports/rp2/mphalport.c b/ports/rp2/mphalport.c
index 3f5015162..4a9fc1c50 100644
--- a/ports/rp2/mphalport.c
+++ b/ports/rp2/mphalport.c
@@ -151,10 +151,13 @@ void mp_hal_delay_us(mp_uint_t us) {
 void mp_hal_delay_ms(mp_uint_t ms) {
     mp_uint_t start = mp_hal_ticks_ms();
     mp_uint_t elapsed = 0;
+    mp_uint_t loop_count = 0;
     do {
         mp_event_wait_ms(ms - elapsed);
         elapsed = mp_hal_ticks_ms() - start;
+       ++loop_count;
     } while (elapsed < ms);
+    mp_printf(MP_PYTHON_PRINTER, "delay loop_count=%d\n", loop_count);
 }
 
 void mp_hal_time_ns_set_from_rtc(void) {

To build the 1.24.0 micropython (commit f212bbe) with my debug code I did:

git clone https://github.com/micropython/micropython.git micropython-direct-clone
cd micropython-direct-clone
git checkout f212bbe
make -C mpy-cross -j4
cd ports/rp2
make -j4 BOARD=RPI_PICO submodules
make -j4 BOARD=RPI_PICO2 submodules
make -j4 BOARD=RPI_PICO2
make -j4 BOARD=RPI_PICO

Expected behaviour

On RPI PICO we see the expected behavior. My code counts the number of times the loop in mp_hal_delay_ms runs.

MicroPython v1.24.0-dirty on 2025-01-09; Raspberry Pi Pico with RP2040
Type "help()" for more information.
>>> from time import sleep_ms
>>> sleep_ms(1000)
delay loop_count=2

Two times around the loop for a one second sleep is reasonable.

Observed behaviour

On RPI 2350 we see:

MicroPython v1.24.0-dirty on 2025-01-09; Raspberry Pi Pico2 with RP2350
Type "help()" for more information.
>>> from time import sleep_ms
>>> sleep_ms(1000)
delay loop_count=200242

See the loop executed 200,242 times for a one second sleep.
Basically we have a busy wait loop.

Additional Information

This issue likely does not impact users.
But it does indicate a RP2350 specific bug.

I care about this behavior because I have code modifying the RP2040 or RP2350 SLEEP_EN0 and SLEEP_EN1 registers to disable hardware blocks while the chip is sleeping.
You can see that code in my github repo RP2-PowerControl,
The intent is to reduce power consumption.

This works fine on the PICO and PICO W with RP2040. I see the current drop by a significant amount.
I do not see any current reduction on PICO2 with RP2350.
But, if I modify registers WAKE_EN0 and WAKE_EN1 to disable hardware while running I do see some power reduction.

I assert this is because the ARM core keeps executing in the busy wait loop.
Since the processor is not sleeping no hardware is disabled and therefore no power reduction.

I would love to investigate more on my own, but I am stuck.
Possibly @projectgus would have insights.
He has been doing work related to softtimer and support for RP2350.

Code of Conduct

Yes, I agree

Activity

  1. cpottle9 commented on Jan 12, 2025

    @cpottle9
    ContributorAuthor

    I got gdb and debug probe running on my 2350 and stepped through the code from mp_hal_delay_ms().
    I did not see anything obvious.

    As an experiment I modified mp_wfe_or_timeout() adding a second __wfe()

    @@ -273,6 +280,7 @@ void mp_wfe_or_timeout(uint32_t timeout_ms) {
         soft_timer_static_init(&timer, SOFT_TIMER_MODE_ONE_SHOT, 0, NULL);
         soft_timer_insert(&timer, timeout_ms);
     
    +    __wfe();
         __wfe();
     
         // Clean up the timer node if it's not already
    

    I was expecting this to cause a freeze on a 2040 and thought it would mask the problem on a 2350.
    The 2040 did not freeze and it did indeed mask the problem on a 2350.
    I guess I don't understand how interrupts and events work on ARM processors.
    I don't think adding a second __wfe() is the answer.

    My test code now prints loop_count=1 and I do see a power reduction while time.sleep_ms() is running.

  2. cpottle9 commented on Jan 14, 2025

    @cpottle9
    ContributorAuthor

    I just became aware of pull request #16454 where @peterharperuk wrote:

    rp2350 generates a sev when using spin locks, which can prevent the device sleeping, see raspberrypi/pico-sdk#1812 for more background.

    @dpgeorge speaks further in issue raspberrypi/pico-sdk#1812/

    I think the SEV from spin locks is the cause of the problem I am seeing.
    I suspect when #16454 goes in my problem will go away.
    I will keep an eye out for when #16454 goes in.

    I have a work-around to mask the problem. I can use it for my testing.

  3. cpottle9 commented on Mar 5, 2025

    @cpottle9
    ContributorAuthor

    I see that pico-sdk 2.1.1 is being used now in master.
    I picked up the changes to mphalport.c from #16454 and I the issue I see of time.sleep_ms() being a busy wait on RP2350 is fixed.

    Thanks @peterharperuk. I look forward to you merging your changes.

  4. linked a pull request that will close this issueAlarm pool sleep changes #16454on Mar 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions