stianeikeland / go-rpio

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

EdgeDetection crashes Raspberry Pi 3 #35

Closed eyJhb closed 5 years ago

eyJhb commented 5 years ago

Using Detect and running a very basic program on the Raspberry Pi 3, will result in the whole Raspberry Pi locking up (and needing a forced restart). This only happens on a pin with very many rises/falls, currently I am using this for a RF receiver, so there are quite a lot of rises/falls.

The code I am using is this ...

package main

import (
    "fmt"
    "time"

    rpio "github.com/stianeikeland/go-rpio"
)

// This program is just going to be
// a POC of the sender working.
// This should and WILL be cleaned up
// I do not care, I will not fucking
// write the report without having
// the time to do this properly

// Raspberry Pi 3 GPIO
// https://i.imgur.com/PPFf2ul.png
const rx_pin_nr = 2

var preamble = [8]int{1, 0, 1, 0, 1, 0, 1, 0}
var sfd = [8]int{1, 0, 1, 0, 1, 0, 1, 1}
var rx_pin rpio.Pin

func main() {
    // initialize go-rpio
    err := rpio.Open()

    if err != nil {
        fmt.Println(err)
    }

    // set our pin as a output
    rx_pin = rpio.Pin(rx_pin_nr)
    rx_pin.Input()
    rx_pin.Detect(rpio.RiseEdge)

    for {
        // sendData(test)
        fmt.Println("Running stuff")
        time.Sleep(100 * time.Millisecond)
    }
}

func check_sync() {

}

Not even doing anything with it. I don't know what the solution would be, but I think that we could get the interrupt etc. if we used such a system as epoll (http://man7.org/linux/man-pages/man7/epoll.7.html), I know it is uses for another Go system for GPIO interaction here - https://godoc.org/github.com/kidoman/embd

eyJhb commented 5 years ago

Edit, it is done using this - https://golang.org/pkg/syscall/#EpollCreate1

drahoslove commented 5 years ago

Hi, this seems to be the same issue as in #33, (which I am not able to reproduce, unfortunately). Does it freeze every time as soon as Detect method is called, or only when you connect it to RF receiver and generate some edges?

Could you provide me more info about your environment?

The approach using epoll seems interesting, I'll take the closer look into it sometime.

eyJhb commented 5 years ago

I will provide more information tomorrow when I am back at the University :)

On Tue, 27 Nov 2018, 15.16 Drahoslav Bednář <notifications@github.com wrote:

Hi, this seems to be the same issue as in #33 https://github.com/stianeikeland/go-rpio/issues/33, (which I am not able to reproduce, unfortunately). Does it freeze every time as soon as Detect method is called, or only when you connect it to RF receiver and generate some edges?

Could you provide me more info about your environment?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/stianeikeland/go-rpio/issues/35#issuecomment-442073100, or mute the thread https://github.com/notifications/unsubscribe-auth/AYwLSv62Bej1Bi2QLuTSwpR9ZqxxhGwHks5uzUkggaJpZM4YzpxP .

drahoslove commented 5 years ago

Greate, also: 1) Post output of hexdump -C /proc/device-tree/soc/ranges please. If the file does not exists try to upgrade your raspbian. (rPi3 uses different memmory base for mapping pheriperals registers, but if this file does not exists, it falls back to range for older Pi versions, which will cause the trouble on newer Pies)

2) If you are not compiling on Pi directy, but using crosscompiling, don't forget to set GOARM=6. This was the isssue in #25.

eyJhb commented 5 years ago
  1. Using the newest version of raspbian downloaded from raspberrypi.org three days ago (and ran update/upgrade)
  2. Going a direct go run main.go when running my code.

But I will check number 1 tomorrow to make sure! :)

eyJhb commented 5 years ago

Setup

Running the latest version of Raspbian (2018-11-13-raspbian-stretch-lite), having the latests updates using sudo apt update && sudo apt upgrade -y

pi@hub:~ $ uname -a
Linux hub 4.14.79-v7+ #1159 SMP Sun Nov 4 17:50:20 GMT 2018 armv7l GNU/Linux
pi@hub:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.6 (stretch)
Release:    9.6
Codename:   stretch
pi@hub:~ $ 

Code execution

Running the code below WITHOUT the RF receiver attached, prints "works" and then exists the program and everything works fine. But attaching the RF receiver, it will print out works and then just completely freeze up and I cannot ping the host, nmap it, ssh into it or anything. I need to unplug the power and plug it in again.

Currently I am just using the polling method, and checking the state each time. There are not that many rises and falls, but it does of course still have some jitter sometimes.

main.go

package main

import (
    "fmt"
    "time"

    rpio "github.com/stianeikeland/go-rpio"
)

func main() {
    // initialize go-rpio
    err := rpio.Open()

    if err != nil {
        fmt.Println(err)
    }

    // set our pin as a output
    rx_pin := rpio.Pin(2)
    rx_pin.Input()
    rx_pin.Detect(rpio.RiseEdge)
    fmt.Println("Works..")
}

Output from hexdump

00000000  7e 00 00 00 3f 00 00 00  01 00 00 00 40 00 00 00  |~...?.......@...|
00000010  40 00 00 00 00 00 10 00                           |@.......|
00000018

Final notes

If you lived nearby, I would be able to give you a module for testing (if the university agrees), but doesn't look like it.

Please say if you need anymore information from me ! Or need me to test some more ;)

drahoslove commented 5 years ago

Thanks for the info! Everything looks fine, so I'm not sure what the problem is. But there are some ideas:

0) Make sure you have disabled I2C interface in sudo raspi-config - I think it might be enabled by default which might cause your pin 2 to be changed from input mode to I2C.

1) Are you sure your RF receiver is attached correctly? It seems it works at 5V, but GPIO pins are 3.3V so you should use the appropriate resistor at pin 2 to reduce the voltage.

2) Not sure how the receiver works, but pin 2 on Pi has built'in 1.8kΩ pull-up resistor. You might try to use another pin for data, eg. 22 - and add rx_pin.PullDown() to your code - this would make more sense to me for detecting rising edges (but it might not be necessary for this receiver, I'm not too good at reading electrical diagrams, you probably know better).

3) Does the system freeze when you try to emulate the activity on the data pin by hand? Eg. connect pin 2 using wire directly with GND/3.3V? Does it freeze when connecting to 5V? - this would point to 1)

And, I'm from Brno in the Czech Republic. I Guess you are from Germany? :world_map: :thinking:

eyJhb commented 5 years ago

Me neither.. It seems quite weird..

  1. I have tried disabling it in sudo raspi-config (though it looked like it was already disabled).
  2. Quite sure it is attached correctly, as everything works if I use it using polling (I can send and receive data using this without a hitch).
  3. Tried using pin 22 instead which still resulted in the previous behaviour. Added the rx_pin.PUllDown() and results in the previous behaviour.
  4. I have ran the tests for this lib running go test -v, with the connected pins (pin 2 connected to pin 3) which passed without complications (which should have been enough I would think?).

Denmark but close! Seems like quite a stretch. But are there anything that I would be able to do from this point out, to debug it? I am not new to debugging various code, but since this is some hardware interaction, I am not that trained in it (yet).

drahoslove commented 5 years ago

That is really some kind of magic.

Maybe pi just can't handle faster changes. You can edit the test file and use pin in Clock mode, and gradually increase the frequency to see if there is problem in that. Actually I can do this myself.

Also we can try to use "asynchronous" GPAREN/GPAFEN registers for detection instead of "synchronous" GPREN/GPFEN registers. The difference is the synchronous looking for 011/100 patterns, and the other dont - so they should be able to detect even shorter pulses. Just change lines 351/352 in rpio.go to

renReg := p/32 + 31
fenReg := p/32 + 34

See chapter 6.1 in https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf if you are interested in details.

roffe commented 5 years ago
package main

import (
    "fmt"
    "github.com/stianeikeland/go-rpio"
    "os"
    "os/signal"
    "sync"
    "time"
)

func pour(pin rpio.Pin, sleep time.Duration) {
    fmt.Printf("Pouring: %f\n", sleep.Seconds())
    pin.High()
    time.Sleep(sleep)
    pin.Low()
    return
}

func main() {
    defer rpio.Close()
    if err := rpio.Open(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    Relay1 := rpio.Pin(18)
    Relay2 := rpio.Pin(22)
    Relay3 := rpio.Pin(26)

    Input1 := rpio.Pin(6)
    Input1.PullUp()

    Relay1.Output()
    Relay2.Output()
    Relay3.Output()

    Relay1.Low()
    Relay2.Low()
    Relay3.Low()

    Input1.Detect(rpio.FallEdge)

    fmt.Println("press button")

    for i := 0; i < 2; {
        if Input1.EdgeDetected() { // check if event occured
            fmt.Println("button pressed")
            pour(Relay1, 2*time.Second)
            pour(Relay2, 3*time.Second)
            i++
        }
        time.Sleep(5 * time.Second)
    }

    Input1.Detect(rpio.NoEdge) // disable edge event detection

}

this code crashes my Rpi3 as well after a button press is detected, it runs the first pour() then pi hardlocks and i have to pull power cable

Pin6 is connected to GND via a push button

drahoslove commented 5 years ago

Solved! tl;dr: Add dtoverlay=gpio-no-irq to /boot/config.txt and restart your pi.

Explanation: Thanks, roffe, for the example - finally something I could reproduce. I realized that the difference between the unit test which works fine and the cases where something useful is connected to pin is that the number of edges generated is much higher than the number of calls to EdgeDetected(). (Single button press generates many edges too due to "switch bounce effect".)

Every edge event generates interruption as the side effect, but these are not handled by the system and after some number of unhandled interruptions it freezes.

In some update of Linux kernel (to which I switched after implementing the event detection functionality) the way the interruptions are handled changed. It worked before "by accident". More info here: https://github.com/raspberrypi/linux/issues/2550#issuecomment-398082371

The solution above will disable all gpio interruption requests. But it is just workaround since it might break some other programs. Therefore I'll try to figure out a better solution. Either by disabling irq from within go-rpio, or better by reimplementing the detection functionality and actually handle the interruptions.

But disabling irq using dtoverlay in config should be good enough for now.

roffe commented 5 years ago

@Drahoslav7 awesome, i'll have results in a few minutes after testing dtoverlay=gpio-no-irq

roffe commented 5 years ago

@Drahoslav7 my code works like a charm with the dtoverlay setting no more freeze, thank you!

drahoslove commented 5 years ago

I'm happy we figured it out. Hope it works for @eyJhb as well. Feel free to reopen this if not.

eyJhb commented 5 years ago

@Drahoslav7 haven't had time to test it, currently in the mid of getting all the code to work together before the deadline. Will test it out :) - But wouldn't it be awesome, to have actual interrupts?

wjessop commented 1 year ago

I had this issue on my Pi 4B running the program as root. Adding dtoverlay=gpio-no-irq to the boot config fixed it. Using go-rpio v4.6.0.