Page 1 of 1

Size of multiple PIO state machines

Posted: Tue Jun 22, 2021 9:59 pm
by mike449
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?

Re: Size of multiple PIO state machines

Posted: Wed Jun 23, 2021 6:17 am
by Roberthh
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.

Re: Size of multiple PIO state machines

Posted: Wed Jun 23, 2021 11:48 am
by hippy
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()))

Re: Size of multiple PIO state machines

Posted: Thu Jun 24, 2021 12:22 am
by mike449
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!