stianeikeland / go-rpio

:electric_plug: Raspberry Pi GPIO library for go-lang
MIT License
2.16k stars 221 forks source link

Device is stuck on EdgeDetected #46

Closed ifree92 closed 4 years ago

ifree92 commented 4 years ago

I'm running this code (just experimenting for now) and after some time (about 1 minute) device is going to be stuck. (I did the same actions with another languages: python, nodejs, but nothing, everything works stable and great, but when running this go application - I have a stuck and need just manually disconnect device from power supply and enable again).

I have Raspberry Pi 3 Model B. Hardware : BCM2835 Revision : a22082

Kernel: 4.19.58-v7+

Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: buster

package main

import (
    "fmt"
    "github.com/stianeikeland/go-rpio"
    "log"
    "time"
)

func main() {
    err := rpio.Open()
    if err != nil {
        log.Fatal(err)
    }

    ch := make(chan struct{})

    pin := rpio.Pin(10)
    pin.Input()
    pin.PullUp()
    pin.Detect(rpio.FallEdge)

    lastTime := time.Now().UnixNano() / 1000000

    go func() {
        for {
            if pin.EdgeDetected() {
                now := time.Now().UnixNano() / 1000000
                diff := now - lastTime
                lastTime = now
                fmt.Println("Heyhey!", diff)
            }
            time.Sleep(time.Millisecond * 10)
        }
    }()
    fmt.Println("init")

    <-ch
}
ifree92 commented 4 years ago

Hm, pretty strange. When I do the same but manually using pin.Read() in cycle inside go routine - then no stuck. But stuck only by using EdgeDetected in go routine.

And when I try to put everything inside go routine, then the device is getting stuck immediately after application runs.

    go func() {
        pin := rpio.Pin(10)
        pin.Input()
        pin.PullUp()
        pin.Detect(rpio.FallEdge)
        lastTime := time.Now().UnixNano() / 1000000
        for {
            if pin.EdgeDetected() {
                now := time.Now().UnixNano() / 1000000
                diff := now - lastTime
                lastTime = now
                fmt.Println("Heyhey!", diff)
            }
            time.Sleep(time.Millisecond * 35)
        }
    }()

UPD: strange. After reboot the stuck is happening not always after run. The kind of random...

UPD2: for now I'm using this "rakes" to keep it working.

package main

import (
    "fmt"
    "github.com/stianeikeland/go-rpio"
    "log"
    "time"
)

// This function getting my device stuck!
func pinWatcher(pinNum uint, ch *chan int64) {
    pin := rpio.Pin(pinNum)
    pin.Input()
    pin.PullUp()
    pin.Detect(rpio.FallEdge)
    lastTime := time.Now().UnixNano() / 1000000
    for {
        if pin.EdgeDetected() {
            now := time.Now().UnixNano() / 1000000
            diff := now - lastTime
            lastTime = now
            *ch <- diff
        }
        time.Sleep(time.Millisecond * 35)
    }
}

// Plan B for a while...
func pinWatcher2(pinNum uint, ch *chan int64) {
    pin := rpio.Pin(pinNum)
    pin.Input()
    pin.PullUp()
    lastTime := time.Now().UnixNano() / 1000000
    lastState := rpio.High
    for {
        state := pin.Read()
        if state == rpio.High {
        } else if state == rpio.Low {
            if lastState == rpio.High {
                now := time.Now().UnixNano() / 1000000
                diff := now - lastTime
                lastTime = now
                *ch <- diff
            }
        }
        lastState = state
        time.Sleep(time.Millisecond)
    }
}

func main() {
    err := rpio.Open()
    if err != nil {
        log.Fatal(err)
    }

    ch := make(chan struct{})

    gpio10pulses := make(chan int64)

    go pinWatcher2(uint(27), &gpio10pulses)

    go func() {
        log.Println("Init reader")
        for {
            select {
            case pin10Diff := <-gpio10pulses:
                fmt.Println("Pulse", pin10Diff)
            }
        }
    }()

    fmt.Println("init")
    <-ch
}
stianeikeland commented 4 years ago

I'm wondering if this could be related how gpio memory is accessed. https://github.com/stianeikeland/go-rpio/blob/a36b96d0b1a40b37017d64875275e7e6312408c7/rpio.go#L634-L637

Are you running as root or regular user? Could you try to run as root if not?

ifree92 commented 4 years ago

@stianeikeland I have made some experiments. Yes, the stuck possible only if I run application as regular user. With root everything is stable.

But I found one interesting behaviour. If I run firstly with root, but then re-run with regular user - then everything good. Pretty strange

drahoslove commented 4 years ago

Hi, I think this is the same issue as #35, There is already a warning comment in the documentation of EdgeDetect:

// WARNING: this might make your Pi unresponsive, if this happens, you should either run the code as root,
// or add `dtoverlay=gpio-no-irq` to `/boot/config.txt` and restart your pi,

Problem is that normally the edge events produces interruptions, which are not handles by the system, and after some number of unhandled interruptions the pi freezes.

We are trying to disable the interruptions, but it only works with root: https://github.com/stianeikeland/go-rpio/blob/a36b96d0b1a40b37017d64875275e7e6312408c7/rpio.go#L383-L387 If you don't call ~EdgeDetect(noEdge)~ Close() before your program ends, the interruptions will stay disabled until next restart of your pi, this explains the "interesting" behavior you observed.

@stianeikeland We should probably find some better way to solve this issue.

ifree92 commented 4 years ago

Yes, that's it. Now everything clear. Thank you for support and help. Basically I don't think this issue is related somehow to the library, more to raspberry workflow. I think the issue might be closed.

ifree92 commented 4 years ago

And I have faced with one mandatory bug. We are using on our terminals this displays: https://www.waveshare.com/wiki/10.1inch_HDMI_LCD#Driver

The resistive touchscreen is connecting through the GPIO pins. So, when I'm running with sudo my application with edge detection - the touchscreen is not working.

In this case I have to use manual reading inputs, no other solution for me right now. Just FYI, or maybe for someone who will face with the same issue.

drahoslove commented 4 years ago

Yes, unfortunately, disabling the IRQ may cause some other GPIO libs/drivers to not working. I forgot to mention that.