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.
GPIO | pin | pin | GPIO | ||
3V3 | – | 1 | 2 | – | 5V |
SDA | 0 | 3 | 4 | – | 5V |
SCL | 1 | 5 | 6 | – | Ground |
4 | 7 | 8 | 14 | TXD | |
Ground | – | 9 | 10 | 15 | RXD |
ce1 | 17 | 11 | 12 | 18 | ce0 |
21 | 13 | 14 | – | Ground | |
22 | 15 | 16 | 23 | ||
3V3 | – | 17 | 18 | 24 | |
MOSI | 10 | 19 | 20 | – | Ground |
MISO | 9 | 21 | 22 | 25 | |
SCLK | 11 | 23 | 24 | 8 | CE0 |
Ground | – | 25 | 26 | 7 | CE1 |
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.
GPIO | pin | pin | GPIO | ||
3V3 | – | 1 | 2 | – | 5V |
SDA | 2 | 3 | 4 | – | 5V |
SCL | 3 | 5 | 6 | – | Ground |
4 | 7 | 8 | 14 | TXD | |
Ground | – | 9 | 10 | 15 | RXD |
ce1 | 17 | 11 | 12 | 18 | ce0 |
27 | 13 | 14 | – | Ground | |
22 | 15 | 16 | 23 | ||
3V3 | – | 17 | 18 | 24 | |
MOSI | 10 | 19 | 20 | – | Ground |
MISO | 9 | 21 | 22 | 25 | |
SCLK | 11 | 23 | 24 | 8 | CE0 |
Ground | – | 25 | 26 | 7 | CE1 |
GPIO | pin | pin | GPIO | ||
5V | – | 1 | 2 | – | 3V3 |
SDA | 28 | 3 | 4 | 29 | SCL |
30 | 5 | 6 | 31 | ||
Ground | – | 7 | 8 | – | Ground |
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).
GPIO | pin | pin | GPIO | ||
3V3 | – | 1 | 2 | – | 5V |
SDA | 2 | 3 | 4 | – | 5V |
SCL | 3 | 5 | 6 | – | Ground |
4 | 7 | 8 | 14 | TXD | |
Ground | – | 9 | 10 | 15 | RXD |
ce1 | 17 | 11 | 12 | 18 | ce0 |
27 | 13 | 14 | – | Ground | |
22 | 15 | 16 | 23 | ||
3V3 | – | 17 | 18 | 24 | |
MOSI | 10 | 19 | 20 | – | Ground |
MISO | 9 | 21 | 22 | 25 | |
SCLK | 11 | 23 | 24 | 8 | CE0 |
Ground | – | 25 | 26 | 7 | CE1 |
ID_SD | 0 | 27 | 28 | 1 | ID_SC |
5 | 29 | 30 | – | Ground | |
6 | 31 | 32 | 12 | ||
13 | 33 | 34 | – | Ground | |
miso | 19 | 35 | 36 | 16 | ce2 |
26 | 37 | 38 | 20 | mosi | |
Ground | – | 39 | 40 | 21 | sclk |
Type 4 – Pi5
- 40 pin expansion header (J8).
- Hardware revision numbers of 16 or greater.
- User GPIO 2-27 (0 and 1 are reserved).
GPIO | pin | pin | GPIO | ||
3V3 | – | 1 | 2 | – | 5V |
SDA | 2 | 3 | 4 | – | 5V |
SCL | 3 | 5 | 6 | – | Ground |
4 | 7 | 8 | 14 | TXD | |
Ground | – | 9 | 10 | 15 | RXD |
ce1 | 17 | 11 | 12 | 18 | ce0 |
27 | 13 | 14 | – | Ground | |
22 | 15 | 16 | 23 | ||
3V3 | – | 17 | 18 | 24 | |
MOSI | 10 | 19 | 20 | – | Ground |
MISO | 9 | 21 | 22 | 25 | |
SCLK | 11 | 23 | 24 | 8 | CE0 |
Ground | – | 25 | 26 | 7 | CE1 |
ID_SD | 0 | 27 | 28 | 1 | ID_SC |
5 | 29 | 30 | – | Ground | |
6 | 31 | 32 | 12 | ||
13 | 33 | 34 | – | Ground | |
miso | 19 | 35 | 36 | 16 | ce2 |
26 | 37 | 38 | 20 | mosi | |
Ground | – | 39 | 40 | 21 | sclk |
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.