github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_stm32_gpio_revb_mp.go (about)

     1  //go:build stm32wlx
     2  
     3  package machine
     4  
     5  import (
     6  	"device/stm32"
     7  )
     8  
     9  //
    10  // This variant of the GPIO input interrupt logic is for
    11  // multi-core chips with a larger number of interrupt
    12  // channels (more than fits in a single register).
    13  //
    14  // This logic is currently used by the single-core stm32wle5
    15  // due to a patch in stm32-rs project that has renamed the
    16  // registers to match the dual-core names.  This renaming is
    17  // being discussed and may change in future.
    18  //
    19  
    20  //
    21  // STM32 allows one interrupt source per pin number, with
    22  // the same pin number in different ports sharing a single
    23  // interrupt source (so PA0, PB0, PC0 all share).  Only a
    24  // single physical pin can be connected to each interrupt
    25  // line.
    26  //
    27  // To call interrupt callbacks, we record here for each
    28  // pin number the callback and the actual associated pin.
    29  //
    30  
    31  // Callbacks for pin interrupt events
    32  var pinCallbacks [16]func(Pin)
    33  
    34  // The pin currently associated with interrupt callback
    35  // for a given slot.
    36  var interruptPins [16]Pin
    37  
    38  // SetInterrupt sets an interrupt to be executed when a particular pin changes
    39  // state. The pin should already be configured as an input, including a pull up
    40  // or down if no external pull is provided.
    41  //
    42  // This call will replace a previously set callback on this pin. You can pass a
    43  // nil func to unset the pin change interrupt. If you do so, the change
    44  // parameter is ignored and can be set to any value (such as 0).
    45  func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
    46  	port := uint32(uint8(p) / 16)
    47  	pin := uint8(p) % 16
    48  
    49  	enableEXTIConfigRegisters()
    50  
    51  	if callback == nil {
    52  		stm32.EXTI.C1IMR1.ClearBits(1 << pin)
    53  		pinCallbacks[pin] = nil
    54  		return nil
    55  	}
    56  
    57  	if pinCallbacks[pin] != nil {
    58  		// The pin was already configured.
    59  		// To properly re-configure a pin, unset it first and set a new
    60  		// configuration.
    61  		return ErrNoPinChangeChannel
    62  	}
    63  
    64  	// Set the callback now (before the interrupt is enabled) to avoid
    65  	// possible race condition
    66  	pinCallbacks[pin] = callback
    67  	interruptPins[pin] = p
    68  
    69  	crReg := getEXTIConfigRegister(pin)
    70  	shift := (pin & 0x3) * 4
    71  	crReg.ReplaceBits(port, 0xf, shift)
    72  
    73  	if (change & PinRising) != 0 {
    74  		stm32.EXTI.RTSR1.SetBits(1 << pin)
    75  	}
    76  	if (change & PinFalling) != 0 {
    77  		stm32.EXTI.FTSR1.SetBits(1 << pin)
    78  	}
    79  	stm32.EXTI.C1IMR1.SetBits(1 << pin)
    80  
    81  	intr := p.registerInterrupt()
    82  	intr.SetPriority(0)
    83  	intr.Enable()
    84  
    85  	return nil
    86  }