Skip to content

rp2: Flash writes disrupt UART IRQ #17236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Gadgetoid opened this issue May 1, 2025 · 3 comments
Open

rp2: Flash writes disrupt UART IRQ #17236

Gadgetoid opened this issue May 1, 2025 · 3 comments
Labels

Comments

@Gadgetoid
Copy link
Contributor

Port, board and/or hardware

rp2

MicroPython version

All.

Reproduction

Attempting to stream data from a UART to Flash - ie: servicing a soft (MicroPython) UART IRQ and writing the UART contents to a file on Flash - will result in lost data.

Using the same code and writing the same data to an SD card works fine.

Expected behaviour

No data should be lost.

Observed behaviour

Flash writes on RP2 disable all interrupts to avoid any code running from Flash while it's being written.

Since the UART copy from its 32 byte buffer into the user-specified (size) ring buffer requires the IRQ to fire, then writing to flash will lose arbitrary portions of incoming UART data since they will never make it to the ring buffer.

Additional Information

It's possible, maybe, that this could be fixed by moving the UART IRQ handler to RAM and being very careful about what it does. IE: This could not interop with a "hard" IRQ since we can't predict what the user might be doing (even if they don't allocate RAM).

AIUI the normal soft UART IRQ is dispatched and handled by MicroPython outside of the IRQ handler so this might just work.

Code of Conduct

Yes, I agree

@Gadgetoid Gadgetoid added the bug label May 1, 2025
@Gadgetoid
Copy link
Contributor Author

The main problem with the UART IRQ is that it gets very spicy very quickly.

It calls out to mp_irq_handler and it can either be set as a "hard" IRQ which runs the user supplied MicroPython IRQ handler in the interrupt or it will call mp_sched_schedule to schedule the interrupt for the VM to run normally (out of IRQ context) as a soft IRQ.

I don't think it's feasible to move the whole dependency chain into RAM but maybe that call could be deferred during flash writes and handled when the flash write has finished.

The whole concept of a "hard" IRQ seems pretty fraught, and would be antithetical to leaving this particular IRQ enabled. I don't know how we reconcile that. Things also get even more spicy if PSRAM is involved.

Maybe an alternate approach would be to hook the UART to a DMA but I only have a nebulous concept how that might work.

What I do know is that losing data from the UART during flash writes is not ideal- especially when it's used for PPP/networking purposes.

@dpgeorge
Copy link
Member

dpgeorge commented May 2, 2025

Ideally people would design RP2xxx boards with two SPI flash: one dedicated as memory-mapped "ROM" for code and ROMFS, and another for read/write access.

Hint, hint 😂

@Gadgetoid
Copy link
Contributor Author

I wish!

I am not getting far with efforts to unravel this, though it's notable that CircuitPython does not rely on the SDK's save_and_disable_interrupts() for similar reasons. It's a little heavy handed. Since I didn't want to deal with mystery meat CMSIS functions I just looped through all the available IRQs, checked if they are enabled, added their state to a bitmap and disabled them. Reverse to re-enable. This seems to work just as well as the heavy-handed PRIMASK.... as long as I disable all IRQs 😆

Afaict there's nothing in the UART IRQ I haven't accounted for, and I have taken pains to defer firing of the user code (pushing the IRQ handler into a global var and picking that up by hooking the soft timer interrupt). But no dice. Same bonkers hacks work fine writing to microSD, hard lock writing to flash. I must be missing a trick!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants