Skip to content

Commit 40a1090

Browse files
soburiDhruvaG2000
authored andcommitted
zephyrCommon: Implement attachInterrupt()/detachInterrupt()
The internal data structure named `gpio_port_callback` stores GPIO callback handlers. The `gpio_port_callback` allocate the data per GPIO device. The `gpio_port_callback` has an array of function pointers to store handler. The largest count of the gpio pin count among the GPIO devices that using (which means it exists in the `digital-pin-gpios`) determines the array size. It calculates the data size at compile time. Signed-off-by: TOKITA Hiroshi <[email protected]>
1 parent 20a342c commit 40a1090

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

cores/arduino/zephyrCommon.cpp

+141
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,108 @@
88

99
namespace {
1010

11+
/*
12+
* Calculate GPIO ports/pins number statically from devicetree configuration
13+
*/
14+
15+
template <class N, class Head> constexpr const N sum_of_list(const N sum, const Head &head)
16+
{
17+
return sum + head;
18+
}
19+
20+
template <class N, class Head, class... Tail>
21+
constexpr const N sum_of_list(const N sum, const Head &head, const Tail &...tail)
22+
{
23+
return sum_of_list(sum + head, tail...);
24+
}
25+
26+
template <class N, class Head> constexpr const N max_in_list(const N max, const Head &head)
27+
{
28+
return (max >= head) ? max : head;
29+
}
30+
31+
template <class N, class Head, class... Tail>
32+
constexpr const N max_in_list(const N max, const Head &head, const Tail &...tail)
33+
{
34+
return max_in_list((max >= head) ? max : head, tail...);
35+
}
36+
37+
template <class Query, class Head>
38+
constexpr const size_t is_first_appearance(const size_t &idx, const size_t &at, const size_t &found,
39+
const Query &query, const Head &head)
40+
{
41+
return ((found == ((size_t)-1)) && (query == head) && (idx == at)) ? 1 : 0;
42+
}
43+
44+
template <class Query, class Head, class... Tail>
45+
constexpr const size_t is_first_appearance(const size_t &idx, const size_t &at, const size_t &found,
46+
const Query &query, const Head &head,
47+
const Tail &...tail)
48+
{
49+
return ((found == ((size_t)-1)) && (query == head) && (idx == at))
50+
? 1
51+
: is_first_appearance(idx + 1, at, (query == head ? idx : found), query,
52+
tail...);
53+
}
54+
55+
#define GET_DEVICE_VARGS(n, p, i, _) DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(n, p, i))
56+
#define FIRST_APPEARANCE(n, p, i) \
57+
is_first_appearance(0, i, ((size_t)-1), DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(n, p, i)), \
58+
DT_FOREACH_PROP_ELEM_SEP_VARGS(n, p, GET_DEVICE_VARGS, (, ), 0))
59+
const int port_num =
60+
sum_of_list(0, DT_FOREACH_PROP_ELEM_SEP(DT_PATH(zephyr_user), digital_pin_gpios,
61+
FIRST_APPEARANCE, (, )));
62+
63+
#define GPIO_NGPIOS(n, p, i) DT_PROP(DT_GPIO_CTLR_BY_IDX(n, p, i), ngpios)
64+
const int max_ngpios = max_in_list(
65+
0, DT_FOREACH_PROP_ELEM_SEP(DT_PATH(zephyr_user), digital_pin_gpios, GPIO_NGPIOS, (, )));
66+
67+
/*
68+
* GPIO callback implementation
69+
*/
70+
71+
struct gpio_port_callback {
72+
struct gpio_callback callback;
73+
voidFuncPtr handlers[max_ngpios];
74+
gpio_port_pins_t pins;
75+
const struct device *dev;
76+
} port_callback[port_num] = {0};
77+
78+
struct gpio_port_callback *find_gpio_port_callback(const struct device *dev)
79+
{
80+
for (size_t i = 0; i < ARRAY_SIZE(port_callback); i++) {
81+
if (port_callback[i].dev == dev) {
82+
return &port_callback[i];
83+
}
84+
if (port_callback[i].dev == nullptr) {
85+
port_callback[i].dev = dev;
86+
return &port_callback[i];
87+
}
88+
}
89+
90+
return nullptr;
91+
}
92+
93+
void setInterruptHandler(pin_size_t pinNumber, voidFuncPtr func)
94+
{
95+
struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port);
96+
97+
if (pcb) {
98+
pcb->handlers[BIT(arduino_pins[pinNumber].pin)] = func;
99+
}
100+
}
101+
102+
void handleGpioCallback(const struct device *port, struct gpio_callback *cb, uint32_t pins)
103+
{
104+
struct gpio_port_callback *pcb = (struct gpio_port_callback *)cb;
105+
106+
for (uint32_t i = 0; i < max_ngpios; i++) {
107+
if (pins & BIT(i)) {
108+
pcb->handlers[BIT(i)]();
109+
}
110+
}
111+
}
112+
11113
#ifdef CONFIG_PWM
12114

13115
#define PWM_DT_SPEC(n,p,i) PWM_DT_SPEC_GET_BY_IDX(n, i),
@@ -181,3 +283,42 @@ int analogRead(pin_size_t pinNumber)
181283
}
182284

183285
#endif
286+
287+
void attachInterrupt(pin_size_t pinNumber, voidFuncPtr callback, PinStatus pinStatus)
288+
{
289+
struct gpio_port_callback *pcb;
290+
gpio_flags_t intmode = 0;
291+
292+
if (!callback) {
293+
return;
294+
}
295+
296+
if (pinStatus == LOW) {
297+
intmode |= GPIO_INT_LEVEL_LOW;
298+
} else if (pinStatus == HIGH) {
299+
intmode |= GPIO_INT_LEVEL_HIGH;
300+
} else if (pinStatus == CHANGE) {
301+
intmode |= GPIO_INT_EDGE_BOTH;
302+
} else if (pinStatus == FALLING) {
303+
intmode |= GPIO_INT_EDGE_FALLING;
304+
} else if (pinStatus == RISING) {
305+
intmode |= GPIO_INT_EDGE_RISING;
306+
} else {
307+
return;
308+
}
309+
310+
pcb = find_gpio_port_callback(arduino_pins[pinNumber].port);
311+
__ASSERT(pcb != nullptr, "gpio_port_callback not found");
312+
313+
pcb->pins |= BIT(arduino_pins[pinNumber].pin);
314+
setInterruptHandler(pinNumber, callback);
315+
316+
gpio_pin_interrupt_configure(arduino_pins[pinNumber].port, arduino_pins[pinNumber].pin, intmode);
317+
gpio_init_callback(&pcb->callback, handleGpioCallback, pcb->pins);
318+
gpio_add_callback(arduino_pins[pinNumber].port, &pcb->callback);
319+
}
320+
321+
void detachInterrupt(pin_size_t pinNumber)
322+
{
323+
setInterruptHandler(pinNumber, nullptr);
324+
}

0 commit comments

Comments
 (0)