Glider
"In het verleden behaalde resultaten bieden geen garanties voor de toekomst"
About this blog

These are the ramblings of Matthijs Kooijman, concerning the software he hacks on, hobbies he has and occasionally his personal life.

Most content on this site is licensed under the WTFPL, version 2 (details).

Questions? Praise? Blame? Feel free to contact me.

My old blog (pre-2006) is also still available.

Sun Mon Tue Wed Thu Fri Sat
           
7
         
Powered by Blosxom &Perl onion
(With plugins: config, extensionless, hide, tagging, Markdown, macros, breadcrumbs, calendar, directorybrowse, entries_index, feedback, flavourdir, include, interpolate_fancy, listplugins, menu, pagetype, preview, seemore, storynum, storytitle, writeback_recent, moreentries)
Valid XHTML 1.0 Strict & CSS
Raspberry pi powerdown and powerup button

Raspberry Pi Zero

TL;DR: This post describes an easy way to add a power button to a raspberryp pi that:

  • Only needs a button and wires, no other components.
  • Allows graceful shutdown and powerup.
  • Only needs modification of config files and does not need a dedicated daemon to read GPIO pins.

There are two caveats:

  • This shuts down in the same way as shutdown -h now or halt does. It does not completely cut the power (like some hardware add-ons do).
  • To allow powerup, the I²C SCL pin (aka GPIO3) must be used, conflicting with externally added I²C devices.

If you want to get started right away, skip to the "Setting this up" section below.

Powering down your pi

To gracefully power down a Raspberry Pi (or any Linux system), it has to be shut down before cutting power. On the rpi, which has no power button, this means using SSH to log in and running a shutdown command. Or, as everybody usually does, cutting the power and accepting the risk of data corruption.

Googling around shows a ton of solutions to this problem, where a button is connected to a GPIO pin. The GPIO pin is monitored and when it changes, a shutdown command is given. However, all of these seem to involve a custom daemon, usually written in Python, to monitor the GPIO pin. A separate daemon just for handling the powerbutton does not sound great, and if it is not apt-get installable, it seems too fragile for my tastes. Ideally, this should be handled by standard system components only.

Another thing is that a lot of these tutorials recommend wiring a pullup or pulldown resistor along with the button, while the raspberry pi has builtin pullups and pulldowns on all of its I/O pins which can just as easily be used.


Shutdown using systemd-logind

Having a shutdown button connected to a GPIO pin is probably not so uncommon, so I Googled some more. I came across the 70-power-switch.rules udev file from systemd-logind, which adds the "power-switch" tag to some kernel event sources representing dedicated power buttons. Since v225 does this for selected gpio sources as well (commit). A bit of digging shows that:

  • The udev rules add the "power-switch" tag to selected devices. Udev does not use these tags itself, but other programs can.
  • The "power-switch" udev tag causes systemd-logind to open the event source as a possible source of power events.
  • When a KEY_POWER keypress is received, systemd-logind initiates a shutdown. It also handles some suspend-related keys.
  • Since last week, 70-power-switch.rules tags all event sources as "power-switch" (commit) and lets systemd-logind figure out which could potentially fire KEY_POWER events (commit) and monitor only those (though this change does not really change things for this usecase).

Linux gpio-keys driver

So, how to let a GPIO pin generate a KEY_POWER event? The first logind commit linked above has an example device tree snippet that sets up the kernel gpio-keys driver which does exactly that: Generate key events based on gpio changes.

Normally, the devicetree is fixed when compiling the kernel, but using a devicetree overlay (see the Rpi device tree docs) we can insert extra configuration at boot time. I found an example that ties multiple buttons to GPIO pins and configures them as a tiny keyboard. Then I found an example in the the gpio-button package that does the same with a single button and also shows how to configure a pulldown on the pin.

I've created a devicetree overlay based on that example, that sets up the gpio-keys driver with a single GPIO to trigger a KEY_POWER event. The overlay is just a text file and I added elaborate comments, so look inside if you are curious. Instructions on installing this overlay are at the end of this post.

Waking up

With the above, you get a shutdown button: Press it to initiate a clean shutdown procedure, after which the raspberry pi will turn off (note that it does not completely cut power, that would require additional hardware. Instead, the system goes into a very deep sleep configuration while still drawing some current).

After shutdown, starting the system back up means removing and reinserting the USB cable to momentarily cut power. This begs the question: Can you not start the system again through one of the GPIO pins?

I found one post that pointed out the RUN pin, present on Rpi 2 and up, which can be shorted to GND to reset the CPU (without clean shutdown!), but can also power the system up. However, having two buttons, along with the risk of accidentally pressing reset instead of shutdown did not seem appealing to me.

After more digging I found a forum post saying that shorting GPIO3 to GND wakes up the Rpi after shutdown. It also says GPIO1 should work, but I do not think any Rpi makes that pin available, so I haven't tested that. Official docs on this feature seem to be lacking, I found one note on the elinux.org wiki saying bootcode.bin (version 12/04/2012 and later) puts the system in sleep mode, and starts the system when GPIO3 goes low.

Since GPIO3 is also a normal IO pin, this is perfect: By configuring the shutdown handling on GPIO3, the same button can be used to shutdown and wake up. Note that GPIO3 is also an I²C pin, so if you need to also connect I²C-devices, another pin must be used for shutdown and you cannot use the wakeup feature. Also note that GPIO3 (and GPIO2) have external pullups at least on the Rpi Zero.

Setting this up

  1. Get and build the DT overlay. If a file /boot/overlays/gpio-shutdown.dtbo is already available on your system, you can skip this step.

    Download the devicetree overlay file. The easiest is to run wget on the raspberry pi itself:

    $ wget http://www.stderr.nl/static/files/Hardware/RaspberryPi/gpio-shutdown-overlay.dts
    

    Compile the devicetreefile:

    $ dtc -@ -I dts -O dtb -o gpio-shutdown.dtbo gpio-shutdown-overlay.dts
    

    Ignore any "Warning (unit_address_vs_reg): Node /fragment@0 has a unit name, but no reg property" messages you might get.

    Copy the compiled file to /boot/overlays where the loader can find it:

    $ sudo cp gpio-shutdown.dtbo /boot/overlays/
    
  2. Enable the overlay by adding a line to /boot/config.txt:

    dtoverlay=gpio-shutdown
    

    If you need to use a different gpio, or different settings, see the dts file for available options and the Rpi devicetree docs for setting them.

  3. If running systemd older than v225 (check with systemd --version), create a file called /etc/udev/rules.d/99-gpio-power.rules containing these lines

    ACTION!="REMOVE", SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="platform", \
        DRIVERS=="gpio-keys", ATTRS{keys}=="116", TAG+="power-switch"
    

    On systemd v225 and above (Raspbian stretch version 2017.08.16 and upwards) this should not be needed, but I have not tested this.

  4. Reboot

Then, if you connect a pushbutton to GPIO3 and GND (pin 5 and 6 on the 40-pin header), you can let your raspberry shutdown and startup using this button.

All this was tested on a Rpi Zero W, Rpi B and a Rpi B+.

This overlay was merged into the official kernel repository, so in the future step 1 above should no longer be needed. It is included in the 1.20170811-1 kernel release, which will hopefull be included in Raspbian images soon (but the 2017.08.16 image does not include it yet).

When the new kernel is included in Raspbian, it would only leave a simple modification to /boot/config.txt to set this up :-D

Comments
Gamemaster wrote at 2017-07-24 09:33

Sadly this did not work for me. However, the solution at 8bitjunkie did if you want to compare notes.

Matthijs wrote at 2017-07-24 09:41

Hm, pity. I wonder what part is failing exactly (the link you gave has a completely different software approach, so hard to compare). If you want to help out debugging this, drop me an e-mail at matthijs@stdin.nl and I'll be happy to suggest some tests to see what is failing exactly.

Windy City Jess wrote at 2017-08-03 06:13

Matthijs, I've tried many solutions with no luck. It works for me now that I followed your directions. You were right on all accounts, the RPi device-tree page you linked above is very helpful and systemd 215 did require 99-gpio-power.rules. Initially skipped over this step because I assumed it was optional. I should learn to read and follow directions :) Thank you for sharing this. - Jess

Blistex77 wrote at 2017-08-18 10:55

I've been looking for a simple solution for a while, I'm quite a noob, but it looks simple enough to achieve, thanks a lot! I have only one question, to be sure, I would only need a jumber cable and a power button (one in this kit for example www.amazon.fr/Elegoo-Composants-Electronique-R%C3%A9sistances-Potentiometre/dp/B01N0D3KTP/ref=sr12?s=computers&ie=UTF8&qid=1503046063&sr=1-2&th=1)?

Matthijs Kooijman wrote at 2017-08-18 11:31

That's correct, you basically only need something that can momentarily connect two pins together. A screwdriver would suffice, but two jumperwires (or one cut in half soldered to the button) and a pushbutton would be more obvious :-)

Blistex7 wrote at 2017-08-18 11:59

Thanks for the fast reply, I'll try this asap!

John w wrote at 2017-08-22 19:04

does the dt overlay collide with i2c? I want both. On this project ill probably resort to an on off ic but not having i2c if you want this functionality with out ic is kinda a deal breaker. pi doesnt have a lot of io to begin with

Matthijs Kooijman wrote at 2017-08-22 19:21

Yeah, this overlay collides with I²C. I haven't tried myself, but got a report from someone that ran into problems. Note that you can easily switch to another pin for the shutdown feature, you'll just lose the button-based power-on (but if you really need it, you could wire a separate reset button to the RUN pin, which should also power on after power off).

Dom C wrote at 2017-08-24 00:22

What would happen if your switch was latching?

I have s nice LED lit one around that would be perfect for this but feel it might not work in this case?

Matthijs Kooijman wrote at 2017-08-24 00:54

I believe that when the pi is powered on, it behaves like a keyboard key, so it sends a keydown when the switch is closed and a keyup when the switch is opened. I'm not sure what systemd responds to, probably both. When the pi is powered down, I believe it only responds to a falling edge, so the switch closing.

This means that if you use a latching switch, things might just work - close the switch to power up, open the switch to generate a keyup and power down. It could be that a keyup is not sufficient, or that on startup a keydown is generated. In that case, it might be needed to set the active_low flag to 0, so you get a keydown on a rising edge instead. One risk of this approach is that the pi state and the button state might become out of sync, but that should be easily fixable by just toggling the button once or twice.

Dom C wrote at 2017-08-27 19:06

I bit the bullet an bought a push-to-make button anyway. All working great until i tried to add a seperate GPIO pin for a Power LED.

I added; dtoverlay=gpio-poweroff,gpiopin=6,active_low

But this seemed to cause some kind of clash? No longer did my button (using GPIO3 as suggested) all me to power back on (although shutdown continued to work fine)

Any thoughts?

Matthijs Kooijman wrote at 2017-08-29 18:46

@Dom, I'm not entirely sure what you're saying, but if you change the pin number in the overlay, that only influences the shutdown, the power-on is hardcoded in the bootloader (or something like that). For you it seems to be reversed, which I can't quite explain?

Also, note that active_low should normally get a value of 0 or 1, and it defaults to 1 (active low). To make it active high, use active_low=0.

uzanto wrote at 2017-08-30 12:25

Thank you mate!

Working in my RPi without the udev rule.

Raspberry Pi 3 B

Raspbian Stretch with kernel 4.9.41-v7+ SystemD 232

I need to make the directory overlays inside /boot/

Simon wrote at 2017-09-01 21:42

Pi ZeroW with Stretch. This seems to shutdown kind-of (ssh and other servers become unreachable, even usb otg serial console dies) but it still responds to ping, then won't start up again. Any ideas?

Matthijs Kooijman wrote at 2017-09-04 10:11

@Simon, interesting, seems like the shutdown fails somehow. Did you install extra packages that might interfere? Does it work with a clean stretch system? Does a normal shutdown from the commandline (shutdown -h now and systemctl poweroff) work? Anything interesting in the syslogs? Perhaps redirect the primary console to serial (with the console= kernel commandline option, not sure how to set that or if that works with an USB-otg serial port) and see if anything shows there?

Arjen wrote at 2017-09-23 17:43

Is there a way to insert a delayed reaction to the button pressed? I do not want it to shut down if I accidentally hit the button, it should be pressed for e.g. 1 sec?

Matthijs Kooijman wrote at 2017-09-25 12:05

Looking at the gpio-keys documentation, it does not support a "delayed press": www.kernel.org/doc/Documentation/devicetree/bindings/input/gpio-keys.txt

However, IIRC the gpio-keys driver does generate proper keydown and keyup events, so systemd could, in theory, detect the length of a press and require a minimum length before shutting down the system. I do not think systemd supports this now, but perhaps the maintainers would be willing to add it. You could see if there's a feature request for this already at github.com/systemd/systemd/issues and, if not, add one? If you find or add one, please post the link here!

Name:
URL:
Comment:

 

 
17 comments -:- permalink -:- 10:51
Copyright by Matthijs Kooijman