@@ -5,7 +5,9 @@ package machine
55import (
66 "device/esp"
77 "errors"
8+ "runtime/interrupt"
89 "runtime/volatile"
10+ "sync"
911 "unsafe"
1012)
1113
@@ -303,6 +305,91 @@ func (p Pin) pinReg() *volatile.Register32 {
303305 return (* volatile .Register32 )(unsafe .Add (unsafe .Pointer (& esp .GPIO .PIN0 ), uintptr (p )* 4 ))
304306}
305307
308+ const maxPin = 49
309+ const cpuInterruptFromPin = 8
310+
311+ type PinChange uint8
312+
313+ // Pin change interrupt constants for SetInterrupt.
314+ const (
315+ PinRising PinChange = iota + 1
316+ PinFalling
317+ PinToggle
318+ )
319+
320+ // SetInterrupt sets an interrupt to be executed when a particular pin changes
321+ // state. The pin should already be configured as an input, including a pull up
322+ // or down if no external pull is provided.
323+ //
324+ // You can pass a nil func to unset the pin change interrupt. If you do so,
325+ // the change parameter is ignored and can be set to any value (such as 0).
326+ // If the pin is already configured with a callback, you must first unset
327+ // this pins interrupt before you can set a new callback.
328+ func (p Pin ) SetInterrupt (change PinChange , callback func (Pin )) (err error ) {
329+ if p >= maxPin {
330+ return ErrInvalidInputPin
331+ }
332+
333+ if callback == nil {
334+ // Disable this pin interrupt
335+ p .pinReg ().ClearBits (esp .GPIO_PIN_INT_TYPE_Msk | esp .GPIO_PIN_INT_ENA_Msk )
336+
337+ if pinCallbacks [p ] != nil {
338+ pinCallbacks [p ] = nil
339+ }
340+ return nil
341+ }
342+
343+ if pinCallbacks [p ] != nil {
344+ // The pin was already configured.
345+ // To properly re-configure a pin, unset it first and set a new
346+ // configuration.
347+ return ErrNoPinChangeChannel
348+ }
349+ pinCallbacks [p ] = callback
350+
351+ onceSetupPinInterrupt .Do (func () {
352+ err = setupPinInterrupt ()
353+ })
354+ if err != nil {
355+ return err
356+ }
357+
358+ p .pinReg ().Set (
359+ (p .pinReg ().Get () & ^ uint32 (esp .GPIO_PIN_INT_TYPE_Msk | esp .GPIO_PIN_INT_ENA_Msk )) |
360+ uint32 (change )<< esp .GPIO_PIN_INT_TYPE_Pos | uint32 (1 )<< esp .GPIO_PIN_INT_ENA_Pos )
361+
362+ return nil
363+ }
364+
365+ var (
366+ pinCallbacks [maxPin ]func (Pin )
367+ onceSetupPinInterrupt sync.Once
368+ )
369+
370+ func setupPinInterrupt () error {
371+ esp .INTERRUPT_CORE0 .SetGPIO_INTERRUPT_PRO_MAP (cpuInterruptFromPin )
372+ return interrupt .New (cpuInterruptFromPin , func (interrupt.Interrupt ) {
373+ // Check status for GPIO0-31
374+ status := esp .GPIO .STATUS .Get ()
375+ for i , mask := 0 , uint32 (1 ); i < 32 ; i , mask = i + 1 , mask << 1 {
376+ if (status & mask ) != 0 && pinCallbacks [i ] != nil {
377+ pinCallbacks [i ](Pin (i ))
378+ }
379+ }
380+ // Check status for GPIO32-48
381+ status1 := esp .GPIO .STATUS1 .Get ()
382+ for i , mask := 32 , uint32 (1 ); i < maxPin ; i , mask = i + 1 , mask << 1 {
383+ if (status1 & mask ) != 0 && pinCallbacks [i ] != nil {
384+ pinCallbacks [i ](Pin (i ))
385+ }
386+ }
387+ // Clear interrupt bits
388+ esp .GPIO .STATUS_W1TC .SetBits (status )
389+ esp .GPIO .STATUS1_W1TC .SetBits (status1 )
390+ }).Enable ()
391+ }
392+
306393var DefaultUART = UART0
307394
308395var (
0 commit comments