Fix attachInterrupt to handle single GPIO callback

The Pico SDK only supports a single callback pointer for all GPIO
interrupt pins.  So we need to track the individual pin-to-CB map
ourselves and dispatch from our own internal callback routine.

Fixes #25
parent ac867d71
...@@ -22,23 +22,37 @@ ...@@ -22,23 +22,37 @@
#include <hardware/gpio.h> #include <hardware/gpio.h>
#include <hardware/sync.h> #include <hardware/sync.h>
#include <stack> #include <stack>
#include <map>
std::stack<uint32_t> irqStack; // Support nested IRQ disable/re-enable
static std::stack<uint32_t> _irqStack;
extern "C" void interrupts() { extern "C" void interrupts() {
if (irqStack.empty()) { if (_irqStack.empty()) {
// ERROR // ERROR
return; return;
} }
restore_interrupts(irqStack.top()); restore_interrupts(_irqStack.top());
irqStack.pop(); _irqStack.pop();
} }
extern "C" void noInterrupts() { extern "C" void noInterrupts() {
irqStack.push(save_and_disable_interrupts()); _irqStack.push(save_and_disable_interrupts());
} }
static uint32_t _irqMap = 0; // Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
// dispatch to the real callback manually
static std::map<pin_size_t, voidFuncPtr> _map;
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
auto irq = _map.find(gpio);
if (irq != _map.end()) {
// Ignore events, only one event per pin supported by Arduino
irq->second(); // Do the callback
} else {
// ERROR, but we're in an IRQ so do nothing
}
}
extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus mode) { extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus mode) {
uint32_t events; uint32_t events;
...@@ -52,16 +66,17 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus ...@@ -52,16 +66,17 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
} }
noInterrupts(); noInterrupts();
detachInterrupt(pin); detachInterrupt(pin);
gpio_set_irq_enabled_with_callback(pin, events, true, (gpio_irq_callback_t)callback); _map.insert({pin, callback});
_irqMap |= 1<<pin; gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
interrupts(); interrupts();
} }
extern "C" void detachInterrupt(pin_size_t pin){ extern "C" void detachInterrupt(pin_size_t pin) {
noInterrupts(); noInterrupts();
if (_irqMap & (1<<pin)) { auto irq = _map.find(pin);
if (irq != _map.end()) {
gpio_set_irq_enabled(pin, 0x0f /* all */, false); gpio_set_irq_enabled(pin, 0x0f /* all */, false);
_irqMap &= ~(1<<pin); _map.erase(pin);
} }
interrupts(); interrupts();
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment