PIO IRQ: Inadequate Documentation = Lost #15897
-
Problem StatementI have two PIO state machines that work well when run in a separate program within Thonny. When I integrate the two state machines into one program, then I experience a conflict with PIO IRQ and I do not understand why this conflict is occurring. The documentation for PIO IRQ is inadequate at describing the syntax that is recommended. rp2.StateMachine.irqhttps://docs.micropython.org/en/latest/library/rp2.StateMachine.html#rp2.StateMachine.irq
irq(…)https://docs.micropython.org/en/latest/library/rp2.html#pio-assembly-language-instructions
Question for HelpCould someone please help with explaining how to use two interrupts with two state machines in a single program? I have placed my code below as an example. Please review my code to show my error and help explain where the IRQ documentation is inadequate so I can accurately submit an issue to have the documentation updated. Note:
### For use with an RP2040 Pico
from rp2 import PIO, asm_pio, StateMachine
from machine import Pin, PWM
import time
pulse_width = 1
SM0_RX_FIFO_Receive = 0b0
SM1_RX_FIFO_Receive = 0b0
### State Machine 1 Code
@rp2.asm_pio(in_shiftdir=0, out_shiftdir=1, autopull=True, pull_thresh=1, autopush=False, push_thresh=32) # set the bit order direction of OSR and ISR as well as autopull threshold to allow a single bit into the state machine while storing these bits in the ISR until full (32-bits)
def build_bitstream():
wrap_target()
set(y, 31) # set scratch y to 31, this will count down for each bit to be added to ISR
label("loop")
pull(block) # wait (block) for a 32-bit word to be added to the TX FIFO, then move the word to the OSR
out(x, 1) # move one bit from OSR to scratch x
in_(x, 1) # move one bit from scratch x to OSR
jmp(y_dec, "loop") # loop back unill 32 bits (bit stream) have filled the ISR
push(noblock) # move the 32-bits from the ISR to the RX FIFO
irq(rel(1)) # set IRQ flag which will trigger the IRQ handler to get the 32-bit word from the RX FIFO
wrap()
def sm1_handler(sm1):
SM1_RX_FIFO_Receive = sm1.get()
print(bin(SM1_RX_FIFO_Receive))
print("sm1_handler_debug")
sm1 = rp2.StateMachine(1, build_bitstream) # build array of bit at clock speed
sm1.irq(sm1_handler, trigger=2, hard=False)
sm1.active(1) # Start state machine
### End State Machine 1 Code
### State Machine 0 Code
# measure pulse width of each squarewave high time to determine a 0 or 1 for decoding DCC per NMRA standard S-9.1
@rp2.asm_pio(set_init=rp2.PIO.IN_LOW)
def pulse_width_measure():
wrap_target()
mov(x, invert(null))# set scratch x to 0xFFFFFFFF
wait(1, gpio, 16) # wait for GPIO pin to go high
label("timer")
jmp(x_dec, "test") # if x not zero, then jump to test, count down x
wrap() # if x is zero, then timed out, therefore wrap to start over
label("test")
jmp(pin, "timer") # test if the pin is still 1, if so, continue counting down
mov(isr, x) # if pin is 0, move the value in x to the ISR
push(noblock) # push the ISR into the RX FIFO
irq(rel(0)) # set IRQ flag for program to retreive data (get) from RX FIFO
wrap()
def sm0_handler(sm0):
SM0_RX_FIFO_Receive = sm0.get()
pulse_width = (0xFFFFFFFF - SM0_RX_FIFO_Receive)
if pulse_width in range(50, 65, 1): # See NMRA standard S-9.1 for source of this range
sm1.put(0b1)
print("1")
time.sleep(0.1)
elif pulse_width in range(90, 10000, 1): # See NMRA standard S-9.1 for source of this range
sm1.put(0b0)
print("0")
time.sleep(0.1)
else:
print("pulse width size error, pulse width is " + str(pulse_width) +" microseconds")
time.sleep(0.1)
sm0 = rp2.StateMachine(0, pulse_width_measure, freq=2000000, jmp_pin=Pin(16)) # sample pin as input at 2MHz or every 0.5 micro second
sm0.irq(sm0_handler, trigger=1, hard=False)
sm0.active(1) # Start state machine
### End State Machine 0 Code
### PWM Code for testing state machine
PWM_Debug = PWM(Pin(22), freq=10000, duty_u16=32768) # PWM signal at 5kHz with 50% duty cycle (high for 100 micro seconds per cycle)
# for testing, connect a jumper wire between GPIO 16 and GPIO 22
|
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 7 replies
-
@robert-hh Would you be able to help? Due to what I believe is inadequate documentation of PIO IRQ, I do not fully understand how to use PIO IRQ syntax as described above. Therefore, I am not sure if I am using PIO IRQ correctly or if there is a bug with MicroPython. Could you help with my question above? |
Beta Was this translation helpful? Give feedback.
-
A valuable source of information and example code is here (in German). There are explicit remarks and experiments regarding usage of PIO interrupts, even for communication between PIO programs on a same state machine. |
Beta Was this translation helpful? Give feedback.
-
Thank you all for you help. I now understand how to properly use PIO irq instructions and how to use the StateMachine irq. I am going to submit an issue with the following suggestions, therefore I would be grateful if you would please review to ensure I have not made a mistake. rp2.StateMachine.irqhttps://docs.micropython.org/en/latest/library/rp2.StateMachine.html#rp2.StateMachine.irq Current documentation
Recommended changes
irq(…)https://docs.micropython.org/en/latest/library/rp2.html#pio-assembly-language-instructions Current documentation
Recommended changes
Note: I incorrectly expected trigger, irq(), and irq(rel()) all use the SAME numeric value to get the trigger to synchronize with the interrupt. I found I could easily stumble across a correct combination of values for a single state machine, but when using two state machines in one program, this doubled the complexity of the combination. I needed documentation to guide me to proper use. |
Beta Was this translation helpful? Give feedback.
-
The difference between hard=True and hard=False is subtle. It tells, how the callback is called. For hard=False the callback is scheduled and executed whenever the scheduler assigns a time slot for it. With hard=True the callback is called immediately by the hardware IRQ handler. The difference: scheduled callback can use all Python features, but the execution may be delayed. With hard=True one cannot use all Python features. Especially memory must not be allocated. But the response is immediate, typically within a few µsec. |
Beta Was this translation helpful? Give feedback.
Thank you all for you help.
I now understand how to properly use PIO irq instructions and how to use the StateMachine irq.
I am going to submit an issue with the following suggestions, therefore I would be grateful if you would please review to ensure I have not made a mistake.
rp2.StateMachine.irq
https://docs.micropython.org/en/latest/library/rp2.StateMachine.html#rp2.StateMachine.irq
Current documentation
Recommended changes