RPi.GPIO basics 3 – How to Exit GPIO programs cleanly, avoid warnings and protect your Pi
You might think I’m going about this series in a funny way. You’d be right! I am. That’s because I’m trying to highlight the bits that people don’t read about in other tutorials/documentation/manuals/books. These bits are useful, important and often overlooked.
If I covered inputs and outputs first, you might not get to the rest because you’d already “know all I need”. That’s only partially true though. Although you can get away with not knowing or using this stuff, it’s much better and safer if you know it and use it.
So today we’re focussing on how to exit cleanly from a program that uses RPi.GPIO
I know – I’m bonkers! I haven’t even told you how to use RPi.GPIO yet and I’m already showing you how to exit cleanly. Bear with me! It makes sense. You need to know this stuff.
Correct use of GPIO.cleanup()
RPi.GPIO provides a built-in function
GPIO.cleanup() to clean up all the ports you’ve used. But be very clear what this does. It only affects any ports you have set in the current program. It resets any ports you have used in this program back to input mode. This prevents damage from, say, a situation where you have a port set HIGH as an output and you accidentally connect it to GND (LOW), which would short-circuit the port and possibly fry it. Inputs can handle either 0V (LOW) or 3.3V (HIGH), so it’s safer to leave ports as inputs.
Here’s a simple example of how to use
import RPi.GPIO as GPIO # the rest of your code would go here # when your code ends, the last line before the program exits would be... GPIO.cleanup() # remember, a program doesn't necessarily exit at the last line!
If you use this, and the program exits normally, all the ports you’ve used will be cleaned up and ready for use straight away. But life’s not often as simple as that is it? More on that in a minute. First I want to show you…
Incorrect use of GPIO.cleanup()
I have seen people using
GPIO.cleanup() wrongly at the start of a program, thinking it will clean up all the ports on the Pi. It does no such thing.1 If you put it at the top of your script, it’s just a wasted line of code. It does nothing until you’ve set up some ports for input or output (which we’re covering soon).
GPIO.cleanup() on exit, as I’ve shown above, and in slightly more complex situations, as I will show below…
Reasons for a program exit
There are at least three reasons, that I can think of, for exiting a program…
- Natural, controlled end – the program finished doing what it was written to do. Hurrah! It worked :)
- Error – something went wrong and the program “throws a wobbly” and “errors out”. Either a process failed in an unforeseen way, or there was a coding error in the program.
- Keyboard Interrupt – you pressed
CTRL+Cto stop the program. This is called a Keyboard Interrupt.
Both 2 & 3 are types of “exceptions”.
The problem is that, unless you code for these situations, any ports which are in use at the time of an error or Keyboard Interrupt will stay set exactly as they were, even after the program exits.
That’s an out of control situation – unacceptable, when you’re trying to take over the world with GPIO programming! Everything has to be under control.
If you then try to run the program again, when you try to set up the ports that are “still set” you’ll get warnings that the ports are “already in use”.
Switch off the warnings?
You can switch off the warnings, but that’s the “chicken’s way out”. It hides the problem, but doesn’t solve it. Still, you may choose to do it, so here’s how you do. Just place…
…near the top of your script, before you start setting up any ports.
Let’s try: a better way
My preferred method to catch errors and Keyboard Interrupts uses a try: except: block.
If you put your main piece of code in a try: block, it won’t “bomb straight out” of the program if an exception occurs (something doesn’t go according to plan).
You can specify different types of exceptions, including KeyboardInterrupt, and/or have a general one to catch every exception. There’s a list of Python Exceptions here. I’ve only ever used a couple of them.
Have a look at the code below to see how the exceptions are coded…
import RPi.GPIO as GPIO # here you would put all your code for setting up GPIO, # we'll cover that tomorrow # initial values of variables etc... counter = 0 try: # here you put your main loop or block of code while counter < 9000000: # count up to 9000000 - takes ~20s counter += 1 print "Target reached: %d" % counter except KeyboardInterrupt: # here you put any code you want to run before the program # exits when you press CTRL+C print "\n", counter # print value of counter except: # this catches ALL other exceptions including errors. # You won't get any error messages for debugging # so only use it once your code is working print "Other error or exception occurred!" finally: GPIO.cleanup() # this ensures a clean exit
If you let the program run for ~22 seconds, it will count up to 9 million, tell you it reached its target, clean up any GPIO ports you've used and exit normally. This is the code within the
try: block (lines 8-13).
The code in the
except KeyboardInterrupt: block (lines 15-18) covers the CTRL+C situation. So when you press CTRL+C, it prints the current value of
counter, cleans up any GPIO ports you've used, and exits.
The code in the
except: block (lines 20-24) covers all other exceptions - including program errors. So if another exeption occurs, it warns you, cleans up any GPIO ports you've used, and exits.
This program will run until it finishes, or a keyboard interrupt or other exception occurs. Whichever of these occurs, the
finally: block (lines 26-27) will run, cleaning up the GPIO ports on exit.
Also note, that we haven't actually used any GPIO ports here, so the cleanup isn't really doing anything yet, but this is a template you can use when we do start using ports.
If you want to try it out, it's a bit long for a live Python session, so you could retype it, or cut and paste it into a program as we did in the first post in this series...
Now you know how to exit an RPi.GPIO program cleanly, without leaving a trail of uncontrolled ports behind you.
That's about it for the preliminaries
So now we've covered...
- How to check what RPi.GPIO version you have
- How to check what Pi board Revision you have
- How to Exit GPIO programs cleanly, avoid warnings and protect your Pi
Tomorrow, we're actually going to set up the GPIO, talk about different pin/port numbering schemes and take a look at reading inputs.
1 If it did clean up all the ports, this would mean you could have major conflicts between different programs, which might not even be trying to use the same ports. Clearly, not a desirable situation!
RasPiO® GPIO Reference Aids
Our sister site RasPiO has three really useful reference products for Raspberry Pi GPIO work...
Instead of duplicating the cleanup() call in 3 places why not just put it in a finally block?
Good question. And the answer is…
because I didn’t know how to use it. I do now though ;) I’ve just read up on “finally”, although I’d heard of it before, I wasn’t quite sure of the usage.
Thanks for the tip – I’ve updated the script and the blog post to incorporate it.
following all your excellent lessons
i encounter in Basics3 an
AtttributeError: ‘ module’ object has no attribute ‘cleanup’
Is this correct?
What version of RPi.GPIO are you running? See RPi.GPIO basics part 1 to find out.
find /usr | grep -i gpio says RPi.GPIO-0.5.3a but when i check
get allways above error message.
This python Installation obviously is faulty, even after update and upgrade the latest Raspbian.
Now used another os-installation without too much application installed and all is OK.
Apparently, if you installed RPi.GPIO using a .deb at some point in the past, it needs to be manually removed or it can cause conflicts. I’m not entirely sure how to do that.
According to comments on http://code.google.com/p/raspberry-gpio-python/issues/detail?id=4 you can get the same error if you install RPi.GPIO via pip as well as apt-get (the latest versions of Raspbian include RPi.GPIO pre-installed via apt-get).
AIUI pip and apt-get are independent install/packaging systems, and neither is aware of the other, so if you’ve installed RPi.GPIO both via pip *and* via apt-get then you might get into confusing situations…
I’m shure i have done this in the past without thinking about a conflict. In general python is working
properly in this Installation. I’am only confused about the above error message.
Alex and AndrewS thank you for the answers
sudo pip install RPi.GPIO –upgrade
…also repaired my python RPi.GPIO.
A Version 0.4.0 is now replaced by 0.5.3a
thanks for the link.
[…] Part 3: “how to Exit GPIO programs cleanly, avoid warnings and protect your Pi”: […]
Thanks for posting this – it’s saved me from keep blowing my transistors whenever I exit my glockenspiel control program. I’ve linked it into my blog too.
Excellent. I enjoyed your video yesterday. Great project. Glad this helped. :)
Thank you very much, it solved a lot of my problems !!!
What a lot of users don’t seem to know is that several port settings are stored in non-volatile memory, probably EEPROM. This means that if you do not clean-up after your program, en power cycle the Pi, you will not get a warning that the port is still in use.
If you experiment a lot with the GPIO ports, and are sloppy about the clean-up, you can have a situation by which several ports have settings like input/output pull-up/down that you may be unaware off.
If you write a simple program that programs all ports to input with no pull, you can remedy that situation.
Oh, did not know that! I always thought a power-cycle reset everything.
Can you point to references / documentation / further info please?
Far too many people have the impression that a power cycle removes the programming.
This is a function of the chip, look for the BCM reference manual. I don’t have a link ready, but you can Google it. I guess this is a feature that is handy for other applications of the BCM, like set-top boxes, where the ports can be programmed in the factory to have a known state, usefull if it drives hardware that needs it.
A newer feature of the clean-up command is also that you can give an individual port, or port range to clean. Like GPIO.cleanup(4).
Again this is handy if you want your connected hardware to always see a known state at boot time at certain ports. This is mostly usefull for pull-up/down settings for connected hardware that drives serious stuff like motors, thermostats, etc.
I suggest that all output settings for ports are always cleared to input under your control, to avoid damage to the port.
Isn’t this one main advantage of HATs? That you can set up the ports on boot exactly how they are needed.
Yup, using a device-tree file stored in the EEPROM on the HAT
But even if not using a HAT, you can still force specific pins into specific states at power-on (i.e. before the Linux kernel even gets loaded)
Yes Alex, but that’s not very easy for most beginners.
I looked up the BCM information, go to this link and then to chapter 6 for the GPIO details.
Oh, btw, whenever it says Reg or Register in the diagram, that means stored in EEPROM or something similar.
I’ve just looked at Chapter 6 in that PDF, and every single register is listed with “Reset: 0”, which I assumed to mean that every register would have the value 0 after the CPU has been reset (i.e. the Pi has been power-cycled) ? I’ll have to do some experimentation this evening… ;-)
I’m fairly sure they’re CPU / SoC registers rather than EEPROM registers, as I don’t think EEPROM would be able to be read/written fast enough?
Doh, just found the relevant section in the PDF… on page 100 it says
“Note that it is not possible to read back the current Pull-up/down settings and so it is the
users’ responsibility to ‘remember’ which pull-up/downs are active. The reason for this is
that GPIO pull-ups are maintained even in power-down mode when the core is off, when
all register contents is lost.
The Alternate function table also has the pull state which is applied after a power down.”
So it’s only the pull-up/down state that is latched, not the contents of the registers.
I just learned today that my earlier observation was incorrect. I cannot explain what happened at the time, but today I proved myself wrong. The pull setting does not survive a complete power cycle. It does however survive a Halt or Restart operation, as long as there is some form of power to the Pi. This could happen when you have an HDMI cable connected to the Pi.
I humbly apologize for misleading you all.
Let (s)he who has never made a mistake cast the first stone. We all get things wrong. No worries.
I was still confused about what I thought I measured and observed earlier in relation to the GPIO pad behavior. It turns out that the recent kernel change, using the Device Tree feature, changed some things. I could not find any details, so I investigated this a bit more and wrote my findings in a post on the raspberrypi forum. Here is that link : https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=112403&p=770169#p770169
I’m not able to fully answer your question, but for the pin-state when no SD-card is inserted, see the “Pull” column of http://elinux.org/RPi_BCM2835_GPIOs (which is copied from the PDF you linked to earlier).
Yes I know, but the interesting questions to me is…how do they configure the pulls high by default?
If all the GPIO pads are alike, and according to the BCM datasheet they are, how is it then that GPIO4, 7 and 8 can be set high as default (without any code running)?
If (IF) all pads are alike, then there is a way that the other pads can be set high that way too.
The more interesting question then becomes how we (as users) do that, and furthermore, why is it hidden or, as I still believe, taken away?
My only explanation at this point is that there must be some form of EEPROM that is used to store the pulls and can be configured to survive power cycles.
The way I understand it, is that all GPIO pads are alike, except that (with no code running) some GPIOs default to pulling high, and other GPIOs default to pulling low. I believe this is just a feature of the BCM2835, and there’s no EEPROM that “configures” this.
If you’re curious as to what *is* stored in the SoC’s One-Time-Programmable memory (revision number, serial number, etc.) have a look at the “vcgencmd otp_dump” command.
I suspect your confusion with firmware versions and DeviceTree might simply be that more recent firmware versions are simply more rigorous at setting all pins to a “known state” during bootup, rather than just leaving them “undefined” as earlier firmware versions did? But again that’s just me guessing… ;-)
It’s a bit old now, but I recently stumbled across this forum thread, which reminded me of the discussion that we’d had here. Dunno if it helps clarify things?
Instead of the try/except/finally you can also do it like this:
That’s all. It’ll GPIO.cleanup when the program exits. I put those lines right after GPIO import at the top.
How can you use GPIO.cleanup() on system shutdown when you’ve got a Python script that runs continuously through something like
Is there a way for the script to detect system shutdown (and then run GPIO.cleanup()) while the script is waiting for GPIO.wait_for_edge to detect something?
See the ‘atexit’ comment immediately above yours.
But if the Pi is being shut down, then there’s no real need to do a ‘GPIO cleanup’ ?
Uhm, does the Pi automatically do a GPIO cleanup on shutdown? Never new that…
Well, in that case I only have to write code that does a cleanup after doing a ctrl+c or if the script ends because of an error in the code. So all I need is “except KeyboardInterrupt:” for ctrl+c and “except:” for the programming error? Or can atexit handle both?
In effect, all GPIO cleanup does is reset all currently-used pins back to a known state and marks them as ‘unused’. And each time the Pi boots up, the firmware also resets the pins to a known state. And of course when the Pi is switched off, all the GPIO pins are ‘inactive’ ;)
Apart from the few special cases mentioned in the documentation, the atexit handler is run *every* time your program terminates, whether normally or via KeyboardInterrupt or any other exceptions etc.
Okay, thanks :)
how do you recover your GPIO after you exited a program with and led running can you clear the ports
I have python app started as a service by the script in /etc/init.d. Do you have an idea how to call gpio.cleanup() on `service myservice stop`. The stop action simply calls “start-stop-daemon –stop –pidfile $PIDFILE –retry 10” but it probably sends TERM signal, so “finally” is not called. In the result service is stopped, but pins stays in their last state.
Does the atexit handler discussed earlier do what you’re after?
Thanks! I didn’t read the comments before ;)
I’ve tested atexit, but it doesn’t work for me. Instead I’ve registered handlers with signal.signal(signal.SIGTERM, handle_exit) and now it works. I’ve described my solution here http://aknowakowski.blogspot.com/2016/05/raspberrypi-python-service-exit-nicely.html
Why not leave the state to what it originally was? for example, if I’m configuring pins at bootup using device tree, after I finish executing a GPIO related program, all used pins are reset to input instead of the the config specified in the device tree. Suggestions to get around this other than manually setting the pins back to the original state?
“Suggestions to get around this other than manually setting the pins back to the original state?”
I suspect that’s the only workaround. None of the GPIO libraries bother “remembering” what state the GPIO pins were in when they first get loaded. (And there’s some GPIO features like pull-state which are write-only, so there’s not even any way for the GPIO libraries to read what state the pullups/pulldowns are in when they first get loaded.)
I’ve been working on a program since yesterday that I need to run perpetually in the background (except when I kill it with signals or CTRL+C during testing).
I saw the post from beau dated July 19, 2015 at 2:50 am that shows how to use atexit, but the Python atexit documentation says it does not do anything for signals not handled by Python. I’m not sure exactly what that means, but I’m using the signal module (thanks to https://nattster.wordpress.com/2013/06/05/catch-kill-signal-in-python/). When a signal is processed by the signal module, finally is run, but when the signal module isn’t set up to capture a signal, finally is not. Given this, I got rid of try-finally and I am doing this instead:
def exit_handler(signal, frame):
Special thanks to all. This was a great discussion for me. Appreciate all question, answers and comments.
I still get the warning on next run of my program even when I call GPIO.cleanup() in a finally block.
Awesome Man! Thank you so much!
can you give me solution , i still get that warning after i place gpio clean up and set warning false in the start and the end of program.
i use raspi using PyQt and multiple windows … please help me i gotta a dead line … thankss