Pico W ENOMEM error when (re)using PIO (rp2_pio_init, CYW43)
First reported here: Pico W ENOMEM error when using PIO - Raspberry Pi Forums.
A program that uses PIO (such as the example code: micropython/pio_1hz.py at master · micropython/micropython) can't be reliably stopped and restarted on a Pico W, while it can on a Pico.
Expected result: being able to stop and start PIO example at will
Actual result: after a small number of attempts OSError: [Errno 12] ENOMEM
The cause appears to be identified as PIO.remove_program() not being usable when the CYW43 driver is loaded, as the CYW43 itself is running a PIO program.
Indeed, comments inside rp2_pio_init() suggest this may be an issue:
void rp2_pio_init(void) {
// Reset all PIO instruction memory.
#if MICROPY_PY_NETWORK_CYW43
// TODO: cannot reset PIO memory when CYW43 driver is enabled and active
// because it uses a PIO for the bus interface.
Version:
MicroPython v1.19.1 on 2022-07-29; Raspberry Pi Pico W with RP2040
rp2-pico-w-20220729-unstable-v1.19.1-223-g963e599ec.uf2
rp2: Fix stale program offset cache after remove_program().
PIO.remove_program() without arguments clears SDK instruction-memory tracking but did not reset cached offsets in program objects. A subsequent StateMachine init using such a program would see the non-negative offset, assume the program was still loaded, and skip re-writing the instructions to PIO instruction memory.
Fix by validating the cached offset against the internal usage mask before trusting it. If the bit is clear the program is not present, so invalidate the stale offset and reload.
Summary
I discovered this issue when writing the PIO test suite in #18974; it caused a hang in test_restart.
Testing
I tested this on both RPI_PICO and RPI_PICO2 boards using the test suite from #18974 (and new PIO assembler support from #18975).
Generative AI
I used generative AI tools when creating this PR, but a human has checked the
code and is responsible for the code and the description above.