Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access to GPIO fails with all versions of RaspiOS starting from 2024-10-28 on Raspberry Pi 5 #2366

Open
ciacco85 opened this issue Nov 27, 2024 · 18 comments
Labels
bug Something isn't working untriaged

Comments

@ciacco85
Copy link

Describe the bug

It was ok with previous versions of RaspiOS until 2024-07-04.
The code runs in a container under IotHub module.

Steps to reproduce
First of all, I've solved with a workaround using this code that isn't production ready

#pragma warning disable SDGPIO0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
        gpioController = new GpioController(PinNumberingScheme.Logical, new LibGpiodDriver(0, LibGpiodDriverVersion.V1));
#pragma warning restore SDGPIO0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
    }

and with the following Dockerfile (I'm sure I can remove some packages)

RUN apt-get update \
    && apt-get install -y sudo libgpiod2 gpiod libgpiod-dev libpigpiod-if-dev libpigpiod-if1 libpigpiod-if2-1

Full very simple code at my repo gpio-tester
Previous attempts as suggested in #2361

  • 1 Create a simple Console App and run outside the container -> OK
  • 2 Containerized the app, but using the old approach that has worked fine in the last year -> KO
        gpioController = new GpioController();

and with the following Dockerfile

RUN apt-get update \
    && apt install -y sudo libgpiod-dev

Made a lot of attempt trying different package without success until I've found the working solution described above

Expected behavior

All should work with

        gpioController = new GpioController();

or at least this code inside your library should be modified from this

case RaspberryBoardInfo.Model.RaspberryPi5:

                // For now, for Raspberry Pi 5, we'll use the LibGpiodDriver.
                // We need to create a new driver for the Raspberry Pi 5,
                // because the Raspberry Pi 5 uses an entirely different GPIO controller (RP1)
                return new LibGpiodDriver(4);

to this

case RaspberryBoardInfo.Model.RaspberryPi5:

                // For now, for Raspberry Pi 5, we'll use the LibGpiodDriver.
                // We need to create a new driver for the Raspberry Pi 5,
                // because the Raspberry Pi 5 uses an entirely different GPIO controller (RP1)
                return new LibGpiodDriver(0, LibGpiodDriverVersion.V1);

I can make a PR, but I think this part is so crucial and you're already working on the implementation for RP1

Actual behavior
This exception is thown

11/11/2024 14:22:45 +01:00 System.IO.IOException: Unable to find a chip, error code: 2
   at System.Device.Gpio.Drivers.Libgpiod.V1.LibGpiodV1Driver..ctor(Int32 gpioChip)
   at System.Device.Gpio.Drivers.LibGpiodDriverFactory.CreateInternal(LibGpiodDriverVersion version, Int32 chipNumber)
   at System.Device.Gpio.Drivers.LibGpiodDriverFactory.CreateAutomaticallyChosenDriver(Int32 chipNumber)
   at System.Device.Gpio.Drivers.LibGpiodDriverFactory.Create(Int32 chipNumber)
   at System.Device.Gpio.Drivers.LibGpiodDriver..ctor(Int32 gpioChip)
   at System.Device.Gpio.GpioController.GetBestDriverForBoardOnLinux()
   at System.Device.Gpio.GpioController.GetBestDriverForBoard()
   at System.Device.Gpio.GpioController..ctor(PinNumberingScheme numberingScheme)
   at System.Device.Gpio.GpioController..ctor()

Versions used

Latest version 3.2.0 of System.Device.Gpio and net9

@ciacco85 ciacco85 added the bug Something isn't working label Nov 27, 2024
@ciacco85
Copy link
Author

One of the attempts I've tried is

 return new LibGpiodDriver(0, LibGpiodDriverVersion.V2);

without succes. Diggin into LibGpiodDriver contructor I've found into LibGpiodDriverFactory

private LibGpiodDriverVersion? GetAutomaticallySelectedDriverVersion()
{
    return DriverCandidates.Any() ? DriverCandidates.Max() : null;
}

that deals with _installedLibraries. Since in my working solution I've forced V1 version, may be that latest RaspiOS now install by the V2 version, the library find it but has some incompatibility with your code?

One more thingh: what about the gpioChip parameter of LibGpiodDriver contructor? Your default is 4, mine is 0 and is working!
Thank you for your amazing job with this ecosystem!

@krwq
Copy link
Member

krwq commented Dec 5, 2024

[Triage] Can you confirm we understand this correctly? V1 works but with gpioChip = 0 and V2 does not work at all?

@ciacco85
Copy link
Author

ciacco85 commented Dec 5, 2024

[Triage] Can you confirm we understand this correctly? V1 works but with gpioChip = 0 and V2 does not work at all?

Yes @krwq. Same error with V2 and gpioChip = 0. This is my final working lazy GpioController initialization.

    private readonly Lazy<GpioController> gpioController;
    private GpioController _gpioController { get => gpioController.Value; }
    public LedManager(ILogger<LedManager> logger)
    {
        _logger = logger;
        gpioController = new(() => GpioControllerFactory());
    }

    /// <summary>
    /// Create GpioController
    /// </summary>
    /// <returns></returns>
    private GpioController GpioControllerFactory()
    {
        try
        {
            //old working way on pre 2024-10-28 RaspiOS devices
            return new GpioController();
        }
        catch (Exception ex)
        {
            _logger.LogWarning($"Error creating GpioController standard, trying new way with experimental features....{Environment.NewLine}{ex.ToString()}");
#pragma warning disable SDGPIO0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
            //new working way on after 2024-10-28 RaspiOS devices
            return new GpioController(PinNumberingScheme.Logical, new LibGpiodDriver(0, LibGpiodDriverVersion.V1));
#pragma warning restore SDGPIO0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
        }
    }

I honestly didn't search what gpioChip stand for, but I can try different combination if you need more test on my side.

@krwq
Copy link
Member

krwq commented Dec 12, 2024

[Triage] @ciacco85 can you run gpiodetect (sudo apt-get install gpiod if needed) command on your PI - we're curious if there are any differences between different versions of RPi5s, I think we're getting closer to figure out the logic for the detection

here is example output:

$ gpiodetect
gpiochip0 [pinctrl-rp1] (54 lines)
gpiochip10 [gpio-brcmstb@107d508500] (32 lines)
gpiochip11 [gpio-brcmstb@107d508520] (4 lines)
gpiochip12 [gpio-brcmstb@107d517c00] (17 lines)
gpiochip13 [gpio-brcmstb@107d517c20] (6 lines)
gpiochip0 [pinctrl-rp1] (54 lines)

the 54 lines chip is likely the one which needs to be passed to LibGpiodDriver

@ciacco85
Copy link
Author

ciacco85 commented Dec 12, 2024

gpiodetect

@krwq here it's the result! it seems the same

$ gpiodetect
gpiochip0 [pinctrl-rp1] (54 lines)
gpiochip10 [gpio-brcmstb@107d508500] (32 lines)
gpiochip11 [gpio-brcmstb@107d508520] (4 lines)
gpiochip12 [gpio-brcmstb@107d517c00] (17 lines)
gpiochip13 [gpio-brcmstb@107d517c20] (6 lines)
gpiochip0 [pinctrl-rp1] (54 lines)

@raffaeler
Copy link
Contributor

I just had access to a RPi5 and the result is very different:

$ gpiodetect
gpiochip0 [gpio-brcmstb@107d508500] (32 lines)
gpiochip1 [gpio-brcmstb@107d508520] (4 lines)
gpiochip2 [gpio-brcmstb@107d517c00] (17 lines)
gpiochip3 [gpio-brcmstb@107d517c20] (6 lines)
gpiochip4 [pinctrl-rp1] (54 lines)
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
$ cat /proc/cpuinfo
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        : d04170
Serial          : 00f314ef4983fb91
Model           : Raspberry Pi 5 Model B Rev 1.0

@ciacco85 I invite you to do the same and compare the results. Thanks

@raffaeler
Copy link
Contributor

BTW I just see a lot of posts saying that the recent kernel update changed the mappings of the chip id.
This article best describes what happened, but there are others specific to the Raspbian distribution.
http://git.munts.com/muntsos/doc/AppNote11-link-gpiochip.pdf

@ciacco85
Copy link
Author

cat /etc/os-release

here it is my results @raffaeler
It seems the same to me!

cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
cat /proc/cpuinfo
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          : e4545656b96ccf93
Model           : Raspberry Pi 5 Model B Rev 1.0

@ciacco85
Copy link
Author

BTW I just see a lot of posts saying that the recent kernel update changed the mappings of the chip id. This article best describes what happened, but there are others specific to the Raspbian distribution. http://git.munts.com/muntsos/doc/AppNote11-link-gpiochip.pdf

@raffaeler
Honestly I'm having hard time with all interfaces "stuff" since october release of RaspiOS! Especially with I2C.
I'm digging all yours source code and, at the very end, it deals with UnixSpiDevice/UnixSpiDevice! In SPI there's always GpioController and I'm testing that, but with I2C I'm getting a lot of bus error like that
kernel: i2c_designware 1f00074000.i2c: timeout waiting for bus ready
I don't want to mix issues related to Rapsberry kernel repository since it's OT, but according to this this and maybe this (my app relys lot on PN532) there're some low level stuffs that are getting out of control!
My opinion is that Raspberry Pi 5, with its new hardware, is causing lot of trouble and they are moving from old compatibility mode to native stuff that new drivers can't manage. Can you tell me if it's wrong?
Honestly, If I'm using C# is because I'm familiar with it, but what I think is that with there kernerl/driver changes on RPi5 you'll have hard time adapting your code! Am I wrong?

@raffaeler
Copy link
Contributor

@ciacco85 Apparently this is "just" a kernel update unrelated to the hardware revision board.
We have to investigate whether there is a reliable way to detect the chip number without making any assumptions.

With regards to the OS kernel issues, I think we can't do much about it from our library.
On your side there are a couple of things that may be useful:

  • provide the simplest possible repro code demonstrating the issues you are having with I2C
  • provide feedback in the raspberry repo so that they hear loud and clear about the issues

HTH

@raffaeler
Copy link
Contributor

After further investigation, I found that the System.Device.Gpio.Drivers.Libgpiod.V2.LibGpiodV2Driver is already able to provide the info needed to detect the correct chip.

In fact it has the following private field:

private readonly Chip _chip;

The Chip class has the GetInfo() method that returns a ChipInfo.
The ChipInfo class has two final methods:

public string GetName()
public string GetLabel()

These methods return the same info provided by gpiodetect.
Anyway, in order to get this field, we should create the driver first, but this needs the gpiochip number, which is exactly what we are trying to identify.

There is some work to do:

  1. Provide a way to open all the available /dev/gpiochipX devices
  2. For each gpiochipX, create the Chip class, read the ChipInfo and use the GetLabel() to verify the chip signature
  3. Once we find the correct gpiochipX we can return it and it can be used by the LibGpioDriver
    These steps should be placed into the autodetect algorithm.

Unfortunately, the libgpiod v1 driver does not provide the same info, but they are available and could be added to the driver similarly to what the v2 does. Once added support for the Chip and ChipInfo in v1, the above steps should be repeated for the v1 as well.

Anyone willing to contribute with a PR on this is welcome.

@ciacco85
Copy link
Author

@ciacco85 Apparently this is "just" a kernel update unrelated to the hardware revision board.
We have to investigate whether there is a reliable way to detect the chip number without making any assumptions.

With regards to the OS kernel issues, I think we can't do much about it from our library.
On your side there are a couple of things that may be useful:

  • provide the simplest possible repro code demonstrating the issues you are having with I2C
  • provide feedback in the raspberry repo so that they hear loud and clear about the issues

HTH

Thank you! I think I'll do both!

@ciacco85
Copy link
Author

After further investigation, I found that the System.Device.Gpio.Drivers.Libgpiod.V2.LibGpiodV2Driver is already able to provide the info needed to detect the correct chip.

In fact it has the following private field:

private readonly Chip _chip;

The Chip class has the GetInfo() method that returns a ChipInfo.
The ChipInfo class has two final methods:

public string GetName()
public string GetLabel()

These methods return the same info provided by gpiodetect.
Anyway, in order to get this field, we should create the driver first, but this needs the gpiochip number, which is exactly what we are trying to identify.

There is some work to do:

  1. Provide a way to open all the available /dev/gpiochipX devices
  2. For each gpiochipX, create the Chip class, read the ChipInfo and use the GetLabel() to verify the chip signature
  3. Once we find the correct gpiochipX we can return it and it can be used by the LibGpioDriver
    These steps should be placed into the autodetect algorithm.

Unfortunately, the libgpiod v1 driver does not provide the same info, but they are available and could be added to the driver similarly to what the v2 does. Once added support for the Chip and ChipInfo in v1, the above steps should be repeated for the v1 as well.

Anyone willing to contribute with a PR on this is welcome.

Now I'll do a short vacation, but a PR could be a really nicr christmas activity. I'll think about it.

@pgrawehr
Copy link
Contributor

@ciacco85 I've just had a look: The SysFs driver also includes logic to read out the chip name and identification. It seems that we just need to make this logic public in some fashion.

@raffaeler
Copy link
Contributor

@pgrawehr Interestingly, we should find a way that allows to do that without loading the entire driver first. Otherwise, this could incur in a performance hit every time we initialize the GpioController.

I would suggest to extract the minimum possible logic from the SysFsDriver so that we have a sort of detector that can be used at the very beginning without the need to load any driver at all.

@pgrawehr
Copy link
Contributor

@raffaeler I agree to that. I was thinking of a static method in GpioDriver or similar. We should however not forget that this is still linux-specific, so not completely hardware-independent.

@raffaeler
Copy link
Contributor

We should however not forget that this is still linux-specific, so not completely hardware-independent.

You are right but I never had any Windows board exposing GPIOs, so I can't imagine an equivalent implementation on Windows.

It could make sense to throw an Exception when no Gpio underlying device is found (on any OS).

@krwq
Copy link
Member

krwq commented Dec 19, 2024

[Triage] @ciacco85 thank you for offering help to implement API here. We suggest to add API in following shape:

// we already have similar internal version of this for LibGpiod but it should be edited to be more generic:
// https://github.com/dotnet/iot/blob/main/src/System.Device.Gpio/Interop/Unix/libgpiod/V2/Proxies/ChipInfo.cs
[Experimental(DiagnosticIds.SDGPIO0001, UrlFormat = DiagnosticIds.UrlFormat)]
public sealed record ChipInfo(int Id, string Name, string Label, int NumberOfLines)
{
}

public partial class SysFsDriver // partial because it already exists
{
    [Experimental(DiagnosticIds.SDGPIO0001, UrlFormat = DiagnosticIds.UrlFormat)]
    public static IEnumerable<ChipInfo> GetAllChipsInfo();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working untriaged
Projects
None yet
Development

No branches or pull requests

4 participants