Introducing sysfs: GPIO

In this first article of the group, I’m going to introduce the sysfs that uses any Linux-based system. The reason of beginning with this topic is that the sysfs will be used in almost all tutorials of this site, since it will be used directly or indirectly in order to use sensors, modules and any other components such servos. Of course, there are many libraries to use these sensors, but many of them just wrap the sysfs functionality within some classes. Anyway, having some knowledge about the sysfs can help us with the development of our projects.

What is sysfs?

As I said, the sysfs is available in any Linux-based system, like Raspbian or Debian. We are going to focus on these Linux distributions because they are the most common operating system of our Raspberry Pi and Beagle Bone, respectively. Therefore, all this article applies to these two machines, but also to any other similar one.

The sysfs is actually a pseudo-filesystem, intended to manage some system features provided by the Linux kernel, such interfacing with external elements. It can be accessed under the /sys/class directory, where all of these interfaces are grouped according to their type or class.

For example, here are all classes which can be accessed within the /sys/class directory of a BeagleBone Black using Debian. Just type “ls /sys/class” on the command prompt.

Example of system classes on the Beagle Bone Black

In case of Raspberry Pi, the system classes can be listed in the same way, just typing the command “ls /sys/class”.

Example of system classes on the Raspberry Pi

The exact contents of the two examples depends on the exact operating system version running on the devices and other installed modules, thus different elements may be shown.

The features of all of these classes are different between them, and it take a lot of time to explain them. As the purpose of this article is to give an introduction, we’ll see the GPIO system as an example of the potential of the sysfs.

Another interesting class of the sysfs is the PWM-class, which let us generate sounds for a beeper and move servos or motors. I’ll write about this class in a later article.

More information about the sysfs can be found at the Linux Programmer’s Manual site.


The GPIO (General Purpose Input Output) is the most basic communication system with our external devices. It consists on several ports which can be configured as read (in) or write (out) function. Therefore they can read the state of the port. That means, if there’s a wire connected to the physical port with voltage, then the level is high, so it reads ‘1’. Otherwise, in case of the wire has no charge, so the level is low, it reads ‘0’. For the write function, when our system writes ‘1’, it set voltage on the wire. And when the system writes ‘0’, no voltage will be on the wire. That is, the system reads or writes a single bit.

In read mode: If wire has voltage then the read value is 1, else the value is 0.

In write mode: If value is 1 then the wire has voltage, else hasn’t.

Probably, it seems that’s not much, but many GPIO ports together can control LEDs, buttons, keypads, LCD-displays or even ultra-sonic sensors. But we’ll discuss about them in future articles.

About the voltage, it is 3.3V for the Beagle Bone and the Raspberry Pi, but other devices uses different voltages, like classic Arduino which uses 5V signals. Thus be aware about the expected voltage of devices. In case of an external device using another voltage signal, a logic-converter must be also used.

Now, let’s take a look at the content of the “/sys/class/gpio” directory:

debian@beaglebone:~$ ls /sys/class/gpio/
export gpiochip0 gpiochip32 gpiochip64 gpiochip96 unexport

Here are some files and directories, which actually are the interface for managing our external connections. The most important thing here is the pseudo-files “export” and “unexport”. The other directories let access to the underlying  hardware system, but they are out of the scope of this article.

As seen on the “ls” command result, there is nothing for managing ports… for the moment. That’s because the ports are deactivated by default. Here comes the pseudo-file “export”, mentioned before. It is a write-only file, where the user can write a port number to tell the system which one should be activated. This port number depends on the machine we are using, and it can be obtained from the IO map specification of our device.

Let’s activate the GPIO port #26:

(using sudo)
debian@beaglebone:~$ sudo bash -c "echo 26 > /sys/class/gpio/export"
(logged as root)
debian@beaglebone:~# echo 26 > /sys/class/gpio/export

Despite the example refers to the Beagle Bone machine, the command can be also executed on a Raspberry Pi. The point is, this command must be executed with root privileges or use sudo because we are modifying the hardware status of our device.

Now let’s see the “/sys/class/gpio” directory again. If all went fine, there’s a gpio26 directory now, in other words, the interface to manage the GPIO port #26.

debian@beaglebone:~$ ls /sys/class/gpio/
export gpio26 gpiochip0 gpiochip32 gpiochip64 gpiochip96 unexport

Let’s take a look inside this new gpio26 directory:

debian@beaglebone:~$ ls /sys/class/gpio/gpio26

active_low direction edge power subsystem uevent value

For this example I used the port #26, but any other can be used. Just to look at the pin-out map of the device we are using.

Beagle Bone Black’s pin-out map
Raspberry Pi pin-out map

Those pins prefixed with “GPIO” are available to use as GPIO-port, thus users can select those more convenient for their projects.

Coming back to the GPIO interface. For our purpose, just to comment the pseudo-files direction and value. The other pseudo-files and directories are intended to advanced purposes, therefore we can ignore them for the moment.

On direction we can indicate the port mode, that is write or read modes. Again, we can use the command prompt, as root or using sudo,  to do so:

--- using sudo ---

(to activate read mode)
debian@beaglebone:~$ sudo bash -c "echo in > /sys/class/gpio/gpio26/direction"

(to activate write mode)
debian@beaglebone:~$ sudo bash -c "echo out > /sys/class/gpio/gpio26/direction"

--- the same as before but logged as root now ---

(to activate read mode)
debian@beaglebone:~# echo in > /sys/class/gpio/gpio26/direction

(to activate write mode)
debian@beaglebone:~# echo out > /sys/class/gpio/gpio26/direction

To check the mode of the port, just to read this pseudo-file:

debian@beaglebone:~$ cat /sys/class/gpio/gpio26/direction


The system will answer ‘in’, like the example, in case of read mode or ‘out’ for the write mode. In this case we don’t need root privileges or sudo to check the port mode, since this action doesn’t change the device’s state.

Finally, as one can guess at this point, the value pseudo-file let us read or write the wire state, depending on the current port mode. In case of GPIO port’s read mode it will be a read-only file, otherwise it will be read & write, so we can change the state of the port, but also check the state. Please don’t confuse the port mode and the file mode, since the first one refers to the direction (hence the name of the pseudo-file) of the bit through the port, but the second one refers to the file that the operating system sees in order to handle the value of the GPIO port.

Knowing that, we can execute the next commands to deal with the GPIO port’s value. The input and output for the value will be 0 or 1, obviously corresponding with a low voltage level and a high voltage level on the wire connected to the port.

--- to read or check the current GPIO port's value ---

debian@beaglebone:~$ cat /sys/class/gpio/gpio26/value

--- to write the GPIO port's value (in write mode only)

(using sudo)
debian@beaglebone:~$ sudo bash -c "echo 1 > /sys/class/gpio/gpio26/value"

(logged as root)
debian@beaglebone:~# echo 1 > /sys/class/gpio/gpio26/value

Finally, when we are done with the GPIO port, it could be nice to deactivate it, in order to save system resources and prevent any conflict with other  systems connected to it. Just type on the command prompt:

(using sudo)
debian@beaglebone:~$ sudo bash -c "echo 26 > /sys/class/gpio/unexport"

(logged as root)
debian@beaglebone:~# echo 26 > /sys/class/gpio/unexport

By this way we can say to our device that we won’t use the GPIO port #26 anymore (until next activation) and therefore it can be deactivated. If we take a look at the /sys/class/gpio directory just after the command execution, we can see that the gpio26 directory is vanished.

debian@beaglebone:~$ ls /sys/class/gpio/
export gpiochip0 gpiochip32 gpiochip64 gpiochip96 unexport

In Summary

Summarizing, the steps to deal with GPIO ports through the common Linux’s systemfs of our devices are:

  1. Enable (export) port(using sudo) $ sudo bash -c “echo port-num > /sys/class/gpio/export” (logged as root) # echo port-num > /sys/class/gpio/export
  2. Set direction (in or out)(using sudo) $ sudo bash -c “echo [in|out] > /sys/class/gpio/gpioport-num/direction” (logged as root) # echo [in|out] > /sys/class/gpio/gpioport-num/direction
  3. Use it
    • Read(no matter which user) $ cat /sys/class/gpio/gpioport-num/value
    • Write(using sudo) $ sudo bash -c “echo [0|1] > /sys/class/gpio/gpioport-num/value” (logged as root) # echo [0|1] > /sys/class/gpio/gpioport-num/value
  4. Disable (unexport port)(using sudo) $ sudo bash -c “echo port-num > /sys/class/gpio/unexport” (logged as root) # echo port-num > /sys/class/gpio/unexport


To see how it works on the device, we’ll make a small project. We need:

  • Computer board (Beagle Bone or Raspberry Pi)
  • LED (suitable for 3.3V or use a resistor to adapt it)
  • Push button (tester)
  • Wires
  • Protoboard

Connect this elements following the next schematics, according the available computer board.

For security reasons connect all components of the project with the device unplugged always, and then check twice all things are correctly connected.

Schematics for Beagle Bone Black
Schematics for Raspberry Pi

In order to connect the LED, keep the polarity as the picture shows.

LED polarity

Remember to connect the long leg of any LED to the positive wire and the short one to ground.

Once we have checked all components are correctly connected, turn the computer board on. The system should boot up now. Finally start a terminal on the device in order to introduce commands.

First at all we are going to configure our GPIO ports. The first one in write mode (to turn the LED on and off), and the second one in read mode to check the button state. Remember to enter the following commands as root or using the sudo command as we have seen above.

Let’s start with the LED port, which is GPIO27 (in this case it is the same port number for the BeagleBone and the Raspberry Pi) :

$ sudo bash -c "echo 27 > /sys/class/gpio/export"
$ sudo bash -c "echo out > /sys/class/gpio/gpio27/direction"

And now activate the button port. In this case it is GPIO65 for the BeagleBone and GPIO23 for the Raspberry Pi.

--- BeagleBone: Port GPIO65 

$ sudo bash -c "echo 65 > /sys/class/gpio/export"
$ sudo bash -c "echo in > /sys/class/gpio/gpio65/direction

--- Raspberry Pi: Port GPIO23

$ sudo bash -c "echo 23 > /sys/class/gpio/export"
$ sudo bash -c "echo in > /sys/class/gpio/gpio23/direction

At this point we have our GPIO ports ready. Let’s turn the LED on.

$ sudo bash -c "echo 1 > /sys/class/gpio/gpio27/value"

The LED should shine at this moment, if all went well.

LED shinning

We can also check the current state of the port. In this case we don’t need execute the command as root or sudo, because we are not modifying the device state.

$ cat /sys/class/gpio/gpio27/value


To turn it off, just type:

$ sudo bash -c "echo 0 > /sys/class/gpio/gpio27/value"

The LED is now off. To check it by software:

$ cat /sys/class/gpio/gpio27/value


Let’s see how to know the push button’s current state. Just read the GPIO port (65 for the BeagleBone or 23 for the Raspberry Pi) value.

--- BeagleBone: Port GPIO65 
$ cat /sys/class/gpio/gpio65/value

--- Raspberry Pi: Port GPIO23
$ cat /sys/class/gpio/gpio23/value

If nothing press the button it returns 0, otherwise returns 1. Let’s try to press the button, execute the last command (still pressing the button) and check the returned value. Now you can stop pressing the button. Now it should be 1.

Type the following command now:

--- BeagleBone: Port GPIO65
$ watch -n0.1 cat /sys/class/gpio/gpio65/value

--- Raspberry Pi: Port GPIO23
$ watch -n0.1 cat /sys/class/gpio/gpio23/value

This makes the device poll the push button state every 0.1 second. Try to press the button and release it several times, and see what happens. To finish just use [Control+C] keyboard combination.

When finished with the GPIO ports, it would be nice to deactivate them using the unexport pseudo-file, in order to release the used resources.

$ sudo bash -c "echo 27 > /sys/class/gpio/unexport"

--- BeagleBone
$ sudo bash -c "echo 65 > /sys/class/gpio/unexport"

--- Raspberry Pi
$ sudo bash -c "echo 23 > /sys/class/gpio/unexport"


The sysfs is the most basic way to communicate with external devices through GPIO. Obviously handling it just using the command prompt is not very useful at the end, but note that all sysfs components are seen as regular directories and files by the operating system. Therefore we can deal with GPIO ports using any programming language capable to handle files and directories (I guess this is the 99% of the languages) and thus making libraries for that purpose is easy.

I suggest to do a GPIO library as an exercise.