mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-11 06:23:39 +00:00
machine/esp32s3: implement Pin.SetInterrupt for GPIO pin change interrupts
Add support for rising, falling, and toggle edge interrupts on all ESP32-S3 GPIO pins (0-48). The GPIO peripheral interrupt is routed to CPU interrupt 8 via the interrupt matrix. The ISR reads both STATUS and STATUS1 registers to cover the full 49-pin range. Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
//go:build xiao_esp32s3
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "machine"
|
||||||
|
|
||||||
|
const (
|
||||||
|
button = machine.D1
|
||||||
|
buttonMode = machine.PinInput
|
||||||
|
buttonPinChange = machine.PinFalling
|
||||||
|
)
|
||||||
@@ -5,7 +5,9 @@ package machine
|
|||||||
import (
|
import (
|
||||||
"device/esp"
|
"device/esp"
|
||||||
"errors"
|
"errors"
|
||||||
|
"runtime/interrupt"
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -303,6 +305,91 @@ func (p Pin) pinReg() *volatile.Register32 {
|
|||||||
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.PIN0), uintptr(p)*4))
|
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.PIN0), uintptr(p)*4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxPin = 49
|
||||||
|
const cpuInterruptFromPin = 8
|
||||||
|
|
||||||
|
type PinChange uint8
|
||||||
|
|
||||||
|
// Pin change interrupt constants for SetInterrupt.
|
||||||
|
const (
|
||||||
|
PinRising PinChange = iota + 1
|
||||||
|
PinFalling
|
||||||
|
PinToggle
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetInterrupt sets an interrupt to be executed when a particular pin changes
|
||||||
|
// state. The pin should already be configured as an input, including a pull up
|
||||||
|
// or down if no external pull is provided.
|
||||||
|
//
|
||||||
|
// 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).
|
||||||
|
// If the pin is already configured with a callback, you must first unset
|
||||||
|
// this pins interrupt before you can set a new callback.
|
||||||
|
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) (err error) {
|
||||||
|
if p >= maxPin {
|
||||||
|
return ErrInvalidInputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
if callback == nil {
|
||||||
|
// Disable this pin interrupt
|
||||||
|
p.pinReg().ClearBits(esp.GPIO_PIN_INT_TYPE_Msk | esp.GPIO_PIN_INT_ENA_Msk)
|
||||||
|
|
||||||
|
if pinCallbacks[p] != nil {
|
||||||
|
pinCallbacks[p] = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pinCallbacks[p] != nil {
|
||||||
|
// The pin was already configured.
|
||||||
|
// To properly re-configure a pin, unset it first and set a new
|
||||||
|
// configuration.
|
||||||
|
return ErrNoPinChangeChannel
|
||||||
|
}
|
||||||
|
pinCallbacks[p] = callback
|
||||||
|
|
||||||
|
onceSetupPinInterrupt.Do(func() {
|
||||||
|
err = setupPinInterrupt()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pinReg().Set(
|
||||||
|
(p.pinReg().Get() & ^uint32(esp.GPIO_PIN_INT_TYPE_Msk|esp.GPIO_PIN_INT_ENA_Msk)) |
|
||||||
|
uint32(change)<<esp.GPIO_PIN_INT_TYPE_Pos | uint32(1)<<esp.GPIO_PIN_INT_ENA_Pos)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pinCallbacks [maxPin]func(Pin)
|
||||||
|
onceSetupPinInterrupt sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupPinInterrupt() error {
|
||||||
|
esp.INTERRUPT_CORE0.SetGPIO_INTERRUPT_PRO_MAP(cpuInterruptFromPin)
|
||||||
|
return interrupt.New(cpuInterruptFromPin, func(interrupt.Interrupt) {
|
||||||
|
// Check status for GPIO0-31
|
||||||
|
status := esp.GPIO.STATUS.Get()
|
||||||
|
for i, mask := 0, uint32(1); i < 32; i, mask = i+1, mask<<1 {
|
||||||
|
if (status&mask) != 0 && pinCallbacks[i] != nil {
|
||||||
|
pinCallbacks[i](Pin(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check status for GPIO32-48
|
||||||
|
status1 := esp.GPIO.STATUS1.Get()
|
||||||
|
for i, mask := 32, uint32(1); i < maxPin; i, mask = i+1, mask<<1 {
|
||||||
|
if (status1&mask) != 0 && pinCallbacks[i] != nil {
|
||||||
|
pinCallbacks[i](Pin(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clear interrupt bits
|
||||||
|
esp.GPIO.STATUS_W1TC.SetBits(status)
|
||||||
|
esp.GPIO.STATUS1_W1TC.SetBits(status1)
|
||||||
|
}).Enable()
|
||||||
|
}
|
||||||
|
|
||||||
var DefaultUART = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
Reference in New Issue
Block a user