I've got an Adafruit PiTFT with the buttons on, so I have the potential to use the 4 GPIOs wired up to the buttons to control stuff.

Now I followed the helpful tutorial, and have gotten the power-button kernel extension working fine on one of my GPIO click-buttons, and I also have working shell scripts that can switch or toggle the screen backlight (though the commands and what is sent where are a mystery to me), however what I would like is to have a second GPIO click button control the backlight, so I can leave the Pi running longer when it is on a battery when e.g. serving a webpage.

I wonder if there is some electrical hack that I can perform to achieve this? This is probably not possible and I would still "use up" the same GPIO ports anyway, so the only value of an electrical method to trigger the backlight if this were doable is to avoid having to tell Linux about it.

Well, going through Linux is already the only way i know of to toggle the backlight...

Moving on from that then, it seems that I will want some sort of daemon to run that can poll GPIOs and trigger events based on them. I hope this can be done without a kernel module since I'm not using it to do something ultra-privileged like powering on/off.

Now I'm not quite enough of a wizard to figure out how the rpi_power_switch kernel module works. Plus, for the purposes of this question, I am only interested in polling GPIO state from userland.

I think I am on to something with this, specifically the bcm2835 library. I guess I can write a lightweight daemon that uses this code to query the GPIOs at a low level?

  • Very interesting. 20Mhz is certainly nothing to sneeze at. – Steven Lu Apr 20 '14 at 0:21

You can use something like this python script, to poll the input, and to run the toggle-backlight script when pressed.

import RPi.GPIO as GPIO
import time
import subprocess


# set button 2 as input, with pull-up resistor
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_UP)

oldButtonState = True
while True:
    buttonState = GPIO.input(22)

    if buttonState != oldButtonState and buttonState == False :
        # print "Button 1 pressed"
        subprocess.call("/home/pi/toggle-backlight.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    oldButtonState = buttonState
  • Hey, thanks! This will be quite functional. I will be hard pressed to justify the effort involved in rolling a C-implementation of this. – Steven Lu Apr 24 '14 at 2:42
  • I wonder if there's a way to poll the GPIO for a specific state. That would be way more efficient than continually reading - even with the sleep timeout in there. – Wayne Werner Nov 29 '14 at 14:01
  • @WayneWerner You can use interrupts for that. – Gerben Nov 29 '14 at 15:46

This might be an old question, but I thought I might share my solution as well. Basically, my goal is to be able to run an arbitrary shell script using GPIO buttons that come with Adafruit PiTFT. Surprisingly, internet search does not turn up much on this topic. I was about to use a Python daemon as suggeested by Gerben and also described in details here, but then stumbled upon this write up. The basic idea is to treat GPIO pins as a virtual keyboard (apparently Unix already has a support for this), and then map events from this virtual keyboard to commands using 'triggerhappy' module. Triggerhappy comes bundled with Raspbian/Noobs, but if your system does not have it - you can install it with 'sudo apt-get triggerhappy'. Here is what needs to be done:

  1. Take a note of already available event devices. I have a touch-sensitive PiTFT and a wireless keyboard, so I've got 2 devices.
$ evtest
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event1:      ft6x06_ts
/dev/input/event2:      Logitech K400
Select the device event number [0-1]: 0
  1. Create a device tree overlay gpio.dts file with the following content (I'm mapping buttons to keys that I know I will not be using; the full list is available here):
    / {
       compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";

       fragment@0 {
          target-path = "/";
          __overlay__ {
             keypad: pitft_gpio_keys {
                compatible = "gpio-keys";
                #address-cells = <1>;
                #size-cells = <0>;
                button@17 {
                   label = "Button 17 down";
                   linux,code = <85>;
                   gpios = <&gpio 17 1>;
                button@22 {
                   label = "Button 22 down";
                   linux,code = <93>;
                   gpios = <&gpio 22 1>;
                button@27 {
                   label = "Button 27 down";
                   linux,code = <94>;
                   gpios = <&gpio 27 1>;
  1. Compile and install the file:
sudo dtc -I dts -O dtb -o /boot/overlays/gpio.dtbo gpio.dts
  1. Open /boot/config.txt and add the new overlay to the end of the file:
  1. Restart the system and verify you can now see the new even device. You can also press the mapped keys to verify the events are being generated:
 $ evtest
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event0:      pitft_gpio_keys
/dev/input/event1:      ft6x06_ts
/dev/input/event2:      Logitech K400
Select the device event number [0-2]: 0
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "pitft_gpio_keys"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 85 (KEY_ZENKAKUHANKAKU)
    Event code 93 (KEY_KATAKANAHIRAGANA)
    Event code 94 (KEY_MUHENKAN)
Testing ... (interrupt to exit)
Event: time 1516058749.600834, type 1 (EV_KEY), code 85 (KEY_ZENKAKUHANKAKU), value 1
Event: time 1516058749.600834, -------------- EV_SYN ------------
Event: time 1516058749.800839, type 1 (EV_KEY), code 85 (KEY_ZENKAKUHANKAKU), value 0
Event: time 1516058749.800839, -------------- EV_SYN ------------
Event: time 1516058751.040851, type 1 (EV_KEY), code 93 (KEY_KATAKANAHIRAGANA), value 1
Event: time 1516058751.040851, -------------- EV_SYN ------------
Event: time 1516058751.360816, type 1 (EV_KEY), code 93 (KEY_KATAKANAHIRAGANA), value 0
Event: time 1516058751.360816, -------------- EV_SYN ------------
Event: time 1516058753.590817, type 1 (EV_KEY), code 94 (KEY_MUHENKAN), value 1
Event: time 1516058753.590817, -------------- EV_SYN ------------
Event: time 1516058753.820817, type 1 (EV_KEY), code 94 (KEY_MUHENKAN), value 0
  1. Check you can see the events with triggerhappy as well:
 $ sudo thd --dump /dev/input/event*
EV_KEY  KEY_ZENKAKUHANKAKU      1       /dev/input/event0
# KEY_ZENKAKUHANKAKU    1       command
EV_KEY  KEY_ZENKAKUHANKAKU      0       /dev/input/event0
# KEY_ZENKAKUHANKAKU    0       command
EV_KEY  KEY_KATAKANAHIRAGANA    1       /dev/input/event0
# KEY_KATAKANAHIRAGANA  1       command
EV_KEY  KEY_KATAKANAHIRAGANA    0       /dev/input/event0
# KEY_KATAKANAHIRAGANA  0       command
EV_KEY  KEY_MUHENKAN    1       /dev/input/event0
# KEY_MUHENKAN  1       command
EV_KEY  KEY_MUHENKAN    0       /dev/input/event0
# KEY_MUHENKAN  0       command
  1. By default, triggerhappy runs as 'nobody', so we need to give it more rights if we want to execute anything useful (more info).
Open /etc/init.d/triggerhappy and change 'nobody' to 'pi' on DAEMON_ARGS. 
  1. Create a file /etc/triggerhappy/triggers.d/gpio.conf with the following content (can be any shell command, but for this example I'm simply printing event names to a file):
# /etc/triggerhappy/triggers.d/gpio.conf
KEY_ZENKAKUHANKAKU             1       echo "Key 17 pressed" >> /home/pi/events.txt
KEY_KATAKANAHIRAGANA           1       echo "Key 22 pressed" >> /home/pi/events.txt
KEY_MUHENKAN                   1       echo "Key 27 pressed" >> /home/pi/events.txt
  1. Reload triggerhappy:
sudo systemctl daemon-reload
service triggerhappy start
service triggerhappy reload
  1. Open events.txt and keep press the buttons to verify everything works:
tail -f /home/pi/events.txt

TROUBLESHOOTING: If you don't see what's expected at step 5 (either gpio or touchscreen is missing), make sure you are not trying to map the same key that is already mapped. By default, Adafruit maps pin 23 to shutdown, so you have to either not map it in the overlay, or unmap in PiTFT config.

  • Nice! Awesome answer (haven’t had chance to try it yet, I definitively haven’t been using the PiTFT lately due to how complicated this is, but this all seems quite scriptable). – Steven Lu Jan 16 '18 at 15:15
  • Just realized Stackoverflow gobbled all of the '<' and '>' - sorry for that, should be fixed now. The answer looks a bit involved, but you are really creating 2 small files and modifying 1 line in each of the 2 config files! – Maksym Jan 16 '18 at 16:13
  • I wonder if you know if there is a way to programmatically detect the presence of one of these SPI displays. – Steven Lu Jan 16 '18 at 16:57
  • 1
    I tried to google if somebody answered this already and found this : raspberrypi.stackexchange.com/questions/23267/… . I used that question to dump some of my ideas for detecting the screen. – Maksym Jan 17 '18 at 0:36
  • Awesome. Thank you for all the breadcrumbs! Super helpful. Really helps for us to bring out more of the latent power within this platform! – Steven Lu Jan 17 '18 at 1:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.