Size of multiple PIO state machines

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
Post Reply
mike449
Posts: 2
Joined: Tue Jun 22, 2021 9:46 pm

Size of multiple PIO state machines

Post by mike449 » Tue Jun 22, 2021 9:59 pm

I am writing a program which uses multiple state machines. Once the total number of lines in all state machines exceeds 32, I see the dereaded message:
OSError: [Errno 12] ENOMEM
The datasheet states right in the first paragraph:
The four state machines execute from a shared instruction memory.
, so I understand this is the architecture limitation.
Is there a programming trick to work around this limitation? In my application SMs run one at a time, it would be ok to reload the program memory before activating the next SM. But how do I do this? Is there a way to "unload" the already instantiated SM?

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Size of multiple PIO state machines

Post by Roberthh » Wed Jun 23, 2021 6:17 am

There are two PIO bloxks. The first four and the second four state machine each share the same 32 word area of these two PIOs. So one optimization would be to put the state machines in the different groups. Unloading a single state machine from the 32 Word area is tricky. What could be achieved is removing all state machines from a single PIO and then reload them again.

hippy
Posts: 130
Joined: Sat Feb 20, 2021 2:46 pm
Location: UK

Re: Size of multiple PIO state machines

Post by hippy » Wed Jun 23, 2021 11:48 am

mike449 wrote:
Tue Jun 22, 2021 9:59 pm
it would be ok to reload the program memory before activating the next SM. But how do I do this? Is there a way to "unload" the already instantiated SM?
That's an interesting question. And harder to figure out than I expected -

Code: Select all

PIO(0).remove_program()
Except there seems to be a bug; it doesn't work a second time.

Full test code ...

Code: Select all

from rp2 import asm_pio, StateMachine, PIO

@asm_pio()
def PioOne():
    nop()       # 0
    nop()       # 1
    nop()       # 2
    nop()       # 3
    nop()       # 4
    nop()       # 5
    nop()       # 6
    nop()       # 7
    nop()       # 8
    nop()       # 9
    nop()       # 10
    nop()       # 11
    nop()       # 12
    nop()       # 13
    nop()       # 14
    nop()       # 15
    nop()       # 16
    nop()       # 17
    nop()       # 18
    nop()       # 19
    nop()       # 20
    nop()       # 21
    nop()       # 22
    nop()       # 23
    nop()       # 24
    nop()       # 25
    nop()       # 26
    nop()       # 27
    nop()       # 28
    set(x, 1)   # 29
    mov(isr, x) # 30
    push(block) # 31
    
@asm_pio()
def PioTwo():
    nop()       # 0
    nop()       # 1
    nop()       # 2
    nop()       # 3
    nop()       # 4
    nop()       # 5
    nop()       # 6
    nop()       # 7
    nop()       # 8
    nop()       # 9
    nop()       # 10
    nop()       # 11
    nop()       # 12
    nop()       # 13
    nop()       # 14
    nop()       # 15
    nop()       # 16
    nop()       # 17
    nop()       # 18
    nop()       # 19
    nop()       # 20
    nop()       # 21
    nop()       # 22
    nop()       # 23
    nop()       # 24
    nop()       # 25
    nop()       # 26
    nop()       # 27
    nop()       # 28
    set(y, 2)   # 29
    mov(isr, y) # 30
    push(block) # 31
 
sm = StateMachine(0, PioOne)
sm.active(1)
print("Should be 1 : {}".format(sm.get()))

PIO(0).remove_program()

sm = StateMachine(0, PioTwo)
sm.active(1)
print("Should be 2 : {}".format(sm.get()))

PIO(0).remove_program()

sm = StateMachine(0, PioOne)
sm.active(1)
print("Should be 1 : {}".format(sm.get()))

Code: Select all

Should be 1 : 1
Should be 2 : 2
Should be 1 : 2         <--- Wrong
Weirdly though, removing PioOne, which had already been removed to allow PioTwo to run, does seem to work ...

Code: Select all

sm = StateMachine(0, PioOne)
sm.active(1)
print("Should be 1 : {}".format(sm.get()))

PIO(0).remove_program()

sm = StateMachine(0, PioTwo)
sm.active(1)
print("Should be 2 : {}".format(sm.get()))

PIO(0).remove_program(PioOne) # <-- Weird

sm = StateMachine(0, PioOne)
sm.active(1)
print("Should be 1 : {}".format(sm.get()))

mike449
Posts: 2
Joined: Tue Jun 22, 2021 9:46 pm

Re: Size of multiple PIO state machines

Post by mike449 » Thu Jun 24, 2021 12:22 am

For now, I was able to fit my SMs into 32 lines by moving the non timing critical setup steps to sm.exec() statements outside of the pioasm code.
When this method runs out of steam, I will try remove_program.
Thanks!

Post Reply