How to Control the Raspberry Pi 5 GPIO with Python 3

Raspberry Pi 5 GPIO with Python 3
(Image credit: Tom's Hardware)

The Raspberry Pi 5 has just been released and it introduced us to a more powerful Pi, but it also changed a few things and most notably it was the GPIO.

We still have the same 40-pin GPIO but it works a little differently now as it is connected to the new RP1 southbridge chip. Why does this matter? Well it all boils down to how we write code that interacts with the GPIO. In the past, alot of projects favored RPi.GPIO. This was a community project by Ben Croston and it served multiple generations of Raspberry Pi well. With the Raspberry Pi 5, we are unable to use RPi.GPIO due to how the GPIO pins are memory mapped. This forces us to use an alternative, and libgpiod is the focus of this how to.

Libgpiod, specifically python3-gpiod is a pure Python module for interacting with the GPIO. It feels similar to RPI.GPIO in that we have to explicitly set the GPIO pins before we use them. We see gpiod as more of an intermediate module for Python and the GPIO. If you are new to this, use GPIO Zero which also works with the Raspberry Pi 5. GPIO Zero was created by Ben Nuttall and Dave Jones and greatly simplifies the GPIO.

We’re going to create two very simple projects using gpiod. The first is an output, an LED. The second is an input, a button which will trigger the LED to turn on and off.

For these projects you will need

(Image credit: Tom's Hardware)

The first goal when learning any language / framework is to create a “Hello World” program. In hardware, hacking and electronics this is a blinking LED.

(Image credit: Future)

The circuit is extremely simple. We have the long leg (anode) of an LED connected to GPIO 17 using a jumper wire. The short leg (cathode) is connected to GND via a resistor and another jumper wire. The resistor can be any value between 100 and 330 Ohms (Orange-Orange-Brown-Gold). Check out our resistor reference guide for more information.

1. Open Thonny and import two modules of code. The first module is gpiod, used to control and read the GPIO. Second is time, which is used to add a pause in the code.

import gpiod
import time

2. Create a variable called LED_PIN and store the value 17 inside of it. This variable contains the Broadcom pin reference for a GPIO pin on all models of Raspberry Pi. Broadcom pin references are the standard used by all Raspberry Pi documentation. It uses the breakout from the SoC to the GPIO. It may not look logical to us, but to the engineers creating the boards, the pins are broken out correctly.

LED_PIN = 17

3. Tell the code where to find the GPIO. Originally the Raspberry Pi had a single gpiomem device, which was mapped into memory and we could use it with Python modules such as RPi.GPIO. With the Raspberry Pi 5 and the RP1 chip we now have dynamically split devices, and our GPIO is at gpiomem4.

chip = gpiod.Chip('gpiochip4')

4. Create a variable called led_line and store a reference to the LED GPIO pin. The gpiod module uses lines to refer to the GPIO pins.

led_line = chip.get_line(LED_PIN)

5. Set the LED as an output. We want current to flow to the LED.

led_line.request(consumer="LED", type=gpiod.LINE_REQ_DIR_OUT)

6. Wrap the main body of code in a try and while True loop.Try is part of an exception handler that will try to run our code, it can handle exceptions and run a section of code when we exit.

try:
   while True:

7. Turn the LED and then wait for one second. This will force the LED to remain on for one second.

       led_line.set_value(1)
       time.sleep(1)

8. Turn the LED off and then wait for one second. The sleep forces the LED to remain off for one second.

       led_line.set_value(0)
       time.sleep(1)  # Sleep for one second

9. Add a section of code to clean up the GPIO when the code exits. With GPIO Zero, we don’t have to do this, but gpiod (and the older RPi.GPIO) we have to clean up before we exit.

finally:
   led_line.release()

10. Save the code as blinky.py and click on Run to start. The LED on GPIO 17 will blink on and off every second. Press CTRL + C or click Stop to end.

Project 1: Complete Code Listing

import gpiod
import time
LED_PIN = 17
chip = gpiod.Chip('gpiochip4')
led_line = chip.get_line(LED_PIN)
led_line.request(consumer="LED", type=gpiod.LINE_REQ_DIR_OUT)
try:
   while True:
       led_line.set_value(1)
       time.sleep(1)
       led_line.set_value(0)
       time.sleep(1)
finally:
   led_line.release()

Project 2: Input, React to User Input

(Image credit: Tom's Hardware)

After “Hello World,” the next goal is to create an input. In this example we create a button, one side is connected to the Button GPIO pin, the other to 3V3. The Button GPIO pin default state is no power (0, False, Low) but when we press the button we connect the 3V3 pin to the Button GPIO pin and change its state to powered (1, True, High). Our code will look for this change of state and react accordingly. All we need is the button and two jumper wires.

(Image credit: Future)

1. Open Thonny and import two modules of code. The first module is gpiod, used to control and read the GPIO. Second is time, which is used to add a pause in the code.

import gpiod
import time

2. Create a variable called LED_PIN and store the value 17 inside of it. This variable contains the Broadcom pin reference for a GPIO pin on all models of Raspberry Pi. Broadcom pin references are the standard used by all Raspberry Pi documentation. It uses the breakout from the SoC to the GPIO. It may not look logical to us, but to the engineers creating the boards, the pins are broken out correctly.

LED_PIN = 17

3. Create a variable called BUTTON_PIN and store the value 27 inside of it. GPIO 27 is right next to GPIO 17.

BUTTON_PIN = 27

4. Tell the code where to find the GPIO. Originally the Raspberry Pi had a single gpiomem device, which was mapped into memory and we could use it with Python modules such as RPi.GPIO. With the Raspberry Pi 5 and the RP1 chip we now have dynamically split devices, and our GPIO is at gpiomem4.

chip = gpiod.Chip('gpiochip4')

5. Create a variable called led_line and store a reference to the LED GPIO pin. The gpiod module uses lines to refer to the GPIO pins.

led_line = chip.get_line(LED_PIN)

6. Create a variable called button_line and store a reference to the Button GPIO pin.

button_line = chip.get_line(BUTTON_PIN)

7. Set the LED as an output. We want current to flow to the LED.

led_line.request(consumer="LED", type=gpiod.LINE_REQ_DIR_OUT)

8. Set the Button as an input.

button_line.request(consumer="Button", type=gpiod.LINE_REQ_DIR_IN)

9. Wrap the main body of code in a try and while True loop.Try is part of an exception handler that will try to run our code, it can handle exceptions and run a section of code when we exit.

try:
   while True:

10. Get the current status of the Button GPIO pin and store it in a variable called button_state.

       button_state = button_line.get_value()

11. Use an if conditional to check if the button has been pressed. If so, turn on the LED. The default state of the Button GPIO pin is to be low (0, False). But when we press the button we connect the 3V pin of the Raspberry Pi 5 to the Button GPIO pin. This pulls the Button pin high (1, True). This change of state is the trigger for our code.

       if button_state == 1:  # Button is pressed
           led_line.set_value(1)  # Turn the LED on

12. Use an else condition to turn the LED off when the button is not pressed.

       else:
           led_line.set_value(0)  # Turn the LED off

13. Add a section of code to clean up the GPIO when the code exits. With GPIO Zero we don’t have to do this, but gpiod (and the older RPi.GPIO) we have to clean up before we exit.

finally:
   led_line.release()
   button_line.release()

14. Save the code as button-press.py and click on Run to start. Press the button to turn the LED on and release to turn it off.  Press CTRL + C or click Stop to end.

Project 2: Complete Code Listing

import gpiod
LED_PIN = 17
BUTTON_PIN = 27
chip = gpiod.Chip('gpiochip4')
led_line = chip.get_line(LED_PIN)
button_line = chip.get_line(BUTTON_PIN)
led_line.request(consumer="LED", type=gpiod.LINE_REQ_DIR_OUT)
button_line.request(consumer="Button", type=gpiod.LINE_REQ_DIR_IN)
try:
   while True:
       button_state = button_line.get_value()
       if button_state == 1:
           led_line.set_value(1)
       else:
           led_line.set_value(0)
finally:
   led_line.release()
button_line.release()
Les Pounder

Les Pounder is an associate editor at Tom's Hardware. He is a creative technologist and for seven years has created projects to educate and inspire minds both young and old. He has worked with the Raspberry Pi Foundation to write and deliver their teacher training program "Picademy".

  • gondor
    "8. Set the Button as an input. We want current to flow to the LED."

    Copy-pasta Les? ;)
    Reply
  • Pi-Plates
    So, is gpiod backwards compatible with the RPi 4 and RPi3? Or do we have to support both RPI.GPIO and gpiod in our scripts?
    Reply
  • pidloop
    What about C?
    Reply
  • Ockwig
    Admin said:
    The Raspberry Pi 5 has a new way to interact with the GPIO and if you need something a little more advanced than GPIO Zero, python3-gpiod is where you need to look. We introduce this Python module by running through two very basic examples that explain the syntax and thinking of the module.

    How to Control the Raspberry Pi 5 GPIO with Python 3 : Read more
    Admin said:
    The Raspberry Pi 5 has a new way to interact with the GPIO and if you need something a little more advanced than GPIO Zero, python3-gpiod is where you need to look. We introduce this Python module by running through two very basic examples that explain the syntax and thinking of the module.

    How to Control the Raspberry Pi 5 GPIO with Python 3 : Read more

    Admin said:
    The Raspberry Pi 5 has a new way to interact with the GPIO and if you need something a little more advanced than GPIO Zero, python3-gpiod is where you need to look. We introduce this Python module by running through two very basic examples that explain the syntax and thinking of the module.

    How to Control the Raspberry Pi 5 GPIO with Python 3 : Read more
    gpiozero or gpiod are not working following error :

    chip = gpiod.Chip('gpiochip4')
    ^^^^^^^^^^^^^^^^^^^^^^^
    File "/home/pi5/pythonprograms/.venv/lib/python3.11/site-packages/gpiod/chip.py", line 58, in __init__
    self._chip = _ext.Chip(path)
    Reply