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.

    Raspberry Pi: Python LED Blink

    In this post we will look at what it takes to blink an LED on the Raspberry Pi using the GPIO pins and Visual Studio. We will use Visual Studio to show the process of software development. We will discuss the electrical components needed to attach an LED and resistor to the Raspberry Pi. We will also dive into the code required to turn the LED on and off.

    Start connecting to your Raspberry Pi using a keyboard/mouse/computer screen or through VNC from your desktop computer. From the top left of the screen select the Visual Studio IDE.

    Visual Studio restarts where we left off when we last worked in the environment.

    From here we click on File -> New File

    Note that we now have an option to start a Python file since we have developed at least one Python file in the IDE.

    We are now ready to start development. Note that the file is Untitled. We can save it as a file with the “.py” extension of just start typing code.

    If we start typing the IDE will suggest what we might want to finish. In this instance we want to include the gpiozero module so that we can talk to the GPIO pins from our program.

    You do need to know a little about the module and interfaces/routines that are available in the module. In this example, we are pulling in the gpiozero module and talking to an LED method.

    The import command says pull in the LED method from the gpiozero module and make it available to use. We want to pull in the sleep command as well so that we can loop and delay between turning on and off the LED. When we call the LED() method the IDE tells us what parameters are needed to call the method.

    In this instance we are using pin 17 as an output to drive the LED. We need to assign the LED to a variable. We select “led” as the variable and call then turn on (with the led.on() call) or off (with the led.off() call). The sleep function allows us to sleep for a number of seconds. The while True statement says anything that is indented below that command will be executed in a loop.

    Now that we have the code ready to run, we can save the file with File -> Save File

    We call the file gpio_led.py and can now debug the code as desired using the IDE. Before we can debug we need to attach the external LED and resistor to pin 17 and ground.

    We connect a wire from GPIO pin 17 to the long side of the LED. The short side of the LED is attached to a resistor. The other side of the resistor is attached to ground on the Raspberry Pi.

    When selecting a resistor it is important to note that different color LEDs need different size resistors. Given that the resistor and LED are in series it creates a voltage division between the two elements. The GPIO pin will output 5 volts across both elements.

    Putting a small resistor in series with the LED will cause the LED to be brighter. A larger resistor will take more voltage from the LED can cause it to not be as bright.

    You need to make sure that the resistor is not too small because it will burn out the LED. If the resistor is too large the LED will never turn on. To calculate the resistor size, we need to know the voltage drop across the LED (which we can get from the chart above) and subtract that number from 5 volts.

    In this example we have a 1.8 volt drop from the LED and a 3.2 volt drop needed across the resistor. If we assume 20 milliAmps of current we can either calculate the resistor needed

    or look up in a table what minimum resistor value is needed.

    In this example we would use a 150 Ohm resistor to get a 2 volt drop across the LED. Note that this would work for most LEDs but not the blue or white LEDs since it would need a 2 volt Vf drop. These LEDs would need a smaller resistor since there would be less voltage across the resistor given that the blue or white LEDs create a 3 volt drop rather than a 2 volt drop. Calculating the resistor size is a bit complex but starting with an LED in the 200 to 330 Ohm range and going up to 1K to 2K are good starting points to keep the LED from burning out. If you use too small of a resistor you risk driving too much voltage across the LED and melting it.

    It is also important to note that the LED has two leads, one long and on short.

    The long lead connects to the GPIO pin in our example and the short lead connects to the resistor. The other side of the resistor connects to ground. The gpiozero module assumes that you are driving the GPIO pin high to turn on the LED. This assumes that you are driving the anode (long side) and not the cathode (short side). If you put 5 volts on the cathode and ground the anode nothing will happen. The LED will stop current from flowing and will not light up. If you put voltage on the anode and ground the cathode the LED will turn on. By calling the led.on() routine, 5 volts is driven through GPIO pin 17 to go across the LED and resistor.

    Running the code from the IDE will start driving pin 17 high and low with a second delay between turning on and turning off.

    Note that there is no output in the console since we don’t print anything to the console. To stop the program click on the red outlined box at the top of the code.

    Note that the console shows that we are ready to execute more code and is no longer running our Python code. If we want to run the code with a breakpoint we can set a breakpoint by clicking to the left of the line number.

    When we try to run again we can only run with Debugger since we have a breakpoint. When we run the code stops at the breakpoint.

    At this point we should have the LED shining brightly. Clicking on the Step Over button will execute the led.off() method.

    This should turn off the LED and get ready to sleep again. Clicking on the Continue button will run the program until we hit the breakpoint again.

    Once we understand how the program works to this point we might want to clear the breakpoint. To do this, right click on the breakpoint and either clear, disable, or edit the breakpoint.

    If we had variables defined in the code we could look at the values stored in the code as it runs. Setting a breakpoint at a critical point can help with unknown values or logic associated with code. This is one of the critical improvements that an IDE brings over just developing at the command line. Unfortunately, the IDE does not help with timing issues in code because the IDE introduces a delay into the code as it steps through everything. The code runs much faster without a debugger. The IDE collects data as it debugs so that you can look at variables and state inside your code.

    In summary, we can use Visual Studio to create, develop, and debug code on the Raspberry Pi. Using Python we can pull in the gpiozero module and control things like an LED attached to the GPIO pins. We can use the time modules to create delays so that we can see the lights blink on and off. We can change the delay with this code and in future posts we will look at changing the brightness of the LED using different parts of the gpiozero code.