← index #18811Issue #15230
Related · high · value 1.341
QUERY · ISSUE

RP2 asyncio stream IO hangs: regression

openby peterhinchopened 2026-02-13updated 2026-03-18
bugport-rp2

Port, board and/or hardware

RP2040 or RP2350

MicroPython version

Fails on release builds >= 22.0

Bug seems RP2-specific: the script runs on STM32 (Pyboard 1.1) and ESP32-S3 with current firmware (1.27).

Reproduction

Either paste the script at the REPL or run from a file foo.py (mpremote mount . "exec import foo")

import asyncio # as asyncio
import time
import io
MP_STREAM_POLL_RD = const(1)
MP_STREAM_POLL = const(3)
MP_STREAM_ERROR = const(-1)

class MillisecTimer(io.IOBase):
    def __init__(self):
        self.end = 0
        self.sreader = asyncio.StreamReader(self)

    def __iter__(self):
        await self.sreader.read(1)

    def __call__(self, ms):
        self.end = time.ticks_add(time.ticks_ms(), ms)
        return self

    def read(self, _):
        return b"a"

    def ioctl(self, req, arg):
        ret = MP_STREAM_ERROR
        #time.sleep_us(2_000)
        if req == MP_STREAM_POLL:  # hangs HERE
            ret = 0
            if arg & MP_STREAM_POLL_RD:
                if time.ticks_diff(time.ticks_ms(), self.end) >= 0:
                    ret |= MP_STREAM_POLL_RD
        return ret

async def timer_test(n):
    timer = MillisecTimer()
    for x in range(n):
        await timer(100)  # Pause 100ms
        print(x)

asyncio.run(timer_test(20))

Expected behaviour

Expected to print integers from 0 to 19.

Observed behaviour

Hangs on the line commented with "hangs HERE".

Behaviour can be "fixed" by uncommenting the 2ms delay.

Additional Information

No, I've provided everything above.

Code of Conduct

Yes, I agree

CANDIDATE · ISSUE

If boot.py doesn't exit then rp2 port will never initialise USB (soft-bricked)

closedby TRadigkopened 2024-06-08updated 2024-11-19
bugport-rp2

Port, board and/or hardware

Raspberry Pico

MicroPython version

MicroPython v1.23.0 on 2024-06-02; Raspberry Pi Pico with RP2040

Reproduction

I took my program code and stripped it down to a working repro. There are more lines that could be deleted but help with visualization. The content is saved to boot.py. There is no other file saved on the microcontroller.
With any version prior 1.23 this will yield a serial device in device manager, whenever the device is connected to the computer. With version 1.23 it will not and can only recovered by flashing a firmware version prior 1.23:

import _thread
import asyncio  # type: ignore
from time import sleep
import gc
import machine

synchronousLoopAlive: bool = True
anyLoopAlive: bool = True
led = machine.Pin(25, machine.Pin.OUT)


async def yieldingBackgroundTaskOne():
    while anyLoopAlive:
        print("One")
        led.value(not led.value())

        await asyncio.sleep_ms(1000)


def synchronousTask():
    while synchronousLoopAlive:
        sleep(2)


if __name__ == "__main__":
    try:
        sleep(3)
        loop = asyncio.get_event_loop()
        gc.collect()

        programThread = _thread.start_new_thread(synchronousTask, ())
        print("program thread started")
        taskOne = loop.create_task(yieldingBackgroundTaskOne())
        print("task One started")

        loop.run_forever()
    except KeyboardInterrupt:
        synchronousLoopAlive = False
        anyLoopAlive = False
        loop.stop()
        print("INTERRUPTED - STOPPING EVERYTHING")
    except Exception as e:
        print(f"error occurred: {e}")

Expected behaviour

Expected a serial device in device manager as in all versions prior 1.23.

Observed behaviour

No serial device in device manager with micropython 1.23, but with any version prior 1.23.

Additional Information

No, I've provided everything above.

Code of Conduct

Yes, I agree

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied