I'm experimenting with GPIO access from Python on an embedded system (ARM core), which is running linux built with Buildroot (kernel 4.1.15).
I want my code to BLOCK waiting for a pin change on GPIO2 (i.e. I don't want to poll the pin by calling "read" repeatedly). I'm trying to do this using "epoll" in edge-triggered mode:
See Python docs for epoll. select.EPOLLET flag is used to get edge triggering for epoll. See also Linux docs for epoll.
For simplicity, I've already set up my GPIO pin from the console, using sysfs:
# cat /sys/class/gpio/gpio2/direction
in
# cat /sys/class/gpio/gpio2/edge
rising
Here's my Python code:
#!/usr/bin/env python
# coding=utf8
from time import sleep
import select
import sys
if __name__ == '__main__':
try:
pinIn = open("/sys/class/gpio/gpio2/value", "r")
except IOError:
print("Error setting up GPIO pin")
sys.exit()
myPoll = select.epoll()
myPoll.register(pinIn.fileno(), select.EPOLLPRI | select.EPOLLET)
while(1):
events = myPoll.poll(4)
print("EPoll result: %s" % (str(events),))
for fd, event_type in events:
print("FD: %d; Events: %d" % (fd, event_type))
if event_type & select.EPOLLIN:
print("-EPOLLIN!")
if event_type & select.EPOLLPRI:
print("-EPOLLPRI!")
if event_type & select.EPOLLERR:
print("-EPOLLERR!")
value = pinIn.read(1)
pinIn.seek(0)
print("--> %s" % (str(value),))
sleep(1)
For testing, I am feeding the input pin with a square wave from a signal generator at about 2 seconds per cycle, so I can see when the pin changes.
When I run this on my embedded system, I get this:
# python3 /usr/sbin/test-gpio-python.py
EPoll result: [(3, 10)]
FD: 3; Events: 10
-EPOLLPRI!
-EPOLLERR!
--> 0
The code sleeps on the 1 seconds sleep, then on the next iteration, the poll() immediately returns and doesn't block. It should block since my input is only operating at one rising edge per 2 seconds.
Why isn't "poll()" blocking?
==== EDIT: ====
Originally, the code caused a weird error when I tried to use "select.EPOLLET":
OverflowError: can't convert negative value to unsigned int
However, I discovered that I had accidentally used myPoll = select.poll() instead of epoll(). Code now fixed.
I decided to check the interrupt information by looking at /proc/interrupts.
Here it is, only a couple of seconds after setting edge to "rising" for the GPIO pin:
Hmm, 421 interrupts have occurred already!
Two seconds later:
That could explain it. Interrupts are piling up at ~400 per second, definitely faster than I am processing them in Python.
Further investigation with a scope showed that the signal generator was only putting out about 1.6 V, and it looks like noise was triggering the input circuit on the device.
When I switched to the correct signal generator output and got a clean signal on the GPIO pin, I started getting the expected number of interrupts, and the python code worked correctly (i.e. poll() blocked correctly between rising edges on the input).