adafruit / Adafruit_Blinka

Add CircuitPython hardware API and libraries to MicroPython & CPython devices
https://learn.adafruit.com/circuitpython-on-raspberrypi-linux
MIT License
453 stars 340 forks source link

Accessing digitalio CE0 results in a device busy error on Pi5 #755

Closed frank-pet closed 9 months ago

frank-pet commented 9 months ago

Board Name

Raspberry Pi 5

Steps

import board, digitalio cs = digitalio.DigitalInOut(board.CE0)

OSError: [Errno 16] Device or Resource Busy will result..

Description

Same code works fine on a PI 4….

Additional information

No response

makermelissa commented 9 months ago

There are some notes related to this in #740. Here's a summary of what I know so far. Blinka on the Pi 5 uses libgpiod rather than RPi.GPIO on the Pi 4 because the author of RPi.GPIO has not updated the library to work on the new hardware, which had pretty significant changes.

The libgpiod_pin file that the Pi 5 is using is currently written for libgpiod 1.6.3. However, there is a gpiod 2.1.3 out and I'm trying to update the pin file so it can run on either. I'm hoping if it works for 2.1.3 it will resolve this issue. If not, I'll need to find another solution.

makermelissa commented 9 months ago

I tried an interesting experiment where I used libgpiod for a Pi 4 and it functioned just fine. So the issue seems to be libgpiod on the Pi 5 specifically.

makermelissa commented 9 months ago

Since gpiozero seems to be the only other alternative that actually works on the Pi 5, I may have to take a look at that. However, it runs about 3 times as slow as libgpiod (see https://adafruit-playground.com/u/MakerMelissa/pages/comparing-libgpiod-and-gpiozero-speeds-on-the-raspberry-pi-5). So I may be able to use it only for the CE0 and CE1 pins at least until something changes (libgpiod or Raspberry Pi OS).

frank-pet commented 9 months ago

I verified the same information.  I think it’s because the SPI device makes it busy.    It may be the case that the issue is really with Adafruit rgb devices, like the minipitft, that require the CS pin in the call when it is already used by the device.  But that’s just a guess. Those devices work in the Pi 5 if you pass None, or DummyPin as the cs_pin argument….Sent from my iPadOn Dec 15, 2023, at 7:46 PM, Melissa LeBlanc-Williams @.***> wrote: I tried an interesting experiment where I used libgpiod for a Pi 4 and it functioned just fine. So the issue seems to be libgpiod on the Pi 5 specifically.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>

makermelissa commented 9 months ago

Hmm, interesting thought. I wonder what would happen if CE0 or CE1 were only used as GPIO without starting up SPI.

makermelissa commented 9 months ago

Hmm, interesting thought. I wonder what would happen if CE0 or CE1 were only used as GPIO without starting up SPI.

Unfortunately, tt still has Device or Resource busy even without initialing SPI.

makermelissa commented 9 months ago

I get similar results when trying to use gpiozero. I have opened an issue under bookworm feedback at https://github.com/raspberrypi/bookworm-feedback/issues/179. Hopefully, I get a promising answer.

makermelissa commented 9 months ago

Ok, I found something that works, but not ideal. Here's what I did:

  1. In /boot/firmware/config.txt set dtparam=spi=off or just comment out or disable spi interface with raspi-config
  2. Add dtoverlay=spi0-0cs to the bottom
  3. Reboot
  4. Run you code and it works
makermelissa commented 9 months ago

What I think was happening is the default SPI driver on the Pi 5 is different and actually marks the Chip Enable lines as busy unlike before. The spi0-0cs device tree overlay enables SPI 0 using 0 Chip Select pins, which is precisely what is needed here.

makermelissa commented 9 months ago

Ok, further testing seems to indicate, that SPI doesn't even need to be disabled and just loading the dtoverlay works.

makermelissa commented 9 months ago

I think the main consequence of loading the DTO is that /dev/spidev0.1 is no longer enabled because the system doesn't have a way to differentiate it from /dev/spidev0.0 anymore, which is fine for this purpose. I'm continuing to test that it doesn't make anything else more complicated.

rreichenbach commented 9 months ago

Thanks a lot for your work on this @makermelissa

The dtoverlay does unblock the SPI0/CE0 issue for me, and my display now is working, which I'm quite happy about. It seems like a fairly reasonable fix to me.

I do now have a problem using SPI0/CE1 for another purpose: a connected MCP3008, but I'll have to dig to see if it is related or not. It does at least initialize fine just like SPI0/CE0. So it could be a totally different issue that I just didn't notice until now.

makermelissa commented 9 months ago

You may want to check out the /boot/firmware/overlays folder on your Pi and try one of the other options to see if that fixes your issue.

graemeok commented 9 months ago

Thanks for all your work on this @makermelissa.
This fix works for me as well with piTFT/adafruit_rgb_display functionality now working.

rreichenbach commented 9 months ago

As I said before, setting: dtoverlay=spi0_0cs

Does allow a display to work on CE0. It however breaks my MCP3008 attached to CE1 (pin7) because spi0_0cs means: "Don't claim any CS pins for SPI0" (CE0 or CE1). My MCP3008 apparently needs it claimed, either having no spi0 overlay or spi0_2cs, but spi0_2cs doesn't work for a display on pin8 (the original issue here).

I might be able to do something clever with spi0_1cs, but so far, it's looking like I might have to choose between my LCD working OR my MCP3008 working, but not both simultaneously like I was able to do with pi3 and pi4.

makermelissa commented 9 months ago

I was going to suggest something like dtoverlay=spi0-1cs,cs1_pin=7, but I just tried it and it grabs CE0, so that didn't work.

Then I tried dtoverlay=spi0-2cs,cs0_pin=22,cs1_pin=7 and that works. CE1 is set to Pin 7 like normal and CE0 is set to pin 22 (you can change to something else unused).

rreichenbach commented 9 months ago

Ah, very clever, @makermelissa !

That does appear to work: both LCD and MCP3008 working on the same pins as they did with pi3 and pi4. Yea, no need to revise the PCB or prevent existing ones from working with pi5.

The disadvantage is sacrificing a GPIO. My current product uses them all, but it's far more important to have both CE's so I can make due.

It would be nice if eventually libgpiod was fixed to deal with "busy" CE's but this seems like a decent work around for now.

I've been converting my other code to use gpiozero and I'm very impressed with that library. It may run at 1/3rd the speed, but from a development perspective, with all of it's support for buttons with bounce & hold timers, encoders, sensors, motors, leds, etc. it's quite impressive.

Anyway, thanks again for all your help on this! BTW, I checked out your youtube channel. Very cool stuff on there! Saw you fixed an electric guitar, so I thought I'd point you towards my main RPi project: https://pistomp.com

makermelissa commented 9 months ago

It would be nice if eventually libgpiod was fixed to deal with "busy" CE's but this seems like a decent work around for now.

This actually is at the OS level and gpiozero also has the issue. From what I can gather, this is really how it was supposed to have been working all along, so it likely won't be changing.

frank-pet commented 9 months ago

You are probably right, and it is the right thing to do.  The authors of other adafruit libraries for devices that use SPI devices (like Adafruit RGB) need to recode their libraries so that they take this into account.Sent from my iPadOn Dec 20, 2023, at 1:26 PM, Melissa LeBlanc-Williams @.***> wrote:

It would be nice if eventually libgpiod was fixed to deal with "busy" CE's but this seems like a decent work around for now.

This actually is at the OS level and gpiozero also has the issue. From what I can gather, this is really how it was supposed to have been working all along, so it likely won't be changing.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>

makermelissa commented 9 months ago

I have updated both a script I had written (https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/main/raspi-spi-reassign.py) and the learn guide page (https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/spi-sensors-devices#reassigning-or-disabling-the-spi-chip-enable-lines-3097985) on how to reassign or disable the OS usage of those pins, so I'm closing this issue since there's not much more I can do.

lurch commented 3 months ago

I was going to suggest something like dtoverlay=spi0-1cs,cs1_pin=7, but I just tried it and it grabs CE0, so that didn't work.

I guess that'll be because you used the wrong parameter name? If you look at https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README#L4338 you can see that the spi0-1cs overlay has a cs0_pin parameter.

makermelissa commented 3 months ago

I guess that'll be because you used the wrong parameter name? If you look at https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README#L4338 you can see that the spi0-1cs overlay has a cs0_pin parameter.

Right. I wanted to only set it for the cs1 pin, but that's just a limitation of that overlay, which is why I ended up going with the spi0-2cs overlay instead.