Skip to content

Commit 93a52f9

Browse files
dok-netdevyte
authored andcommitted
Bugfix: attach interrupt (#6049) (#6048)
* Properly check for "functional" ISRs and expose C-style attachInterruptArg * Use RAII idiom (cherry picked from commit 15c0b5b356aad0c3032b96ed6db0ec70cbf719d3) # Conflicts: # cores/esp8266/core_esp8266_wiring_digital.cpp * Indentation * Easier reviewability * Refactored after review input. * Finish up insights from review comments.
1 parent 3f35506 commit 93a52f9

File tree

3 files changed

+67
-54
lines changed

3 files changed

+67
-54
lines changed

cores/esp8266/Arduino.h

+1
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
218218

219219
void attachInterrupt(uint8_t pin, void (*)(void), int mode);
220220
void detachInterrupt(uint8_t pin);
221+
void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode);
221222

222223
void preinit(void);
223224
void setup(void);

cores/esp8266/FunctionalInterrupt.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ typedef void (*voidFuncPtr)(void);
77
typedef void (*voidFuncPtrArg)(void*);
88

99
// Helper functions for Functional interrupt routines
10-
extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp , int mode);
10+
extern "C" void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtr userFunc, void*fp, int mode, bool functional);
1111

1212

1313
void ICACHE_RAM_ATTR interruptFunctional(void* arg)
@@ -47,7 +47,7 @@ void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode
4747
as->interruptInfo = ii;
4848
as->functionInfo = fi;
4949

50-
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
50+
__attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true);
5151
}
5252

5353
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode)
@@ -61,5 +61,5 @@ void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> sc
6161
as->interruptInfo = ii;
6262
as->functionInfo = fi;
6363

64-
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
64+
__attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true);
6565
}

cores/esp8266/core_esp8266_wiring_digital.cpp

+63-51
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "ets_sys.h"
2727
#include "user_interface.h"
2828
#include "core_esp8266_waveform.h"
29+
#include "interrupts.h"
2930

3031
extern "C" {
3132

@@ -109,8 +110,9 @@ typedef void (*voidFuncPtrArg)(void*);
109110

110111
typedef struct {
111112
uint8_t mode;
112-
void (*fn)(void);
113+
voidFuncPtr fn;
113114
void * arg;
115+
bool functional;
114116
} interrupt_handler_t;
115117

116118
//duplicate from functionalInterrupt.h keep in sync
@@ -125,11 +127,11 @@ typedef struct {
125127
void* functionInfo;
126128
} ArgStructure;
127129

128-
static interrupt_handler_t interrupt_handlers[16];
130+
static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0, 0}, };
129131
static uint32_t interrupt_reg = 0;
130132

131-
void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
132-
(void) arg;
133+
void ICACHE_RAM_ATTR interrupt_handler(void*)
134+
{
133135
uint32_t status = GPIE;
134136
GPIEC = status;//clear them interrupts
135137
uint32_t levels = GPI;
@@ -144,34 +146,49 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
144146
if (handler->fn &&
145147
(handler->mode == CHANGE ||
146148
(handler->mode & 1) == !!(levels & (1 << i)))) {
147-
// to make ISR compatible to Arduino AVR model where interrupts are disabled
148-
// we disable them before we call the client ISR
149-
uint32_t savedPS = xt_rsil(15); // stop other interrupts
150-
ArgStructure* localArg = (ArgStructure*)handler->arg;
151-
if (localArg && localArg->interruptInfo)
152-
{
153-
localArg->interruptInfo->pin = i;
154-
localArg->interruptInfo->value = __digitalRead(i);
155-
localArg->interruptInfo->micro = micros();
156-
}
157-
if (handler->arg)
158-
{
159-
((voidFuncPtrArg)handler->fn)(handler->arg);
160-
}
161-
else
162-
{
163-
handler->fn();
149+
// to make ISR compatible to Arduino AVR model where interrupts are disabled
150+
// we disable them before we call the client ISR
151+
esp8266::InterruptLock irqLock; // stop other interrupts
152+
if (handler->functional)
153+
{
154+
ArgStructure* localArg = (ArgStructure*)handler->arg;
155+
if (localArg && localArg->interruptInfo)
156+
{
157+
localArg->interruptInfo->pin = i;
158+
localArg->interruptInfo->value = __digitalRead(i);
159+
localArg->interruptInfo->micro = micros();
160+
}
161+
}
162+
if (handler->arg)
163+
{
164+
((voidFuncPtrArg)handler->fn)(handler->arg);
165+
}
166+
else
167+
{
168+
handler->fn();
169+
}
164170
}
165-
xt_wsr_ps(savedPS);
166-
}
167171
}
168172
ETS_GPIO_INTR_ENABLE();
169173
}
170174

171175
extern void cleanupFunctional(void* arg);
172176

173-
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) {
177+
static void set_interrupt_handlers(uint8_t pin, voidFuncPtr userFunc, void* arg, uint8_t mode, bool functional)
178+
{
179+
interrupt_handler_t* handler = &interrupt_handlers[pin];
180+
handler->mode = mode;
181+
handler->fn = userFunc;
182+
if (handler->functional && handler->arg) // Clean when new attach without detach
183+
{
184+
cleanupFunctional(handler->arg);
185+
}
186+
handler->arg = arg;
187+
handler->functional = functional;
188+
}
174189

190+
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode, bool functional)
191+
{
175192
// #5780
176193
// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
177194
if ((uint32_t)userFunc >= 0x40200000)
@@ -183,14 +200,7 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu
183200

184201
if(pin < 16) {
185202
ETS_GPIO_INTR_DISABLE();
186-
interrupt_handler_t *handler = &interrupt_handlers[pin];
187-
handler->mode = mode;
188-
handler->fn = userFunc;
189-
if (handler->arg) // Clean when new attach without detach
190-
{
191-
cleanupFunctional(handler->arg);
192-
}
193-
handler->arg = arg;
203+
set_interrupt_handlers(pin, (voidFuncPtr)userFunc, arg, mode, functional);
194204
interrupt_reg |= (1 << pin);
195205
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
196206
GPIEC = (1 << pin); //Clear Interrupt for this pin
@@ -200,31 +210,32 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu
200210
}
201211
}
202212

203-
extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode )
213+
extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode)
204214
{
205-
__attachInterruptArg (pin, userFunc, 0, mode);
215+
__attachInterruptFunctionalArg(pin, userFunc, arg, mode, false);
206216
}
207217

208218
extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
209-
if(pin < 16) {
210-
ETS_GPIO_INTR_DISABLE();
211-
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
212-
GPIEC = (1 << pin); //Clear Interrupt for this pin
213-
interrupt_reg &= ~(1 << pin);
214-
interrupt_handler_t *handler = &interrupt_handlers[pin];
215-
handler->mode = 0;
216-
handler->fn = 0;
217-
if (handler->arg)
218-
{
219-
cleanupFunctional(handler->arg);
220-
}
221-
handler->arg = 0;
222-
if (interrupt_reg)
223-
ETS_GPIO_INTR_ENABLE();
224-
}
219+
if (pin < 16)
220+
{
221+
ETS_GPIO_INTR_DISABLE();
222+
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
223+
GPIEC = (1 << pin); //Clear Interrupt for this pin
224+
interrupt_reg &= ~(1 << pin);
225+
set_interrupt_handlers(pin, nullptr, nullptr, 0, false);
226+
if (interrupt_reg)
227+
{
228+
ETS_GPIO_INTR_ENABLE();
229+
}
230+
}
231+
}
232+
233+
extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode)
234+
{
235+
__attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, 0, mode, false);
225236
}
226237

227-
void initPins() {
238+
extern void initPins() {
228239
//Disable UART interrupts
229240
system_set_os_print(0);
230241
U0IE = 0;
@@ -243,6 +254,7 @@ extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pi
243254
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
244255
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")));
245256
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
257+
extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg")));
246258
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));
247259

248260
};

0 commit comments

Comments
 (0)