← index #9316Issue #7117
Off-topic · high · value 1.937
QUERY · ISSUE

pico - zombie pio state machines after soft reset

openby ccanepaopened 2022-09-14updated 2026-03-19
bugport-rp2

version:

>>> import sys
>>> sys.implementation
(name='micropython', version=(1, 19, 1), _machine='Raspberry Pi Pico with RP2040', _mpy=4102)

Problem description: pio sm instances can be unexpectedly resucitated after a soft reset

More detailed description:

  • instantiate and activate many pio state machines with the same pio program
  • call machine.soft_reset()
  • instantiate and activate only one sm, with the same pio program
  • Expected: only one sm activelly driven his output
  • Observed: all sm with same pio program will be activelly driven their outputs

The demo script expects to have led + resistor in gpios 10..13

It will instantiate and activate four sm, each blinling a led, do a soft reset, instantiate and activate only one sm, do a hard reset and repeat.

Expected 5 seconds of four led blinking, followed by 5 seconds of only one led blinking, repeat

Observed always four leds blinking

See docstring for instuctions to run

demo script: pio_and_machine_reset.py

""" demoing zombie state machines after soft reset

Using a pico lean and mean, not W or other variants
HW: led + resistor on gpios 10..13

Shoul do: blink the four leds 5 seconds, then blink only the led in gpio 13
Observed: four leds blinking always

Operation:
   - if not first run, ensure the file 'soft_reset_flag.txt' does not
     exist in the pico
   - Close Thonny or other runner / debugger to discard other sw interference 
   - Unplug and plug the pico to ensure a hard reset
   - Use minicom or Bootterm ( bt ) to get the serial output from the pico
"""

from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
import time

def report_state_machines():
    for p in (0, 1):
        for sm_c in range(4):
            fmt = "rp2.PIO(%d).state_machine(%d).active(): %s"
            print( fmt % (p, sm_c, rp2.PIO(p).state_machine(sm_c).active()))

class FSFlag:
    def __init__(self, name):
        self.name = name
        self.fname = name + "_flag.txt"
        
    def is_flag_set(self):
        present = False
        try:
            f = open(self.fname, "r")
            present = True
            f.close()
        except Exception:
            present = False
        return present

    def set_(self):
        f = open(self.fname, "w")
        f.write("flag file")
        f.close()

    def clear(self):
        import os
        if self.is_flag_set():
            os.remove(self.fname)

    def value(self, val=None):
        if val is None:
            return self.is_flag_set()
        elif val:
            self.set_()
        else:
            self.clear()


@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def blink():
    set(pins, 1)   [31]
    nop()          [31]
    nop()          [31]
    nop()          [31]
    nop()          [31]
    set(pins, 0)   [31]
    nop()          [31]
    nop()          [31]
    nop()          [31]
    nop()          [31]

def blink_1_led(dt):
    print("only led on gpio 13 should blink")
    print("only SM 3 should be active")
    sm = StateMachine(3, blink, freq=2000, set_base=Pin(13, Pin.OUT, value=0))
    sm.active(1)
    report_state_machines()
    time.sleep(dt)

def blink_4_leds(dt):
    print("leds in gpios (10, 11, 12, 13) should blink")
    print("SMs 0..4 should be active")
    gpios = (10, 11, 12, 13)
    py_sm_ids = (0, 1, 2, 3)
    pairs = [(id_, Pin(gp, Pin.OUT, value=0)) for id_, gp in zip(py_sm_ids, gpios)]
    sms = {id_: StateMachine(id_, blink, freq=2000, set_base=pin) for id_, pin in pairs} 
    for sm in sms.values():
        sm.active(1)
    report_state_machines()
    time.sleep(dt)

print("Comming Alive")
report_state_machines()
soft_reset = FSFlag("soft_reset")
if soft_reset.value():
    print("after soft reset")
    blink_1_led(5)
    soft_reset.value(0)
    machine.reset()
else:
    print("after hard reset")
    blink_4_leds(5)
    soft_reset.value(1)
    machine.soft_reset()

Additional info, not demoed but can easily show with variants on the demo code:

  • always after soft reset all the sm active before the reset are shown as active by rp2.PIO(p).state_machine(sm_c).active()
  • if no sm is instantiated after the soft reset, no pin activity shows in the pins controlled by the old sm's
  • if a pio sm with a different pio program is instantiated after the soft reset, no pin activity shows in the pins controlled by the old sm's
  • if a pio sm with same pio program is activated after the soft reset, the old sm's activelly drive their pins

This issue is probably related to
https://forums.raspberrypi.com/viewtopic.php?t=340099
https://github.com/thonny/thonny/issues/2455

CANDIDATE · ISSUE

rp2 import PIO, StateMachine, asm_pio -> Info -> Black Cat in a Coal Bunker

openby kevindawsonopened 2021-04-13updated 2021-08-20
  • μpython v1.14 on 2021-04-09 (GNU 10.2.0 MinSizeRel)

from - Raspberry Pi Pico Python SDK (2021-04-07)
The idea is that for the 4 sets of pins ( in , out , set , sideset , excluding jmp ) that can be connected to a state machine,
there’s the following that need configuring for each set:

Sample code:

from rp2 import PIO, StateMachine, asm_pio
from machine import Pin

@asm_pio(set_pins=(PIO.OUT_LOW, PIO.OUT_HIGH,  PIO.IN_LOW), sideset_pins=PIO.OUT_LOW)
def foo():
    pass

sm0 = StateMachine( 0, foo, freq=2000, set_pins=Pin(15), sideset_pins=Pin(22))

it just produces errors

Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "rp2.py", line 230, in asm_pio
TypeError: unexpected keyword argument 'set_pins'

I can find info -> machine -> https://docs.micropython.org/en/latest/library/machine.html
but info for rp2 -> null

looking in the rp2 stubs - StateMachine

def __init__(self, id, prog, freq: int=-1, *, in_base: Pin=None, out_base: Pin=None, set_base: Pin=None, jmp_pin: Pin=None, sideset_base: Pin=None, in_shiftdir: int=None, out_shiftdir: int=None, push_thresh: int=None, pull_thresh: int=None):

Ureka - moment - there NO set_pins in StateMachine instantiation

from rp2 import PIO, StateMachine, asm_pio
from machine import Pin

@asm_pio(set_pins=(PIO.OUT_LOW, PIO.OUT_HIGH,  PIO.IN_LOW), sideset_pins=PIO.OUT_LOW)
def foo():
    pass

sm0 = StateMachine( 0, foo, freq=2000, set_base=Pin(15), out_base=Pin(16), sideset_base=Pin(22))

looking in the rp2 stubs - asm_pio

def asm_pio(set_init: int = None, out_shiftdir: int = None, autopull: bool = None, pull_thresh: int = None, set_pins: Iterable[Sequence[int]] = None, sideset_pins: int = None, sideset_init: int = None, out_init: int = None, autopush: bool = None, push_thresh: int = None, in_base: int = None, out_base: int = None) -> Any:

Just hit the brick wall:(

Any chance someone that knows can put a working example up:
The idea is that for the 4 sets of pins ( in , out , set , sideset , excluding jmp ) that can be connected to a state machine,
there’s the following that need configuring for each set:

  1. base GPIO
  2. number of consecutive GPIO
  3. initial GPIO direction (in or out pin)
  4. initial GPIO value (high or low)

or do I need to add a documentation request -> Roadmap to next release v1.15

Thanks in Adv.

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