Jul 132013
 
RasPiTV-RPi.GPIO-EXIT

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 GPIO.cleanup()

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).

Use 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…

  1. Natural, controlled end – the program finished doing what it was written to do. Hurrah! It worked :)
  2. 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.
  3. Keyboard Interrupt – you pressed CTRL+C to stop the program. This is called a Keyboard Interrupt.

Both 2 & 3 are types of “exceptions”.

So what?

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…

GPIO.setwarnings(False)

…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...

  1. How to check what RPi.GPIO version you have
  2. How to check what Pi board Revision you have
  3. How to Exit GPIO programs cleanly, avoid warnings and protect your Pi

What next?

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® Portsplus is really useful with RPi.GPIO

The RasPiO® Portsplus board labels the GPIO ports clearly for you so that you don't need to count pins. This helps you avoid wiring errors and damage. Click the photo for more information. RasPiO Portsplus on Pi2

  30 Responses to “RPi.GPIO basics 3 – How to Exit GPIO programs cleanly, avoid warnings and protect your Pi”

  1. 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.

  2. Hallo Alex,

    following all your excellent lessons
    i encounter in Basics3 an
    AtttributeError: ‘ module’ object has no attribute ‘cleanup’

    Is this correct?

    Regards
    Olaf

    • 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

        >>>PYTHON.VERSION

        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.

  3. 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…

    • Hi AndrewS,
      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
      Olaf

      • Hurra,

        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.
        Olaf

  4. […] Part 3: “how to Exit GPIO programs cleanly, avoid warnings and protect your Pi”: […]

  5. 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.

  6. Thank you very much, it solved a lot of my problems !!!

  7. 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
          https://www.raspberrypi.org/documentation/configuration/device-tree.md

          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)
          https://www.raspberrypi.org/documentation/configuration/pin-configuration.md

        • 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.

          https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

          • 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.

  8. 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.
    Paulv

  9. 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

  10. Hi Andrew

    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?
      https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=48919

  11. Hi,

    Instead of the try/except/finally you can also do it like this:

    import atexit
    atexit.register(GPIO.cleanup)

    That’s all. It’ll GPIO.cleanup when the program exits. I put those lines right after GPIO import at the top.

    cheers,
    Beau

Leave a Reply