Sunday, May 22, 2016

Event driven GPIO with Python on UDOO

In the previous post, a shell script was used to read periodically on a GPIO pin for input.  That could be inefficient and in the worst case missing the input completely.



Using the same hardware design as in previous post, we can change the software part to a more efficient event driven approach.  First, setup the GPIO pin (GPIO 42 in this example) as input:

echo 42 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio42/direction
echo falling > /sys/class/gpio/gpio42/edge

Note that on UDOO, GPIO pins can be set to trigger interrupt when the value change.  Here, we set the "edge" as "falling" to indicate that we want to be notified when the input change from 1 to 0.  You can also set it as "rising" or "both" to suit your needs.  You can also change the value in the file "active_low" to reverse the order.  See the Sysfs document for details.

With the GPIO pin setup properly, we can use a Python script to wait for input using Linux epoll(7):

import sys
import os
import select
import time
import datetime

if len(sys.argv) < 2:
    print('Missing gpio')
    sys.exit(1)

fd = None
e = None
ignore = True
gpio = sys.argv[1]

try:
    fd = os.open("/sys/class/gpio/gpio%s/value" % gpio, os.O_RDONLY)
    e = select.epoll()
    e.register(fd, select.EPOLLIN | select.EPOLLET)

    while True:
        events = e.poll()
        if not ignore:
            for fd, event_type in events:
                print(datetime.datetime.now().isoformat() + " event_type " + str(event_type) + " detected on " + str(fd))
            break
        ignore = False

finally:
    if e is not None:
      e.close()
    if fd is not None:
        os.close(fd)


We register the GPIO pin with a epoll object.  Since we want to wait till the value change from 1 to 0, we used the flag select.EPOLLET to use edge-triggered instead of the default level-triggered mechanism.  Then the program enters an infinite loop to wait for the value change.

Note that the first trigger is ignored as epoll returns immediately on the first call.

Also, you can register multiple GPIO pins with the epoll object.  Check the (file descriptor, event type) tuple returned by poll() and you can handle the case differently.

The whole Python script will not return until the GPIO input changed from 1 to 0.  To use it to trigger a shutdown, create a shell script similar to the following to setup the GPIO pin and wait for the Python script to return. Run the shell script on every reboot using systemd.  For details, refer to the previous post.

#!/bin/sh

GPIO=42

echo $GPIO > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio$GPIO/direction
echo falling > /sys/class/gpio/gpio$GPIO/edge

/usr/bin/python /root/scripts/pwrbtncheck/poll.py $GPIO
if [ $? = 0 ]
then
  echo "Shutdown button pressed"
  /usr/bin/sync; /usr/bin/sync; /usr/bin/shutdown -h now
fi




Yes. 42 is "The Answer to the Ultimate Question of Life, The Universe, and Everything" :)

No comments: