Merge pull request #22 from Drahoslav7/feature/edge-event

Edge detection, closes #21
This commit is contained in:
Stian Eikeland 2018-06-07 00:40:09 +02:00 committed by GitHub
commit 4f808926bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 245 additions and 4 deletions

49
examples/event/event.go Normal file
View File

@ -0,0 +1,49 @@
/*
An example of edge event handling by @Drahoslav7, using the go-rpio library
Waits for button to be pressed twice before exit.
Connect a button between pin 22 and some GND pin.
*/
package main
import (
"fmt"
"os"
"time"
"github.com/stianeikeland/go-rpio"
)
var (
// Use mcu pin 22, corresponds to GPIO 3 on the pi
pin = rpio.Pin(22)
)
func main() {
// Open and map memory to access gpio, check for errors
if err := rpio.Open(); err != nil {
fmt.Println(err)
os.Exit(1)
}
// Unmap gpio memory when done
defer rpio.Close()
pin.Input()
pin.PullUp()
pin.Detect(rpio.FallEdge) // enable falling edge event detection
fmt.Println("press a button")
for i := 0; i < 2; {
if pin.EdgeDetected() { // check if event occured
fmt.Println("button pressed")
i++
}
time.Sleep(time.Second / 2)
}
pin.Detect(rpio.NoEdge) // disable edge event detection
}

78
rpio.go
View File

@ -6,6 +6,7 @@ Supports simple operations such as:
- Pin mode/direction (input/output/clock/pwm) - Pin mode/direction (input/output/clock/pwm)
- Pin write (high/low) - Pin write (high/low)
- Pin read (high/low) - Pin read (high/low)
- Pin edge detection (no/rise/fall/any)
- Pull up/down/off - Pull up/down/off
And clock/pwm related oparations: And clock/pwm related oparations:
- Set Clock frequency - Set Clock frequency
@ -76,6 +77,7 @@ type Mode uint8
type Pin uint8 type Pin uint8
type State uint8 type State uint8
type Pull uint8 type Pull uint8
type Edge uint8
// Memory offsets for gpio, see the spec for more details // Memory offsets for gpio, see the spec for more details
const ( const (
@ -121,6 +123,14 @@ const (
PullUp PullUp
) )
// Edge events
const (
NoEdge Edge = iota
RiseEdge
FallEdge
AnyEdge = RiseEdge | FallEdge
)
// Arrays for 8 / 32 bit access to memory and a semaphore for write locking // Arrays for 8 / 32 bit access to memory and a semaphore for write locking
var ( var (
memlock sync.Mutex memlock sync.Mutex
@ -212,6 +222,16 @@ func (pin Pin) PullOff() {
PullMode(pin, PullOff) PullMode(pin, PullOff)
} }
// Enable edge event detection on pin
func (pin Pin) Detect(edge Edge) {
DetectEdge(pin, edge)
}
// Check edge event on pin
func (pin Pin) EdgeDetected() bool {
return EdgeDetected(pin)
}
// PinMode sets the mode (direction) of a given pin (Input, Output, Clock or Pwm) // PinMode sets the mode (direction) of a given pin (Input, Output, Clock or Pwm)
// //
// Clock is possible only for pins 4, 5, 6, 20, 21. // Clock is possible only for pins 4, 5, 6, 20, 21.
@ -262,7 +282,6 @@ func PinMode(pin Pin, mode Mode) {
// WritePin sets a given pin High or Low // WritePin sets a given pin High or Low
// by setting the clear or set registers respectively // by setting the clear or set registers respectively
func WritePin(pin Pin, state State) { func WritePin(pin Pin, state State) {
p := uint8(pin) p := uint8(pin)
// Clear register, 10 / 11 depending on bank // Clear register, 10 / 11 depending on bank
@ -278,7 +297,6 @@ func WritePin(pin Pin, state State) {
} else { } else {
gpioMem[setReg] = 1 << (p & 31) gpioMem[setReg] = 1 << (p & 31)
} }
} }
// Read the state of a pin // Read the state of a pin
@ -304,6 +322,60 @@ func TogglePin(pin Pin) {
} }
} }
// Enable edge event detection on pin.
//
// Combine with pin.EdgeDetected() to check whether event occured.
//
// 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.
//
// 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.
func DetectEdge(pin Pin, edge Edge) {
p := uint8(pin)
// Rising edge detect enable register (19/20 depending on bank)
// Falling edge detect enable register (22/23 depending on bank)
// Event detect status register (16/17)
renReg := p/32 + 19
fenReg := p/32 + 22
edsReg := p/32 + 16
bit := uint32(1 << (p & 31))
if edge&RiseEdge > 0 { // set bit
gpioMem[renReg] = gpioMem[renReg] | bit
} else { // clear bit
gpioMem[renReg] = gpioMem[renReg] &^ bit
}
if edge&FallEdge > 0 { // set bit
gpioMem[fenReg] = gpioMem[fenReg] | bit
} else { // clear bit
gpioMem[fenReg] = gpioMem[fenReg] &^ bit
}
gpioMem[edsReg] = bit // to clear outdated detection
}
// Check whether edge event occured since last call
// or since detection was enabled
//
// There is no way (yet) to handle interruption caused by edge event, you have to use polling.
//
// Event detection has to be enabled first, by pin.Detect(edge)
func EdgeDetected(pin Pin) bool {
p := uint8(pin)
// Event detect status register (16/17)
edsReg := p/32 + 16
test := gpioMem[edsReg] & (1 << (p & 31))
gpioMem[edsReg] = test // set bit to clear it
return test != 0
}
func PullMode(pin Pin, pull Pull) { func PullMode(pin Pin, pull Pull) {
// Pull up/down/off register has offset 38 / 39, pull is 37 // Pull up/down/off register has offset 38 / 39, pull is 37
pullClkReg := pin/32 + 38 pullClkReg := pin/32 + 38
@ -343,7 +415,7 @@ func PullMode(pin Pin, pull Pull) {
// changing frequency for one pin will change it also for all pins within a group. // changing frequency for one pin will change it also for all pins within a group.
// The groups are: // The groups are:
// gp_clk0: pins 4, 20, 32, 34 // gp_clk0: pins 4, 20, 32, 34
// gp_clk1: pins 5, 21, 42, 43 // gp_clk1: pins 5, 21, 42, 44
// gp_clk2: pins 6 and 43 // gp_clk2: pins 6 and 43
// pwm_clk: pins 12, 13, 18, 19, 40, 41, 45 // pwm_clk: pins 12, 13, 18, 19, 40, 41, 45
func SetFreq(pin Pin, freq int) { func SetFreq(pin Pin, freq int) {

120
rpio_test.go Normal file
View File

@ -0,0 +1,120 @@
package rpio
import (
"os"
"testing"
"time"
)
func TestMain(m *testing.M) {
println("Note: bcm pins 2 and 3 has to be directly connected")
if err := Open(); err != nil {
panic(err)
}
defer Close()
os.Exit(m.Run())
}
func TestEvent(t *testing.T) {
src := Pin(3)
src.Mode(Output)
pin := Pin(2)
pin.Mode(Input)
pin.PullDown()
t.Run("rising edge", func(t *testing.T) {
pin.Detect(RiseEdge)
src.Low()
for i := 0; ; i++ {
src.High()
time.Sleep(time.Second / 10)
if pin.EdgeDetected() {
t.Log("edge rised")
} else {
t.Errorf("Rise event should be detected")
}
if i == 5 {
break
}
src.Low()
}
time.Sleep(time.Second / 10)
if pin.EdgeDetected() {
t.Error("Rise should not be detected, no change since last call")
}
pin.Detect(NoEdge)
src.High()
if pin.EdgeDetected() {
t.Error("Rise should not be detected, events disabled")
}
})
t.Run("falling edge", func(t *testing.T) {
pin.Detect(FallEdge)
src.High()
for i := 0; ; i++ {
src.Low()
time.Sleep(time.Second / 10)
if pin.EdgeDetected() {
t.Log("edge fallen")
} else {
t.Errorf("Fall event should be detected")
}
if i == 5 {
break
}
src.High()
}
time.Sleep(time.Second / 10)
if pin.EdgeDetected() {
t.Error("Fall should not be detected, no change since last call")
}
pin.Detect(NoEdge)
src.Low()
if pin.EdgeDetected() {
t.Error("Fall should not be detected, events disabled")
}
})
t.Run("both edges", func(t *testing.T) {
pin.Detect(AnyEdge)
src.Low()
for i := 0; i < 5; i++ {
src.High()
if pin.EdgeDetected() {
t.Log("edge detected")
} else {
t.Errorf("Rise event shoud be detected")
}
src.Low()
if pin.EdgeDetected() {
t.Log("edge detected")
} else {
t.Errorf("Fall edge should be detected")
}
}
pin.Detect(NoEdge)
src.High()
src.Low()
if pin.EdgeDetected() {
t.Errorf("No edge should be detected, events disabled")
}
})
}