Open fischerman opened 1 month ago
I think the problem is that starting with Bookworm sysfs GPIO has been removed. It might affect other distributions as well. At least all Raspberries are affected.
Can you test if https://github.com/periph/host/commit/b69b28c4e40f9f233222c9d7ea610ef0fcc8a54b fixes the problem? If so, I'll do a release.
On the Pi 2 I'm getting a lot of errors now:
go run cmd/edge/edge.go
2024/09/24 10:28:43 chip gpiochip0 gpioreg.Register(line) {
"Line": 33,
"Name": "NC",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "NC" twice; already registered as "{\n \"Line\": 30,\n \"Name\": \"NC\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
2024/09/24 10:28:43 chip gpiochip0 gpioreg.Register(line) {
"Line": 34,
"Name": "NC",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "NC" twice; already registered as "{\n \"Line\": 30,\n \"Name\": \"NC\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
2024/09/24 10:28:43 chip gpiochip0 gpioreg.Register(line) {
"Line": 36,
"Name": "NC",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "NC" twice; already registered as "{\n \"Line\": 30,\n \"Name\": \"NC\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
2024/09/24 10:28:43 chip gpiochip0 gpioreg.Register(line) {
"Line": 37,
"Name": "NC",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "NC" twice; already registered as "{\n \"Line\": 30,\n \"Name\": \"NC\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
2024/09/24 10:28:43 chip gpiochip0 gpioreg.Register(line) {
"Line": 39,
"Name": "NC",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "NC" twice; already registered as "{\n \"Line\": 30,\n \"Name\": \"NC\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
2024/09/24 10:28:43 bcm283x-gpio (GPIO17): subsystem gpiomem not initialized and sysfs not accessible
exit status 1
Not sure if it is related but header-list no longer returns functions:
$ go run headers-list/main.go
AUDIO: 2 pins
Pos Name Func
1 GPIO45
2 GPIO40
HDMI: 1 pins
Pos Name Func
1 GPIO46
P1: 40 pins
Func Name Pos Pos Name Func
3.3V 1 2 5V
GPIO2 3 4 5V
GPIO3 5 6 GROUND
GPIO4 7 8 GPIO14
GROUND 9 10 GPIO15
GPIO17 11 12 GPIO18
GPIO27 13 14 GROUND
GPIO22 15 16 GPIO23
3.3V 17 18 GPIO24
GPIO10 19 20 GROUND
GPIO9 21 22 GPIO25
GPIO11 23 24 GPIO8
GROUND 25 26 GPIO7
GPIO0 27 28 GPIO1
GPIO5 29 30 GROUND
GPIO6 31 32 GPIO12
GPIO13 33 34 GROUND
GPIO19 35 36 GPIO16
GPIO26 37 38 GPIO20
GROUND 39 40 GPIO21
@fischerman Can you try running this example:
host/gpioioctl/example_test.go
I want to see this fixed so I ran a gpio out on my RPI 5, using the branch you provided @maruel
pi@worker-pi-1:~/GraftXL/cmd/run3 $ go get periph.io/x/host/v3@b69b28c4e40f9f233222c9d7ea610ef0fcc8a54b
go: downloading periph.io/x/host/v3 v3.8.3-0.20240918234808-b69b28c4e40f
which quickly died:
2024/10/08 20:13:09 chip gpiochip4 gpioreg.Register(line) {
"Line": 47,
"Name": "2712_WAKE",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "2712_WAKE" twice; already registered as "{\n \"Line\": 8,\n \"Name\": \"2712_WAKE\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
Failed to set pin as output: bcm283x-gpio (GPIO17): subsystem gpiomem not initialized and sysfs not accessible
Using this example code for my motor that works on the RPI4:
package main
import (
"fmt"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/host/v3"
"periph.io/x/host/v3/rpi"
)
func main() {
if _, err := host.Init(); err != nil {
fmt.Println("Failed to initialize periph:", err)
return
}
stepPin := rpi.P1_11 // Use GPIO17
// Set the pin as an output
if err := stepPin.Out(gpio.Low); err != nil {
fmt.Println("Failed to set pin as output:", err)
return
}
pulseCount := 800
pulseDuration := 1000 * time.Microsecond
// Generate pulses
fmt.Printf("Sending %d pulses...\n", pulseCount)
for i := 0; i < pulseCount; i++ {
if err := stepPin.Out(gpio.High); err != nil {
fmt.Println("Failed to set pin high:", err)
return
}
time.Sleep(pulseDuration / 2)
if err := stepPin.Out(gpio.Low); err != nil {
fmt.Println("Failed to set pin low:", err)
return
}
time.Sleep(pulseDuration / 2)
}
fmt.Println("Finished sending pulses.")
}
I hope this helps in someway!
@Evert-Arends
There are 4 GPIO chips on the Pi 5, and they all export a pin named "2712_WAKE". This causes the error you're seeing.
Take the return out of the host.Init() statement and see what it does.
Did that, removed the return.
2024/10/09 19:10:11 chip gpiochip4 gpioreg.Register(line) {
"Line": 47,
"Name": "2712_WAKE",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "2712_WAKE" twice; already registered as "{\n \"Line\": 8,\n \"Name\": \"2712_WAKE\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
Failed to set pin as output: bcm283x-gpio (GPIO23): subsystem gpiomem not initialized and sysfs not accessible
func main() {
if _, err := host.Init(); err != nil {
fmt.Println("Failed to initialize periph:", err)
// return
}
stepPin := rpi.P1_16 // 23
// Set the pin as an output
if err := stepPin.Out(gpio.Low); err != nil {
fmt.Println("Failed to set pin as output:", err)
return
}
pulseCount := 800
pulseDuration := 1000 * time.Microsecond
// Generate pulses
fmt.Printf("Sending %d pulses...\n", pulseCount)
for i := 0; i < pulseCount; i++ {
if err := stepPin.Out(gpio.High); err != nil {
fmt.Println("Failed to set pin high:", err)
return
}
time.Sleep(pulseDuration / 2)
if err := stepPin.Out(gpio.Low); err != nil {
fmt.Println("Failed to set pin low:", err)
return
}
time.Sleep(pulseDuration / 2)
}
fmt.Println("Finished sending pulses.")
}
@fischerman and @Evert-Arends
Here is a basic program using the gpioioctl code that demonstrates edge detection. It assumes you have a jumper connecting GPIO2 and GPIO 10. This was run on a Raspberry Pi 5:
gsexton@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 12 (bookworm)
Release: 12
Codename: bookworm
gsexton@raspberrypi:~ $ uname -a
Linux raspberrypi 6.6.45-v8-16k+ #1791 SMP PREEMPT Tue Aug 13 12:52:29 BST 2024 aarch64 GNU/Linux
To build this, you'll need the commit that has gpioioctl in it:
gsexton@raspberrypi:~ $ go get periph.io/x/host/v3@b69b28c4e40f9f233222c9d7ea610ef0fcc8a54b
main.go
package main
import (
"fmt"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/host/v3"
"periph.io/x/host/v3/gpioioctl"
)
func main() {
if _, err := host.Init(); err != nil {
fmt.Println("Failed to initialize periph:", err)
// return
}
gpiochip:=gpioioctl.Chips[0]
outPin:=gpiochip.ByName("GPIO2")
inPin:=gpiochip.ByName("GPIO10")
inPin.In(gpio.PullDown,gpio.RisingEdge)
fmt.Println("inPin=",inPin)
fmt.Println("outPin=",outPin)
l:=gpio.Low
go func() {
for {
l=!l
fmt.Println("setting outPin to ",l)
outPin.Out(l)
time.Sleep(1000 * time.Millisecond)
}
}()
for {
if inPin.WaitForEdge(0){
fmt.Println("Received edge")
} else {
fmt.Println("WaitForEdge() unblocked without receiving edge.")
}
}
}
Sample Output:
gsexton@raspberrypi:~ $ ./simpledge
2024/10/09 18:57:50 chip gpiochip12 gpioreg.Register(line) {
"Line": 8,
"Name": "2712_WAKE",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
} returned gpioreg: can't register pin "2712_WAKE" twice; already registered as "{\n \"Line\": 47,\n \"Name\": \"2712_WAKE\",\n \"Consumer\": \"\",\n \"Direction\": \"NotSet\",\n \"Pull\": \"PullNoChange\",\n \"Edges\": \"NoEdge\"\n}"
inPin= {
"Line": 10,
"Name": "GPIO10",
"Consumer": "simpledge@2246",
"Direction": "Input",
"Pull": "PullDown",
"Edges": "RisingEdge"
}
outPin= {
"Line": 2,
"Name": "GPIO2",
"Consumer": "",
"Direction": "NotSet",
"Pull": "PullNoChange",
"Edges": "NoEdge"
}
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
setting outPin to Low
setting outPin to High
Received edge
^C
@gsexton Your example works on my RPi2. I compared it to my program and what seems to break it is:
gpioreg.ByName("GPIO17")
gpioioctl.Chips[0]
on the other hand works fine.
@fischerman I've looked into this.
The problem is the bcm283x driver is running after the gpioioctl register code. That driver explicitly unregisters the gpioioctl registered GPIO pins values and supplies non-working sysfs based pins, causing things to break (line 1395 of host/bcm283x/gpio.go).
@maruel do you have any ideas on the correct fix?
bcm283x needs to condition on which driver is loaded and act accordingly.
Is this then solved by https://github.com/periph/host/pull/63 ? Should this be closed? Thanks!
Describe the bug
The pin cannot be associated with a sysfs pin.
To Reproduce Steps to reproduce the behavior:
import ( "log"
)
func main() { if _, err := host.Init(); err != nil { log.Fatal(err) }
}