1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-25 20:02:37 +03:00

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.
This commit is contained in:
Dirk O. Kaar 2019-07-04 05:13:48 +02:00 committed by Develo
parent 3f35506684
commit 93a52f923b
3 changed files with 67 additions and 54 deletions

View File

@ -218,6 +218,7 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t pin, void (*)(void), int mode); void attachInterrupt(uint8_t pin, void (*)(void), int mode);
void detachInterrupt(uint8_t pin); void detachInterrupt(uint8_t pin);
void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode);
void preinit(void); void preinit(void);
void setup(void); void setup(void);

View File

@ -7,7 +7,7 @@ typedef void (*voidFuncPtr)(void);
typedef void (*voidFuncPtrArg)(void*); typedef void (*voidFuncPtrArg)(void*);
// Helper functions for Functional interrupt routines // Helper functions for Functional interrupt routines
extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp , int mode); extern "C" void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtr userFunc, void*fp, int mode, bool functional);
void ICACHE_RAM_ATTR interruptFunctional(void* arg) void ICACHE_RAM_ATTR interruptFunctional(void* arg)
@ -47,7 +47,7 @@ void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode
as->interruptInfo = ii; as->interruptInfo = ii;
as->functionInfo = fi; as->functionInfo = fi;
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); __attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true);
} }
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode) 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
as->interruptInfo = ii; as->interruptInfo = ii;
as->functionInfo = fi; as->functionInfo = fi;
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); __attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true);
} }

View File

@ -26,6 +26,7 @@
#include "ets_sys.h" #include "ets_sys.h"
#include "user_interface.h" #include "user_interface.h"
#include "core_esp8266_waveform.h" #include "core_esp8266_waveform.h"
#include "interrupts.h"
extern "C" { extern "C" {
@ -109,8 +110,9 @@ typedef void (*voidFuncPtrArg)(void*);
typedef struct { typedef struct {
uint8_t mode; uint8_t mode;
void (*fn)(void); voidFuncPtr fn;
void * arg; void * arg;
bool functional;
} interrupt_handler_t; } interrupt_handler_t;
//duplicate from functionalInterrupt.h keep in sync //duplicate from functionalInterrupt.h keep in sync
@ -125,11 +127,11 @@ typedef struct {
void* functionInfo; void* functionInfo;
} ArgStructure; } ArgStructure;
static interrupt_handler_t interrupt_handlers[16]; static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0, 0}, };
static uint32_t interrupt_reg = 0; static uint32_t interrupt_reg = 0;
void ICACHE_RAM_ATTR interrupt_handler(void *arg) { void ICACHE_RAM_ATTR interrupt_handler(void*)
(void) arg; {
uint32_t status = GPIE; uint32_t status = GPIE;
GPIEC = status;//clear them interrupts GPIEC = status;//clear them interrupts
uint32_t levels = GPI; uint32_t levels = GPI;
@ -146,7 +148,9 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
(handler->mode & 1) == !!(levels & (1 << i)))) { (handler->mode & 1) == !!(levels & (1 << i)))) {
// to make ISR compatible to Arduino AVR model where interrupts are disabled // to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR // we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts esp8266::InterruptLock irqLock; // stop other interrupts
if (handler->functional)
{
ArgStructure* localArg = (ArgStructure*)handler->arg; ArgStructure* localArg = (ArgStructure*)handler->arg;
if (localArg && localArg->interruptInfo) if (localArg && localArg->interruptInfo)
{ {
@ -154,6 +158,7 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
localArg->interruptInfo->value = __digitalRead(i); localArg->interruptInfo->value = __digitalRead(i);
localArg->interruptInfo->micro = micros(); localArg->interruptInfo->micro = micros();
} }
}
if (handler->arg) if (handler->arg)
{ {
((voidFuncPtrArg)handler->fn)(handler->arg); ((voidFuncPtrArg)handler->fn)(handler->arg);
@ -162,7 +167,6 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
{ {
handler->fn(); handler->fn();
} }
xt_wsr_ps(savedPS);
} }
} }
ETS_GPIO_INTR_ENABLE(); ETS_GPIO_INTR_ENABLE();
@ -170,8 +174,21 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
extern void cleanupFunctional(void* arg); extern void cleanupFunctional(void* arg);
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) { static void set_interrupt_handlers(uint8_t pin, voidFuncPtr userFunc, void* arg, uint8_t mode, bool functional)
{
interrupt_handler_t* handler = &interrupt_handlers[pin];
handler->mode = mode;
handler->fn = userFunc;
if (handler->functional && handler->arg) // Clean when new attach without detach
{
cleanupFunctional(handler->arg);
}
handler->arg = arg;
handler->functional = functional;
}
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode, bool functional)
{
// #5780 // #5780
// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
if ((uint32_t)userFunc >= 0x40200000) if ((uint32_t)userFunc >= 0x40200000)
@ -183,14 +200,7 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu
if(pin < 16) { if(pin < 16) {
ETS_GPIO_INTR_DISABLE(); ETS_GPIO_INTR_DISABLE();
interrupt_handler_t *handler = &interrupt_handlers[pin]; set_interrupt_handlers(pin, (voidFuncPtr)userFunc, arg, mode, functional);
handler->mode = mode;
handler->fn = userFunc;
if (handler->arg) // Clean when new attach without detach
{
cleanupFunctional(handler->arg);
}
handler->arg = arg;
interrupt_reg |= (1 << pin); interrupt_reg |= (1 << pin);
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
GPIEC = (1 << pin); //Clear Interrupt for this pin GPIEC = (1 << pin); //Clear Interrupt for this pin
@ -200,31 +210,32 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu
} }
} }
extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode ) extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode)
{ {
__attachInterruptArg (pin, userFunc, 0, mode); __attachInterruptFunctionalArg(pin, userFunc, arg, mode, false);
} }
extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) { extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
if(pin < 16) { if (pin < 16)
{
ETS_GPIO_INTR_DISABLE(); ETS_GPIO_INTR_DISABLE();
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
GPIEC = (1 << pin); //Clear Interrupt for this pin GPIEC = (1 << pin); //Clear Interrupt for this pin
interrupt_reg &= ~(1 << pin); interrupt_reg &= ~(1 << pin);
interrupt_handler_t *handler = &interrupt_handlers[pin]; set_interrupt_handlers(pin, nullptr, nullptr, 0, false);
handler->mode = 0;
handler->fn = 0;
if (handler->arg)
{
cleanupFunctional(handler->arg);
}
handler->arg = 0;
if (interrupt_reg) if (interrupt_reg)
{
ETS_GPIO_INTR_ENABLE(); ETS_GPIO_INTR_ENABLE();
} }
}
} }
void initPins() { extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode)
{
__attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, 0, mode, false);
}
extern void initPins() {
//Disable UART interrupts //Disable UART interrupts
system_set_os_print(0); system_set_os_print(0);
U0IE = 0; U0IE = 0;
@ -243,6 +254,7 @@ extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pi
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"))); extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")));
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg")));
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));
}; };