0

I should make it clear that I do not have a Pi5 (all the authorised resellers in Australia are out of stock - and I can't even preorder - my normal supplier got a few in late November, but they sold out in minutes) so I have been unable to test.

There has been lots of documentation on the Pi5 and some discussion but it appears that the existing GPIO libraries will not work on Pi5.

Joan posted "pigpio does not work on the Pi 5, I do not think it can be made to work (but hope to be proved wrong). lgpio will work."

6by9 posted "libgpio is the correct answer for any variant of Pi now. There should be no need to directly bash registers through gpiomem holes at all".

lgpio accesses GPIO through the gpiochip device and libgpiod provides some command line tools. When I first tested these (a few years ago) the access was very restrictive but I believe this may have been somewhat relaxed.

gpiozero now uses the lgpio library by default.

raspi-gpio fails on Pi5 but pinctrl I have written a version of my gpioreadall which uses pinctrl.

I already use kernel drivers for SPI & i2c which are quite functional.

I have successfully tested my pi-gpio & pi_gpio libraries on Bookworm.

The main thing that is missing is hardware PWM. There has been a pwm dtoverlay (since at least Stretch) but is largely undocumented and the dtoverlay description states "4) Currently the clock must have been enabled and configured by other means" which is less than helpful. I have since found https://docs.kernel.org/driver-api/pwm.html#using-pwms-with-the-sysfs-interface; I had thought this was deprecated (like the GPIO sysfs interface) but have been assured by a Raspberry Pi Engineer that it is supported. I have written and tested c code (on Pi4 Bookworm) and am writing Python code.

Milliways
  • 59,890
  • 31
  • 101
  • 209
  • Maybe you should edit (or delete) this... you're correct of course; it's not a question. On the subject pf Pi5 availability: the Pi Hut (a UK-domiciled co) may be the best source for any hardware, but you'll wait a long time to get anything delivered. – Seamus Nov 29 '23 at 04:54

1 Answers1

0

In Bookworm (and latest Bullseye) the kernel device driver for GPIO has been updated so GPIO settings are persistent and it is now possible to specify pulls.
This means libgpiod behaves similarly to sysfs (and most tools accessing registers).

There is kernel documentation and a python module gpiod but it is difficult to follow (unless you are a kernel developer) and no User Documentation.

There are a few examples e.g. https://www.tomshardware.com/how-to/control-raspberry-pi-5-gpio-with-python-3

The current libgpiod is old (v1.6.3 in Bookworm and even older in Bullseye) the v2 code is significantly different but it unclear if or when this may be included in Raspberry Pi OS.

I decided to test the gpiod module and write a wrapper which uses the same functions as my pi_gpio library.

This obviously excludes I²C, SPI or Hardware PWM but I have code implementing these using kernel drivers which will be included in a final library as will Information functions.

This code has been updated and tested on a Pi5 and allows existing code to run with minimal change, but if writing new code use gpiod or lgpio (which is faster and includes additional functionality).

#! /usr/bin/env python3
"""
p_gpio is a Python module for the RaspberryPi
Using gpiod Python Interface
This is a wrapper which uses the same functions as pi_gpio library.

OVERVIEW

GPIO setup_gpio - Set gpio as an input or an output

input_gpio - Returns the GPIO level__plibrary

output_gpio - Output to a GPIO channel

input_28 - Returns value of GPIO 0-27

output_28 - Sets value of GPIO 0-27

gpio_function - The current GPIO mode

get_pullupdn - The current GPIO pull/up down

"""

2024-04-04

import gpiod

VERSION='0.2'

chip = gpiod.find_line('ID_SDA').owner() # find chip with ID_SDA

gpiomap = {} # This is a dictionary to avoid repeated chip.get_line(gpio) calls

GPIO

NOTE all gpio use Broadcom BCM numbers

INPUT=0 OUTPUT=1

LINE_REQ_DIR_AS_IS = 1

LINE_REQ_DIR_IN = 2

LINE_REQ_DIR_OUT = 3

LINE_REQ_EV_BOTH_EDGES = 6

LINE_REQ_EV_FALLING_EDGE = 4

LINE_REQ_EV_RISING_EDGE = 5

LINE_REQ_FLAG_ACTIVE_LOW = 4

LINE_REQ_FLAG_BIAS_DISABLE = 8

LINE_REQ_FLAG_BIAS_PULL_DOWN = 16

LINE_REQ_FLAG_BIAS_PULL_UP = 32

LINE_REQ_FLAG_OPEN_DRAIN = 1

LINE_REQ_FLAG_OPEN_SOURCE = 2

ACTIVE_HIGH = 1

ACTIVE_LOW = 2

BIAS_AS_IS = 1

BIAS_DISABLE = 2

BIAS_PULL_DOWN = 4

BIAS_PULL_UP = 3

DIRECTION_INPUT = 1

DIRECTION_OUTPUT = 2

def setup_gpio(gpio, direction, pud):

def setup_gpio(gpio, direction, pud=0): # optional pud

""" Set gpio as an input or an output direction: 0=IN, 1=OUT pud: 0=None 1=Up 2=Down """ line = chip.get_line(gpio) gpiomap[gpio] = line if direction: line.request(consumer="p_gpio", type=gpiod.LINE_REQ_DIR_OUT) else: f = gpiod.LINE_REQ_FLAG_BIAS_DISABLE if pud==1: f = gpiod.LINE_REQ_FLAG_BIAS_PULL_UP if pud==2: f = gpiod.LINE_REQ_FLAG_BIAS_PULL_DOWN line.request("p_gpio", gpiod.LINE_REQ_DIR_IN, f) print('pud= ', pud, 'bias= ', line.bias())

def input_gpio(gpio): """ Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False """ return gpiomap[gpio].get_value()

def output_gpio(gpio, value): """ Output to a GPIO channel. value - 0/1 or False/True or LOW/HIGH """ gpiomap[gpio].set_value(value)

def gpio_function(gpio): """ Returns the current GPIO direction Only works if gpio in use Returns 0,1 (IN, OUT) """ if gpio in gpiomap: return gpiomap[gpio].direction() - 1 return 0

def get_pullupdn(gpio): """ Return the current GPIO pull Only works if gpio in use Returns 0:None/Unknown 1:Up 2:Down """ if gpio in gpiomap: return gpiomap[gpio].bias()-2 return 0

Dummy functions

def setup(): pass

def cleanup(): pass

#------------- import time

def main(): global chip SigOUT = 12 SigIN = 13 LOOPS = 20000 setup_gpio(SigOUT, 1, 0)

setup_gpio(SigIN, 0, 0)

setup_gpio(SigIN, 0, 1)

setup_gpio(SigIN, 0, 2)

t0 = time.time()

for i in range(LOOPS): output_gpio(SigOUT, 1) output_gpio(SigOUT, 0)

t1 = time.time()

print("gpiod Python\t{:>10.0f} toggles per second".format((1.0 * LOOPS) / (t1 - t0))) output_gpio(SigOUT, 1) print("{}".format(input_gpio(SigIN))) print('SigIN function= ', gpio_function(SigIN)) print('SigOUT function= ', gpio_function(SigOUT)) print('pud= ', get_pullupdn(SigIN)) print('pud= ', get_pullupdn(4))

if name == 'main': main()

Milliways
  • 59,890
  • 31
  • 101
  • 209
  • The libgpiod v2 documentation. Not quite up to date, but the differences are minor. And there are more examples in the libgpiod source tree, for C and all the other language bindings, including python. If you need examples that aren't already covered there then let us know and we'll add some. Of course that is for v2, which you are reluctant to use as it isn't packaged in Raspberry Pi OS yet, but I can't help you with that. And you couldn't pay me to write examples for v1. – Kent Gibson Jan 05 '24 at 16:03
  • The Toms Hardware example is no longer functional with the most recent version of gpiod. You will need to install an older version of gpiod for it to work. – utdream Mar 28 '24 at 21:44