23
23
24
24
#include <string.h>
25
25
26
- static voidFuncPtr callbacksInt [EXTERNAL_NUM_INTERRUPTS ];
26
+ static voidFuncPtr ISRcallback [EXTERNAL_NUM_INTERRUPTS ];
27
+ static uint32_t ISRlist [EXTERNAL_NUM_INTERRUPTS ];
28
+ static uint32_t nints ; // Stores total number of attached interrupts
27
29
28
30
/* Configure I/O interrupt sources */
29
31
static void __initialize ()
30
32
{
31
- memset (callbacksInt , 0 , sizeof (callbacksInt ));
33
+ memset (ISRlist , 0 , sizeof (ISRlist ));
34
+ memset (ISRcallback , 0 , sizeof (ISRcallback ));
35
+ nints = 0 ;
32
36
33
37
NVIC_DisableIRQ (EIC_IRQn );
34
38
NVIC_ClearPendingIRQ (EIC_IRQn );
@@ -86,47 +90,69 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
86
90
return ;
87
91
#endif
88
92
89
- // Assign pin to EIC
90
- if (pinPeripheral (pin , PIO_EXTINT ) != RET_STATUS_OK )
91
- return ;
93
+ uint32_t inMask = 1 << in ;
92
94
93
95
// Enable wakeup capability on pin in case being used during sleep (WAKEUP always enabled on SAML and SAMC)
94
96
#if (SAMD21 || SAMD11 )
95
- EIC -> WAKEUP .reg |= (1 << in );
97
+ EIC -> WAKEUP .reg |= (inMask );
96
98
#endif
97
99
98
- // Assign callback to interrupt
99
- callbacksInt [in ] = callback ;
100
+ // Assign pin to EIC
101
+ if (pinPeripheral (pin , PIO_EXTINT ) != RET_STATUS_OK )
102
+ return ;
100
103
101
- // Look for right CONFIG register to be addressed
102
- if (in > EXTERNAL_INT_7 ) {
103
- config = 1 ;
104
- } else {
105
- config = 0 ;
106
- }
104
+ // Only store when there is really an ISR to call.
105
+ // This allow for calling attachInterrupt(pin, NULL, mode), we set up all needed register
106
+ // but won't service the interrupt, this way we also don't need to check it inside the ISR.
107
+ if (callback )
108
+ {
109
+ // Store interrupts to service in order of when they were attached
110
+ // to allow for first come first serve handler
111
+ uint32_t current = 0 ;
112
+
113
+ // Check if we already have this interrupt
114
+ for (current = 0 ; current < nints ; current ++ ) {
115
+ if (ISRlist [current ] == inMask ) {
116
+ break ;
117
+ }
118
+ }
119
+ if (current == nints ) {
120
+ // Need to make a new entry
121
+ nints ++ ;
122
+ }
123
+ ISRlist [current ] = inMask ; // List of interrupt in order of when they were attached
124
+ ISRcallback [current ] = callback ; // List of callback adresses
125
+
126
+ // Look for right CONFIG register to be addressed
127
+ if (in > EXTERNAL_INT_7 ) {
128
+ config = 1 ;
129
+ } else {
130
+ config = 0 ;
131
+ }
107
132
108
- // Configure the interrupt mode
109
- pos = (in - (8 * config )) << 2 ; // compute position (ie: 0, 4, 8, 12, ...)
133
+ // Configure the interrupt mode
134
+ pos = (in - (8 * config )) << 2 ; // compute position (ie: 0, 4, 8, 12, ...)
110
135
111
- #if (SAML21 || SAMC21 )
112
- EIC -> CTRLA .reg = 0 ; // disable EIC before changing CONFIG
113
- while (EIC -> SYNCBUSY .reg & EIC_SYNCBUSY_MASK ) { }
114
- #endif
136
+ #if (SAML21 || SAMC21 )
137
+ EIC -> CTRLA .reg = 0 ; // disable EIC before changing CONFIG
138
+ while (EIC -> SYNCBUSY .reg & EIC_SYNCBUSY_MASK ) { }
139
+ #endif
115
140
116
- uint32_t regConfig = (~(EIC_CONFIG_SENSE0_Msk << pos ) & EIC -> CONFIG [config ].reg ); // copy register to variable, clearing mode bits
117
- // insert new mode and write to register (the hardware numbering for the 5 interrupt modes is in reverse order to the arduino numbering, so using '5-mode').
118
- EIC -> CONFIG [config ].reg = (regConfig | ((5 - mode ) << pos ));
141
+ uint32_t regConfig = (~(EIC_CONFIG_SENSE0_Msk << pos ) & EIC -> CONFIG [config ].reg ); // copy register to variable, clearing mode bits
142
+ // insert new mode and write to register (the hardware numbering for the 5 interrupt modes is in reverse order to the arduino numbering, so using '5-mode').
143
+ EIC -> CONFIG [config ].reg = (regConfig | ((5 - mode ) << pos ));
119
144
120
- #if (SAML21 || SAMC21 )
121
- EIC -> CTRLA .reg = EIC_CTRLA_ENABLE ; // enable EIC
122
- while (EIC -> SYNCBUSY .reg & EIC_SYNCBUSY_MASK ) { }
123
- #endif
145
+ #if (SAML21 || SAMC21 )
146
+ EIC -> CTRLA .reg = EIC_CTRLA_ENABLE ; // enable EIC
147
+ while (EIC -> SYNCBUSY .reg & EIC_SYNCBUSY_MASK ) { }
148
+ #endif
149
+ }
124
150
125
151
// Clear the interrupt flag
126
- EIC -> INTFLAG .reg = (1 << in );
152
+ EIC -> INTFLAG .reg = (inMask );
127
153
128
154
// Enable the interrupt
129
- EIC -> INTENSET .reg = (1 << in );
155
+ EIC -> INTENSET .reg = (inMask );
130
156
}
131
157
132
158
/*
@@ -138,31 +164,48 @@ void detachInterrupt(uint32_t pin)
138
164
if (in == NOT_AN_INTERRUPT || in == EXTERNAL_INT_NMI )
139
165
return ;
140
166
141
- EIC -> INTENCLR .reg = EIC_INTENCLR_EXTINT (1 << in );
167
+ uint32_t inMask = 1 << in ;
168
+ EIC -> INTENCLR .reg = EIC_INTENCLR_EXTINT (inMask );
142
169
143
170
// Disable wakeup capability on pin during sleep (WAKEUP always enabled on SAML and SAMC)
144
171
#if (SAMD21 || SAMD11 )
145
- EIC -> WAKEUP .reg &= ~(1 << in );
172
+ EIC -> WAKEUP .reg &= ~(inMask );
146
173
#endif
174
+
175
+ // Remove callback from the ISR list
176
+ uint32_t current ;
177
+ for (current = 0 ; current < nints ; current ++ ) {
178
+ if (ISRlist [current ] == inMask ) {
179
+ break ;
180
+ }
181
+ }
182
+ if (current == nints ) return ; // We didn't have it
183
+
184
+ // Shift the reminder down
185
+ for (; current < nints - 1 ; current ++ ) {
186
+ ISRlist [current ] = ISRlist [current + 1 ];
187
+ ISRcallback [current ] = ISRcallback [current + 1 ];
188
+ }
189
+ nints -- ;
147
190
}
148
191
149
192
/*
150
193
* External Interrupt Controller NVIC Interrupt Handler
151
194
*/
152
195
void EIC_Handler (void )
153
196
{
154
- // Test the normal interrupts
155
- for (uint32_t i = EXTERNAL_INT_0 ; i <=EXTERNAL_INT_15 ; i ++ )
197
+ // Calling the routine directly from -here- takes about 1us
198
+ // Depending on where you are in the list it will take longer
199
+
200
+ // Loop over all enabled interrupts in the list
201
+ for (uint32_t i = 0 ; i < nints ; i ++ )
156
202
{
157
- if ((EIC -> INTFLAG .reg & ( 1 << i ) ) != 0 )
203
+ if ((EIC -> INTFLAG .reg & ISRlist [ i ] ) != 0 )
158
204
{
159
- // Call the callback function if assigned
160
- if (callbacksInt [i ]) {
161
- callbacksInt [i ]();
162
- }
163
-
205
+ // Call the callback function
206
+ ISRcallback [i ]();
164
207
// Clear the interrupt
165
- EIC -> INTFLAG .reg = 1 << i ;
208
+ EIC -> INTFLAG .reg = ISRlist [ i ] ;
166
209
}
167
210
}
168
211
}
0 commit comments