Skip to content

Commit

Permalink
Update interrupt functions (#1850)
Browse files Browse the repository at this point in the history
* Updates to Interrupts module

* Use InterruptDelegate type
* Put delegate callback into separate function to save IRAM
* Use `ESP_MAX_INTERRUPTS` consistently

* Refactor attachInterrupt code using inlines

Be clear with distinction between ESP *GPIO_INT_TYPE* and Arduino interrupt *mode*.

* Update `Basic_Interrupts` sample

Use function instead of lambda and explain reason in comments.
  • Loading branch information
mikee47 authored and slaff committed Sep 29, 2019
1 parent 2a47e22 commit 6b64931
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 144 deletions.
85 changes: 26 additions & 59 deletions Sming/Arch/Esp8266/Core/Interrupts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@
#include <Platform/System.h>
#include <BitManipulations.h>

static InterruptCallback gpioInterruptsList[16] = {0};
static InterruptDelegate delegateFunctionList[16];
static bool gpioInterruptsInitialied = false;
static InterruptCallback gpioInterruptsList[ESP_MAX_INTERRUPTS] = {0};
static InterruptDelegate delegateFunctionList[ESP_MAX_INTERRUPTS];
static bool interruptHandlerAttached = false;

static void interruptDelegateCallback(uint32_t interruptNumber)
{
auto& delegate = delegateFunctionList[interruptNumber];
if(delegate) {
delegate();
}
}

/** @brief Interrupt handler
* @param intr_mask Interrupt mask
Expand All @@ -24,78 +32,61 @@ static bool gpioInterruptsInitialied = false;
static void IRAM_ATTR interruptHandler(uint32 intr_mask, void* arg)
{
bool processed;
uint32 gpioStatus;

do {
gpioStatus = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
uint32 gpioStatus = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
processed = false;
for(uint8 i = 0; i < ESP_MAX_INTERRUPTS; i++) {
if(!bitRead(gpioStatus, i)) {
continue;
}

// clear interrupt status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpioStatus & _BV(i));
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, _BV(i));

if(gpioInterruptsList[i]) {
gpioInterruptsList[i]();
} else if(delegateFunctionList[i]) {
System.queueCallback(
[](uint32_t interruptNumber) {
auto& delegate = delegateFunctionList[interruptNumber];
if(delegate)
delegate();
},
i);
System.queueCallback(interruptDelegateCallback, i);
}

processed = true;
}
} while(processed);
}

void attachInterrupt(uint8_t pin, InterruptCallback callback, uint8_t mode)
{
GPIO_INT_TYPE type = ConvertArduinoInterruptMode(mode);
attachInterrupt(pin, callback, type);
}

void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, uint8_t mode)
{
GPIO_INT_TYPE type = ConvertArduinoInterruptMode(mode);
attachInterrupt(pin, delegateFunction, type);
}

void attachInterrupt(uint8_t pin, InterruptCallback callback, GPIO_INT_TYPE mode)
void attachInterrupt(uint8_t pin, InterruptCallback callback, GPIO_INT_TYPE type)
{
if(pin >= 16)
if(pin >= ESP_MAX_INTERRUPTS) {
return; // WTF o_O
}
gpioInterruptsList[pin] = callback;
delegateFunctionList[pin] = nullptr;
attachInterruptHandler(pin, mode);
attachInterruptHandler(pin, type);
}

void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, GPIO_INT_TYPE mode)
void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, GPIO_INT_TYPE type)
{
if(pin >= 16)
if(pin >= ESP_MAX_INTERRUPTS) {
return; // WTF o_O
}
gpioInterruptsList[pin] = nullptr;
delegateFunctionList[pin] = delegateFunction;
attachInterruptHandler(pin, mode);
attachInterruptHandler(pin, type);
}

void attachInterruptHandler(uint8_t pin, GPIO_INT_TYPE mode)
void attachInterruptHandler(uint8_t pin, GPIO_INT_TYPE type)
{
ETS_GPIO_INTR_DISABLE();

if(!gpioInterruptsInitialied) {
if(!interruptHandlerAttached) {
ETS_GPIO_INTR_ATTACH((ets_isr_t)interruptHandler, nullptr); // Register interrupt handler
gpioInterruptsInitialied = true;
interruptHandlerAttached = true;
}

pinMode(pin, INPUT);

gpio_pin_intr_state_set(GPIO_ID_PIN(pin), mode); // Enable GPIO pin interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(pin), type); // Enable GPIO pin interrupt

ETS_GPIO_INTR_ENABLE();
}
Expand All @@ -107,12 +98,6 @@ void detachInterrupt(uint8_t pin)
attachInterruptHandler(pin, GPIO_PIN_INTR_DISABLE);
}

void interruptMode(uint8_t pin, uint8_t mode)
{
GPIO_INT_TYPE type = ConvertArduinoInterruptMode(mode);
interruptMode(pin, type);
}

void interruptMode(uint8_t pin, GPIO_INT_TYPE type)
{
ETS_GPIO_INTR_DISABLE();
Expand All @@ -123,21 +108,3 @@ void interruptMode(uint8_t pin, GPIO_INT_TYPE type)

ETS_GPIO_INTR_ENABLE();
}

GPIO_INT_TYPE ConvertArduinoInterruptMode(uint8_t mode)
{
switch(mode) {
case LOW: // to trigger the interrupt whenever the pin is low,
return GPIO_PIN_INTR_LOLEVEL;
case CHANGE: // to trigger the interrupt whenever the pin changes value
return (GPIO_INT_TYPE)3; // GPIO_PIN_INTR_ANYEDGE
case RISING: // to trigger when the pin goes from low to high,
return GPIO_PIN_INTR_POSEDGE;
case FALLING: // for when the pin goes from high to low.
return GPIO_PIN_INTR_NEGEDGE;
case HIGH: // to trigger the interrupt whenever the pin is high.
return GPIO_PIN_INTR_HILEVEL;
default:
return GPIO_PIN_INTR_DISABLE;
}
}
36 changes: 3 additions & 33 deletions Sming/Arch/Host/Core/Interrupts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,52 +12,22 @@
#include <Digital.h>
#include <Platform/System.h>

void attachInterrupt(uint8_t pin, InterruptCallback callback, uint8_t mode)
void attachInterrupt(uint8_t pin, InterruptCallback callback, GPIO_INT_TYPE type)
{
}

void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, uint8_t mode)
void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, GPIO_INT_TYPE type)
{
}

void attachInterrupt(uint8_t pin, InterruptCallback callback, GPIO_INT_TYPE mode)
{
}

void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, GPIO_INT_TYPE mode)
{
}

void attachInterruptHandler(uint8_t pin, GPIO_INT_TYPE mode)
void attachInterruptHandler(uint8_t pin, GPIO_INT_TYPE type)
{
}

void detachInterrupt(uint8_t pin)
{
}

void interruptMode(uint8_t pin, uint8_t mode)
{
}

void interruptMode(uint8_t pin, GPIO_INT_TYPE type)
{
}

GPIO_INT_TYPE ConvertArduinoInterruptMode(uint8_t mode)
{
switch(mode) {
case LOW: // to trigger the interrupt whenever the pin is low,
return GPIO_PIN_INTR_LOLEVEL;
case CHANGE: // to trigger the interrupt whenever the pin changes value
return (GPIO_INT_TYPE)3; // GPIO_PIN_INTR_ANYEDGE
case RISING: // to trigger when the pin goes from low to high,
return GPIO_PIN_INTR_POSEDGE;
case FALLING: // for when the pin goes from high to low.
return GPIO_PIN_INTR_NEGEDGE;
case HIGH: // to trigger the interrupt whenever the pin is high.
return GPIO_PIN_INTR_HILEVEL;
default:
return GPIO_PIN_INTR_DISABLE;
}
}
91 changes: 60 additions & 31 deletions Sming/Core/Interrupts.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,54 +17,85 @@
#include <stdint.h>
#include <driver/gpio.h>
#include <Delegate.h>
#include <WConstants.h>
#include <sming_attr.h>

#define ESP_MAX_INTERRUPTS 16
constexpr unsigned ESP_MAX_INTERRUPTS = 16;

typedef void (*InterruptCallback)();
typedef Delegate<void()> InterruptDelegate;

/** @brief Convert Arduino interrupt mode to Sming mode
* @param mode Arduino mode type
* @retval GPIO_INT_TYPE Sming interrupt type
*/
__forceinline GPIO_INT_TYPE ConvertArduinoInterruptMode(uint8_t mode)
{
switch(mode) {
case LOW: // to trigger the interrupt whenever the pin is low,
return GPIO_PIN_INTR_LOLEVEL;
case CHANGE: // to trigger the interrupt whenever the pin changes value
return (GPIO_INT_TYPE)3; // GPIO_PIN_INTR_ANYEDGE
case RISING: // to trigger when the pin goes from low to high,
return GPIO_PIN_INTR_POSEDGE;
case FALLING: // for when the pin goes from high to low.
return GPIO_PIN_INTR_NEGEDGE;
case HIGH: // to trigger the interrupt whenever the pin is high.
return GPIO_PIN_INTR_HILEVEL;
default:
return GPIO_PIN_INTR_DISABLE;
}
}

/** @brief Attach a function to a GPIO interrupt
* @param pin GPIO to configure
* @param callback Function to call when interrupt occurs on GPIO
* @param mode Arduino type interrupt mode
* @note Traditional c-type callback function method, MUST use IRAM_ATTR
* Use this type of interrupt handler for timing-sensitive applications.
* @param type Interrupt type
* @note Traditional c-type callback function method
*/
void attachInterrupt(uint8_t pin, InterruptCallback callback, uint8_t mode);
void attachInterrupt(uint8_t pin, InterruptCallback callback, GPIO_INT_TYPE type);

/** @brief Attach a function to a GPIO interrupt
* @param pin GPIO to configure
* @param delegateFunction Function to call when interrupt occurs on GPIO
* @param callback Function to call when interrupt occurs on GPIO
* @param mode Arduino type interrupt mode
* @note Delegate function method, can be a regular function, method, etc.
* The delegate function is called via the system task queue so does not need any special consideration.
* Note that this type of interrupt handler is not suitable for timing-sensitive applications.
* @note Traditional c-type callback function method, MUST use IRAM_ATTR
* Use this type of interrupt handler for timing-sensitive applications.
*/
void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, uint8_t mode);
__forceinline void attachInterrupt(uint8_t pin, InterruptCallback callback, uint8_t mode)
{
GPIO_INT_TYPE type = ConvertArduinoInterruptMode(mode);
attachInterrupt(pin, callback, type);
}

/** @brief Attach a function to a GPIO interrupt
* @param pin GPIO to configure
* @param callback Function to call when interrupt occurs on GPIO
* @param mode Interrupt mode
* @note Traditional c-type callback function method
* @todo Add GPIO_INT_TYPE documentation - is this in SDK?
* @param delegateFunction Function to call when interrupt occurs on GPIO
* @param type Interrupt type
* @note Delegate function method
*/
void attachInterrupt(uint8_t pin, InterruptCallback callback, GPIO_INT_TYPE mode); // ESP compatible version
void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, GPIO_INT_TYPE type);

/** @brief Attach a function to a GPIO interrupt
* @param pin GPIO to configure
* @param delegateFunction Function to call when interrupt occurs on GPIO
* @param mode Interrupt mode
* @note Delegate function method
* @param mode Arduino type interrupt mode (LOW, HIGH, CHANGE, RISING, FALLING)
* @note Delegate function method, can be a regular function, method, etc.
* The delegate function is called via the system task queue so does not need any special consideration.
* Note that this type of interrupt handler is not suitable for timing-sensitive applications.
*/
void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, GPIO_INT_TYPE mode); // ESP compatible version
__forceinline void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, uint8_t mode)
{
GPIO_INT_TYPE type = ConvertArduinoInterruptMode(mode);
attachInterrupt(pin, delegateFunction, type);
}

/** @brief Enable interrupts on GPIO pin
* @param pin GPIO to enable interrupts for
* @param mode Interrupt mode
* @note Configure interrupt handler with attachInterrupt(pin, callback, mode)
* @param type Interrupt type
* @note Configure interrupt handler with attachInterrupt(pin, callback, type)
*/
void attachInterruptHandler(uint8_t pin, GPIO_INT_TYPE mode);
void attachInterruptHandler(uint8_t pin, GPIO_INT_TYPE type);

/** @brief Disable interrupts on GPIO pin
* @param pin GPIO to disable interrupts for
Expand All @@ -73,23 +104,21 @@ void detachInterrupt(uint8_t pin);

/** @brief Set interrupt mode
* @param pin GPIO to configure
* @param mode Interrupt mode
* @param type Interrupt type
* @note Use ConvertArduinoInterruptMode to get Sming interrupt type from an Arduino interrupt type
*/
void interruptMode(uint8_t pin, uint8_t mode);
void interruptMode(uint8_t pin, GPIO_INT_TYPE type);

/** @brief Set interrupt mode
* @param pin GPIO to configure
* @param type Interrupt type
* @param mode Interrupt mode
* @note Use ConvertArduinoInterruptMode to get Sming interrupt type from an Arduino interrupt type
*/
void interruptMode(uint8_t pin, GPIO_INT_TYPE type);

/** @brief Convert Arduino interrupt mode to Sming mode
* @param mode Arduino mode type
* @retval GPIO_INT_TYPE Sming interrupt mode type
*/
GPIO_INT_TYPE ConvertArduinoInterruptMode(uint8_t mode);
__forceinline void interruptMode(uint8_t pin, uint8_t mode)
{
GPIO_INT_TYPE type = ConvertArduinoInterruptMode(mode);
interruptMode(pin, type);
}

#define digitalPinToInterrupt(pin) ((pin) < ESP_MAX_INTERRUPTS ? (pin) : -1)

Expand Down
Loading

0 comments on commit 6b64931

Please sign in to comment.