Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completes #6048: let FunctionalInterrupt.h support only IRAM-safe scheduled ISRs #6055

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cores/esp8266/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,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);
Expand Down
65 changes: 0 additions & 65 deletions cores/esp8266/FunctionalInterrupt.cpp

This file was deleted.

35 changes: 0 additions & 35 deletions cores/esp8266/FunctionalInterrupt.h

This file was deleted.

152 changes: 68 additions & 84 deletions cores/esp8266/core_esp8266_wiring_digital.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,27 +109,15 @@ typedef void (*voidFuncPtrArg)(void*);

typedef struct {
uint8_t mode;
void (*fn)(void);
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;
Expand All @@ -147,102 +135,98 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
// 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)
{
// ISR not in IRAM
::printf((PGM_P)F("ISR not in IRAM!\r\n"));
abort();
}

// #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();
}
}

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 __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode)
{
__attachInterruptArg(pin, (voidFuncPtrArg)userFunc, 0, mode);
}

extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode )
extern void __detachInterrupt(uint8_t pin)
{
__attachInterruptArg (pin, userFunc, 0, mode);
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 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();
}
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;
//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);
}
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")));

};
81 changes: 81 additions & 0 deletions libraries/FunctionalInterrupt/examples/Functional/Functional.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <FunctionalInterrupt.h>
#include <Arduino.h>

#ifndef IRAM_ATTR
#define IRAM_ATTR ICACHE_RAM_ATTR
#endif

#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<Button*>(self)->isr();
//}, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM"
//attachInterruptArg(PIN, reinterpret_cast<void(*)(void*)>(&isr_static), this, FALLING); // works on ESP32; works on ESP8266
// FunctionalInterrupts API:
attachScheduledInterrupt(PIN, [this](InterruptInfo ii) {
Serial.print("Pin ");
Serial.println(ii.pin);
isr();
}, FALLING); // works on ESP32; works on ESP8266
};
~Button() {
// Arduino C API:
//detachInterrupt(PIN);
// FunctionalInterrupt API:
detachFunctionalInterrupt(PIN);
}

void IRAM_ATTR isr() {
numberKeyPresses += 1;
pressed = true;
}

static void IRAM_ATTR isr_static(Button* const self) {
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);
Serial.println("FunctionalInterrupt test/example");

button1 = new Button(BUTTON1);
button2 = new Button(BUTTON2);

Serial.println("setup() complete");
}

void loop() {
button1->checkPressed();
button2->checkPressed();
}
Loading