mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-05 03:27:48 +00:00
machine/esp32s3: use edge-triggered CPU interrupt for GPIO pin interrupts
When SPI is configured via the GPIO Matrix, SPI signal transitions set GPIO.STATUS bits on the routed pins. With a level-triggered CPU interrupt (line 8), the ISR re-enters continuously as long as any STATUS bit is asserted — causing user GPIO callbacks to fire spuriously. Switch cpuInterruptFromPin to CPU interrupt 10, which is edge-triggered (level 1) on the Xtensa LX7. This ensures the ISR fires once per GPIO event rather than looping while SPI is active. Also move STATUS_W1TC clears to before callback dispatch so that new GPIO events arriving during handler execution generate a fresh edge, and add writeINTCLEAR(active) in handleInterrupt to properly acknowledge edge-triggered CPU interrupt pending bits via the INTCLEAR register. Fixes GPIO interrupts firing constantly when SPI and pin interrupts are used together. Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
@@ -107,6 +107,12 @@ func handleInterrupt() {
|
||||
enabled := readINTENABLE()
|
||||
active := pending & enabled
|
||||
|
||||
// Clear edge-triggered pending bits before dispatching handlers so that
|
||||
// new edges arriving during handler execution are not lost. Writing to
|
||||
// INTCLEAR is a no-op for level-triggered lines, so this is safe for all
|
||||
// interrupt types.
|
||||
writeINTCLEAR(active)
|
||||
|
||||
for i := firstCPUInt; i <= lastCPUInt; i++ {
|
||||
if active&(1<<uint(i)) != 0 {
|
||||
// callHandlers requires a compile-time constant, so we
|
||||
@@ -212,6 +218,16 @@ func readINTERRUPT() uint32 {
|
||||
return uint32(device.AsmFull("rsr {}, INTERRUPT", nil))
|
||||
}
|
||||
|
||||
// writeINTCLEAR writes the INTCLEAR special register (SR 227).
|
||||
// Setting bit N clears CPU interrupt N if it is edge-triggered or
|
||||
// software-triggered. Bits corresponding to level-triggered interrupts
|
||||
// are ignored by hardware.
|
||||
func writeINTCLEAR(val uint32) {
|
||||
device.AsmFull("wsr {val}, INTCLEAR", map[string]interface{}{
|
||||
"val": val,
|
||||
})
|
||||
}
|
||||
|
||||
// -- Interrupt matrix helpers -----------------------------------------------
|
||||
// The ESP32-S3 interrupt matrix has one mapping register per peripheral
|
||||
// source. These are memory-mapped in the INTERRUPT_CORE0 peripheral.
|
||||
|
||||
Reference in New Issue
Block a user