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

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