Skip to content

Commit 9a49ce2

Browse files
joverbeecmaglie
authored andcommitted
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
1 parent 610c0e2 commit 9a49ce2

File tree

1 file changed

+85
-40
lines changed

1 file changed

+85
-40
lines changed

cores/arduino/WInterrupts.c

Lines changed: 85 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121

2222
#include <string.h>
2323

24-
static voidFuncPtr callbacksInt[EXTERNAL_NUM_INTERRUPTS];
24+
static voidFuncPtr ISRcallback[EXTERNAL_NUM_INTERRUPTS];
25+
static EExt_Interrupts ISRlist[EXTERNAL_NUM_INTERRUPTS];
26+
static uint32_t nints; // Stores total number of attached interrupts
27+
2528

2629
/* Configure I/O interrupt sources */
2730
static void __initialize()
2831
{
29-
memset(callbacksInt, 0, sizeof(callbacksInt));
32+
memset(ISRlist, 0, sizeof(ISRlist));
33+
memset(ISRcallback, 0, sizeof(ISRcallback));
34+
nints = 0;
3035

3136
NVIC_DisableIRQ(EIC_IRQn);
3237
NVIC_ClearPendingIRQ(EIC_IRQn);
@@ -76,42 +81,65 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
7681
// Assign pin to EIC
7782
pinPeripheral(pin, PIO_EXTINT);
7883

79-
// Assign callback to interrupt
80-
callbacksInt[in] = callback;
84+
// Only store when there is really an ISR to call.
85+
// This allow for calling attachInterrupt(pin, NULL, mode), we set up all needed register
86+
// but won't service the interrupt, this way we also don't need to check it inside the ISR.
87+
if (callback)
88+
{
89+
// Store interrupts to service in order of when they were attached
90+
// to allow for first come first serve handler
91+
uint32_t current=0;
92+
93+
// Check if we already have this interrupt
94+
int id = -1;
95+
for (uint32_t i=0; i<nints; i++) {
96+
if (ISRlist[i] == in) id = in;
97+
}
8198

82-
// Look for right CONFIG register to be addressed
83-
if (in > EXTERNAL_INT_7) {
84-
config = 1;
85-
} else {
86-
config = 0;
87-
}
99+
if (id == -1) {
100+
// Need to make a new entry
101+
current = nints;
102+
nints++;
103+
} else {
104+
// We already have an entry for this pin
105+
current = id;
106+
}
107+
ISRlist[current] = in; // List with nr of interrupt in order of when they were attached
108+
ISRcallback[current] = callback; // List of callback adresses
109+
110+
// Look for right CONFIG register to be addressed
111+
if (in > EXTERNAL_INT_7) {
112+
config = 1;
113+
} else {
114+
config = 0;
115+
}
88116

89-
// Configure the interrupt mode
90-
pos = (in - (8 * config)) << 2;
91-
EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos);//reset sense mode, important when changing trigger mode during runtime
92-
switch (mode)
93-
{
94-
case LOW:
95-
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos;
96-
break;
117+
// Configure the interrupt mode
118+
pos = (in - (8 * config)) << 2;
119+
EIC->CONFIG[config].reg &=~ (EIC_CONFIG_SENSE0_Msk << pos); // Reset sense mode, important when changing trigger mode during runtime
120+
switch (mode)
121+
{
122+
case LOW:
123+
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos;
124+
break;
97125

98-
case HIGH:
99-
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos;
100-
break;
126+
case HIGH:
127+
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos;
128+
break;
101129

102-
case CHANGE:
103-
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos;
104-
break;
130+
case CHANGE:
131+
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos;
132+
break;
105133

106-
case FALLING:
107-
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos;
108-
break;
134+
case FALLING:
135+
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos;
136+
break;
109137

110-
case RISING:
111-
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos;
112-
break;
138+
case RISING:
139+
EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos;
140+
break;
141+
}
113142
}
114-
115143
// Enable the interrupt
116144
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in);
117145
}
@@ -133,25 +161,42 @@ void detachInterrupt(uint32_t pin)
133161

134162
// Disable wakeup capability on pin during sleep
135163
EIC->WAKEUP.reg &= ~(1 << in);
164+
165+
// Remove callback from the ISR list
166+
int id = -1;
167+
for (uint32_t i=0; i<nints; i++) {
168+
if (ISRlist[i] == in) id = in;
169+
}
170+
if (id == -1) return; // We didn't have it
171+
172+
// Shift the reminder down
173+
for (uint32_t i=id; i<nints-1; i++) {
174+
ISRlist[i] = ISRlist[i+1];
175+
ISRcallback[i] = ISRcallback[i+1];
176+
}
177+
// And remove the top item
178+
ISRlist[nints]=0;
179+
ISRcallback[nints]=NULL;
180+
nints--;
136181
}
137182

138183
/*
139184
* External Interrupt Controller NVIC Interrupt Handler
140185
*/
141186
void EIC_Handler(void)
142187
{
143-
// Test the 16 normal interrupts
144-
for (uint32_t i=EXTERNAL_INT_0; i<=EXTERNAL_INT_15; i++)
188+
// Calling the routine directly from -here- takes about 1us
189+
// Depending on where you are in the list it will take longer
190+
191+
// Loop over all enabled interrupts in the list
192+
for (uint32_t i=0; i<nints; i++)
145193
{
146-
if ((EIC->INTFLAG.reg & (1 << i)) != 0)
194+
if ((EIC->INTFLAG.reg & 1<<ISRlist[i]) != 0)
147195
{
148-
// Call the callback function if assigned
149-
if (callbacksInt[i]) {
150-
callbacksInt[i]();
151-
}
152-
196+
// Call the callback function
197+
ISRcallback[i]();
153198
// Clear the interrupt
154-
EIC->INTFLAG.reg = 1 << i;
199+
EIC->INTFLAG.reg = 1<<ISRlist[i];
155200
}
156201
}
157202
}

0 commit comments

Comments
 (0)