Trying to read the values from gpio chips in a Python script using the gpiod python module. When calling get_value() we are getting "Operation not permitted".

Have tried running the python script as both root and pi user.

My python test script

import logging
import gpiod

_log = logging.getLogger(__name__)

device = "/dev/gpiochip3"
chip = None

    chip = gpiod.chip(device, gpiod.chip.OPEN_BY_PATH)
except OSError:
    _log.warning("Unable to open gpio chip {device}.")

if chip is None:
    _log.error("GPIO chip {device} not available")

line = chip.get_line(12)
if line is not None:
    print("Line name: ", line.name)
    print(" Line direction: ", line.direction)
    print(" Line consumer: ", line.consumer)
    print(" Line active state: ", line.active_state)
    print(" Line bias: ", line.bias)
    print(" Line value: ", line.get_value())
    print("Line {line_name} was not found")

Running this I get the following output

root@rpi2:~# python3.9 gpio.py 
Line name:  
 Line direction:  1
 Line consumer:  
 Line active state:  2
 Line bias:  1
Traceback (most recent call last):
  File "/root/gpio.py", line 25, in <module>
    print(" Line value: ", line.get_value())
  File "/usr/local/lib/python3.9/dist-packages/gpiod/libgpiodcxx/__init__.py", line 611, in get_value
    raise OSError(
PermissionError: [Errno 1] Operation not permitted: 'error reading GPIO line value'

We have tried using the gpoizero, which seem to work better. The problem with gpiozero is

  1. Support for GPIO expander access the chip directly via I2C-bus, and not via the OS.
  2. It does not support the GPIO expander we are using.

Running Debian Bullseye on a Raspberry Pi.

root@rpi2:~# uname -a
Linux rpi2 5.15.44-rt46-v8+ #1 SMP PREEMPT Mon Jun 13 10:36:58 CEST 2022 aarch64 GNU/Linux

I also tried creating a C++ application using the C++ bindings of the libgpiod. I am getting the same error there, Operation not permitted.

#include <chrono>
#include <cstdlib>
#include <gpiod.hpp>
#include <iostream>
#include <string>

int main(int argc, char **argv) {
    std::string CHIP = "gpiochip1;
    int         LINE_OFFSET = 2;

    gpiod::chip chip(CHIP);
    gpiod::line line = chip.get_line(LINE_OFFSET);

    std::cout << "Line name: " << line.name();
    std::cout << " Line direction: " << line.direction();
    std::cout << " Line consumer: " << line.consumer();
    std::cout << " Line active state: " << line.active_state();
    std::cout << " Line bias: " << line.bias();
    std::cout << " Line value: " << line.get_value();

Using the command line tools gpioget works fine. This tool is using the C-library of libgpiod. Could then the problem be the C++ and Python bindings?

root@rpi2:~# gpioget gpiochip3 12
root@rpi2:~# gpiodetect 
gpiochip0 [pinctrl-bcm2711] (58 lines)
gpiochip1 [raspberrypi-exp-gpio] (8 lines)
gpiochip2 [ftdi-cbus] (4 lines)
gpiochip3 [1-0021] (16 lines)
gpiochip4 [1-0020] (16 lines)

The gpiochip3 and gpiochip 4 are both PCAL6416APW on the I2C-bus. They are configured in /boot/config as following

root@rpi2:~# ls -l /dev/gpiochip*
crw-rw---- 1 root gpio 254, 0 Sep 16 13:34 /dev/gpiochip0
crw-rw---- 1 root gpio 254, 1 Sep 16 13:34 /dev/gpiochip1
crw-rw---- 1 root gpio 254, 2 Sep 16 13:35 /dev/gpiochip2
crw-rw---- 1 root gpio 254, 3 Sep 16 13:35 /dev/gpiochip3
crw-rw---- 1 root gpio 254, 4 Sep 16 13:35 /dev/gpiochip4
  • I wrote using Raspberry Pi, on Debian Bullseye. Using gpioget works fine, on these devices, so why would you say they are imaginary?
    – DJViking
    Commented Sep 19, 2022 at 12:05
  • I added the output from gpiodetect which lists 5 devices.
    – DJViking
    Commented Sep 19, 2022 at 12:08
  • The gpiochip3 is something we have made.
    – DJViking
    Commented Sep 19, 2022 at 12:18
  • I added some information on the gpiochip3 and gpiochip4.
    – DJViking
    Commented Sep 19, 2022 at 12:37
  • 1
    Permissions? Edit result of ls -l /dev/gpiochip* into your question.
    – joan
    Commented Sep 19, 2022 at 15:16

1 Answer 1


The solution was to set the line request.


gpiod::line_request config;
config.consumer     = "Line";
config.request_type = gpiod::line_request::DIRECTION_INPUT;

Same for Python:

config = gpiod.line_request()
config.consumer     = "Line"
config.request_type = gpiod.line_request.DIRECTION_INPUT

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.