periph / conn

Go·Hardware·Lean - Interfaces
https://periph.io
Apache License 2.0
65 stars 11 forks source link

gpioreg in v3 fails to register and list All() GPIOs on IMX8 aarch64 #15

Open romatou18 opened 2 years ago

romatou18 commented 2 years ago

Describe the bug Trying to list GPIOs using

import v3gpioreg "periph.io/x/conn/v3/gpio/gpioreg" 

gpioreg.All() fails to list the gpios on the board len() == 0

This is a bug tested against a standard IMX8 yocto aarch64. And again as per my previous bug report that was ignored and wrongly so, this is a bug that is specific to v3, and this is not about trying to mix periph.io/x/conn/v3 and periph.io/x/periph/conn together.

So please this time read, build and run the following bug report example code, on an IMX8 or IMX6.

This is fair enough if this lib is not tested on IMX8 or 6 in CI, and only Rpi beaglebon, Odroid are. But this is still a valid bug report nonetheless.

To Reproduce

  1. Run program
    
    package main

import ( "fmt" "log"

"periph.io/x/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"

)

func getGPIOSystemIndex(port, index int) int { name := ((((port) - 1) * 32) + ((index) & 31)) return name }

func main() {

if _, err := driverreg.Init(); err != nil {
    log.Fatal(err)
}

if len(gpioreg.All()) < 1 {
    fmt.Println("gpioregFailed to read GPIOs ! using v3 conn.")
}
fmt.Printf("gpioreg len = %d, ALL(): %+v \n", len(gpioreg.All()), gpioreg.All())

gpioLinuxIndex := getGPIOSystemIndex(1, 8) // GPIO1_IO08 => port 1 gpio 08 VAR-DT8MCustomBoard_Datasheet.pdf
log.Println("gpio sys index = ", gpioLinuxIndex)
gpioSysName := fmt.Sprintf("GPIO%d", gpioLinuxIndex)
log.Println("gpio name = ", gpioSysName)

// get the specified GPIO pin
p := gpioreg.ByName(gpioSysName)
if p == nil {
    log.Fatal("Failed to find " + gpioSysName)
}

// Switch LEd on
if err := p.Out(gpio.High); err != nil {
    log.Fatal(err)
}

}

2. Run it.
3. See error

**Expected behavior**
```bash
gpioregFailed to read GPIOs ! using v3 conn.
gpioreg len = 0, ALL(): [] 
2021/09/02 01:17:19 gpio sys index =  8
2021/09/02 01:17:19 gpio name =  GPIO8
2021/09/02 01:17:19 Failed to find GPIO8

Platform (please complete the following information):

Additional context The distribution used are the standard downloadable demo yocto using on the demo board VAR-DT8Customboard v1.4 All in all this is a market standard IMX8 board. Fails with both IMX8 and IMX8 plus Socs on Zeus kernel 5.4 and Sumo kernel 4.14 versions of yocto.

Note This bug report is here to help out fix problen, this code was run and tested, please do not ignore it and take the time to actually run it on an imx8 Thanks. I am from the Flightcell International, embedded software dev team. We are considering your work in terms of open source efforts, and trying to help this effort, let's all work together please. Saying this due to my previous bug report on this very same issue, being ignored and brush aside without consideration which is not helping.

maruel commented 2 years ago

Your code is incorrect, you never import periph.io/x/host/v3, so you never load the drivers that register the GPIO in the first place.

The driverreg.Init() description is fairly clear about that, https://periph.io/x/conn/v3/driver/driverreg#Init

The driverreg package example is fairly clear about that, https://periph.io/x/conn/v3/driver/driverreg#example-package

Here's the code you need to run:

package main

import (
    "fmt"
    "log"

    "periph.io/x/conn/v3/gpio"
    "periph.io/x/conn/v3/gpio/gpioreg"
    "periph.io/x/host/v3"
)

func getGPIOSystemIndex(port, index int) int {
    name := ((((port) - 1) * 32) + ((index) & 31))
    return name
}

func main() {
    if _, err := host.Init(); err != nil {
        log.Fatal(err)
    }

    if len(gpioreg.All()) < 1 {
        fmt.Println("gpioregFailed to read GPIOs ! using v3 conn.")
    }
    fmt.Printf("gpioreg len = %d, ALL(): %+v \n", len(gpioreg.All()), gpioreg.All())

    gpioLinuxIndex := getGPIOSystemIndex(1, 8) // GPIO1_IO08 => port 1 gpio 08 VAR-DT8MCustomBoard_Datasheet.pdf
    log.Println("gpio sys index = ", gpioLinuxIndex)
    gpioSysName := fmt.Sprintf("GPIO%d", gpioLinuxIndex)
    log.Println("gpio name = ", gpioSysName)

    // get the specified GPIO pin
    p := gpioreg.ByName(gpioSysName)
    if p == nil {
        log.Fatal("Failed to find " + gpioSysName)
    }

    // Switch LEd on
    if err := p.Out(gpio.High); err != nil {
        log.Fatal(err)
    }
}

Please confirm it works now (I haven't tested it) then you can close the issue.

maruel commented 2 years ago

I'm open to updating documentation to make this clearer, hence I'll leave this issue open.

romatou18 commented 2 years ago

Hi,

Thanks, to elaborate a bit I was the following documentations v1 and v3 as I am no expert. V3 : mentions host as if it was gonna cause a circular ref, so then following the example code. https://pkg.go.dev/periph.io/x/conn/v3/gpio

package main

import (
    "fmt"
    "log"

    "periph.io/x/conn/v3/driver/driverreg"
    "periph.io/x/conn/v3/gpio/gpioreg"
)

func main() {
    // Make sure periph is initialized.
    // TODO: Use host.Init(). It is not used in this example to prevent circular
    // go package import.
    if _, err := driverreg.Init(); err != nil {
        log.Fatal(err)
    }

    // Use gpioreg GPIO pin registry to find a GPIO pin by name.
    p := gpioreg.ByName("GPIO6")
    if p == nil {
        log.Fatal("Failed to find GPIO6")
    }

    // A pin can be read, independent of its state; it doesn't matter if it is
    // set as input or output.
    fmt.Printf("%s is %s\n", p, p.Read())
}

v1: has a very clear mention of host https://github.com/google/periph/blob/main/conn/gpio/example_test.go

// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package gpio_test

import (
    "fmt"
    "log"

    "periph.io/x/periph/conn/gpio"
    "periph.io/x/periph/conn/gpio/gpioreg"
    "periph.io/x/periph/conn/physic"
    "periph.io/x/periph/host"
)

func Example() {
    // Make sure periph is initialized.
    if _, err := host.Init(); err != nil {
        log.Fatal(err)
    }

    // Use gpioreg GPIO pin registry to find a GPIO pin by name.
    p := gpioreg.ByName("GPIO6")
    if p == nil {
        log.Fatal("Failed to find GPIO6")
    }

    // A pin can be read, independent of its state; it doesn't matter if it is
    // set as input or output.
    fmt.Printf("%s is %s\n", p, p.Read())
}

As per your previous note before closing the initial issue I raised, that " v1 and v3 are incompatible", in absence of documentation I had to assume that host init was deprecated.

Having an actual working and tested example would be great, I would be suprised if this very example would work on Rpi for instance without the host init.

Many thanks, Kind regards

The Flightcell team.

maruel commented 2 years ago

Does this help? https://github.com/periph/cmd/blob/main/gpio-read/main.go