diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 34e5fb8fce..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) }; @@ -218,6 +219,8 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); void attachInterrupt(uint8_t pin, void (*)(void), 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); @@ -295,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/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..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,220 +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; - void (*fn)(void); - 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 uint32_t interrupt_reg = 0; - -void ICACHE_RAM_ATTR interrupt_handler(void *arg) { - (void) arg; - 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 - 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); - } - 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 cleanupFunctional(void* arg); - -extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr 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 = userFunc; - if (handler->arg) // Clean when new attach without detach - { - cleanupFunctional(handler->arg); - } - 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 ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode ) -{ - __attachInterruptArg (pin, userFunc, 0, mode); -} - -extern void ICACHE_RAM_ATTR __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 = 0; - if (handler->arg) - { - cleanupFunctional(handler->arg); - } - handler->arg = 0; - if (interrupt_reg) - ETS_GPIO_INTR_ENABLE(); - } -} - -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 __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"))); }; diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino new file mode 100644 index 0000000000..de218dd15f --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -0,0 +1,85 @@ +#include +#include +#include "FunctionalInterrupts.h" + +#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 { + public: + 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, 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() { + detachInterrupt(PIN); + } + +#if defined(ESP8266) + void ICACHE_RAM_ATTR isr() +#elif defined(ESP32) + void IRAM_ATTR isr() +#endif + { + numberKeyPresses += 1; + 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); + pressed = false; + } + } + + private: + const uint8_t PIN; + volatile uint32_t numberKeyPresses = 0; + volatile bool pressed = false; +}; + +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(); +} diff --git a/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp new file mode 100644 index 0000000000..6a15176c93 --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -0,0 +1,80 @@ +#include "FunctionalInterrupts.h" +#include +#include + +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(); + } +} + +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 + + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } + + FunctionInfo* fi = new FunctionInfo; + fi->reqFunction = intRoutine; + + ArgStructure* as = new ArgStructure; + as->functionInfo = fi; + + attachInterruptArg(pin, interruptFunctional, as, mode); +} + +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) +{ + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } + + InterruptInfo* ii = new InterruptInfo(pin); + + FunctionInfo* fi = new FunctionInfo; + fi->reqScheduledFunction = scheduledIntRoutine; + + ArgStructure* as = new ArgStructure; + as->interruptInfo = ii; + as->functionInfo = fi; + + attachInterruptArg(pin, interruptFunctional, as, mode); +} + +void detachFunctionalInterrupt(uint8_t pin) +{ + 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 new file mode 100644 index 0000000000..a0444f4260 --- /dev/null +++ b/libraries/esp8266/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -0,0 +1,37 @@ +#ifndef FUNCTIONALINTERRUPTS_H +#define FUNCTIONALINTERRUPTS_H + +#include + +// 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