Raspberry Pi: working with GPIO from C/C++

There are a variety of libraries available for the C and C++ compilers that allow you to talk to the GPIO on a Raspberry Pi. Unfortunately, most do not support the Raspberry Pi 5. The Raspberry Pi 5 uses a different chip than the Raspberry Pi 4 to control the GPIO pins. This means that most libraries that worked on a Pi4 do not work on the Pi5. Again, unfortunately, there are similar problems with the Pi3 and Pi2 because the chips that control the GPIO pins are different between all of the boards. Fortunately, the older boards have been around a while and most libraries support upto the Pi4.

GPIO differences

If we look at the history of the GPIO controller chip and pinouts, function and operation have changes with each board release

Type 1 – Model B (original model)

  • 26 pin header (P1).
  • Hardware revision numbers of 2 and 3.
  • User GPIO 0-1, 4, 7-11, 14-15, 17-18, 21-25.
GPIOpinpinGPIO
3V3125V
SDA0345V
SCL156Ground
47814TXD
Ground91015RXD
ce117111218ce0
211314Ground
22151623
3V3171824
MOSI101920Ground
MISO9212225
SCLK1123248CE0
Ground25267CE1

Type 2 – Model A, B (revision 2)

  • 26 pin header (P1) and an additional 8 pin header (P5).
  • Hardware revision numbers of 4, 5, 6 (B), 7, 8, 9 (A), and 13, 14, 15 (B).
  • User GPIO 2-4, 7-11, 14-15, 17-18, 22-25, 27-31.
    GPIOpinpinGPIO
    3V3125V
    SDA2345V
    SCL356Ground
    47814TXD
    Ground91015RXD
    ce117111218ce0
    271314Ground
    22151623
    3V3171824
    MOSI101920Ground
    MISO9212225
    SCLK1123248CE0
    Ground25267CE1
    GPIOpinpinGPIO
    5V123V3
    SDA283429SCL
    305631
    Ground78Ground

    Type 3 – Model A+, B+, Pi Zero, Pi Zero W, Pi2B, Pi3B, Pi4B

    • 40 pin expansion header (J8).
    • Hardware revision numbers of 16 or greater.
    • User GPIO 2-27 (0 and 1 are reserved).
    GPIOpinpinGPIO
    3V3125V
    SDA2345V
    SCL356Ground
    47814TXD
    Ground91015RXD
    ce117111218ce0
    271314Ground
    22151623
    3V3171824
    MOSI101920Ground
    MISO9212225
    SCLK1123248CE0
    Ground25267CE1
    ID_SD027281ID_SC
    52930Ground
    6313212
    133334Ground
    miso19353616ce2
    26373820mosi
    Ground394021sclk

    Type 4 – Pi5

    • 40 pin expansion header (J8).
    • Hardware revision numbers of 16 or greater.
    • User GPIO 2-27 (0 and 1 are reserved).
    GPIOpinpinGPIO
    3V3125V
    SDA2345V
    SCL356Ground
    47814TXD
    Ground91015RXD
    ce117111218ce0
    271314Ground
    22151623
    3V3171824
    MOSI101920Ground
    MISO9212225
    SCLK1123248CE0
    Ground25267CE1
    ID_SD027281ID_SC
    52930Ground
    6313212
    133334Ground
    miso19353616ce2
    26373820mosi
    Ground394021sclk

    Even though the pinouts remain the same between the Raspberry Pi 4 and Raspberry Pi 5, the functionality changes between the two and how you program them internally is different. If you are using the command line on a Raspberry Pi 4 the raspi-gpio is the command that has traditionally been used. The operating systems takes care of talking to the controller chip and everything works as expected. When the Raspberry Pi 5 came out, the raspi-gpio command was no longer supported.

    $ raspi-gpio help

    raspi-gpio is not supported on Pi 5 – use pinctrl

    The pinctrl command replaces raspi-gpio and uses a different kernel call and process to talk to the GPIO. Fortunately pinctrl accepts the same arguments as raspi-gpio so little if any changes will be needed for command line programs.

    Pigpio

    The pigpio library, https://abyz.me.uk/rpi/pigpio/index.html , is a library that supports Python, C/C++, and Java with some extensions. Unfortunately, this library only works with the older versions and has not been ported to the Raspberry Pi 5. The authors of the library have stated that the port is not insignificant and will require some work to get things working as with previous versions.

    Libgpiod

    An alternate is to have a common user call given that the command lines have changed from hardware version to hardware version. The libgpiod, https://github.com/brgl/libgpiod , is designed to be a common user interface that hides the hardware dependencies between hardware and operating system flavors. On a grander scale, this would also work on an Arduino using the same or similar code that runs on the Raspberry Pi.

    RPi.GPIO

    The RPi.GPIO library, https://pypi.org/project/RPi.GPIO/ , is a Python only library and does not work with C/C++ or Java.

    WiringPi

    The WiringPi, https://github.com/WiringPi/WiringPi/ , library appears to be one of the first GPIO libraries that support the Raspberry Pi. To install WiringPi, use git to download the source and build to build the library

    $ sudo git clone https://github.com/WiringPi/WiringPi.git
    $ cd WiringPi
    $ sudo ./build

    If we look in the examples folder there is a blink.c file that writes to an LED on GPIO pin 17.

    // LED Pin – wiringPi pin 0 is BCM_GPIO 17.

    #include <stdio.h>

    #include <wiringPi.h>

    #define LED 0

    int main (void) {
    printf (“Raspberry Pi blink\n”) ;

    wiringPiSetup () ;
    pinMode (LED, OUTPUT) ;

    for (;;) {
    digitalWrite (LED, HIGH) ; // On
    delay (500) ; // mS

    digitalWrite (LED, LOW) ; // Off
    delay (500) ;

    }
    return 0 ;
    }

    The Makefile has one significant change with the compile in that it pulls in the libwiringPi library that gets installed in /usr/local/lib

    LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt

    $ gcc -o blink blink.c -L/usr/local/lib -lwiringPi

    The -L/usr/local/lib command tells the compiler to look in the /usr/local/lib folder the the libraries. The -lwiringPi tells the compiler to look for the libwiringPi.so or libwiringPi.a library. These libraries contain the routines wiringPiSetup(), pinMode(), and digitalWrite(). The wiringPiSetup() routine initializes the GPIO chip and linkages that are needed for the connection. The pinMode(<pinNumber>,<mode>) routine programs the pin number as an input or an output. It is important to note that the GPIO pins do not necessarily match with the library pin numbers. For example, pin 0 with the library correlates to pin 17 on the GPIO pins.

    If you type gpio readall it will show the pin mappings

    If you look at the BCM column, that corresponds to the GPIO label. Looking at the right of the table, physical pin 12 corresponds to the name GPIO.1, GPIO pin 18, or wPi library number 1. All of this is confusing but works. My suggestion would be to define your own labels. For example, I would define gpio_pin_17 as 0 and gpio_pin_18 as 1 rather than using the wPi library names GPIO.0 and GPIO.1.

    In summary, we do have one solution that allows us to use C/C++ to read and write GPIO pins. The code is not optimal but it does function. Mapping of the GPIO pin labels to the wPi library labels is a little more complex than needed. If you have code previously developed on the Raspberry Pi 4 or older versions the same code might or might not work on a Raspberry Pi 5 based on what library was selected and if the library is available on the new board. In time, the other libraries should be ported to the Raspberry Pi 5 and less complex solutions will be available.