Skip to content
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

ENOMEM errors on Galactic Pico and Pico2 #8

Open
LesterThree opened this issue Jan 19, 2025 · 8 comments
Open

ENOMEM errors on Galactic Pico and Pico2 #8

LesterThree opened this issue Jan 19, 2025 · 8 comments

Comments

@LesterThree
Copy link

Hi

Attached are some files to use. I had removed a lot of the code to make it easier to duplicate the error.

Using the Galactic Unicorn Pico2 and firmware pico2_w_galactic-v1.24.0-rc0-micropython:

  • Run stopNow.py.
  • You will get OSError: [Errno 12] ENOMEM on line 51 (parkTimer.init).
  • Power cycle Galactic and comment out line 47 (display.showRainbows).
  • Run stopNow.py. You should not get any errors.
  • Comment back in line 47.
  • Comment out line 58 (_thread.start_new_thread)
  • Run stopNow.py. You should still not get any errors.
  • Comment back in line 58.
  • Run stopNow.py and you will get the error again.

Now, I get the same results when I use Galactic Unicorn Pico and running pico_w_galactic-v1.24.0-rc0-micropython.
But when I use a previous firmware version - v1.23.0-1, it all works fine.

Any help would be appreciated. Thank you.

Code Test.zip

@Gadgetoid
Copy link
Member

I'll try running this on hardware, but I suspect both the timer and the previous firmware version are something of a red herring.

From what I can tell you're writing to the display from two cores simultaneously. MicroPython on the RP2040/RP2350 has no GIL (Global Interpreter Lock) so two cores will just trample over each other and potentially cause all kinds of havoc.

IIRC it was also something of a pot luck which core actually services a timer, which I created a repro for here micropython/micropython#12041 (comment)

TLDR: Don't use core1, it will bring only misery. Using it alongside timers will just make everything even worse. Look into asyncio.

@Gadgetoid
Copy link
Member

Gadgetoid commented Jan 21, 2025

Ha, to indicate just how incredibly fragile everything is, I tried to validate just how much RAM was available before the call to init the Timer to see if I could substantiate the error...

Adding: print(gc.mem_free()) right before parkTimer.init(mode = Timer.PERIODIC... stopped the ENOMEM error 🤦

Edit: As an aside, I'm having a lot of trouble writing files if I fire up core1, repro:

import _thread
from time import sleep


def core1Thread():
    while True:
        sleep(0.1)


_thread.start_new_thread(core1Thread, ())

while True:
    sleep(0.1)

@Gadgetoid
Copy link
Member

Gadgetoid commented Jan 21, 2025

After much tinkering I can repro with just:

import _thread
from machine import Timer
from time import sleep_ms
import gc


def core1():
    while True:
        sleep_ms(100)  


def timer_callback(timer):
    pass


_thread.start_new_thread(core1, ())
timer = Timer()

while True:
    print(gc.mem_free())
    timer.init(mode=Timer.PERIODIC, period=1500, callback=timer_callback)
    sleep_ms(10)
    timer.deinit()

It's hard to tell what's going on under the hood here, since Timer seems to be erroneously throwing ENOMEM due to some other resource constraints. gc.mem_free() shows 190368 on every iteration so there's no leak and no shortage of RAM whatsoever.

Some flavour of this seems to have been reported before: micropython/micropython#11597

Edit: Notably I cannot repro on RPI_PICO_W-20241129-v1.24.1.uf2 so we've probably gained a regression from the Pico 2 stuff.

@LesterThree
Copy link
Author

I wasn't writing to the display from two cores simultaneously. I was displaying rainbows on core 0 and when that was done, I was displaying a message from core 1.

But your comment gave me the idea to run rainbows from core 1 rather than core 0. And that seems to work on both Galactic Pico and Pico2 in the test code.
So I modified my actual code project to do the same and I'm no longer getting memory errors.

So that takes care of the problem I was having. Thank you very much for your time to look into this!

@Gadgetoid
Copy link
Member

Awesome. I think I was a little hasty implicating your specific use of multicore - it seems things were more fundamentally broken.

It looks like I might have a build for you that fixes the underlying issue anyway. We weren't ahead but a little behind the curve. Grabbing the Galactic build from here should help: https://github.com/pimoroni/pimoroni-pico/actions/runs/12891559478?pr=1019

I'm still having trouble with activating core1 breaking my ability to write files (via Thonny), but otherwise I think this was some already fixed quirk.

@LesterThree
Copy link
Author

Yea, your fix will be great. In my project code, I write a settings json file from core 0. I haven't tried writing from core 1 since I was using that for only writing to the display.

@Gadgetoid
Copy link
Member

I finally tracked down the unrelated core1 bug as a "known" caveat of Pico SDK and reported it upstream. (micropython/micropython#16619)

It probably wont affect you writing files (although folks have had trouble with that too) but definitely makes using soft reset a misery while Core 1 is running.

@LesterThree
Copy link
Author

Good deal. I've always had to power cycle Pico to ensure core 1 is reset. If I understand this correctly, that will take care of the problem?

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

No branches or pull requests

2 participants