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 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) {
|
||||||
|
@ -452,7 +524,7 @@ func SetDutyCycle(pin Pin, dutyLen, cycleLen uint32) {
|
||||||
const msen = 1 << 7 // use M/S transition instead of pwm algorithm
|
const msen = 1 << 7 // use M/S transition instead of pwm algorithm
|
||||||
|
|
||||||
// reset settings
|
// 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
|
// set duty cycle
|
||||||
pwmMem[pwmDatReg] = dutyLen
|
pwmMem[pwmDatReg] = dutyLen
|
||||||
pwmMem[pwmRngReg] = cycleLen
|
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