diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 5a2d8b9ed..c78ddf62b 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -21,12 +21,17 @@ #include -static voidFuncPtr callbacksInt[EXTERNAL_NUM_INTERRUPTS]; +static voidFuncPtr ISRcallback[EXTERNAL_NUM_INTERRUPTS]; +static uint32_t ISRlist[EXTERNAL_NUM_INTERRUPTS]; +static uint32_t nints; // Stores total number of attached interrupts + /* Configure I/O interrupt sources */ static void __initialize() { - memset(callbacksInt, 0, sizeof(callbacksInt)); + memset(ISRlist, 0, sizeof(ISRlist)); + memset(ISRcallback, 0, sizeof(ISRcallback)); + nints = 0; NVIC_DisableIRQ(EIC_IRQn); NVIC_ClearPendingIRQ(EIC_IRQn); @@ -71,49 +76,70 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) } // Enable wakeup capability on pin in case being used during sleep - EIC->WAKEUP.reg |= (1 << in); + uint32_t inMask = 1 << in; + EIC->WAKEUP.reg |= inMask; // Assign pin to EIC pinPeripheral(pin, PIO_EXTINT); - // Assign callback to interrupt - callbacksInt[in] = callback; - - // Look for right CONFIG register to be addressed - if (in > EXTERNAL_INT_7) { - config = 1; - } else { - config = 0; - } - - // Configure the interrupt mode - pos = (in - (8 * config)) << 2; - EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos);//reset sense mode, important when changing trigger mode during runtime - switch (mode) + // Only store when there is really an ISR to call. + // This allow for calling attachInterrupt(pin, NULL, mode), we set up all needed register + // but won't service the interrupt, this way we also don't need to check it inside the ISR. + if (callback) { - case LOW: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos; - break; + // Store interrupts to service in order of when they were attached + // to allow for first come first serve handler + uint32_t current = 0; + + // Check if we already have this interrupt + for (current=0; current EXTERNAL_INT_7) { + config = 1; + pos = (in - 8) << 2; + } else { + config = 0; + pos = in << 2; + } - case HIGH: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos; - break; + // Configure the interrupt mode + EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos); // Reset sense mode, important when changing trigger mode during runtime + switch (mode) + { + case LOW: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos; + break; - case CHANGE: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos; - break; + case HIGH: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos; + break; - case FALLING: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos; - break; + case CHANGE: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos; + break; - case RISING: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos; - break; - } + case FALLING: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos; + break; + case RISING: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos; + break; + } + } // Enable the interrupt - EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in); + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(inMask); } /* @@ -129,10 +155,27 @@ void detachInterrupt(uint32_t pin) if (in == NOT_AN_INTERRUPT || in == EXTERNAL_INT_NMI) return; - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(1 << in); + uint32_t inMask = 1 << in; + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(inMask); // Disable wakeup capability on pin during sleep - EIC->WAKEUP.reg &= ~(1 << in); + EIC->WAKEUP.reg &= ~inMask; + + // Remove callback from the ISR list + uint32_t current; + for (current=0; currentINTFLAG.reg & (1 << i)) != 0) + if ((EIC->INTFLAG.reg & ISRlist[i]) != 0) { - // Call the callback function if assigned - if (callbacksInt[i]) { - callbacksInt[i](); - } - + // Call the callback function + ISRcallback[i](); // Clear the interrupt - EIC->INTFLAG.reg = 1 << i; + EIC->INTFLAG.reg = ISRlist[i]; } } }