Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 88 additions & 45 deletions cores/arduino/WInterrupts.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,17 @@

#include <string.h>

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);
Expand Down Expand Up @@ -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<nints; current++) {
if (ISRlist[current] == inMask) {
break;
}
}
if (current == nints) {
// Need to make a new entry
nints++;
}
ISRlist[current] = inMask; // List of interrupt in order of when they were attached
ISRcallback[current] = callback; // List of callback adresses

// Look for right CONFIG register to be addressed
if (in > 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);
}

/*
Expand All @@ -129,29 +155,46 @@ 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; current<nints; current++) {
if (ISRlist[current] == inMask) {
break;
}
}
if (current == nints) return; // We didn't have it

// Shift the reminder down
for (; current<nints-1; current++) {
ISRlist[current] = ISRlist[current+1];
ISRcallback[current] = ISRcallback[current+1];
}
nints--;
}

/*
* External Interrupt Controller NVIC Interrupt Handler
*/
void EIC_Handler(void)
{
// Test the 16 normal interrupts
for (uint32_t i=EXTERNAL_INT_0; i<=EXTERNAL_INT_15; i++)
// Calling the routine directly from -here- takes about 1us
// Depending on where you are in the list it will take longer

// Loop over all enabled interrupts in the list
for (uint32_t i=0; i<nints; i++)
{
if ((EIC->INTFLAG.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];
}
}
}