Raspberry Pi GPIO 4 Ways
Tags: raspberrypi, c, cpp, nim
Published: 2020-03-22 15:24:02

I've been practicing recently with GPIO on my Raspberry Pi 4.  My journey to controller nirvana hasn't been as easy as advertised as I chose to use [Ubuntu server for Pi](https://ubuntu.com/download/raspberry-pi) instead of [Raspbian](https://www.raspberrypi.org/downloads/).  I've found it very difficult to add the python GPIO module.  Yet, I haven't given up.  With some interwebbing, I've discovered that that little module isn't needed and one doesn't have to use python to control GPIO pins.

Automatically set up upon starting the Pi, even with Ubuntu is the `sysfs` system.  This is similar to the `procfs` system that some are familiar with using.  There is a `/cpuinfo` file in the `procfs` system one can read to determine machine specific data. Most of the `sysfs` system can be identified because they are the `/sys/class/` folders in the file system.

This collection of folders and files, when properly set up, can be used to programmatically control GPIO pins on the Raspberry Pi with any programming language that supports file I/O.  In this example (this is not a tutorial, folks), I am going to show the simple flow of what one does to control GPIO pins in `C`, `C++`, `nim`, and even `python`.

There are two articles I used to help figure all this out.  I'll put links to each at the end of the article.  My `C` code is the same as the Auctoris link.

First, we'll step through the things that have to be done to set up GPIO for use, set the direction of a pin, and either turn on or turn off a pin.  I'll be using pin 4 in my examples, but any of the general purpose pins will work.  For the SPI, one-wire, and other analog or bus type pins, you'll need to do some research on how these work through `sysfs`.

The steps are:
1. Set up GPIO pin for use. Write `"4"` into the export file at `/sys/class/gpio/export`.
2. Establish pin as input or output. Write `"out"` or `"in"` at `/sys/class/gpio/gpio4/direction`.
3. Finally, turn pin on or off.  Write `"1"` or `"0"` at `/sys/class/gpio/gpio4/value`.

Before we get to the code section, a few caveats. All of what you write to the `sysfs` files are strings. Don't confuse `"4"` with `4`.  If you alternate writing the `"4"` to both the `export` and `unexport` files, you will see the `gpio4` folder appear and disappear when `ls`-ing the folder list.  That is what is meant by setting up the pin. Without doing so, you won't have files where you can write 1's or 0's. Also, all of these files are owned by `root`.  You must be `root` or use `sudo` when running your executable file or you will get errors.

A little side note. According to what I've read, it is correct procedure to `unexport` your pin set ups after you are through with them.  This is probably good information; yet, I figure most real world applications will be in continuous use. Use your judgment as to whether this step is necessary or not.  From my observation, when I power down the Pi, `export` settings are lost anyway.  GPIO pin set up must be done again upon start up.

Without any more delay, let's get to our code.  First up is the `C` code from the Auctoris post.  He was very worried about buffer overwrites in the `sysfs` files.  That is why he is using write methods that specify how many characters write to the files.  While I believe that is good practice, I don't have enough facility in the other languages to mimic that operation.

File: `gpio.c`

```
#include <stdio.h> 

int main(){
FILE *sysfs_handle = NULL;           
        sysfs_handle = fopen("/sys/class/gpio/export", "w");
        if (sysfs_handle != NULL){
                fwrite("4", sizeof(char), 2, sysfs_handle);
                printf("\nGPIO 4 opened for EXPORT\n");
                fclose(sysfs_handle);       
        }
        else
        {
 printf("\nCan't open gpio/export.  Something went wrong. Are you root?\n");

        }
        sysfs_handle = fopen("/sys/class/gpio/gpio4/direction", "w" );
        if (sysfs_handle != NULL){
    
                fwrite("out", sizeof(char), 4, sysfs_handle);
                printf("\nGPIO 4 assigned to be an output.\n");
                fclose(sysfs_handle);
        }
        else
        {
                printf("\nCan't open gpio/direction.  Something went wrong. Are  you root?\n");
        }
sysfs_handle = fopen("/sys/class/gpio/gpio4/value", "w");
        if (sysfs_handle != NULL){
                fwrite("out", sizeof(char), 4, sysfs_handle);
                printf("\nGPIO 4 assigned to be an output.\n");
                fclose(sysfs_handle);
        }
        else
        {
 printf("\nCan't open gpio/direction.  Something went wrong. Are  you root?\n");

        }
        sysfs_handle = fopen("/sys/class/gpio/gpio4/value", "w");

        if (sysfs_handle != NULL){
                fwrite("1", sizeof(char), 2, sysfs_handle);
                printf("\nGPIO 4 given an ON command.\n");
                fclose(sysfs_handle);
        }
        else
        {

                printf("\nCan't open gpio/value. Something went wrong. Are you root?\n");

        }
return 0;
}
```
The above code should compile with `gcc gpio.c` (assuming you named your source that way, you don't have to do so).  After a successful compile, you would run the `a.out` executable with `sudo ./a.out`

The following code is for `C++`.  In all of these examples, I stuck with the file object (pointer, whatever) method to match up with Auctoris' example.

File: `gpio.cpp`

```
#include <iostream>
#include <fstream>          
using namespace std;   

int main () {

fstream sysfs_handle;                                  

sysfs_handle.open ("/sys/class/gpio/export", ios::out);        

if( sysfs_handle.is_open()){
   sysfs_handle<<"4";   
   cout<<"\nGPIO 4 opened for EXPORT.\n";
   sysfs_handle.close();                                
   }else{
       cout<<"\nCan't open gpio/export.  Are you root?\n";
   }
         
sysfs_handle.open ("/sys/class/gpio4/direction", ios::out);     
        
if( sysfs_handle.is_open()){
   sysfs_handle<<"out";         
   cout<<"\nGPIO 4 opened as output pin.\n";
   sysfs_handle.close();                           
   }else{
       cout<<"\nCan't open gpio4/direction.  Are you root?\n";
   }
        
sysfs_handle.open ("/sys/class/gpio/export", ios::out);    
        
if( sysfs_handle.is_open()){
   sysfs_handle<<"1"; 
   cout<<"\nGPIO 4 turned ON.\n";
   sysfs_handle.close();
   }else{
       cout<<"\nCan't open gpio/export.  Are you root?\n";
   }

  return 0;
}
```
Your `C++` code should compile with `g++ gpio.cpp` and you should be able to run the resultant a.out file the same as you did with `C`.

Next, let's get to the `nim` version.  I've been studying `nim` for a little while.  I've only made some headway in that regard.  I had to do a lot of searching to work the file I/O operations.  My observation of `nim` is that there are several methods to accomplish file I/O.  I've chosen what is closest to what I've already written above in `C` and `C++`.  `nim` is available in the Ubuntu Raspberry Pi repository.  One word of warning.  Do not use tabs in nim.  It doesn't like that and will give you some error about tabulators not allowed.  Took quite a bit to figure out that meaning.

File: `gpio.nim`

```
var sysfs_handle: File

if open( sysfs_handle, "/sys/class/gpio/export", fmWrite):

     sysfs_handle.writeLine("4")
     echo "GPIO export set."

else:
     echo "Problem opening File, are you root?"

sysfs_handle.close()

if open( sysfs_handle, "/sys/class/gpio/gpio4/direction", fmWrite):

     sysfs_handle.writeLine("out")
     echo "GPIO pin 4 assigned to be an output."

else:

     echo "Problem opening file. Are you root?"

sysfs_handle.close()


if open( sysfs_handle, "/sys/class/gpio/gpio4/value", fmWrite):

     sysfs_handle.writeLine("1")
     echo "GPIO pin 4 turned on."

else:

     echo "problem opening file, are you root?"

sysfs_handle.close()
```
You could compile the above code with `nim compile gpio.nim` and if you needed debugging, that is the method to choose.  One of the weaknesses I see in `nim` is the size of the executable.  `nim` outputs `C` code and then compiles that, so the resulting executables are much larger than expected.  I'd recommend `nim compile -d:release gpio.nim` in order to remove the debugging info from your executable.  It reduces the size significantly.

Just a side note before moving on: this is not a `nim` tutorial.  If you wish for me to write one (because the ones I've found can be confusing, save one), let me know in the comments below and I'll try to do one as I go along learning `nim`.

Finally, yes, you can still program in `python` and use the `sysfs` system.  The following code is just that, for grins and giggles.  It is in `python3`, which is standard on Ubuntu Raspberry.  If you wish to use `python 2.xx`, you'll have to install it from the repository.  It is there.

File: `gpio.py`

```
#!/usr/bin/python3

sysfs_handle = open("/sys/class/gpio/export", "w", 2)

if (sysfs_handle):
     sysfs_handle.write("4")
     print("GPIO 4 opened for EXPORT")

else:

     print("Can't open gpio/export.  Something went wrong. Are you root?")

sysfs_handle = open("/sys/class/gpio/gpio4/direction", "w")

if(sysfs_handle):
     sysfs_handle.write("out")
     print("GPIO pin 4 set as output")

else:

     print("Can't open gpio/direction. Are you root?")

sysfs_handle = open("/sys/class/gpio/gpio4/value", "w")

if(sysfs_handle):
     sysfs_handle.write("1")
     print("GPIO pin 4 is ON")

else:

    print("Can't open gpio4/value. Are you root?")

```
All that is required to make `gpio.py` executable is `chmod +x gpio.py`.  Don't forget to run as root.

To wrap things up, it is not necessary to use Raspbian on your Raspberry Pi if you would rather use one of the other OS's.  You are not tied to the `python` language and it's GPIO module if you would prefer to use another language.  The `sysfs` file system in there for your use and will do an adequate job.  These are example source files on the process of using `sysfs` to set up and command or read GPIO pins on the Pi.  Your next steps would be to write a library of functions that make setting up pins and commanding them easier to do as a programmer.  Yes, it is more work, but we like programming right?

[Link to Auctoris article, one of two.](https://www.auctoris.co.uk/2012/07/19/gpio-with-sysfs-on-a-raspberry-pi/)
[Link to sysfs use on Big Mess'O'Wires.](https://www.bigmessowires.com/2018/05/26/raspberry-pi-gpio-programming-in-c/)