Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiency of infinite loop to service GPIO

I'm using Python on Raspbian (a type of linux) on the Raspberry Pi (an embedded processor board) to monitor GPIO inputs.

See simplified version of my code below. I have an infinite loop in the python script waiting for something to happen on a GPIO i/p. Is this the correct way to do it? I.e. does this mean that the CPU is running at full whack just going round this loop, leaving no CPU cycles for other stuff? Especially as I need to be running other things in parallel (e.g. the browser).

Also what happens if the CPU is busy doing something else and a GPIO i/p changes? Does the GPIO event get stored somewhere so it is eventually serviced, or does it just get lost?

Is there a better way of doing this?

(For your answers, please note that I'm new to linux, and v. new to python and real-time programming)

#!/usr/bin/python
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def ButtonHandler(channel):
    print "Button pressed " + str(channel)
    # do stuff here

GPIO.add_event_detect(16, GPIO.FALLING, callback=ButtonHandler, bouncetime=200)

while True:
    pass
like image 769
spiderplant0 Avatar asked Aug 09 '13 23:08

spiderplant0


1 Answers

Yes, doing while True: pass will burn 100% of your CPU (or as close to it as possible) doing nothing.

From what I understand (hopefully this is documented somewhere), the RPi.GPIO module spawns a background thread that waits on the GPIO and calls your callback function for each event. So your main thread really has nothing to do. If you want this to run as a service, make it sleep for long periods of time. If you want to run it interactively (in which case you probably want it easier to cancel), sleep for shorter periods of time, maybe 0.5 seconds, and add some way to exit the loop.

It would be even nicer if you could do the GPIO select in the main thread, or get a handle to the GPIO background thread that you can just join, either of which would burn no CPU at all. However, the module doesn't seem to be designed in a way to make that easy.

However, looking at the source, there is a wait_for_edge method. Presumably you could loop around GPIO.wait_for_edge instead of setting a callback. But without the documentation, and without a device to test for myself, I'm not sure I'd want to recommend this to a novice.

Meanwhile:

Also what happens if the CPU is busy doing something else and a GPIO i/p changes? Does the GPIO event get stored somewhere so it is eventually serviced, or does it just get lost?

Well, while your thread isn't doing anything, the GPIO background thread seems to be waiting on select, and select won't let it miss events. (Based on the name, that wait_for_edge function sounds like it might be edge-triggered rather than level-triggered, however, which is part of the reason I'm wary of recommending it.)

like image 104
abarnert Avatar answered Oct 25 '22 02:10

abarnert