Friday, October 31, 2014

55. Exploring the Pi B+'s GPIO Ports I - The J8 Header

24,000 page views!!
Before I start this blog post, I would like to acknowledge the great contribution to the subject by Alex Eames, of RasPi.TV, who has blogged most of what I have done below.  As usual I have described my take on the things that I learn, this time on the various lessons Alex has described.  Much of what follows here has been taken from Alex's work.  My record serves as a reference for myself, while hopefully being of possible use to other enthusiasts interested in exploring the Raspberry Pi.


As my Raspberry Pi Model A is dedicated to my PiBot, and my Model B is tied up with the windguru project (I have a duplicate system at home, as well as one at the yacht club), I had a good excuse to buy the latest Model B+ Pi (see description HERE).  The detailed differences and improvements on this latest model are explained elsewhere, but basically, there are now 40 pins on the GPIO header, and these are summarised below:

I have added in the alternative functions of ports where they apply, to Alex's diagram. I took advantage of the opportunity to dress my Pi up in a swanky hot-chilli red Pibow Coupé case (available from Pimoroni HERE), which protects it from dust and other hazards like spilled tea, falling screwdrivers, curious cats, etc.  The Pibow case has convenient openings for connections, and the opening for the 40 GPIO pins has the pin port numbers etched beside them:


I even went one step further and treated myself to a Cyntech B+ 40-way Paddle Board (HERE), which makes it easier to get access to the GPIO ports.  This board allows connection of jumper wires, by pushing the orange tabs down, inserting the wire (which needs to be stripped at the end to a length of about 10mm).  Pre-manufactured jumper wire connector ends are not long enough.  However, when stripped wire is connected, a very reliable connection is achieved:


I have connected the rainbow ribbon cable to the Pi's J8 header "the wrong way round" as it makes the whole experiment's footprint smaller.  I discovered that it is necessary to push the 40-pin connector onto the Paddle Board and through the Pibow case onto the Pi, very firmly, otherwise you can get a 'floating terminal', possibly made worse by an aerial effect from the ribbon cable.



What this Example Does:

There are 4 buttons, referred to as Button 0 (top) and Buttons 1, 2 and 3 at the bottom. These buttons are wired to GND on one side, and on the other terminal, connections are made to GPIO ports 20, 21, 22 and 23 respectively.  The RGB LED's common cathode runs to GND via a 325 resistor, so that not too much current is drawn from the Pi.  The red, green and blue anodes are wired to the Pi's GPIO ports 24, 25 and 26.


The Code Explained:

When the code runs, it firstly prints the message that it is waiting for Button 0 to be pressed to terminate the program.  If Button 1 is pressed, the red LED lights up, Button 2 illuminates the green LED and Button 3 switches the blue LED on.  These 3 can be pressed randomly ad nauseum, lighting up the respective LEDs.  When you get bored, you can press Button 0 and the program will terminate.  CTRL-C will also terminate the program.

Rather than go through the Python programs as I came across them on Alex's blog, I will start with a fairly advanced example of my own and try to explain what the code means:

Firstly, let's see what circuit this code works with.  The four buttons on the breadboard are Button 0 (at the top) then Button 1, Button 2 and Button 3 (at the bottom):


Let's look at the script in detail, so that all aspects of the code can be explained:


Lines 1 & 2:
1 #!/usr/bin/env python2.7
2 # script by Sparks N Smoke based on Alex Eames at http://RasPi.tv

These two lines, beginning with a #, are descriptive comments.  These comments are always a good idea to indicate the language, acknowledgements etc. However there's a bit more to it than that. the characters #! in Line 1 is what's known as a shebang (or a hashbang) - although it starts with a #, the normal indicator for a comment, the program loading software uses this information to run the script with the specified version of Python. The Pi currently comes with 2 versions of Python, so the line beginning with the shebang identifies which version is to be used and where it is on the Pi's file system.


Line 4: 

4 import RPi.GPIO as GPIO

This line imports the Python module RPi.GPIO and calls it GPIO for future reference in the script.


Line 5:

5 from time import sleep

This is an instruction to the Python interpreter to go to the Python module time and load the sleep part of it, for use later on.


Line 6:

6 GPIO.setmode(GPIO.BCM)

There are two possible modes of referencing the GPIO pins - GPIO.BOARD for pin numbering (see the pin chart above), and GPIO.BCM for Broadcom GPIO numbering.  The choice of numbering mode is usually a personal preference, but as I needed to refer to the GPIO numbers, I have used the GPIO.BCM mode.


Lines 8 to 11:

8 GPIO.setup(20, GPIO.IN, pull_up_down = GPIO.PUD_UP)                   # Button 0
etc
 

This line sets up the GPIO20 pin as an input, and invokes the in-built pull-up resistor.  In a similar way, lines 9, 10 and 11 do exactly the same thing for GPIO21GPIO22 and GPIO23.  These pins are where the 4 physical buttons are connected.


Lines 13 to 15:

13 GPIO.setup(24, GPIO.OUT)                                                                     # LED Red
etc

This line sets up the GPIO24 pin as an output.  In a similar way, lines 14 and 15 do exactly the same thing for GPIO25 and GPIO26.  These pins are where the respective anodes of the RGB LED are connected.

Lines 17 to 21:

17 def my_callback1(GPIO24):
18         GPIO.output(24, 1)                                                                     # Red ON
19         sleep(0.5)

20         GPIO.output(24, 0)                                                                     
# Red OFF
21         print "BUTTON 1 PRESSED - main thread interrupted by another thread"

These lines define a function called my_callback1 which puts the GPIO24 pin in a HIGH state, thus switching on the RED element of the RGB LED.  I have specified the argument (in the brackets) as the GPIO port, although the word "channel" which Alex uses, also works. Presumably the dummy value satisfies the need to have something there.  Line 18 keeps the state the same for half a second, Line 20 then puts GPIO24 in a LOW state, turning off the RED element and Line 21 puts the message on the screen to indicate that a particular button has been pressed.  


Similarly, lines 23 to 27 and 29 to 33 do the same for GPIO25 and GPIO26.  The functions my_callback1, my_callback2 and my_callback3 are only executed when other lines of code call for them by name.  However, when they are executed, they run in a different thread.  This means that two things are running at the same time.


Lines 35 to 37:

35 GPIO.add_event_detect(21, GPIO.FALLING, callback = my_callback1, bouncetime = 300)
etc

This line sets up the ability to detect an event on pin GPIO21 - Button 1, that event being the fall from a HIGH state to a LOW state, of pin GPIO21.  This is where the callback function my_callback1 is invoked.  A further interesting argument is bouncetime = 300.  What this does is to compensate for switch bounce, where the switch actually makes contact more than the intended once per press.  If there are any bounces within 300 milliseconds (in this case), they will be ignored.

Lines 36 and 37 set up event detection for GPIO22, (Button2) and GPIO23
 (Button 3)

Lines 39 to 48:

39 try:

40     print "Main thread waiting for falling edge on port 20 - ie BUTTON 0"

41     GPIO.wait_for_edge (20, GPIO.FALLING)

42     print "Falling edge on port 20 detected. BUTTON 0 PRESSED"                                

44 except KeyboardInterrupt:

45     GPIO.cleanup() # Reset ports on CTRL-C


47 finally:

48     GPIO.cleanup() # Reset on normal exit

This is the main "thread" of the program, where the Pi's processor is in a relatively idle state, just waiting for something to happen.  The event it is waiting for is when pin GPIO20 - Button 0, falls from its initial HIGH state to the LOW state, that is, when the button is pressed.

When Button 0 is pressed, the execution of the code jumps to Line 47 and 48, where all the GPIO ports are reset to an initial LOW state, ready for other programs to be executed without receiving a message stating that the port it wants to use is already in use.

There is an exception to this flow - when CTRL-C is pressed on the keyboard.  This is called a keyboard interrupt and it will terminate the program, but only after Line 45 is executed - cleaning up the GPIO ports.

The program uses the method known as Threaded Callback Interrupts where the callback functions run in a separate thread from the main program.  This is less demanding on the processor as most of the activity is in a fairly idle state.

An alternative and simpler method is to use Polling, where a while True loop keeps running until an event happens like a button press.  The CPU activity is shown in the bottom right of the Pi's desktop.  The image below shows the desktop for the current Threaded Callback Interrupts.  


Compare the CPU indicator with that for an earlier one-button Polling program:



This heavy use of the processor would presumably consume more power - a point that is important when using batteries.

Thanks Alex !

No comments:

Post a Comment