Tuesday, July 26, 2022

RP2040 Micropython PIO - Part 4 - Using IRQ to signal when pins changes have been pushed!

I'm delighted that this worked exactly as it seemed it ought to.  Just like we did in Part 3, we track the pins states and only push them when there's been a change.  But now, when we push the changed pins, we toggle the irq. 

When we initialize the state machine, we bind a function, "printFromGet" to the state machine irq. When the irq is toggled, this function is called, and a pointer to the state machine is passed to the function.  Then we can call sm.get() to read the new pins values.   This is fantastic because python doesn't need to spin checking the pins using the gpio library wasting cpu cycles.  When we press a key, python is detoured momentarily to our needed function to handle the pin press, and once it returns, python can resume whatever else it was working on!

Here's a more complete code from the last couple examples. 

import safety_pin
import pio_junk
from machine import Pin
import rp2
import time

COUNT = 0

def initPinsAsIn(direction=Pin.PULL_UP):
for n in range(32):
try:
Pin(n, Pin.IN, direction)
except:
print("Couldn't initialize pin:", n)

def printFromGet(sm):
global COUNT
out = sm.get()
print(f'{COUNT} - {out:>032b}')
COUNT += 1

@rp2.asm_pio( set_init=[PIO.IN_HIGH]*32 )
def irq_pins_changes():
mov(y, pins)
#in_(y, 32)
mov(isr, y)
push()

wrap_target()
label("read loop")
mov(x, pins)

jmp(x_not_y, "exit read loop")
jmp("read loop")
label("exit read loop")
mov(isr, x)
mov(y, x)
push()
irq(1)

wrap()

if __name__ == '__main__':
print('In Main Now')
initPinsAsIn()

sm = rp2.StateMachine(0, irq_pins_changes,
freq=2000, in_base=Pin(0))
sm.irq(printFromGet, 0)

sm.active(1)
for n in range(10):
out = sm.get()
print(f'{n}, {out:>032b}')
sm.active(0)

The last thing I might want to do is sort of look up which pin changed and push an integer value corresponding with the addr of the changed pin so each time I do a get() in python, I get the number of the changed pin.  

No comments: