nrf: add support for pin change interrupts
Этот коммит содержится в:
родитель
c248418dbe
коммит
19c7965fc5
5 изменённых файлов: 140 добавлений и 4 удалений
2
Makefile
2
Makefile
|
@ -203,6 +203,8 @@ smoketest:
|
|||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick
|
||||
|
|
10
src/examples/pininterrupt/pca10040.go
Обычный файл
10
src/examples/pininterrupt/pca10040.go
Обычный файл
|
@ -0,0 +1,10 @@
|
|||
// +build pca10040
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
buttonMode = machine.PinInputPullup
|
||||
buttonPinChange = machine.PinRising
|
||||
)
|
52
src/examples/pininterrupt/pininterrupt.go
Обычный файл
52
src/examples/pininterrupt/pininterrupt.go
Обычный файл
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
// This example demonstrates how to use pin change interrupts.
|
||||
//
|
||||
// This is only an example and should not be copied directly in any serious
|
||||
// circuit, because it lacks an important feature: debouncing.
|
||||
// See: https://en.wikipedia.org/wiki/Switch#Contact_bounce
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"runtime/volatile"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
button = machine.BUTTON
|
||||
led = machine.LED
|
||||
)
|
||||
|
||||
func main() {
|
||||
var lightLed volatile.Register8
|
||||
lightLed.Set(0)
|
||||
|
||||
// Configure the LED, defaulting to on (usually setting the pin to low will
|
||||
// turn the LED on).
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
led.Low()
|
||||
|
||||
// Make sure the pin is configured as a pullup to avoid floating inputs.
|
||||
// Pullup works for most buttons, as most buttons short to ground when
|
||||
// pressed.
|
||||
button.Configure(machine.PinConfig{Mode: buttonMode})
|
||||
|
||||
// Set an interrupt on this pin.
|
||||
err := button.SetInterrupt(buttonPinChange, func(machine.Pin) {
|
||||
if lightLed.Get() != 0 {
|
||||
lightLed.Set(0)
|
||||
led.Low()
|
||||
} else {
|
||||
lightLed.Set(1)
|
||||
led.High()
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
println("could not configure pin interrupt:", err.Error())
|
||||
}
|
||||
|
||||
// Make sure the program won't exit.
|
||||
for {
|
||||
time.Sleep(time.Hour)
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ var (
|
|||
ErrInvalidOutputPin = errors.New("machine: invalid output pin")
|
||||
ErrInvalidClockPin = errors.New("machine: invalid clock pin")
|
||||
ErrInvalidDataPin = errors.New("machine: invalid data pin")
|
||||
ErrNoPinChangeChannel = errors.New("machine: no channel available for pin interrupt")
|
||||
)
|
||||
|
||||
type PinConfig struct {
|
||||
|
|
|
@ -21,6 +21,18 @@ const (
|
|||
PinOutput PinMode = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
||||
)
|
||||
|
||||
type PinChange uint8
|
||||
|
||||
// Pin change interrupt constants for SetInterrupt.
|
||||
const (
|
||||
PinRising PinChange = nrf.GPIOTE_CONFIG_POLARITY_LoToHi
|
||||
PinFalling PinChange = nrf.GPIOTE_CONFIG_POLARITY_HiToLo
|
||||
PinToggle PinChange = nrf.GPIOTE_CONFIG_POLARITY_Toggle
|
||||
)
|
||||
|
||||
// Callbacks to be called for pins configured with SetInterrupt.
|
||||
var pinCallbacks [len(nrf.GPIOTE.CONFIG)]func(Pin)
|
||||
|
||||
// Configure this pin with the given configuration.
|
||||
func (p Pin) Configure(config PinConfig) {
|
||||
cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
|
||||
|
@ -59,6 +71,65 @@ func (p Pin) Get() bool {
|
|||
return (port.IN.Get()>>pin)&1 != 0
|
||||
}
|
||||
|
||||
// SetInterrupt sets an interrupt to be executed when a particular pin changes
|
||||
// state.
|
||||
//
|
||||
// This call will replace a previously set callback on this pin. You can pass a
|
||||
// nil func to unset the pin change interrupt. If you do so, the change
|
||||
// parameter is ignored and can be set to any value (such as 0).
|
||||
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||
// Some variables to easily check whether a channel was already configured
|
||||
// as an event channel for the given pin.
|
||||
// This is not just an optimization, this is requred: the datasheet says
|
||||
// that configuring more than one channel for a given pin results in
|
||||
// unpredictable behavior.
|
||||
expectedConfigMask := uint32(nrf.GPIOTE_CONFIG_MODE_Msk | nrf.GPIOTE_CONFIG_PSEL_Msk)
|
||||
expectedConfig := nrf.GPIOTE_CONFIG_MODE_Event<<nrf.GPIOTE_CONFIG_MODE_Pos | uint32(p)<<nrf.GPIOTE_CONFIG_PSEL_Pos
|
||||
|
||||
foundChannel := false
|
||||
for i := range nrf.GPIOTE.CONFIG {
|
||||
config := nrf.GPIOTE.CONFIG[i].Get()
|
||||
if config == 0 || config&expectedConfigMask == expectedConfig {
|
||||
// Found an empty GPIOTE channel or one that was already configured
|
||||
// for this pin.
|
||||
if callback == nil {
|
||||
// Disable this channel.
|
||||
nrf.GPIOTE.INTENCLR.Set(uint32(1 << uint(i)))
|
||||
pinCallbacks[i] = nil
|
||||
return nil
|
||||
}
|
||||
// Enable this channel with the given callback.
|
||||
nrf.GPIOTE.INTENCLR.Set(uint32(1 << uint(i)))
|
||||
nrf.GPIOTE.CONFIG[i].Set(nrf.GPIOTE_CONFIG_MODE_Event<<nrf.GPIOTE_CONFIG_MODE_Pos |
|
||||
uint32(p)<<nrf.GPIOTE_CONFIG_PSEL_Pos |
|
||||
uint32(change)<<nrf.GPIOTE_CONFIG_POLARITY_Pos)
|
||||
pinCallbacks[i] = callback
|
||||
nrf.GPIOTE.INTENSET.Set(uint32(1 << uint(i)))
|
||||
foundChannel = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !foundChannel {
|
||||
return ErrNoPinChangeChannel
|
||||
}
|
||||
|
||||
// Set and enable the GPIOTE interrupt. It's not a problem if this happens
|
||||
// more than once.
|
||||
interrupt.New(nrf.IRQ_GPIOTE, func(interrupt.Interrupt) {
|
||||
for i := range nrf.GPIOTE.EVENTS_IN {
|
||||
if nrf.GPIOTE.EVENTS_IN[i].Get() != 0 {
|
||||
nrf.GPIOTE.EVENTS_IN[i].Set(0)
|
||||
pin := Pin((nrf.GPIOTE.CONFIG[i].Get() & nrf.GPIOTE_CONFIG_PSEL_Msk) >> nrf.GPIOTE_CONFIG_PSEL_Pos)
|
||||
pinCallbacks[i](pin)
|
||||
}
|
||||
}
|
||||
}).Enable()
|
||||
|
||||
// Everything was configured correctly.
|
||||
return nil
|
||||
}
|
||||
|
||||
// UART on the NRF.
|
||||
type UART struct {
|
||||
Buffer *RingBuffer
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче