GPIO with sysfs on a Raspberry Pi
EDIT (August 2023) – The technique outlined here will still work, but it’s been deprecated for some time now – so I’ve written a new post about how to use the new methods…
The Raspberry Pi (in case you’ve been living under a rock for the last six-months) is a cheap ($25) ARM Linux computer, primarily designed to be used to help teach kids to learn programming & computer science.
It’s also makes a pretty nice alternative to something like a BeagleBone, if you’re looking to play with some embedded computing technology. Whilst it’s less powerful than BeagleBone (and has less GPIO connectivity), Raspberry Pi does have a few advantages. It’s cheap, and it has an HDMI output – meaning that you can interact with it directly, without the need to ssh in from another computer.
The whole ethos of the Raspberry Pi foundation is to make the device as easy to use as possible: to encourage children (and adults!) to play with it, and learn to program. As with Arduino though, this user-friendly layer doesn’t mean that you can’t get your hands a little dirty and see what’s going on underneath.
If you’re going to play with GPIO on Raspberry Pi, then I suggest that you pick-up an Adafruit Raspberry Cobbler. Whilst the cobbler doesn’t provide any kind of over-voltage protection, it does provide a neat way to link from the Raspberry Pi’s header, to a breadboard: and it the labels PCB make it very easy to see which pin is which (without the need to have to refer to a diagram, and count pins).
There are a dozen and one tutorials on the web about how to use GPIO from your Raspberry Pi – but most of them (at least all the ones I’ve found) do so from a point of view of using a pre-written library (usually the RPi.GPIO Python library). Whilst these are a good place to start (especially if you just want to make something that works – and you aren’t too worried about all of the low-level details): they don’t explain what’s going on, at a low-level.
So in this piece, I’m going to have a quick look at one way to access the hardware at a much lower level: using Linux sysfs. Sysfs provides a way in Linux for users (or code in the user-space) to interact with devices at the system (kernel) level. Dr. Derek Molloy at Dublin City University, has an excellent video demonstrating using sysfs on a BeagleBone on his YouTube channel: and that is the inspiration for this piece. However, things are a little different on the Raspberry Pi, so let’s go through the process of setting GPIO pins on a Pi.
Firstly we’ll need a circuit. In this example, we’ll drive a couple of LEDs from the GPIO. Since we want to keep the current drawn through the GPIO pins as low as possible, we’ll use a transistor to switch – and actually power the LED from the board’s 5v pin.
Here’s what that looks like when built on a breadboard, using the Adafruit cobbler.
Note that I’ve picked the two GPIO pins that I’m using, more or less at random. Any of the pins (apart from the power rails, the ground, and the DNC pins) can be used – though you’ll want to avoid using the reserved pins (such as UART TXD & RXD) if you plan on using them for their main purpose (like serial I/O).
Unlike on the beaglebone we don’t need to worry about multiplexing modes for the pins – and we can skip ahead to using sysfs to get at the pins. Note that we need root privileges to use sysfs: and because we’ll be piping the output from one command into a sysfs file the easiest way to do this is to invoke a root shell – using the su
command. (If you’re new to Linux – a good tip is that a root shell has a # prompt, instead of the usual $ prompt).
pi@raspberrypi ~ $ su
root@raspberrypi: /home/pi #
Next we need to go to the sysfs directory pertaining to the GPIO pins – /sys/class/gpio
root@raspberrypi: /home/pi # cd /sys/class/gpio
Now we’re ready to start, by creating the sysfs alias for the pin we want to use – by exporting that pin. We do this by adding the pin we want to work with to the export list: export
isn’t a normal file though – it’s part of the mechanism of sysfs. Closer inspection will show us that this is an unusual file…
root@raspberrypi: /sys/class/gpio/ # ls -l total 0 --w------- 1 root root 4096 Jul 19 19:41 export lrwxrwxrwx 1 root root 0 Jul 19 19:41 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0 ... --w------- 1 root root 4096 Jul 19 19:41 unexport
Both export
(and it’s counterpart unexport
) are write-only files! Of course, what actually happens is that sysfs monitors these files, and updates the links between user-space and kernel-space when they’re updated (a more thorough description of which, is beyond the scope of this tutorial).
On the Raspberry Pi the pin identifier is just the GPIO pin number: note that this doesn’t directly correspond to the physical number of the physical pin in the P1 header – GPIO4 which we’re using, is physically pin 7 in P1. (For more information, see the GPIO section on the Raspberry Pi wiki).
We add GPIO4 to the export list – by simply appending 4 to export
. There’s no output from doing this – but if we do an ls -l
root@raspberrypi: /sys/class/gpio/ # echo 4 > export root@raspberrypi: /sys/class/gpio/ # ls -l total 0 --w------- 1 root root 4096 Jul 19 19:41 export lrwxrwxrwx 1 root root 0 Jul 19 19:41 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0 lrwxrwxrwx 1 root root 0 Jul 19 19:41 gpio4 -> ../../devices/virtual/gpio/gpio4 ... --w------- 1 root root 4096 Jul 19 19:41 unexport
Sysfs has created a direction which is a symbolic link corresponding to GPIO4. If we look inside that directory we’ll see a number of files.
root@raspberrypi: /sys/class/gpio/ # cd gpio4 root@raspberrypi: /sys/class/gpio/gpio4 # ls active_low direction edge power subsystem uevent value
For our purposes we’re interested in only two of these: direction
and value
.
If we look at the value of these files, we can see how they’re set:
root@raspberrypi: /sys/class/gpio/gpio4 # cat direction in root@raspberrypi: /sys/class/gpio/gpio4 # cat value 0
To turn on GPIO4 – we need to set it to be an output pin, and then set it’s value to high.
root@raspberrypi: /sys/class/gpio/gpio4 # echo out > direction root@raspberrypi: /sys/class/gpio/gpio4 # echo 1 > value
If everything is correct, we should now see our LED illuminate. To turn in off again, we simply write a 0 to the value
.
root@raspberrypi: /sys/class/gpio/gpio4 # echo 0 > value
Finally when we’ve finished: it’s good practice to unexport the pins we were using (to free them up for anything that might want to use them).
root@raspberrypi: /sys/class/gpio/gpio4 # cd /sys/class/gpio root@raspberrypi: /sys/class/gpio # echo 4 > unexport
We could, of course, also do all of this programmatically: and that’ll be the subject of part two.
6 thoughts on “GPIO with sysfs on a Raspberry Pi”
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
Filed under: Hardware,Raspberry Pi,Uncategorised - @ July 19, 2012 20:34
Tags: gpio, Raspberry Pi, sysfs
sys/class/gpio # echo 4 > inexpert
should be
sys/class/gpio # echo 4 > unexport
You’re quite right. Good spot!
I’ll change that.
I blame autocorrect… 🙂
Now that sysfs is deprecated, is it still wise to go this route?
That’s a good question. This post is now more than 10-years old – and there are certainly more modern ways to do this. Perhaps I need to write a 2023 edition?
In terms of using this technique – there’s no particular problem with doing so: just that support for sysfs *could* now be removed in a future software update (after which – whatever you were doing with it obviously won’t work any more)…
I’ve now written a new post talking about how to do this using the new gpiod method. https://www.auctoris.co.uk/2023/08/18/how-not-to-use-sysfs-for-gpio-on-a-raspberry-pi-how-you-should-do-it-in-2023/