Skip to content
Snippets Groups Projects
Commit 9a49ce2f authored by joverbee's avatar joverbee Committed by Cristian Maglie
Browse files

Improve interrupt handling response time

Change the way ISRs are stored. Store now in a list on a ‘first come
first served basis’, the first interrupt that gets attached will be
served first. This improves the speed of the ISR calling from about 6us
to 2us for a single interrupt on extint14

See #200
parent 610c0e28
No related branches found
No related tags found
No related merge requests found
......@@ -21,12 +21,17 @@
#include <string.h>
static voidFuncPtr callbacksInt[EXTERNAL_NUM_INTERRUPTS];
static voidFuncPtr ISRcallback[EXTERNAL_NUM_INTERRUPTS];
static EExt_Interrupts 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);
......@@ -76,42 +81,65 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
// Assign pin to EIC
pinPeripheral(pin, PIO_EXTINT);
// Assign callback to interrupt
callbacksInt[in] = callback;
// 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)
{
// 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
int id = -1;
for (uint32_t i=0; i<nints; i++) {
if (ISRlist[i] == in) id = in;
}
// Look for right CONFIG register to be addressed
if (in > EXTERNAL_INT_7) {
config = 1;
} else {
config = 0;
}
if (id == -1) {
// Need to make a new entry
current = nints;
nints++;
} else {
// We already have an entry for this pin
current = id;
}
ISRlist[current] = in; // List with nr 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;
} 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)
{
case LOW:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos;
break;
// 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)
{
case LOW:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos;
break;
case HIGH:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos;
break;
case HIGH:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos;
break;
case CHANGE:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos;
break;
case CHANGE:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos;
break;
case FALLING:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_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;
case RISING:
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos;
break;
}
}
// Enable the interrupt
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in);
}
......@@ -133,6 +161,23 @@ void detachInterrupt(uint32_t pin)
// Disable wakeup capability on pin during sleep
EIC->WAKEUP.reg &= ~(1 << in);
// Remove callback from the ISR list
int id = -1;
for (uint32_t i=0; i<nints; i++) {
if (ISRlist[i] == in) id = in;
}
if (id == -1) return; // We didn't have it
// Shift the reminder down
for (uint32_t i=id; i<nints-1; i++) {
ISRlist[i] = ISRlist[i+1];
ISRcallback[i] = ISRcallback[i+1];
}
// And remove the top item
ISRlist[nints]=0;
ISRcallback[nints]=NULL;
nints--;
}
/*
......@@ -140,18 +185,18 @@ void detachInterrupt(uint32_t pin)
*/
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 & 1<<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 = 1<<ISRlist[i];
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment