Pin interrupts and getting the value of the PIN state WHEN the ISR occurred
Posted: Tue Apr 28, 2020 3:35 am
Background: I'm writing code in MicroPython to process data from a sensor that interrupts pretty quickly. However, I'm getting strange behavior in the ISR. I'm running the code on an ESP32, which if I write similar code in C works fine. Also similarly written C code works pretty well on a bone stock Arduino Uno, so the HW is more than capable of handling the interrupt load. However, I want to write it in Python.
Is there a way to read what the value of the pin was AT THE TIME the isr routine was called. Obviously, I tried disabling interrupts, but that didn't seem to make any difference at all, and I know that calling print in an ISR is very bad, but it was the only way I could easily demonstrate the issue. Also, it does seem to behave slightly better by NOT disabling interrupts, but it's still not good enough to actually get the value of the pin.
Am I asking too much to use MicroPython to measure how long a digital pin is held HIGH/LOW? A very simplified version of what I'm trying to do is below (error-handling and other biz-logic removed).

Code: Select all
from machine import Pin, disable_irq, enable_irq
import micropython
from utime import sleep
def isr(p):
state = disable_irq()
pin_state = p.value()
if pin_state != p.value(): # XXX - I'm reading the value of the pin immediately, and a large percentage of the time the value is different
print("<Boo>", end="")
enable_irq(state)
def main():
micropython.alloc_emergency_exception_buf(100)
sensor = Pin(25, Pin.IN)
sensor.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=isr)
while True:
sleep(1)
print(".", end="")
if __name__ == "__main__":
main()
Am I asking too much to use MicroPython to measure how long a digital pin is held HIGH/LOW? A very simplified version of what I'm trying to do is below (error-handling and other biz-logic removed).
Code: Select all
import array
from machine import Pin
import micropython
from utime import sleep, ticks_us, ticks_diff
NUM_VALUES = 128
data_to_process = False
prev_time = ticks_us()
values = array.array('i', (0 for _ in range(NUM_VALUES)))
value_idx = 0
def isr(p):
global data_to_process, prev_time, values, value_idx
curr_time = ticks_us()
# Only capture new data if we've processed the old data
if not data_to_process
len = ticks_diff(curr_time, prev_time)
# Capture if the value was HIGH/LOW
if p.value() == 0:
len *= -1
# There's a bit more biz-logic here, but it's pretty simple (comparisons)
values[value_idx] = len
value_idx += 1
if value_idx == NUM_VALUES:
data_to_process = True
prev_time = curr_time
def process():
global data_to_process, values, value_idx
if not data_to_process:
return
# Will be smarter in the real code
for i in range(len(values)):
print("c[{}]={}".format(i, values[i]))
print("")
# Reset the data so we can capture more!
value_idx = 0
data_to_process = False
def main():
micropython.alloc_emergency_exception_buf(100)
sensor = Pin(25, Pin.IN)
sensor.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=isr)
while True:
sleep(1)
process()
if __name__ == "__main__":
main()