From 3720f4de736202871ea194eeb3c428d973473a6d Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 08:07:08 +0200 Subject: [PATCH 01/12] Remove special support for FunctionalInterrupt from core interrupt handling: - VIP treatment in general attach/detach/handling looks untidy: extern symbols without matching header include but copy&paste special under-the-hood c++ delete support, where everyone else has to do their own resource tracking as usual. - FunctionalInterrupt is not used by anything inside core ESP8266 Arduino for 2 years now, it can be a library, which reduces precious core size for everyone else. Expose attachInterruptArg via Arduino.h. --- cores/esp8266/Arduino.h | 1 + cores/esp8266/FunctionalInterrupt.cpp | 71 ----------- cores/esp8266/FunctionalInterrupt.h | 37 ------ cores/esp8266/ScheduledFunctions.cpp | 117 ------------------ cores/esp8266/ScheduledFunctions.h | 51 -------- cores/esp8266/core_esp8266_wiring_digital.cpp | 77 ++++-------- 6 files changed, 24 insertions(+), 330 deletions(-) delete mode 100644 cores/esp8266/FunctionalInterrupt.cpp delete mode 100644 cores/esp8266/FunctionalInterrupt.h delete mode 100644 cores/esp8266/ScheduledFunctions.cpp delete mode 100644 cores/esp8266/ScheduledFunctions.h diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 34e5fb8fce..91ef7a43f1 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -217,6 +217,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); void attachInterrupt(uint8_t pin, void (*)(void), int mode); +void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode); void detachInterrupt(uint8_t pin); void preinit(void); diff --git a/cores/esp8266/FunctionalInterrupt.cpp b/cores/esp8266/FunctionalInterrupt.cpp deleted file mode 100644 index 2633c63182..0000000000 --- a/cores/esp8266/FunctionalInterrupt.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include "Arduino.h" -#include - -// Duplicate typedefs from core_esp8266_wiring_digital_c -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); - -// Helper functions for Functional interrupt routines -extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp , int mode); - - -void ICACHE_RAM_ATTR interruptFunctional(void* arg) -{ - ArgStructure* localArg = (ArgStructure*)arg; - if (localArg->functionInfo->reqScheduledFunction) - { - schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo)))); -// scheduledInterrupts->scheduleFunctionReg(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))), false, true); - } - if (localArg->functionInfo->reqFunction) - { - localArg->functionInfo->reqFunction(); - } -} - -extern "C" -{ - void cleanupFunctional(void* arg) - { - ArgStructure* localArg = (ArgStructure*)arg; - delete (FunctionInfo*)localArg->functionInfo; - delete (InterruptInfo*)localArg->interruptInfo; - delete localArg; - } -} - -void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) -{ - // use the local interrupt routine which takes the ArgStructure as argument - - InterruptInfo* ii = nullptr; - - FunctionInfo* fi = new FunctionInfo; - fi->reqFunction = intRoutine; - - ArgStructure* as = new ArgStructure; - as->interruptInfo = ii; - as->functionInfo = fi; - - __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); -} - -void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) -{ - if (!scheduledInterrupts) - { - scheduledInterrupts = new ScheduledFunctions(32); - } - InterruptInfo* ii = new InterruptInfo; - - FunctionInfo* fi = new FunctionInfo; - fi->reqScheduledFunction = scheduledIntRoutine; - - ArgStructure* as = new ArgStructure; - as->interruptInfo = ii; - as->functionInfo = fi; - - __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); -} diff --git a/cores/esp8266/FunctionalInterrupt.h b/cores/esp8266/FunctionalInterrupt.h deleted file mode 100644 index a6d53188ae..0000000000 --- a/cores/esp8266/FunctionalInterrupt.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef FUNCTIONALINTERRUPT_H -#define FUNCTIONALINTERRUPT_H - -#include -#include -#include -#include - -extern "C" { -#include "c_types.h" -#include "ets_sys.h" -} - -// Structures for communication - -struct InterruptInfo { - uint8_t pin = 0; - uint8_t value = 0; - uint32_t micro = 0; -}; - -struct FunctionInfo { - std::function reqFunction = nullptr; - std::function reqScheduledFunction = nullptr; -}; - -struct ArgStructure { - InterruptInfo* interruptInfo = nullptr; - FunctionInfo* functionInfo = nullptr; -}; - -static ScheduledFunctions* scheduledInterrupts; -void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); -void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode); - - -#endif //INTERRUPTS_H diff --git a/cores/esp8266/ScheduledFunctions.cpp b/cores/esp8266/ScheduledFunctions.cpp deleted file mode 100644 index 25bc58db61..0000000000 --- a/cores/esp8266/ScheduledFunctions.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ScheduledFunctions.cpp - * - * Created on: 27 apr. 2018 - * Author: Herman - */ -#include "ScheduledFunctions.h" - -std::list ScheduledFunctions::scheduledFunctions; - -ScheduledFunctions::ScheduledFunctions() -:ScheduledFunctions(UINT_MAX) -{ -} - -ScheduledFunctions::ScheduledFunctions(unsigned int reqMax) -{ - maxElements = reqMax; -} - -ScheduledFunctions::~ScheduledFunctions() { -} - -ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front) -{ - if (countElements >= maxElements) - { - return nullptr; - } - else - { - countElements++; - if (front) - { - scheduledFunctions.push_front(se); - return scheduledFunctions.begin()->registration; - } - else - { - scheduledFunctions.push_back(se); - return scheduledFunctions.rbegin()->registration; - } - } -} - -std::list::iterator ScheduledFunctions::eraseElement(std::list::iterator it) -{ - countElements--; - return scheduledFunctions.erase(it); -} - -bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front) -{ - return (insertElement({this,continuous,nullptr,sf}, front) == nullptr); -} - -bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf) -{ - return scheduleFunction(sf, false, false); -} - -ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front) -{ - return insertElement({this,continuous,std::make_shared(1),sf},front); -} - -void ScheduledFunctions::runScheduledFunctions() -{ - auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions - auto it = scheduledFunctions.begin(); - while (it != lastElement) - { - bool erase = false; - if (it->registration == nullptr) - { - it->function(); - } - else - { - if (it->registration.use_count() > 1) - { - it->function(); - } - else - { - erase = true; - } - } - if ((!it->continuous) || (erase)) - { - it = it->_this->eraseElement(it); - } - else - { - it++; - } - } -} - -void ScheduledFunctions::removeFunction(ScheduledRegistration sr) -{ - auto it = scheduledFunctions.begin(); - bool removed = false; - while ((!removed) && (it != scheduledFunctions.end())) - { - if (it->registration == sr) - { - it = eraseElement(it); - removed = true; - } - else - { - it++; - } - } -} - diff --git a/cores/esp8266/ScheduledFunctions.h b/cores/esp8266/ScheduledFunctions.h deleted file mode 100644 index 0129635364..0000000000 --- a/cores/esp8266/ScheduledFunctions.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ScheduledFunctions.h - * - * Created on: 27 apr. 2018 - * Author: Herman - */ -#include "Arduino.h" -#include "Schedule.h" - -#include -#include -#include -#include - -#ifndef SCHEDULEDFUNCTIONS_H_ -#define SCHEDULEDFUNCTIONS_H_ - -typedef std::function ScheduledFunction; -typedef std::shared_ptr ScheduledRegistration; - -class ScheduledFunctions { - -public: - ScheduledFunctions(); - ScheduledFunctions(unsigned int reqMax); - virtual ~ScheduledFunctions(); - - struct ScheduledElement - { - ScheduledFunctions* _this; - bool continuous; - ScheduledRegistration registration; - ScheduledFunction function; - }; - - ScheduledRegistration insertElement(ScheduledElement se, bool front); - std::list::iterator eraseElement(std::list::iterator); - bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front); - bool scheduleFunction(ScheduledFunction sf); - ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front); - static void runScheduledFunctions(); - void removeFunction(ScheduledRegistration sr); - - - static std::list scheduledFunctions; - unsigned int maxElements; - unsigned int countElements = 0; - -}; - -#endif /* SCHEDULEDFUNCTIONS_H_ */ diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index 0a8a7252f1..e4663334bb 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -53,17 +53,17 @@ extern void __pinMode(uint8_t pin, uint8_t mode) { GPEC = (1 << pin); //Disable GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) if(mode == INPUT_PULLUP) { - GPF(pin) |= (1 << GPFPU); // Enable Pullup + GPF(pin) |= (1 << GPFPU); // Enable Pullup } } else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){ GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO GPEC = (1 << pin); //Disable if(mode == WAKEUP_PULLUP) { - GPF(pin) |= (1 << GPFPU); // Enable Pullup - GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED) + GPF(pin) |= (1 << GPFPU); // Enable Pullup + GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED) } else { - GPF(pin) |= (1 << GPFPD); // Enable Pulldown - GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED) + GPF(pin) |= (1 << GPFPD); // Enable Pulldown + GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED) } } } else if(pin == 16){ @@ -109,27 +109,14 @@ typedef void (*voidFuncPtrArg)(void*); typedef struct { uint8_t mode; - void (*fn)(void); - void * arg; + voidFuncPtr fn; + void* arg; } interrupt_handler_t; -//duplicate from functionalInterrupt.h keep in sync -typedef struct InterruptInfo { - uint8_t pin; - uint8_t value; - uint32_t micro; -} InterruptInfo; - -typedef struct { - InterruptInfo* interruptInfo; - void* functionInfo; -} ArgStructure; - -static interrupt_handler_t interrupt_handlers[16]; +static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0}, }; static uint32_t interrupt_reg = 0; -void ICACHE_RAM_ATTR interrupt_handler(void *arg) { - (void) arg; +void ICACHE_RAM_ATTR interrupt_handler(void*) { uint32_t status = GPIE; GPIEC = status;//clear them interrupts uint32_t levels = GPI; @@ -140,38 +127,28 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) { while(changedbits){ while(!(changedbits & (1 << i))) i++; changedbits &= ~(1 << i); - interrupt_handler_t *handler = &interrupt_handlers[i]; + interrupt_handler_t* handler = &interrupt_handlers[i]; if (handler->fn && - (handler->mode == CHANGE || - (handler->mode & 1) == !!(levels & (1 << i)))) { + (handler->mode == CHANGE || + (handler->mode & 1) == !!(levels & (1 << i)))) { // to make ISR compatible to Arduino AVR model where interrupts are disabled // we disable them before we call the client ISR uint32_t savedPS = xt_rsil(15); // stop other interrupts - ArgStructure* localArg = (ArgStructure*)handler->arg; - if (localArg && localArg->interruptInfo) - { - localArg->interruptInfo->pin = i; - localArg->interruptInfo->value = __digitalRead(i); - localArg->interruptInfo->micro = micros(); - } if (handler->arg) { - ((voidFuncPtrArg)handler->fn)(handler->arg); + ((voidFuncPtrArg)handler->fn)(handler->arg); } else { - handler->fn(); + handler->fn(); } - xt_wsr_ps(savedPS); + xt_wsr_ps(savedPS); } } ETS_GPIO_INTR_ENABLE(); } -extern void cleanupFunctional(void* arg); - -extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) { - +extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode) { // #5780 // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map if ((uint32_t)userFunc >= 0x40200000) @@ -183,13 +160,9 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu if(pin < 16) { ETS_GPIO_INTR_DISABLE(); - interrupt_handler_t *handler = &interrupt_handlers[pin]; + interrupt_handler_t* handler = &interrupt_handlers[pin]; handler->mode = mode; - handler->fn = userFunc; - if (handler->arg) // Clean when new attach without detach - { - cleanupFunctional(handler->arg); - } + handler->fn = (voidFuncPtr)userFunc; handler->arg = arg; interrupt_reg |= (1 << pin); GPC(pin) &= ~(0xF << GPCI);//INT mode disabled @@ -200,24 +173,19 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu } } -extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode ) -{ - __attachInterruptArg (pin, userFunc, 0, mode); +extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode ) { + __attachInterruptArg(pin, (voidFuncPtrArg)userFunc, 0, mode); } -extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) { +extern void __detachInterrupt(uint8_t pin) { if(pin < 16) { ETS_GPIO_INTR_DISABLE(); GPC(pin) &= ~(0xF << GPCI);//INT mode disabled GPIEC = (1 << pin); //Clear Interrupt for this pin interrupt_reg &= ~(1 << pin); - interrupt_handler_t *handler = &interrupt_handlers[pin]; + interrupt_handler_t* handler = &interrupt_handlers[pin]; handler->mode = 0; handler->fn = 0; - if (handler->arg) - { - cleanupFunctional(handler->arg); - } handler->arg = 0; if (interrupt_reg) ETS_GPIO_INTR_ENABLE(); @@ -243,6 +211,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 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 attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg"))); extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); }; From e4f6e6cd626b96fb78be67d41d425756075ee483 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 13:14:07 +0200 Subject: [PATCH 02/12] Add supporting function for interrupt arg memory management, linke with functional interrupts. --- cores/esp8266/core_esp8266_wiring_digital.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index e4663334bb..acf8f470f8 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -185,13 +185,17 @@ extern void __detachInterrupt(uint8_t pin) { interrupt_reg &= ~(1 << pin); interrupt_handler_t* handler = &interrupt_handlers[pin]; handler->mode = 0; - handler->fn = 0; - handler->arg = 0; + handler->fn = nullptr; + handler->arg = nullptr; if (interrupt_reg) ETS_GPIO_INTR_ENABLE(); } } +extern interrupt_handler_t* __getInterruptHandler(uint8_t pin) { + return (pin < 16) ? &interrupt_handlers[pin] : nullptr; +} + void initPins() { //Disable UART interrupts system_set_os_print(0); From 035551d7594c90217a8af8e8241ce86d88ec86e6 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 13:15:22 +0200 Subject: [PATCH 03/12] Bring back FunctionalInterrupt, and ScheduledFunctions, as example code. It should be decided whether to reinstate these in the core, or make them an optional library. --- .../FunctionalInterrupt.ino | 57 +++++++++ .../FunctionalInterrupts.cpp | 121 ++++++++++++++++++ .../FunctionalInterrupts.h | 37 ++++++ .../ScheduledFunctions.cpp | 117 +++++++++++++++++ .../FunctionalInterrupt/ScheduledFunctions.h | 51 ++++++++ 5 files changed, 383 insertions(+) create mode 100644 libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino create mode 100644 libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp create mode 100644 libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h create mode 100644 libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp create mode 100644 libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino new file mode 100644 index 0000000000..5f63106991 --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -0,0 +1,57 @@ +#include +#include "FunctionalInterrupts.h" + +#if defined(ESP8266) || defined(ARDUINO_D1_MINI32) +#define BUTTON1 D3 +#define BUTTON2 D4 +#else +#define BUTTON1 16 +#define BUTTON2 17 +#endif + +class Button +{ +public: + Button(uint8_t reqPin) : PIN(reqPin) { + pinMode(PIN, INPUT_PULLUP); + attachInterrupt(PIN, std::bind(&Button::isr,this), FALLING); + }; + ~Button() { + detachFunctionalInterrupt(PIN); + } + +#if defined(ESP8266) + void ICACHE_RAM_ATTR isr() +#elif defined(ESP32) + void IRAM_ATTR isr() +#endif + { + numberKeyPresses += 1; + pressed = true; + } + + void checkPressed() { + if (pressed) { + Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses); + pressed = false; + } + } + +private: + const uint8_t PIN; + volatile uint32_t numberKeyPresses; + volatile bool pressed; +}; + +Button button1(BUTTON1); +Button button2(BUTTON2); + + +void setup() { + Serial.begin(115200); +} + +void loop() { + button1.checkPressed(); + button2.checkPressed(); +} diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp new file mode 100644 index 0000000000..8b56e61b2c --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -0,0 +1,121 @@ +#include "FunctionalInterrupts.h" +#include +#include "Arduino.h" + +#if defined(ESP8266) + +// Duplicate typedefs from core_esp8266_wiring_digital.cpp +// Keep in sync +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); + +typedef struct { + uint8_t mode; + voidFuncPtr fn; + void* arg; +} interrupt_handler_t; + +// Helper functions for Functional interrupt routines +extern "C" interrupt_handler_t* __getInterruptHandler(uint8_t pin); + +#elif defined(ESP32) + +// Duplicate typedefs from esp32-hal-gpio.c +// Keep in sync +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); +typedef struct { + voidFuncPtr fn; + void* arg; +} InterruptHandle_t; + +// Helper functions for Functional interrupt routines +extern "C" InterruptHandle_t* __getInterruptHandler(uint8_t pin); + +#endif + +void ICACHE_RAM_ATTR interruptFunctional(void* arg) +{ + ArgStructure* localArg = static_cast(arg); + if (localArg->interruptInfo) + { + localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); + localArg->interruptInfo->micro = micros(); + } + if (localArg->functionInfo->reqScheduledFunction) + { + schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo)))); + } + if (localArg->functionInfo->reqFunction) + { + localArg->functionInfo->reqFunction(); + } +} + + void cleanupFunctional(void* arg) + { + ArgStructure* localArg = static_cast(arg); + delete localArg; + } + +void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) +{ + // use the local interrupt routine which takes the ArgStructure as argument + +#if defined(ESP8266) + interrupt_handler_t* handler = __getInterruptHandler(pin); +#elif defined(ESP32) + InterruptHandle_t* handler = __getInterruptHandler(pin); +#endif + if (handler->arg) + { + cleanupFunctional(handler->arg); + } + + FunctionInfo* fi = new FunctionInfo; + fi->reqFunction = intRoutine; + + ArgStructure* as = new ArgStructure; + as->functionInfo = fi; + + ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); +} + +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) +{ +#if defined(ESP8266) + interrupt_handler_t* handler = __getInterruptHandler(pin); +#elif defined(ESP32) + InterruptHandle_t* handler = __getInterruptHandler(pin); +#endif + if (handler->arg) + { + cleanupFunctional(handler->arg); + } + + InterruptInfo* ii = new InterruptInfo(pin); + + FunctionInfo* fi = new FunctionInfo; + fi->reqScheduledFunction = scheduledIntRoutine; + + ArgStructure* as = new ArgStructure; + as->interruptInfo = ii; + as->functionInfo = fi; + + ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); +} + +void detachFunctionalInterrupt(uint8_t pin) +{ +#if defined(ESP8266) + interrupt_handler_t* handler = __getInterruptHandler(pin); +#elif defined(ESP32) + InterruptHandle_t* handler = __getInterruptHandler(pin); +#endif + if (handler->arg) + { + cleanupFunctional(handler->arg); + } + ::detachInterrupt (pin); +} + diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h new file mode 100644 index 0000000000..ef75a9525f --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -0,0 +1,37 @@ +#ifndef FUNCTIONALINTERRUPTS_H +#define FUNCTIONALINTERRUPTS_H + +#include +#include +#include +#include "ScheduledFunctions.h" + +// Structures for communication + +struct InterruptInfo { + InterruptInfo(uint8_t _pin) : pin(_pin) {} + const uint8_t pin; + uint8_t value = 0; + uint32_t micro = 0; +}; + +struct FunctionInfo { + std::function reqFunction = nullptr; + std::function reqScheduledFunction = nullptr; +}; + +struct ArgStructure { + ~ArgStructure() + { + delete functionInfo; + delete interruptInfo; + } + InterruptInfo* interruptInfo = nullptr; + FunctionInfo* functionInfo = nullptr; +}; + +void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode); +void detachFunctionalInterrupt(uint8_t pin); + +#endif //INTERRUPTS_H diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp new file mode 100644 index 0000000000..25bc58db61 --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp @@ -0,0 +1,117 @@ +/* + * ScheduledFunctions.cpp + * + * Created on: 27 apr. 2018 + * Author: Herman + */ +#include "ScheduledFunctions.h" + +std::list ScheduledFunctions::scheduledFunctions; + +ScheduledFunctions::ScheduledFunctions() +:ScheduledFunctions(UINT_MAX) +{ +} + +ScheduledFunctions::ScheduledFunctions(unsigned int reqMax) +{ + maxElements = reqMax; +} + +ScheduledFunctions::~ScheduledFunctions() { +} + +ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front) +{ + if (countElements >= maxElements) + { + return nullptr; + } + else + { + countElements++; + if (front) + { + scheduledFunctions.push_front(se); + return scheduledFunctions.begin()->registration; + } + else + { + scheduledFunctions.push_back(se); + return scheduledFunctions.rbegin()->registration; + } + } +} + +std::list::iterator ScheduledFunctions::eraseElement(std::list::iterator it) +{ + countElements--; + return scheduledFunctions.erase(it); +} + +bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front) +{ + return (insertElement({this,continuous,nullptr,sf}, front) == nullptr); +} + +bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf) +{ + return scheduleFunction(sf, false, false); +} + +ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front) +{ + return insertElement({this,continuous,std::make_shared(1),sf},front); +} + +void ScheduledFunctions::runScheduledFunctions() +{ + auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions + auto it = scheduledFunctions.begin(); + while (it != lastElement) + { + bool erase = false; + if (it->registration == nullptr) + { + it->function(); + } + else + { + if (it->registration.use_count() > 1) + { + it->function(); + } + else + { + erase = true; + } + } + if ((!it->continuous) || (erase)) + { + it = it->_this->eraseElement(it); + } + else + { + it++; + } + } +} + +void ScheduledFunctions::removeFunction(ScheduledRegistration sr) +{ + auto it = scheduledFunctions.begin(); + bool removed = false; + while ((!removed) && (it != scheduledFunctions.end())) + { + if (it->registration == sr) + { + it = eraseElement(it); + removed = true; + } + else + { + it++; + } + } +} + diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h new file mode 100644 index 0000000000..0129635364 --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h @@ -0,0 +1,51 @@ +/* + * ScheduledFunctions.h + * + * Created on: 27 apr. 2018 + * Author: Herman + */ +#include "Arduino.h" +#include "Schedule.h" + +#include +#include +#include +#include + +#ifndef SCHEDULEDFUNCTIONS_H_ +#define SCHEDULEDFUNCTIONS_H_ + +typedef std::function ScheduledFunction; +typedef std::shared_ptr ScheduledRegistration; + +class ScheduledFunctions { + +public: + ScheduledFunctions(); + ScheduledFunctions(unsigned int reqMax); + virtual ~ScheduledFunctions(); + + struct ScheduledElement + { + ScheduledFunctions* _this; + bool continuous; + ScheduledRegistration registration; + ScheduledFunction function; + }; + + ScheduledRegistration insertElement(ScheduledElement se, bool front); + std::list::iterator eraseElement(std::list::iterator); + bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front); + bool scheduleFunction(ScheduledFunction sf); + ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front); + static void runScheduledFunctions(); + void removeFunction(ScheduledRegistration sr); + + + static std::list scheduledFunctions; + unsigned int maxElements; + unsigned int countElements = 0; + +}; + +#endif /* SCHEDULEDFUNCTIONS_H_ */ From bd339ec835377b3953759d5f0c1af199679ab94c Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 13:46:20 +0200 Subject: [PATCH 04/12] Ridiculous port number mistake. --- .../GPIO/FunctionalInterrupt/FunctionalInterrupt.ino | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index 5f63106991..491d1962ff 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -1,12 +1,15 @@ #include #include "FunctionalInterrupts.h" -#if defined(ESP8266) || defined(ARDUINO_D1_MINI32) -#define BUTTON1 D3 -#define BUTTON2 D4 -#else +#if defined(ESP32) #define BUTTON1 16 #define BUTTON2 17 +#elif defined(ARDUINO_ESP8266_WEMOS_D1MINI) +#define BUTTON1 D4 +#define BUTTON2 D3 +#else +#define BUTTON1 2 +#define BUTTON2 0 #endif class Button From 4f621ea69a4c98186f7cb1a589134ff7c9911af1 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 17:38:23 +0200 Subject: [PATCH 05/12] Apply astyle to example INO. --- .../FunctionalInterrupt.ino | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index 491d1962ff..b386b1d83f 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -12,38 +12,37 @@ #define BUTTON2 0 #endif -class Button -{ -public: - Button(uint8_t reqPin) : PIN(reqPin) { - pinMode(PIN, INPUT_PULLUP); - attachInterrupt(PIN, std::bind(&Button::isr,this), FALLING); - }; - ~Button() { - detachFunctionalInterrupt(PIN); - } +class Button { + public: + Button(uint8_t reqPin) : PIN(reqPin) { + pinMode(PIN, INPUT_PULLUP); + attachInterrupt(PIN, std::bind(&Button::isr, this), FALLING); + }; + ~Button() { + detachFunctionalInterrupt(PIN); + } #if defined(ESP8266) - void ICACHE_RAM_ATTR isr() + void ICACHE_RAM_ATTR isr() #elif defined(ESP32) - void IRAM_ATTR isr() + void IRAM_ATTR isr() #endif - { - numberKeyPresses += 1; - pressed = true; - } - - void checkPressed() { - if (pressed) { - Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses); - pressed = false; - } - } - -private: - const uint8_t PIN; - volatile uint32_t numberKeyPresses; - volatile bool pressed; + { + numberKeyPresses += 1; + pressed = true; + } + + void checkPressed() { + if (pressed) { + Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses); + pressed = false; + } + } + + private: + const uint8_t PIN; + volatile uint32_t numberKeyPresses; + volatile bool pressed; }; Button button1(BUTTON1); @@ -51,10 +50,10 @@ Button button2(BUTTON2); void setup() { - Serial.begin(115200); + Serial.begin(115200); } void loop() { - button1.checkPressed(); - button2.checkPressed(); + button1.checkPressed(); + button2.checkPressed(); } From 4b045f536705e30d5fd923de3b4b56bc6486fb2a Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 21:37:19 +0200 Subject: [PATCH 06/12] Remove ScheduledFunctions.(h|cpp), per comment https://github.com/esp8266/Arduino/pull/6038#issuecomment-488758509 --- .../FunctionalInterrupts.h | 1 - .../ScheduledFunctions.cpp | 117 ------------------ .../FunctionalInterrupt/ScheduledFunctions.h | 51 -------- 3 files changed, 169 deletions(-) delete mode 100644 libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp delete mode 100644 libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h index ef75a9525f..9c5d554e27 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -4,7 +4,6 @@ #include #include #include -#include "ScheduledFunctions.h" // Structures for communication diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp deleted file mode 100644 index 25bc58db61..0000000000 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ScheduledFunctions.cpp - * - * Created on: 27 apr. 2018 - * Author: Herman - */ -#include "ScheduledFunctions.h" - -std::list ScheduledFunctions::scheduledFunctions; - -ScheduledFunctions::ScheduledFunctions() -:ScheduledFunctions(UINT_MAX) -{ -} - -ScheduledFunctions::ScheduledFunctions(unsigned int reqMax) -{ - maxElements = reqMax; -} - -ScheduledFunctions::~ScheduledFunctions() { -} - -ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front) -{ - if (countElements >= maxElements) - { - return nullptr; - } - else - { - countElements++; - if (front) - { - scheduledFunctions.push_front(se); - return scheduledFunctions.begin()->registration; - } - else - { - scheduledFunctions.push_back(se); - return scheduledFunctions.rbegin()->registration; - } - } -} - -std::list::iterator ScheduledFunctions::eraseElement(std::list::iterator it) -{ - countElements--; - return scheduledFunctions.erase(it); -} - -bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front) -{ - return (insertElement({this,continuous,nullptr,sf}, front) == nullptr); -} - -bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf) -{ - return scheduleFunction(sf, false, false); -} - -ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front) -{ - return insertElement({this,continuous,std::make_shared(1),sf},front); -} - -void ScheduledFunctions::runScheduledFunctions() -{ - auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions - auto it = scheduledFunctions.begin(); - while (it != lastElement) - { - bool erase = false; - if (it->registration == nullptr) - { - it->function(); - } - else - { - if (it->registration.use_count() > 1) - { - it->function(); - } - else - { - erase = true; - } - } - if ((!it->continuous) || (erase)) - { - it = it->_this->eraseElement(it); - } - else - { - it++; - } - } -} - -void ScheduledFunctions::removeFunction(ScheduledRegistration sr) -{ - auto it = scheduledFunctions.begin(); - bool removed = false; - while ((!removed) && (it != scheduledFunctions.end())) - { - if (it->registration == sr) - { - it = eraseElement(it); - removed = true; - } - else - { - it++; - } - } -} - diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h deleted file mode 100644 index 0129635364..0000000000 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ScheduledFunctions.h - * - * Created on: 27 apr. 2018 - * Author: Herman - */ -#include "Arduino.h" -#include "Schedule.h" - -#include -#include -#include -#include - -#ifndef SCHEDULEDFUNCTIONS_H_ -#define SCHEDULEDFUNCTIONS_H_ - -typedef std::function ScheduledFunction; -typedef std::shared_ptr ScheduledRegistration; - -class ScheduledFunctions { - -public: - ScheduledFunctions(); - ScheduledFunctions(unsigned int reqMax); - virtual ~ScheduledFunctions(); - - struct ScheduledElement - { - ScheduledFunctions* _this; - bool continuous; - ScheduledRegistration registration; - ScheduledFunction function; - }; - - ScheduledRegistration insertElement(ScheduledElement se, bool front); - std::list::iterator eraseElement(std::list::iterator); - bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front); - bool scheduleFunction(ScheduledFunction sf); - ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front); - static void runScheduledFunctions(); - void removeFunction(ScheduledRegistration sr); - - - static std::list scheduledFunctions; - unsigned int maxElements; - unsigned int countElements = 0; - -}; - -#endif /* SCHEDULEDFUNCTIONS_H_ */ From 9e239eca0ca7cbc84fcbec70d1a4c6de7770c44e Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 12:11:17 +0200 Subject: [PATCH 07/12] Invented void* detachInterruptArg() that returns the argument given in attachInterruptArg(). This is sufficient for resource management - the function has static duration anyway. --- cores/esp8266/Arduino.h | 3 +- cores/esp8266/core_esp8266_wiring_digital.cpp | 11 ++- .../FunctionalInterrupts.cpp | 82 +++++-------------- 3 files changed, 28 insertions(+), 68 deletions(-) diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 91ef7a43f1..2be19b5e22 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -217,8 +217,9 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); void attachInterrupt(uint8_t pin, void (*)(void), int mode); -void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode); void detachInterrupt(uint8_t pin); +void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode); +void* detachInterruptArg(uint8_t pin); void preinit(void); void setup(void); diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index acf8f470f8..c96033df42 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -192,8 +192,10 @@ extern void __detachInterrupt(uint8_t pin) { } } -extern interrupt_handler_t* __getInterruptHandler(uint8_t pin) { - return (pin < 16) ? &interrupt_handlers[pin] : nullptr; +extern void* __detachInterruptArg(uint8_t pin) { + void* arg = (pin < 16) ? interrupt_handlers[pin].arg : nullptr; + __detachInterrupt(pin); + return arg; } void initPins() { @@ -215,7 +217,8 @@ 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 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 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"))); +extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg"))); +extern void* detachInterruptArg(uint8_t pin) __attribute__((weak, alias("__detachInterruptArg"))); }; diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index 8b56e61b2c..be29554bc2 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -2,38 +2,6 @@ #include #include "Arduino.h" -#if defined(ESP8266) - -// Duplicate typedefs from core_esp8266_wiring_digital.cpp -// Keep in sync -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); - -typedef struct { - uint8_t mode; - voidFuncPtr fn; - void* arg; -} interrupt_handler_t; - -// Helper functions for Functional interrupt routines -extern "C" interrupt_handler_t* __getInterruptHandler(uint8_t pin); - -#elif defined(ESP32) - -// Duplicate typedefs from esp32-hal-gpio.c -// Keep in sync -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); -typedef struct { - voidFuncPtr fn; - void* arg; -} InterruptHandle_t; - -// Helper functions for Functional interrupt routines -extern "C" InterruptHandle_t* __getInterruptHandler(uint8_t pin); - -#endif - void ICACHE_RAM_ATTR interruptFunctional(void* arg) { ArgStructure* localArg = static_cast(arg); @@ -44,7 +12,9 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) } if (localArg->functionInfo->reqScheduledFunction) { - schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo)))); + schedule_function( + [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, + interruptInfo = *localArg->interruptInfo]() { reqScheduledFunction(interruptInfo); }); } if (localArg->functionInfo->reqFunction) { @@ -52,24 +22,20 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) } } - void cleanupFunctional(void* arg) - { - ArgStructure* localArg = static_cast(arg); - delete localArg; - } +void cleanupFunctional(void* arg) +{ + ArgStructure* localArg = static_cast(arg); + delete localArg; +} void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) { // use the local interrupt routine which takes the ArgStructure as argument -#if defined(ESP8266) - interrupt_handler_t* handler = __getInterruptHandler(pin); -#elif defined(ESP32) - InterruptHandle_t* handler = __getInterruptHandler(pin); -#endif - if (handler->arg) + void* localArg = detachInterruptArg(pin); + if (localArg) { - cleanupFunctional(handler->arg); + cleanupFunctional(localArg); } FunctionInfo* fi = new FunctionInfo; @@ -78,19 +44,15 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode ArgStructure* as = new ArgStructure; as->functionInfo = fi; - ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); + attachInterruptArg (pin, interruptFunctional, as, mode); } void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { -#if defined(ESP8266) - interrupt_handler_t* handler = __getInterruptHandler(pin); -#elif defined(ESP32) - InterruptHandle_t* handler = __getInterruptHandler(pin); -#endif - if (handler->arg) + void* localArg = detachInterruptArg(pin); + if (localArg) { - cleanupFunctional(handler->arg); + cleanupFunctional(localArg); } InterruptInfo* ii = new InterruptInfo(pin); @@ -102,20 +64,14 @@ void attachScheduledInterrupt(uint8_t pin, std::function sc as->interruptInfo = ii; as->functionInfo = fi; - ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); + attachInterruptArg(pin, interruptFunctional, as, mode); } void detachFunctionalInterrupt(uint8_t pin) { -#if defined(ESP8266) - interrupt_handler_t* handler = __getInterruptHandler(pin); -#elif defined(ESP32) - InterruptHandle_t* handler = __getInterruptHandler(pin); -#endif - if (handler->arg) + void* localArg = detachInterruptArg(pin); + if (localArg) { - cleanupFunctional(handler->arg); + cleanupFunctional(localArg); } - ::detachInterrupt (pin); } - From f89b22cb5d02d35dc7a63475b8a60f8c4d9db655 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 12:59:39 +0200 Subject: [PATCH 08/12] Modified example to showcase how general FunctionalInterrupt uses violate the ISR in ICACHE_RAM rule. --- .../FunctionalInterrupt.ino | 38 +++++++++++++++---- .../FunctionalInterrupts.cpp | 15 ++------ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index b386b1d83f..aae06082eb 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -1,4 +1,5 @@ #include +#include #include "FunctionalInterrupts.h" #if defined(ESP32) @@ -16,10 +17,15 @@ class Button { public: Button(uint8_t reqPin) : PIN(reqPin) { pinMode(PIN, INPUT_PULLUP); - attachInterrupt(PIN, std::bind(&Button::isr, this), FALLING); + // Arduino C API: + attachInterruptArg(PIN, [](void* self) { static_cast(self)->isr(); }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" + //attachInterruptArg(PIN, reinterpret_cast(&isr_static), this, FALLING); // works on ESP32; works on ESP8266 + // FunctionalInterrupts API: + //attachInterrupt(PIN, [this]() { isr(); }, FALLING); // works on ESP32; works on ESP8266 + //attachScheduledInterrupt(PIN, [this](InterruptInfo ii) { Serial.print("Pin "); Serial.println(ii.pin); isr(); }, FALLING); // works on ESP32; works on ESP8266 }; ~Button() { - detachFunctionalInterrupt(PIN); + detachInterrupt(PIN); } #if defined(ESP8266) @@ -32,6 +38,15 @@ class Button { pressed = true; } +#if defined(ESP8266) + static void ICACHE_RAM_ATTR isr_static(Button* const self) +#elif defined(ESP32) + static void IRAM_ATTR isr_static(Button* const self) +#endif + { + self->isr(); + } + void checkPressed() { if (pressed) { Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses); @@ -41,19 +56,26 @@ class Button { private: const uint8_t PIN; - volatile uint32_t numberKeyPresses; - volatile bool pressed; + volatile uint32_t numberKeyPresses = 0; + volatile bool pressed = false; }; -Button button1(BUTTON1); -Button button2(BUTTON2); +Button* button1; +Button* button2; void setup() { Serial.begin(115200); + schedule_function([]() { Serial.println("Scheduled function"); }); + Serial.println("FunctionalInterrupt test/example"); + + button1 = new Button(BUTTON1); + button2 = new Button(BUTTON2); + + Serial.println("setup() complete"); } void loop() { - button1.checkPressed(); - button2.checkPressed(); + button1->checkPressed(); + button2->checkPressed(); } diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index be29554bc2..1867e7bd92 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -33,10 +33,7 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode // use the local interrupt routine which takes the ArgStructure as argument void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } + if (localArg) cleanupFunctional(localArg); FunctionInfo* fi = new FunctionInfo; fi->reqFunction = intRoutine; @@ -50,10 +47,7 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } + if (localArg) cleanupFunctional(localArg); InterruptInfo* ii = new InterruptInfo(pin); @@ -70,8 +64,5 @@ void attachScheduledInterrupt(uint8_t pin, std::function sc void detachFunctionalInterrupt(uint8_t pin) { void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } + if (localArg) cleanupFunctional(localArg); } From 346d3c34a4894ce55ffe1cbf43fac6c7b99e8046 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 15:23:44 +0200 Subject: [PATCH 09/12] Direct call or scheduled is either-or. --- .../FunctionalInterrupts.cpp | 4 +-- .../FunctionalInterrupts.h | 26 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index 1867e7bd92..6d990440be 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -1,6 +1,6 @@ #include "FunctionalInterrupts.h" #include -#include "Arduino.h" +#include void ICACHE_RAM_ATTR interruptFunctional(void* arg) { @@ -16,7 +16,7 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, interruptInfo = *localArg->interruptInfo]() { reqScheduledFunction(interruptInfo); }); } - if (localArg->functionInfo->reqFunction) + else if (localArg->functionInfo->reqFunction) { localArg->functionInfo->reqFunction(); } diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h index 9c5d554e27..b1867f73ad 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -1,32 +1,30 @@ #ifndef FUNCTIONALINTERRUPTS_H #define FUNCTIONALINTERRUPTS_H -#include -#include #include // Structures for communication struct InterruptInfo { - InterruptInfo(uint8_t _pin) : pin(_pin) {} - const uint8_t pin; - uint8_t value = 0; - uint32_t micro = 0; + InterruptInfo(uint8_t _pin) : pin(_pin) {} + const uint8_t pin; + uint8_t value = 0; + uint32_t micro = 0; }; struct FunctionInfo { std::function reqFunction = nullptr; - std::function reqScheduledFunction = nullptr; + std::function reqScheduledFunction = nullptr; }; struct ArgStructure { - ~ArgStructure() - { - delete functionInfo; - delete interruptInfo; - } - InterruptInfo* interruptInfo = nullptr; - FunctionInfo* functionInfo = nullptr; + ~ArgStructure() + { + delete functionInfo; + delete interruptInfo; + } + InterruptInfo* interruptInfo = nullptr; + FunctionInfo* functionInfo = nullptr; }; void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); From a844d43418cb6918273a958e5aa65773f99cda5a Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 15:40:52 +0200 Subject: [PATCH 10/12] Always apply astyle to examples. --- .../GPIO/FunctionalInterrupt/FunctionalInterrupt.ino | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index aae06082eb..de218dd15f 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -18,7 +18,9 @@ class Button { Button(uint8_t reqPin) : PIN(reqPin) { pinMode(PIN, INPUT_PULLUP); // Arduino C API: - attachInterruptArg(PIN, [](void* self) { static_cast(self)->isr(); }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" + attachInterruptArg(PIN, [](void* self) { + static_cast(self)->isr(); + }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" //attachInterruptArg(PIN, reinterpret_cast(&isr_static), this, FALLING); // works on ESP32; works on ESP8266 // FunctionalInterrupts API: //attachInterrupt(PIN, [this]() { isr(); }, FALLING); // works on ESP32; works on ESP8266 @@ -44,7 +46,7 @@ class Button { static void IRAM_ATTR isr_static(Button* const self) #endif { - self->isr(); + self->isr(); } void checkPressed() { @@ -66,7 +68,9 @@ Button* button2; void setup() { Serial.begin(115200); - schedule_function([]() { Serial.println("Scheduled function"); }); + schedule_function([]() { + Serial.println("Scheduled function"); + }); Serial.println("FunctionalInterrupt test/example"); button1 = new Button(BUTTON1); From c8c8bfb2547ea9c890669d48f2b0f1acc7d044ed Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 6 May 2019 02:16:51 +0200 Subject: [PATCH 11/12] astyle Arduino.h and core_esp8266_wiring_digital.cpp - reduced diff to d60f4b6 --- cores/esp8266/Arduino.h | 39 +- cores/esp8266/core_esp8266_wiring_digital.cpp | 471 ++++++++++-------- 2 files changed, 291 insertions(+), 219 deletions(-) diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 2be19b5e22..3c0cf74c4d 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -1,21 +1,21 @@ /* - Arduino.h - Main include file for the Arduino SDK - Copyright (c) 2005-2013 Arduino Team. All right reserved. + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ #ifndef Arduino_h #define Arduino_h @@ -86,10 +86,11 @@ extern "C" { #define EXTERNAL 0 //timer dividers -enum TIM_DIV_ENUM { - TIM_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max) - TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.4 us max) - TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max) +enum TIM_DIV_ENUM +{ + TIM_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max) + TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.4 us max) + TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max) }; @@ -297,7 +298,7 @@ long secureRandom(long, long); long map(long, long, long, long, long); extern "C" void configTime(long timezone, int daylightOffset_sec, - const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); + const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); #endif diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index c96033df42..a9abe3bbd4 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -1,22 +1,22 @@ /* - digital.c - wiring digital implementation for esp8266 + digital.c - wiring digital implementation for esp8266 - Copyright (c) 2015 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #define ARDUINO_MAIN #include "wiring_private.h" @@ -29,196 +29,267 @@ extern "C" { -uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x04, 0x08, 0x0C, 0x10}; - -extern void __pinMode(uint8_t pin, uint8_t mode) { - if(pin < 16){ - if(mode == SPECIAL){ - GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - GPEC = (1 << pin); //Disable - GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin) - if(pin == 3) GPF(pin) |= (1 << GPFPU);//enable pullup on RX - } else if(mode & FUNCTION_0){ - GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - GPEC = (1 << pin); //Disable - GPF(pin) = GPFFS((mode >> 4) & 0x07); - if(pin == 13 && mode == FUNCTION_4) GPF(pin) |= (1 << GPFPU);//enable pullup on RX - } else if(mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN){ - GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - if(mode == OUTPUT_OPEN_DRAIN) GPC(pin) |= (1 << GPCD); - GPES = (1 << pin); //Enable - } else if(mode == INPUT || mode == INPUT_PULLUP){ - GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPEC = (1 << pin); //Disable - GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) - if(mode == INPUT_PULLUP) { - GPF(pin) |= (1 << GPFPU); // Enable Pullup - } - } else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){ - GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPEC = (1 << pin); //Disable - if(mode == WAKEUP_PULLUP) { - GPF(pin) |= (1 << GPFPU); // Enable Pullup - GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED) - } else { - GPF(pin) |= (1 << GPFPD); // Enable Pulldown - GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED) - } + uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x04, 0x08, 0x0C, 0x10}; + + extern void __pinMode(uint8_t pin, uint8_t mode) + { + if (pin < 16) + { + if (mode == SPECIAL) + { + GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) + GPEC = (1 << pin); //Disable + GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin) + if (pin == 3) + { + GPF(pin) |= (1 << GPFPU); //enable pullup on RX + } + } + else if (mode & FUNCTION_0) + { + GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) + GPEC = (1 << pin); //Disable + GPF(pin) = GPFFS((mode >> 4) & 0x07); + if (pin == 13 && mode == FUNCTION_4) + { + GPF(pin) |= (1 << GPFPU); //enable pullup on RX + } + } + else if (mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN) + { + GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO + GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) + if (mode == OUTPUT_OPEN_DRAIN) + { + GPC(pin) |= (1 << GPCD); + } + GPES = (1 << pin); //Enable + } + else if (mode == INPUT || mode == INPUT_PULLUP) + { + GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO + GPEC = (1 << pin); //Disable + GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED) + if (mode == INPUT_PULLUP) + { + GPF(pin) |= (1 << GPFPU); // Enable Pullup + } + } + else if (mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN) + { + GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO + GPEC = (1 << pin); //Disable + if (mode == WAKEUP_PULLUP) + { + GPF(pin) |= (1 << GPFPU); // Enable Pullup + GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED) + } + else + { + GPF(pin) |= (1 << GPFPD); // Enable Pulldown + GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED) + } + } + } + else if (pin == 16) + { + GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO + GPC16 = 0; + if (mode == INPUT || mode == INPUT_PULLDOWN_16) + { + if (mode == INPUT_PULLDOWN_16) + { + GPF16 |= (1 << GP16FPD);//Enable Pulldown + } + GP16E &= ~1; + } + else if (mode == OUTPUT) + { + GP16E |= 1; + } + } } - } else if(pin == 16){ - GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO - GPC16 = 0; - if(mode == INPUT || mode == INPUT_PULLDOWN_16){ - if(mode == INPUT_PULLDOWN_16){ - GPF16 |= (1 << GP16FPD);//Enable Pulldown - } - GP16E &= ~1; - } else if(mode == OUTPUT){ - GP16E |= 1; + + extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) + { + stopWaveform(pin); + if (pin < 16) + { + if (val) + { + GPOS = (1 << pin); + } + else + { + GPOC = (1 << pin); + } + } + else if (pin == 16) + { + if (val) + { + GP16O |= 1; + } + else + { + GP16O &= ~1; + } + } } - } -} - -extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) { - stopWaveform(pin); - if(pin < 16){ - if(val) GPOS = (1 << pin); - else GPOC = (1 << pin); - } else if(pin == 16){ - if(val) GP16O |= 1; - else GP16O &= ~1; - } -} - -extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) { - if(pin < 16){ - return GPIP(pin); - } else if(pin == 16){ - return GP16I & 0x01; - } - return 0; -} -/* - GPIO INTERRUPTS -*/ + extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) + { + if (pin < 16) + { + return GPIP(pin); + } + else if (pin == 16) + { + return GP16I & 0x01; + } + return 0; + } + + /* + GPIO INTERRUPTS + */ + + typedef void (*voidFuncPtr)(void); + typedef void (*voidFuncPtrArg)(void*); + + typedef struct + { + uint8_t mode; + voidFuncPtr fn; + void* arg; + } interrupt_handler_t; + + static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0}, }; + static uint32_t interrupt_reg = 0; + + void ICACHE_RAM_ATTR interrupt_handler(void*) + { + uint32_t status = GPIE; + GPIEC = status;//clear them interrupts + uint32_t levels = GPI; + if (status == 0 || interrupt_reg == 0) + { + return; + } + ETS_GPIO_INTR_DISABLE(); + int i = 0; + uint32_t changedbits = status & interrupt_reg; + while (changedbits) + { + while (!(changedbits & (1 << i))) + { + i++; + } + changedbits &= ~(1 << i); + interrupt_handler_t* handler = &interrupt_handlers[i]; + if (handler->fn && + (handler->mode == CHANGE || + (handler->mode & 1) == !!(levels & (1 << i)))) + { + // to make ISR compatible to Arduino AVR model where interrupts are disabled + // we disable them before we call the client ISR + uint32_t savedPS = xt_rsil(15); // stop other interrupts + if (handler->arg) + { + ((voidFuncPtrArg)handler->fn)(handler->arg); + } + else + { + handler->fn(); + } + xt_wsr_ps(savedPS); + } + } + ETS_GPIO_INTR_ENABLE(); + } -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); - -typedef struct { - uint8_t mode; - voidFuncPtr fn; - void* arg; -} interrupt_handler_t; - -static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0}, }; -static uint32_t interrupt_reg = 0; - -void ICACHE_RAM_ATTR interrupt_handler(void*) { - uint32_t status = GPIE; - GPIEC = status;//clear them interrupts - uint32_t levels = GPI; - if(status == 0 || interrupt_reg == 0) return; - ETS_GPIO_INTR_DISABLE(); - int i = 0; - uint32_t changedbits = status & interrupt_reg; - while(changedbits){ - while(!(changedbits & (1 << i))) i++; - changedbits &= ~(1 << i); - interrupt_handler_t* handler = &interrupt_handlers[i]; - if (handler->fn && - (handler->mode == CHANGE || - (handler->mode & 1) == !!(levels & (1 << i)))) { - // to make ISR compatible to Arduino AVR model where interrupts are disabled - // we disable them before we call the client ISR - uint32_t savedPS = xt_rsil(15); // stop other interrupts - if (handler->arg) - { - ((voidFuncPtrArg)handler->fn)(handler->arg); - } - else - { - handler->fn(); - } - xt_wsr_ps(savedPS); + extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode) + { + // #5780 + // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map + if ((uint32_t)userFunc >= 0x40200000) + { + // ISR not in IRAM + ::printf((PGM_P)F("ISR not in IRAM!\r\n")); + abort(); + } + + if (pin < 16) + { + ETS_GPIO_INTR_DISABLE(); + interrupt_handler_t* handler = &interrupt_handlers[pin]; + handler->mode = mode; + handler->fn = (voidFuncPtr)userFunc; + handler->arg = arg; + interrupt_reg |= (1 << pin); + GPC(pin) &= ~(0xF << GPCI);//INT mode disabled + GPIEC = (1 << pin); //Clear Interrupt for this pin + GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode" + ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg); + ETS_GPIO_INTR_ENABLE(); + } + } + + extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode) + { + __attachInterruptArg(pin, (voidFuncPtrArg)userFunc, 0, mode); } - } - ETS_GPIO_INTR_ENABLE(); -} - -extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode) { - // #5780 - // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map - if ((uint32_t)userFunc >= 0x40200000) - { - // ISR not in IRAM - ::printf((PGM_P)F("ISR not in IRAM!\r\n")); - abort(); - } - - if(pin < 16) { - ETS_GPIO_INTR_DISABLE(); - interrupt_handler_t* handler = &interrupt_handlers[pin]; - handler->mode = mode; - handler->fn = (voidFuncPtr)userFunc; - handler->arg = arg; - interrupt_reg |= (1 << pin); - GPC(pin) &= ~(0xF << GPCI);//INT mode disabled - GPIEC = (1 << pin); //Clear Interrupt for this pin - GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode" - ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg); - ETS_GPIO_INTR_ENABLE(); - } -} - -extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode ) { - __attachInterruptArg(pin, (voidFuncPtrArg)userFunc, 0, mode); -} - -extern void __detachInterrupt(uint8_t pin) { - if(pin < 16) { - ETS_GPIO_INTR_DISABLE(); - GPC(pin) &= ~(0xF << GPCI);//INT mode disabled - GPIEC = (1 << pin); //Clear Interrupt for this pin - interrupt_reg &= ~(1 << pin); - interrupt_handler_t* handler = &interrupt_handlers[pin]; - handler->mode = 0; - handler->fn = nullptr; - handler->arg = nullptr; - if (interrupt_reg) - ETS_GPIO_INTR_ENABLE(); - } -} - -extern void* __detachInterruptArg(uint8_t pin) { - void* arg = (pin < 16) ? interrupt_handlers[pin].arg : nullptr; - __detachInterrupt(pin); - return arg; -} - -void initPins() { - //Disable UART interrupts - system_set_os_print(0); - U0IE = 0; - U1IE = 0; - - for (int i = 0; i <= 5; ++i) { - pinMode(i, INPUT); - } - // pins 6-11 are used for the SPI flash interface - for (int i = 12; i <= 16; ++i) { - pinMode(i, INPUT); - } -} - -extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); -extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); -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 detachInterrupt(uint8_t pin) __attribute__((weak, alias("__detachInterrupt"))); -extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg"))); -extern void* detachInterruptArg(uint8_t pin) __attribute__((weak, alias("__detachInterruptArg"))); + + extern void __detachInterrupt(uint8_t pin) + { + if (pin < 16) + { + ETS_GPIO_INTR_DISABLE(); + GPC(pin) &= ~(0xF << GPCI);//INT mode disabled + GPIEC = (1 << pin); //Clear Interrupt for this pin + interrupt_reg &= ~(1 << pin); + interrupt_handler_t* handler = &interrupt_handlers[pin]; + handler->mode = 0; + handler->fn = nullptr; + handler->arg = nullptr; + if (interrupt_reg) + { + ETS_GPIO_INTR_ENABLE(); + } + } + } + + extern void* __detachInterruptArg(uint8_t pin) + { + void* arg = (pin < 16) ? interrupt_handlers[pin].arg : nullptr; + __detachInterrupt(pin); + return arg; + } + + void initPins() + { + //Disable UART interrupts + system_set_os_print(0); + U0IE = 0; + U1IE = 0; + + for (int i = 0; i <= 5; ++i) + { + pinMode(i, INPUT); + } + // pins 6-11 are used for the SPI flash interface + for (int i = 12; i <= 16; ++i) + { + pinMode(i, INPUT); + } + } + + extern void pinMode(uint8_t pin, uint8_t mode) __attribute__((weak, alias("__pinMode"))); + extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__((weak, alias("__digitalWrite"))); + 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 detachInterrupt(uint8_t pin) __attribute__((weak, alias("__detachInterrupt"))); + extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg"))); + extern void* detachInterruptArg(uint8_t pin) __attribute__((weak, alias("__detachInterruptArg"))); }; From 6a33d994265ea670bb4d93c66c2481704a9be895 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 6 May 2019 02:19:56 +0200 Subject: [PATCH 12/12] astyle libraries/esp8266/examples/GPIO/FunctionalInterrupt --- .../FunctionalInterrupts.cpp | 86 +++++++++++-------- .../FunctionalInterrupts.h | 9 +- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index 6d990440be..6a15176c93 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -4,65 +4,77 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) { - ArgStructure* localArg = static_cast(arg); - if (localArg->interruptInfo) - { - localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); - localArg->interruptInfo->micro = micros(); - } - if (localArg->functionInfo->reqScheduledFunction) - { - schedule_function( - [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, - interruptInfo = *localArg->interruptInfo]() { reqScheduledFunction(interruptInfo); }); - } - else if (localArg->functionInfo->reqFunction) - { - localArg->functionInfo->reqFunction(); - } + ArgStructure* localArg = static_cast(arg); + if (localArg->interruptInfo) + { + localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); + localArg->interruptInfo->micro = micros(); + } + if (localArg->functionInfo->reqScheduledFunction) + { + schedule_function( + [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, + interruptInfo = *localArg->interruptInfo]() + { + reqScheduledFunction(interruptInfo); + }); + } + else if (localArg->functionInfo->reqFunction) + { + localArg->functionInfo->reqFunction(); + } } void cleanupFunctional(void* arg) { - ArgStructure* localArg = static_cast(arg); - delete localArg; + ArgStructure* localArg = static_cast(arg); + delete localArg; } void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) { - // use the local interrupt routine which takes the ArgStructure as argument + // use the local interrupt routine which takes the ArgStructure as argument - void* localArg = detachInterruptArg(pin); - if (localArg) cleanupFunctional(localArg); + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } - FunctionInfo* fi = new FunctionInfo; - fi->reqFunction = intRoutine; + FunctionInfo* fi = new FunctionInfo; + fi->reqFunction = intRoutine; - ArgStructure* as = new ArgStructure; - as->functionInfo = fi; + ArgStructure* as = new ArgStructure; + as->functionInfo = fi; - attachInterruptArg (pin, interruptFunctional, as, mode); + attachInterruptArg(pin, interruptFunctional, as, mode); } void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { - void* localArg = detachInterruptArg(pin); - if (localArg) cleanupFunctional(localArg); + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } - InterruptInfo* ii = new InterruptInfo(pin); + InterruptInfo* ii = new InterruptInfo(pin); - FunctionInfo* fi = new FunctionInfo; - fi->reqScheduledFunction = scheduledIntRoutine; + FunctionInfo* fi = new FunctionInfo; + fi->reqScheduledFunction = scheduledIntRoutine; - ArgStructure* as = new ArgStructure; - as->interruptInfo = ii; - as->functionInfo = fi; + ArgStructure* as = new ArgStructure; + as->interruptInfo = ii; + as->functionInfo = fi; - attachInterruptArg(pin, interruptFunctional, as, mode); + attachInterruptArg(pin, interruptFunctional, as, mode); } void detachFunctionalInterrupt(uint8_t pin) { - void* localArg = detachInterruptArg(pin); - if (localArg) cleanupFunctional(localArg); + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } } diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h index b1867f73ad..a0444f4260 100644 --- a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -5,19 +5,22 @@ // Structures for communication -struct InterruptInfo { +struct InterruptInfo +{ InterruptInfo(uint8_t _pin) : pin(_pin) {} const uint8_t pin; uint8_t value = 0; uint32_t micro = 0; }; -struct FunctionInfo { +struct FunctionInfo +{ std::function reqFunction = nullptr; std::function reqScheduledFunction = nullptr; }; -struct ArgStructure { +struct ArgStructure +{ ~ArgStructure() { delete functionInfo;