RPi5 uses different gpio pin numbers (per Linux kernel update)
SherbertLemon64 opened this issue ยท 48 comments
Running the getting started code in examples_linux in cpp gives the error
terminate called after throwing an instance of 'GPIOException' what(): can't access /sys/class/gpio/gpio%d/direction GPIO pin. check access rights Aborted
Running the python code gives an equivalent error. Everything here is run as root
I have the library working on a pi zero however it is giving some issues on a pi 5
I have installed it using spidev
Does anyone have an idea what this is, could it be compatibility with the pi 5 as I have got it working following the same steps on the pi zero with a much older version of the os
I have installed it using spidev
The SPIDEV driver uses the Linux kernel user space API. While this doesn't require root privilege, it does require the user belong to whatever user-group owns the /sys/class/gpio. The solution you seek may be in the form of a udev rule.
FYI, this doesn't usually happen on RPi OS distributions because they set up necessary permissions as defaults for the user pi
.
PS - Its not conventionally recommended to run python as root. Use a venv and invoke root permission on the venv executable:
(env) $ sudo /path/to/env/bin/python3 examples_linux/getting_started.py
I forgot the RPi5 is using an offshoot the RP2040 as the gpio controller. I'm hoping this doesn't mean a breaking change to how the Linux kernel is mapped out for hardware peripherals.
@SherbertLemon64 Seems like RPi5 just came out. If you find the solution, please update this thread. And please confirm what OS (including 32 bit or 64 bit arch) you are using.
I forgot the RPi5 is using an offshoot the RP2040 as the gpio controller. I'm hoping this doesn't mean a breaking change to how the Linux kernel is mapped out for hardware peripherals.
@SherbertLemon64 Seems like RPi5 just came out. If you find the solution, please update this thread. And please confirm what OS (including 32 bit or 64 bit arch) you are using.
Ah that could be it, I'll look into it later and see if I get anywhere. It seemed to be broken for the bcm and spidev versions but in different ways, bcm would freeze and couldn't be ctrl c stopped, and spidev would give this error
I'm using the latest 64 bit Debian as of this post, bookworm.
Keep in mind I'm not entirely sure what I am doing here and haven't properly used the library yet, so it could also just be my incompetence, but an issue with the RPi 5 seems likely
Reading through the RPi doc page now. I noticed this new section about gpio permission. Have you tried the recommended command?
sudo usermod -a -G gpio $USER
Most of what I can find right now is focused on pure python code.
I'm using the latest 64 bit Debian as of this post, bookworm.
64 bit means you have to use our newer CMake install instructions (or auto-install script that's linked from that page). Using the older .configure
script isn't designed for aarch64.
bcm would freeze and couldn't be ctrl c stopped
I'd be surprised if any drivers other than SPIDEV work on such freshly minted products.
- The BCM2835 lib (antiquatedly named) isn't updated often.
- We're lucky if MRAA is still supporting new RPi hardware.
- PiGPIO uses the same approach as SPIDEV but with an extra layer of abstraction so it can be managed remotely via service daemon.
- WiringPi support is deprecated, so we're not patching that up anymore.
issue with the RPi 5 seems likely
Maybe because of the drastic hardware changes. But we went through similar speculations when the RPi4 came out, and those issues/questions boiled down to "noob problems".
I have that user setting, and will try that different make, however the python version is giving the same error so it shouldn't be that
I believe that I have found the issue. In the spidev file gpio.cpp and RF24_arch_config.h the port is conflated with pin numbers, this has been changed on the pi 5
Lines 30 to 38 in 638095e
the port here should be altered either here or otherwise to account for the offset now used in the pi 5 and others going forward,
This is talked about in this forum post by a Pi Engineer
the port here should be altered either here or otherwise to account for the offset now used in the pi 5 and others going forward,
This is talked about in this forum post by a Pi Engineer
According to that linked forum post, the solution was to update the kernel on the user's machine (which used the RPi OS). I'll be honest, I didn't really follow all the pinctrl
stuff (which seems like program specific to the RPi OS).
In the spidev file gpio.cpp and RF24_arch_config.h the port is conflated with pin numbers
I don't understand this. The pin numbers passed to RF24::RF24()
(constructor) are what is used by the SPIDEV/gpio.cpp in GPIO::open()
. So, maybe the examples' pin numbers need to change specifically for the RPi5?
the port here should be altered either here or otherwise to account for the offset now used in the pi 5 and others going forward
Again, I find this statement confusing. Given the exception that you're reporting, the port
number never gets used because fopen("/sys/class/gpio/export", "w")
failed.
Determining the hardware at build time
Ok, this might sound super confusing, but I'll try to keep it simple.
We detect what machine (and version of RPi model) is being used during the "build process" (more accurately put "building the Makefile scripts"). As I've said before, the .configure
script is not designed for aarch64 compilers. It was designed for armeabihf compilers. I'll be focusing on the Cmake build scripts because that's the recommended build instruction (since v1.4.2) and is required for 64 bit systems.
I need to see the output of the cmake ..
command (executed from within a new folder called "build" at repo root). What I'm looking for are the lines that show the value of the detected "SoC" and "CPU type".
On my RPi4, it looks like this
(env) brendan@rpi4-ubuntu-64bit:~/github/RF24/build$ cmake ..
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Setting build type to 'Release' as none was specified.
-- RF24 library version: 1.4.8
CMake Warning at cmake/Cache.cmake:27 (message):
ccache is enabled but was not found. Not using it
Call Stack (most recent call first):
CMakeLists.txt:39 (include)
-- detected SoC: BCM2835
-- detected CPU type: aarch64
-- tool name being used: aarch64-linux-gnu
-- Using driver: RPi
-- ready to package: librf24-RPi_1.4.8-1_arm64.deb
-- ready to package: librf24-RPi-1.4.8-1.arm64.rpm
-- Disabling IRQ pin support
-- Configuring done
-- Generating done
-- Build files have been written to: /home/brendan/github/RF24/build
I'm guessing the detected SoC for the RPi5 is
-- detected SoC: BCM2712
I need my guess confirmed before we can start talking about how to alter the library source code (or examples' code).
Just going to respond to your question before I respond to the last bit, the actual detected SoC for the RPi is ..... UNKNOWN
don't judge me for using pi as my username (you definitely don't know my password)
The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Setting build type to 'Release' as none was specified.
-- RF24 library version: 1.4.8
CMake Warning at cmake/Cache.cmake:27 (message):
ccache is enabled but was not found. Not using it
Call Stack (most recent call first):
CMakeLists.txt:39 (include)
-- detected SoC: UNKNOWN
-- detected CPU type: aarch64
-- tool name being used: aarch64-linux-gnu
-- Found pigpio library: /usr/lib/libpigpio.so
-- Using driver: pigpio
-- ready to package: librf24-pigpio_1.4.8-1_arm64.deb
-- ready to package: librf24-pigpio-1.4.8-1.arm64.rpm
-- Using utility library: /usr/lib/libpigpio.so
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/Desktop/code/transciever/rf24libs/RF24/build
I went through the code and the sys_info file does not exist on this machine, however the proc/cpuinfo does and gives
processor : 0
BogoMIPS : 108.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x4
CPU part : 0xd0b
CPU revision : 1
processor : 1
BogoMIPS : 108.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x4
CPU part : 0xd0b
CPU revision : 1
processor : 2
BogoMIPS : 108.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x4
CPU part : 0xd0b
CPU revision : 1
processor : 3
BogoMIPS : 108.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x4
CPU part : 0xd0b
CPU revision : 1
Revision : c04170
Serial : a**************f
Model : Raspberry Pi 5 Model B Rev 1.0
don't judge me for using pi as my username (you definitely don't know my password
I don't care if it was named "clown". I deeply appreciate freedom of choice; cyber-secure practices is a choice as evident to all privacy policies we are subjected to nowadays.
Why did this come up? Did I say something out-of-line?
the actual detected SoC for the RPi is ..... UNKNOWN
That's troubling! In the past we were able get system info using
Lines 2 to 26 in 638095e
So if running grep Hardware /proc/cpuinfo
returns nothing, we have to find another way to identify the system CPU. Keep in mind that this tactic is specific to the OS, not the RPi5.
Oh no I was just joking because I felt self conscious leaving it as the default password,
Indeed let's see, it looks like the cpuinfo is happy being fairly different for each system
I see the same output in our Linux build CI logs:
-- detected SoC: UNKNOWN
-- detected CPU type: x86_64
All this really mean to the build is that there are no special compiler optimizations enabled. It should still build fine. Obviously testing GPIO hardware in CI is impossible without a self-hosted runner (using a RPi4 which we have considered but never decided).
Yeah I think that I was going somewhere with what I said before I'm just rephrasing it and failing to use permalinks to code properly
According to that linked forum post, the solution was to update the kernel on the user's machine (which used the RPi OS). I'll be honest, I didn't really follow all the
pinctrl
stuff (which seems like program specific to the RPi OS).
Sorry I don't think I explained myself particularly well, That was a forum post which highlighted how the pins are numbered in newer versions of the os, when you do cat /sys/kernel/debug/gpio
in older versions the number would match up with the pin number, however they have changed this so that it doesn't.
To try this for yourself you can follow the commands in the gpio.cpp program with the first function open
(forgive the lack of nice permalinks, i'll redo it in an edit when I get them working - did you get them working? I pasted links with characters in which was the issue)
The lines which I referenced before
Lines 32 to 39 in 638095e
are equivalent to
echo {NUMBER} > /sys/class/gpio/export
we can then do
cat gpio{NUMBER}/value
to get if the pin is high or low
Given that the number references a valid pin listed above in the cat, it will create a file to reference the pin, What that forum post talks about in some parts is that this used to be a 1-1 match with the GPIO number of the pin, now it is somewhat arbiturary values ie 402 - GPIO 3
This is to say that the code then fails at this point
Lines 42 to 52 in 638095e
When there is no file created as the pin number above was incorrect. This is not correctly identified as an error in line 37, instead caught as an error in line 48
I'm beginning to get curious about using Debian instead of RPi OS 64 bit. Can you swap out the SD card for one that is flashed with RPi OS instead of Debian?
I have my RPi4 running Ubuntu 64 bit and the setup process is rather cumbersome compared to RPi OS. For Ubuntu on RPi, I have to
- install/enable SSH server
- disable the desktop env (and uninstall the libreoffice stuff)
- modify my user's groups (to include
dialout
for SPI I2C and UART buses) - configure GPIO access rights (and I don't recall how I did that now)
๐
forgive the lack of nice permalinks
The column numbers aren't respected in github comments, only the line numbers. Just have to remove the Cy
bit from #LxCy
part of the permalinks
I am using the RPi OS 64 bit, I just gave the debian version as the rpi os is just debian with some minor added extras, or so I thought?
The debian version is from the website https://www.raspberrypi.com/software/operating-systems/
Do you have a spare SD to give this a go on a four? I think that this should be the same on there given the latest Pi OS version, I might also give it a go chucking it into a 3B+ as that is the only other 64 bit capable pi I have
Or If you want to move this conversation onto discord while we are working things out I can show you my ssh
This is to say that the code then fails at this point
Does that mean using a new build has yielded a different error than was reported in the OP? I was unaware of that development.
I am using the RPi OS 64 bit, I just gave the debian version as the rpi os is just debian with some minor added extras, or so I thought?
Oh! Yeah, they aren't that similar. RPi OS is a "based on" Debian, just like Ubuntu is a also based Debian, the 2 distros are very different in many respects (thus the complete name change).
I could try spinning up my RPi3 or RPi4 with a newly flashed SD card. I've been meaning to do this for my RPi3, so I'll probably start with that.
Or If you want to move this conversation onto discord while we are working things out I can show you my ssh
I'm not against the idea, but I rarely use discord (not much of a gamer anymore). Although this thread should be apprised of any relevant findings.
Does that mean using a new build has yielded a different error than was reported in the OP? I was unaware of that development.
I believe it does but that is something for us to test now
Oh! Yeah, they aren't that similar. RPi OS is a "based on" Debian, just like Ubuntu is a also based Debian, the 2 distros are very different in many respects (thus the complete name change).
Ahhh okay yep I should have been clearer in my original message way back then
I'm not against the idea, but I rarely use discord (not much of a gamer anymore). Although this thread should be apprised of any relevant findings.
I'll email you my discord username and we can write up something as we go, I get the apprehension in the message though and it is absolutely fine if you just want to continue it all on here
As described in https://www.thegoodpenguin.co.uk/blog/stop-using-sys-class-gpio-its-deprecated/ , gpio.cpp relies on deprecated linux code, in newer versions of the RPi os they have changed the numbers that sys/class/gpio uses to higher numbers, this seems like a somewhat aesthetic change by the developers as they see sysfs as something that people should stop using anyway as it has been deprecated for 7 years so to them it doesn't matter if these libraries no longer work. This is described in the forum post referred to earlier https://forums.raspberrypi.com/viewtopic.php?t=359302#p2165403
I'll give it a go rewriting the gpio.cpp file to use libgpiod as that is now the accepted way to do it in linux
Think I found a workaround for the SoC info:
(.env) brendan@rpi3-64bit:~/github/RF24/build $ cat /proc/device-tree/compatible
raspberrypi,3-model-b-plusbrcm,bcm2837
Tip
libgpiod was not included with the Ubuntu OS jammy (64-bit).
I had to install it using
sudo apt install gpiod
It was included in the minimal image download for RPi OS bookworm.
A no-dependency solution is to use the linux kernel character device API (which is the replacement for GPIO user space API). The libgpiod library is an API that wraps the Linux kernel's character device API into a more user-friendly interface (documented with doxygen which is hosted at https://libgpiod.rtfd.io).
Since linux 4.8 the GPIO sysfs interface is deprecated. User space should use
the character device instead. This library encapsulates the ioctl calls and
data structures behind a straightforward API.
I'm not too keen on requiring users have another library installed to use the Linux kernel's character device API, which doesn't require any dependencies. The SPIDEV driver was meant to directly use the Linux kernel API to avoid a complicated build process (and for speed).
There are examples of using the character device APi on the web:
- https://blog.lxsang.me/post/id/33
This is a simple and straight forward overview of using the character device API - https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html
A not-so-simple documented "lab" (from a online course?) about using character device API.
This will have some historic information (which adds to the confusion for me).
The latest docs for a generic Linux kernel seem rather vague or too detailed. I'm half tempted to just boot into Ubuntu on my desktop just to look at the Linux kernel headers source files (located at /usr/include/linux/**.h
) which are very terse in terms of any explanation/meaning). About a year ago, this is how I wrapped the Arduino I2C API around the Linux kernel user space API for SMBUS. When I finally got it working, I hoped I would never have to do that again, and no I didn't dare delve into interrupts.
Too bad we didn't catch this before the RPi5 came out, I still can't get my hands on one.
Are you taking this up @2bndy5 or should I delve into this?
Apologies, my RPi 5 is unable to boot past initramfs so I am unable to give pi 5 specific information for a little while, hopefully i can get it working soon I'll confirm the pi 5 SoC detecting then
I'm not volunteering. I spent about an hour researching for my last comment.
@SherbertLemon64 I just hacked together some code that should work on the RPi5 and put it in https://github.com/nRF24/RF24/tree/GPIO_Changes
Its really rudimentary, but I'm only wondering if it functions on the RPi5. I will put more work into it later if it actually functions. Please let me know if/when you have a chance to test it out.
I'll give that a go if/when I get my pi working again
Just got it booting from usb, should have tried this earlier it is definitely an sd card reader problem for this pi
firstly
Think I found a workaround for the SoC info:
(.env) brendan@rpi3-64bit:~/github/RF24/build $ cat /proc/device-tree/compatible raspberrypi,3-model-b-plusbrcm,bcm2837
This works, as expected it gives me raspberrypi,5-model-bbrcm,bcm2712
so that should be used for the cpuinfo make file
When I ran your code in https://github.com/nRF24/RF24/tree/GPIO_Changes
it gave me the exception
terminate called after throwing an instance of 'SPIException' what(): can't open device Aborted
I believe that this is partly due to using "/dev/gpiochip0" I think it should be 4? but I could be wrong, where did you get it being 0 from?
What is your workflow for compiling and debugging the library, I have programmed a lot in c# but this is my first proper venture into cpp. I couldn't tinker because I couldn't bet my changes in gpio.cpp to compile, that's just something I need to learn
Thanks for the info. Unfortunately its probably going to be a while before I can get a RPi5 for testing.
Have you enabled SPI via sudo raspi-config
? Modifying the GPIO functions shouldn't typically result in an SPI error AFAIK.
I'm just using /dev/gpiochip0 because thats what was in the example and its common between the RPi2 through RPi4. My RPi3 and 4 have gpiochip0, 1 and 2, where the earlier models just have 0. If you call ls /dev | grep gpiochip
you should see what is there. You can try it with 4, but I believe it should work with 0.
I typically just use the installer(s) for compilation and tend to debug things manually, reading through code and testing things. Can't really explain my workflow there hehe. I just pretend to know what I'm doing most of the time. :p
ah yep that would be it, I forgot this was a fresh install of the os, Ill give that a go shortly
I'll have a look at that, when I was doing it in sys/class/gpio before, it is was the gpiochip4 that had all the pins on it so I think it would be the same
what do you mean by the installer(s)? just the configure executable?
wget https://raw.githubusercontent.com/nRF24/.github/main/installer/install.sh
for the CMake installer
chmod +x install.sh
./install.sh
yep it all works now, I'm getting the same error as before which is good I think?
edit:
by before I mean the /sys/class/... error
wget https://raw.githubusercontent.com/nRF24/.github/main/installer/install.sh
for the CMake installer
chmod +x install.sh
./install.sh
ah yep, I meant recompiling after editing /utility/ files so the edits are reflected when you run, my confusion probably comes from my lack of understanding of cpp
I mean the /sys/class/... error
Did you remember to copy the files from the GPIO_Changes branch into the rf24libs/RF24 folder that the installer creates?
I mean the /sys/class/... error
Did you remember to copy the files from the GPIO_Changes branch into the rf24libs/RF24 folder that the installer creates?
oh I could give that a go, I was just copying your changed files and running configure. Yes that looks like it would do it
Do you have a spare SD to give this a go on a four?
I ran out of space on my RPi4's SD card (which was using Ubuntu 64-bit). So, I just flashed the new RPi OS lite 64-bit (bookworm) onto my RPi4. Unfortunately, I was not able to reproduce this issue.
I was able to replicate this issue on a new RPi5 with RPi OS 64-bit Bookworm. I have it working with the RF24 layer, but am having troubles with the RF24Network and higher layers. Will update once I have more info...
So as of this AM, this is where I'm at:
I have RF24 working.
With RF24Network, the helloworld_rx sketch works, but helloworld_tx results in Sending .. RF24 HARDWARE FAIL: Radio not responding, verify pin connections, wiring, etc.
I am having a lot of trouble isolating the issue, since everything works on RPi v2 to 4, just not on the v5. The issue pops up when txStandBy()
is called from RF24Network. I've tried using writeFast()
& txStandBy()
in the gettingstarted example and it works fine...
Have you pushed your changes to some branches?
I'm just using the changes in the https://github.com/nRF24/RF24/tree/GPIO_Changes branch which I've been running on my other RPis with no issues.
Line 25 in 6a78ecf
Are we sure this path is correct on RPi5? I wish I had an RPi5 to help reproduce.
Genius! You solved it without a RPi5 hehe. I just tested with const char* dev_name = "/dev/gpiochip4";
and it works...
gpiochip1-3 all fail, and gpiochip0 works with RF24 layer lol.
Now I just have to address some issues in the examples that relate to using a 64 bit OS. ie: helloworld.tx with its unsigned long ms;
unsigned long counter; should be uint32_t
instead of unsigned long
. I think there are issues in the Gateway layer also.
Wow! That was like a blind person playing darts and hitting the bullseye.
My only concern going forward is: Will this path remain consistent for all RPi5 (or future) models?
I think we could probe the file system at compile-time, but that seems a bit hacky, even for me.
Yeah I don't know. Only the RPi5 has gpiochip4, the RPi4 only has 0,1 & 2. We could just start by trying to read/write to gpiochip4, if that fails, use gpiochip0. This could all be contained in the gpio.cpp file.
char* dev_name = "/dev/gpiochip4";
fd = open(dev_name, O_RDONLY);
if (fd >= 0){
close(fd);
}else{
dev_name = "/dev/gpiochip0";
fd = open(dev_name, O_RDONLY);
if (fd >= 0){
close(fd);
}
}
Looks good! Apologies I haven't been much use the past month, did badly on a mock and been revising a tonne. How are you thinking of managing the different pin mappings, there is sys/kernel/debug/gpio that gives a decent mapping but that still seems a bit iffy to map properly through code. The burden of mapping the pin numbers could be passed onto the user but that doesn't seem ideal, this also gives what gpiochip to use so seems like a good idea to solve both problems in one
Not sure what you mean? We are using the pin numbers for GPIO, so they should remain the same as in previous versions. I didn't have to change any of the GPIO pins in the examples to get it working.
really? That's what my original problem was all about, what do you get if you look at the file I suggested before
edit It basically shows the correct pins are on /dev/gpiochip4 instead of 0 like the other RPis. That should be the only change required. I have the whole RF24 stack running with the https://github.com/nRF24/RF24/tree/GPIO_Changes modifications. If installed correctly, you should be getting different GPIO error messages if any.