From 84326092ab1b1d64cfac206cefcc9eeff380069a Mon Sep 17 00:00:00 2001 From: Drahoslav Date: Sat, 1 Dec 2018 05:25:37 +0100 Subject: [PATCH] Disable gpio IRQ on Detect edge --- rpio.go | 13 +++++++++++-- rpio_test.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/rpio.go b/rpio.go index 7e8f28d..cd1afb1 100644 --- a/rpio.go +++ b/rpio.go @@ -372,12 +372,20 @@ func TogglePin(pin Pin) { // // Note that using this function might conflict with the same functionality of other gpio library. // -// It also clears previously detected event of this pin if any. +// It also clears previously detected event of this pin if there was any. // // Note that call with RiseEdge will disable previously set FallEdge detection and vice versa. // You have to call with AnyEdge, to enable detection for both edges. // To disable previously enabled detection call it with NoEdge. +// +// 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, func DetectEdge(pin Pin, edge Edge) { + if edge != NoEdge { + // disable GPIO event interruption to prevent freezing in some cases + DisableIRQs(1<<49 | 1<<52) // gpio_int[0] and gpio_int[3] + } + p := uint8(pin) // Rising edge detect enable register (19/20 depending on bank) @@ -692,6 +700,8 @@ func memMap(fd uintptr, base int64) (mem []uint32, mem8 []byte, err error) { // Close unmaps GPIO memory func Close() error { + EnableIRQs(irqsBackup) // Return IRQs to state where it was before - just to be nice + memlock.Lock() defer memlock.Unlock() for _, mem8 := range [][]uint8{gpioMem8, clkMem8, pwmMem8, spiMem8, intrMem8} { @@ -699,7 +709,6 @@ func Close() error { return err } } - EnableIRQs(irqsBackup) // Return IRQs to state where it was before - just to be nice return nil } diff --git a/rpio_test.go b/rpio_test.go index d534f5f..9797a9d 100644 --- a/rpio_test.go +++ b/rpio_test.go @@ -1,6 +1,7 @@ package rpio import ( + "fmt" "os" "testing" "time" @@ -15,6 +16,21 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestInterrupt(t *testing.T) { + logIrqRegs(t) + EnableIRQs(1 << 49) + EnableIRQs(1 << 50) + EnableIRQs(1 << 51) + EnableIRQs(1 << 52) + logIrqRegs(t) + DisableIRQs(1 << 49) + DisableIRQs(1 << 50) + DisableIRQs(1 << 51) + DisableIRQs(1 << 52) + logIrqRegs(t) + EnableIRQs(irqsBackup) +} + func TestEvent(t *testing.T) { src := Pin(3) src.Mode(Output) @@ -118,6 +134,33 @@ func TestEvent(t *testing.T) { }) + // If this frā½eezes your pi, + // add `dtoverlay=gpio-no-irq` to `/boot/config.txt` and restart your pi, + // or run as root. + t.Run("multiple edges", func(t *testing.T) { + EnableIRQs(15 << 49) // all 4 gpio_int[] + logIrqRegs(t) + src.High() + pin.Detect(FallEdge) + + logIrqRegs(t) + + for i := 0; i < 10000; i++ { + time.Sleep(time.Millisecond) + src.High() + time.Sleep(time.Millisecond) + src.Low() + } + logIrqRegs(t) + if !pin.EdgeDetected() { + t.Errorf("Edge not detected") + } + logIrqRegs(t) + pin.Detect(NoEdge) + logIrqRegs(t) + EnableIRQs(irqsBackup) + }) + } func BenchmarkGpio(b *testing.B) { @@ -191,3 +234,12 @@ func BenchmarkGpio(b *testing.B) { }) } + +func logIrqRegs(t *testing.T) { + fmt.Printf("PENDING(% X) FIQ(% X) ENAB(% X) DISAB(% X)\n", + intrMem8[0x200:0x20C], + intrMem8[0x20C:0x210], + intrMem8[0x210:0x21C], + intrMem8[0x21C:0x228], + ) +}