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.