Skip to content

Commit 322a1af

Browse files
Avoid memory (de)allocation in GPIO ISR handler (#2623)
Replace std::map, which can `new` and `delete` elements of the tree, with a statically allocated array and housekeeping. Fixes #2622
1 parent e25d382 commit 322a1af

File tree

1 file changed

+25
-47
lines changed

1 file changed

+25
-47
lines changed

cores/rp2040/wiring_private.cpp

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include <CoreMutex.h>
2323
#include <hardware/gpio.h>
2424
#include <hardware/sync.h>
25-
#include <map>
2625
#include "_freertos.h"
2726

2827

@@ -59,58 +58,34 @@ extern "C" void noInterrupts() {
5958
}
6059
}
6160

62-
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
63-
// dispatch to the real callback manually
6461
auto_init_mutex(_irqMutex);
65-
class CBInfo {
66-
public:
67-
CBInfo(voidFuncPtr cb) : _cb(cb), _useParam(false), _param(nullptr) { };
68-
CBInfo(voidFuncPtrParam cbParam, void *param) : _cbParam(cbParam), _useParam(true), _param(param) { };
69-
void callback() {
70-
if (_useParam && _cbParam) {
71-
_cbParam(_param);
72-
} else if (_cb) {
73-
_cb();
74-
}
75-
}
76-
private:
77-
union {
78-
voidFuncPtr _cb;
79-
voidFuncPtrParam _cbParam;
80-
};
81-
bool _useParam;
82-
void *_param;
83-
};
84-
85-
86-
static std::map<pin_size_t, CBInfo> _map;
62+
static uint64_t _gpioIrqEnabled = 0; // Sized to work with RP2350B, 48 GPIOs
63+
static uint64_t _gpioIrqUseParam;
64+
void *_gpioIrqCB[__GPIOCNT];
65+
void *_gpioIrqCBParam[__GPIOCNT];
8766

67+
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
68+
// dispatch to the real callback manually
8869
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
8970
(void) events;
90-
91-
// Only need to lock around the std::map check, not the whole IRQ callback
92-
CBInfo *cb;
93-
{
94-
CoreMutex m(&_irqMutex);
95-
if (m) {
96-
auto irq = _map.find(gpio);
97-
if (irq == _map.end()) {
98-
return;
99-
}
100-
cb = &irq->second;
71+
uint64_t mask = 1LL << gpio;
72+
if (_gpioIrqEnabled & mask) {
73+
if (_gpioIrqUseParam & mask) {
74+
voidFuncPtr cb = (voidFuncPtr)_gpioIrqCB[gpio];
75+
cb();
10176
} else {
102-
return;
77+
voidFuncPtrParam cb = (voidFuncPtrParam)_gpioIrqCB[gpio];
78+
cb(_gpioIrqCBParam[gpio]);
10379
}
10480
}
105-
cb->callback();
10681
}
10782

10883
// To be called when appropriately protected w/IRQ and mutex protects
10984
static void _detachInterruptInternal(pin_size_t pin) {
110-
auto irq = _map.find(pin);
111-
if (irq != _map.end()) {
85+
uint64_t mask = 1LL << pin;
86+
if (_gpioIrqEnabled & mask) {
11287
gpio_set_irq_enabled(pin, 0x0f /* all */, false);
113-
_map.erase(pin);
88+
_gpioIrqEnabled &= ~mask;
11489
}
11590
}
11691

@@ -119,7 +94,7 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
11994
if (!m) {
12095
return;
12196
}
122-
97+
uint64_t mask = 1LL << pin;
12398
uint32_t events;
12499
switch (mode) {
125100
case LOW: events = 1; break;
@@ -131,8 +106,9 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
131106
}
132107
noInterrupts();
133108
_detachInterruptInternal(pin);
134-
CBInfo cb(callback);
135-
_map.insert({pin, cb});
109+
_gpioIrqEnabled |= mask;
110+
_gpioIrqUseParam &= ~mask; // No parameter
111+
_gpioIrqCB[pin] = (void *)callback;
136112
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
137113
interrupts();
138114
}
@@ -142,7 +118,7 @@ void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus m
142118
if (!m) {
143119
return;
144120
}
145-
121+
uint64_t mask = 1LL << pin;
146122
uint32_t events;
147123
switch (mode) {
148124
case LOW: events = 1; break;
@@ -154,8 +130,10 @@ void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus m
154130
}
155131
noInterrupts();
156132
_detachInterruptInternal(pin);
157-
CBInfo cb(callback, param);
158-
_map.insert({pin, cb});
133+
_gpioIrqEnabled |= mask;
134+
_gpioIrqUseParam &= ~mask; // No parameter
135+
_gpioIrqCB[pin] = (void *)callback;
136+
_gpioIrqCBParam[pin] = param;
159137
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
160138
interrupts();
161139
}

0 commit comments

Comments
 (0)