mirror of
https://github.com/stianeikeland/go-rpio.git
synced 2025-01-23 02:31:05 +01:00
Merge pull request #22 from Drahoslav7/feature/edge-event
Edge detection, closes #21
This commit is contained in:
commit
4f808926bf
49
examples/event/event.go
Normal file
49
examples/event/event.go
Normal 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
|
||||
}
|
80
rpio.go
80
rpio.go
|
@ -6,6 +6,7 @@ Supports simple operations such as:
|
|||
- Pin mode/direction (input/output/clock/pwm)
|
||||
- Pin write (high/low)
|
||||
- Pin read (high/low)
|
||||
- Pin edge detection (no/rise/fall/any)
|
||||
- Pull up/down/off
|
||||
And clock/pwm related oparations:
|
||||
- Set Clock frequency
|
||||
|
@ -76,6 +77,7 @@ type Mode uint8
|
|||
type Pin uint8
|
||||
type State uint8
|
||||
type Pull uint8
|
||||
type Edge uint8
|
||||
|
||||
// Memory offsets for gpio, see the spec for more details
|
||||
const (
|
||||
|
@ -121,6 +123,14 @@ const (
|
|||
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
|
||||
var (
|
||||
memlock sync.Mutex
|
||||
|
@ -212,6 +222,16 @@ func (pin 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)
|
||||
//
|
||||
// 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
|
||||
// by setting the clear or set registers respectively
|
||||
func WritePin(pin Pin, state State) {
|
||||
|
||||
p := uint8(pin)
|
||||
|
||||
// Clear register, 10 / 11 depending on bank
|
||||
|
@ -278,7 +297,6 @@ func WritePin(pin Pin, state State) {
|
|||
} else {
|
||||
gpioMem[setReg] = 1 << (p & 31)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Pull up/down/off register has offset 38 / 39, pull is 37
|
||||
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.
|
||||
// The groups are:
|
||||
// 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
|
||||
// pwm_clk: pins 12, 13, 18, 19, 40, 41, 45
|
||||
func SetFreq(pin Pin, freq int) {
|
||||
|
@ -452,7 +524,7 @@ func SetDutyCycle(pin Pin, dutyLen, cycleLen uint32) {
|
|||
const msen = 1 << 7 // use M/S transition instead of pwm algorithm
|
||||
|
||||
// reset settings
|
||||
pwmMem[pwmCtlReg] = pwmMem[pwmCtlReg]&^(ctlMask<<shift) | msen<<shift | pwen <<shift
|
||||
pwmMem[pwmCtlReg] = pwmMem[pwmCtlReg]&^(ctlMask<<shift) | msen<<shift | pwen<<shift
|
||||
// set duty cycle
|
||||
pwmMem[pwmDatReg] = dutyLen
|
||||
pwmMem[pwmRngReg] = cycleLen
|
||||
|
|
120
rpio_test.go
Normal file
120
rpio_test.go
Normal 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")
|
||||
}
|
||||
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user