Raspberry Pi GPIO via the Shell

In my last post I mentioned my interest in using the Raspberry Pi as a microcontroller. I figured it would be easy to access the GPIO capabilities of the Pi, since most devices on Linux can be manipulated directly through the filesystem.

So when I first booted up my Pi I was surprised to not find anything relating to GPIO in the /dev directory, where block and character device nodes typically reside. However, I did notice a directory, /sys/class/gpio (/sys is a special in-memory directory that contains metadata about hardware devices; like /dev, it doesn’t actually exist on disk). By manipulating the files in this directory I was able to control the GPIO pins of the Pi.

The filesystem is only one way of accessing GPIO. It is also accessible through libraries or by writing directly to an address in memory, but I like the idea of the filesystem as it is readily accessible from any programming language and even the command-line.

The /sys/class/gpio folder contains two files, export and unexport, and a subdirectory called gpiochip0. Typing cat /sys/class/gpiochip0/ngpio into the shell will output the number of logical GPIO pins on the CPU, which is 54. Why so high a number? There are only 17 pins exposed on the GPIO header, but the CPU itself has many other pins that are not connected or are used to control other devices on the Pi.

The CPU pins that you can use for GPIO are 0, 1, 4, 7-11, 14, 15, 17, 18, 21-25 (pins 0, 1, and 21 become 2, 3, and 27, respectively, if you have the Revision 2 Pi). These numbers have nothing to do with the position of the pins on the GPIO header itself. Additionally, certain projects, such as such as Gordon Henderson's WiringPi library, have adopting their own simplified numbering schemes. If you're confused, there is a nice wiki article with a diagram that can help clear things up. It's worth noting that some of the pins support more advanced I/O modes, such as RS-232 (serial), SPI, I2C, PWM, and clock, none of which I've attempted to use as of yet.

To access any of these pins we first have to export them to the filesystem using the export file I mentioned above – for some reason they are not exposed by default. So if we want to be able to access pin 4, we would type echo 4 > /sys/class/gpio/export (all these commands must be run as root). This would cause a new directory entry, /sys/class/gpio/gpio4, to appear in the filesystem. There are several items in the gpio4 directory, but of immediate interest are direction and value. To specify that we want to use the pin as an output, we can do echo out > /sys/class/gpio/gpio4/direction. Then we can set the pin high or low by echoing a 0 or 1, respectively, to /sys/class/gpio/gpio4/value.

One of the mistakes that I made when I first started playing with the GPIO pins was thinking of them as either on or off (as I was taught to think of computers). In reality, a digital logic signal is either high (3.3V) or low (0V); both states allow current to flow between the pins, from high to low. Each of the GPIO pins is limited to 15mA, which is not very much current – your average LED is rated for a maximum of 20mA. Connecting the pins to a circuit without sufficient resistance (or to the 5V power pin) may damage the Pi. The 3.3V power pin is limited to 50mA (all these limits are discussed on the wiki page I previously linked to).

I decided to create a simple utility script for working with GPIO so that I don't have to repeat the filesystem paths in all my scripts. The script can be called the command-line, or it can be sourced from within another script to allow direct access to its gpio function. It also allows the pin numbering to be remapped with the GPIO_PINS environment variable. Using my utility, a script to flash an LED would look like the following:

#!/bin/bash
source gpio  
gpio mode 4 out  
while true; do  
    gpio write 4 1
    sleep 0.5
    gpio write 4 0
    sleep 0.5
done  

I created a couple examples of using the utility, a LED chaser and a binary counter. I plan to continue updating the Github repository as I complete more projects.

Below is a picture of the binary counter in action. As you can see, I'm utilizing the Adafruit Pi Dish along with the Prototyping Pi Plate, since I find its headers easier to work with than the Cobbler Breakout.

Binary Counter

Luke Sandell

Read more posts by this author.

comments powered by Disqus