micropythonledraspberry-pi-pico

OSError: [Errno 12] ENOMEM


I use code from here. After running multiple times from Thonny without issue I got:

OSError: [Errno 12] ENOMEM

I used nuke.uf2 to clear storage on Raspberry Pi Pico W. The error re-occurred after running the file too many times. nuke.uf2 was a temporary fix.

###############################################################
# WS2812 RGB LED Ring Light Breathing
# with the Raspberry Pi Pico Microcontroller
#
# by Joshua Hrisko, Maker Portal LLC (c) 2021
#
# Based on the Example neopixel_ring at:
# https://github.com/raspberrypi/pico-micropython-examples
###############################################################
#
import array, time
from machine import Pin
import rp2

#
############################################
# RP2040 PIO and Pin Configurations
############################################
#
# WS2812 LED Ring Configuration
led_count = 12 # number of LEDs in ring light
PIN_NUM = 1 # pin connected to ring light
brightness = 0.2 # 0.1 = darker, 1.0 = brightest

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT,
             autopull=True, pull_thresh=24) # PIO configuration

# define WS2812 parameters
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)    [T3 - 1]
    jmp(not_x, "do_zero")   .side(1)    [T1 - 1]
    jmp("bitloop")          .side(1)    [T2 - 1]
    label("do_zero")
    nop()                   .side(0)    [T2 - 1]
    wrap()

# Create the StateMachine with the ws2812 program, outputting on pre-defined pin
# at the 8MHz frequency
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(PIN_NUM))

# Activate the state machine
sm.active(1)

# Range of LEDs stored in an array
ar = array.array("I", [0 for _ in range(led_count)])
#
############################################
# Functions for RGB Coloring
############################################
#
def pixels_show(brightness_input=brightness):
    dimmer_ar = array.array("I", [0 for _ in range(led_count)])
    for ii,cc in enumerate(ar):
        r = int(((cc >> 8) & 0xFF) * brightness_input) # 8-bit red dimmed to brightness
        g = int(((cc >> 16) & 0xFF) * brightness_input) # 8-bit green dimmed to brightness
        b = int((cc & 0xFF) * brightness_input) # 8-bit blue dimmed to brightness
        dimmer_ar[ii] = (g<<16) + (r<<8) + b # 24-bit color dimmed to brightness
    sm.put(dimmer_ar, 8) # update the state machine with new colors
    time.sleep_ms(10)

def pixels_set(i, color):
    ar[i] = (color[1]<<16) + (color[0]<<8) + color[2] # set 24-bit color

def breathing_led(color):
    step = 5
    breath_amps = [ii for ii in range(0,255,step)]
    breath_amps.extend([ii for ii in range(255,-1,-step)])
    for ii in breath_amps:
        for jj in range(len(ar)):
            pixels_set(jj, color) # show all colors
        pixels_show(ii/255)
        time.sleep(0.02)
#
############################################
# Main Calls and Loops
############################################
#
# color specifications
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
yellow = (255,255,0)
cyan = (0,255,255)
white = (255,255,255)
blank = (0,0,0)
colors = [blue,yellow,cyan,red,green,white]

while True: # loop indefinitely
for color in colors: # emulate breathing LED (similar to Amazon's Alexa)
breathing_led(color)
time.sleep(0.1) # wait between colors

Solution

  • I just tripped over this myself.

    The quick fix is to type machine.reset() into the Thonny console (you might need to type import machine first).

    The issue is the line that initialises the state machine. The number of times that you can run it without hitting the error depends on the length of the PIO code (the ws2812() function), so I assume that for some reason it is not resetting the PIO memory which can only hold 32 instructions.

    Your code has 4 PIO instructions, and in my tests it fails on the 9th run, so that adds up.

    This seems to be specific to the Pico W, as exactly the same code on the same MicroPython nightly build works fine on a non-W Pico.

    EDIT: Here's the problem - MicroPython doesn't reset PIO memory on the Pico W because it interferes with the Wireless driver.

    EDIT: Another solution is to put rp2.PIO(0).remove_program() before the rp2.StateMachine line, to clear the PIO memory.