Skip to content

Commit 3e44192

Browse files
committed
zephyrCommon: Implement attachInterrupt()/detachInterrupt()
This implementation depends on CONFIG_GPIO_GET_CONFIG to keep the GPIO state already configured by pinMode(). Signed-off-by: TOKITA Hiroshi <[email protected]>
1 parent 5a76d45 commit 3e44192

File tree

1 file changed

+181
-13
lines changed

1 file changed

+181
-13
lines changed

cores/arduino/zephyrCommon.cpp

+181-13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,162 @@
66

77
#include <Arduino.h>
88

9+
#define GPIO_MODE_MASK (GPIO_INPUT | GPIO_OUTPUT | GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN | GPIO_PULL_UP)
10+
#define DIGITAL_PIN_MAX 256
11+
12+
#define dN_gpios(N) _CONCAT(_CONCAT(d, N), _gpios)
13+
#define GPIO_ELEM(n,_) COND_CODE_1( DT_NODE_HAS_PROP(DT_PATH(zephyr_user), dN_gpios(n)), \
14+
(DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX( DT_PATH(zephyr_user), dN_gpios(n), 0)),), ())
15+
16+
#define GPIO_NGPIOS(n,_) COND_CODE_1( DT_NODE_HAS_PROP(DT_PATH(zephyr_user), dN_gpios(n)), \
17+
(DT_PROP(DT_GPIO_CTLR_BY_IDX( DT_PATH(zephyr_user), dN_gpios(n), 0), ngpios),), ())
18+
19+
namespace {
20+
21+
/*
22+
* Calculate GPIO ports/pins number statically from devicetree configuration
23+
*/
24+
25+
template<class First>
26+
constexpr int count_ngpios(const int sum, const First&) { return sum; }
27+
28+
template<class First, class Second, class... Rest>
29+
constexpr int count_ngpios(const int max, const First& first, const Second& second, const Rest&... rest)
30+
{
31+
return count_ngpios(first == second ? first.ngpios : second, second, rest...);
32+
}
33+
34+
template<class First>
35+
constexpr int count_groups(const int sum, const First&) { return sum; }
36+
37+
template<class First, class Second, class... Rest>
38+
constexpr int count_groups(const int sum, const First& first, const Second& second, const Rest&... rest)
39+
{
40+
return count_groups(first == second ? sum : sum + 1, second, rest...);
41+
}
42+
43+
template<class First>
44+
constexpr int max_in_list(const int max, const First&) { return max; }
45+
46+
template<class First, class Second, class... Rest>
47+
constexpr int max_in_list(const int max, const First& first, const Second& second, const Rest&... rest)
48+
{
49+
return max_in_list(first >= second ? first : second, second, rest...);
50+
}
51+
52+
const int port_num = count_groups(0, LISTIFY(DIGITAL_PIN_MAX, GPIO_ELEM, ()) nullptr);
53+
const int max_ngpios = max_in_list(0, LISTIFY(DIGITAL_PIN_MAX, GPIO_NGPIOS, ()) 0);
54+
55+
/*
56+
* GPIO callback implementation
57+
*/
58+
59+
struct gpio_port_callback {
60+
struct gpio_callback callback;
61+
voidFuncPtr handlers[max_ngpios];
62+
gpio_port_pins_t pins;
63+
const struct device* dev;
64+
} port_callback[port_num] = {0};
65+
66+
struct gpio_port_callback* find_gpio_port_callback(const struct device* dev)
67+
{
68+
for(size_t i=0; i<ARRAY_SIZE(port_callback); i++) {
69+
if(port_callback[i].dev == dev) {
70+
return &port_callback[i];
71+
}
72+
if(port_callback[i].dev == nullptr) {
73+
port_callback[i].dev = dev;
74+
return &port_callback[i];
75+
}
76+
}
77+
78+
return nullptr;
79+
}
80+
81+
void setInterruptHandler(pin_size_t pinNumber, voidFuncPtr func)
82+
{
83+
struct gpio_port_callback* pcb = find_gpio_port_callback(arduino_pins[pinNumber]->port);
84+
85+
if (pcb) {
86+
pcb->handlers[BIT(arduino_pins[pinNumber]->pin)] = func;
87+
}
88+
}
89+
90+
void handleGpioCallback(const struct device *port, struct gpio_callback *cb, uint32_t pins)
91+
{
92+
struct gpio_port_callback* pcb = (struct gpio_port_callback*)cb;
93+
94+
for(uint32_t i=0; i<max_ngpios; i++) {
95+
if (pins & BIT(i)) {
96+
pcb->handlers[BIT(i)]();
97+
}
98+
}
99+
}
100+
101+
void pinModeImpl(pin_size_t pinNumber, gpio_flags_t pinmode, voidFuncPtr callback, gpio_flags_t intmode)
102+
{
103+
/* no use configure_dt to override PinMode config */
104+
gpio_pin_configure(arduino_pins[pinNumber]->port, arduino_pins[pinNumber]->pin,
105+
(arduino_pins[pinNumber]->dt_flags & ~GPIO_MODE_MASK) | pinmode);
106+
107+
if (callback) {
108+
struct gpio_port_callback* pcb = find_gpio_port_callback(arduino_pins[pinNumber]->port);
109+
__ASSERT(pcb != nullptr, "");
110+
111+
pcb->pins |= BIT(arduino_pins[pinNumber]->pin);
112+
setInterruptHandler(pinNumber, callback);
113+
114+
gpio_pin_interrupt_configure_dt(arduino_pins[pinNumber], intmode);
115+
gpio_init_callback(&pcb->callback, handleGpioCallback, pcb->pins);
116+
gpio_add_callback(arduino_pins[pinNumber]->port, &pcb->callback);
117+
}
118+
}
119+
120+
gpio_flags_t pinMode2flags(PinMode pinMode) {
121+
if (pinMode == INPUT) {
122+
return (GPIO_INPUT | GPIO_ACTIVE_HIGH);
123+
} else if (pinMode == INPUT_PULLUP) {
124+
return (GPIO_INPUT | GPIO_PULL_UP | GPIO_ACTIVE_HIGH);
125+
} else if (pinMode == INPUT_PULLDOWN) {
126+
return (GPIO_INPUT | GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH);
127+
} else if (pinMode == OUTPUT) {
128+
return (GPIO_OUTPUT_LOW | GPIO_ACTIVE_HIGH);
129+
} else if (pinMode == OUTPUT_OPENDRAIN) {
130+
return (GPIO_OUTPUT_LOW | GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN);
131+
} else {
132+
__ASSERT(false, "Unknown PinMode");
133+
return 0;
134+
}
135+
}
136+
137+
gpio_flags_t pinStatus2flags(PinStatus status) {
138+
if (status == LOW) {
139+
return GPIO_INT_LEVEL_LOW;
140+
}
141+
else if (status == HIGH) {
142+
return GPIO_INT_LEVEL_HIGH;
143+
}
144+
else if (status == CHANGE) {
145+
return GPIO_INT_EDGE_BOTH;
146+
}
147+
else if (status == FALLING) {
148+
return GPIO_INT_EDGE_FALLING;
149+
}
150+
else if (status == RISING) {
151+
return GPIO_INT_EDGE_RISING;
152+
} else {
153+
__ASSERT(false, "Unknown PinStatus");
154+
return 0;
155+
}
156+
}
157+
158+
} // anonymous namespace
159+
160+
161+
/*
162+
* APIs
163+
*/
164+
9165
void yield(void) {
10166
k_yield();
11167
}
@@ -16,19 +172,14 @@ void yield(void) {
16172
* A high physical level will be interpreted as value 1
17173
*/
18174
void pinMode(pin_size_t pinNumber, PinMode pinMode) {
19-
if (pinMode == INPUT) { // input mode
20-
gpio_pin_configure_dt(arduino_pins[pinNumber],
21-
GPIO_INPUT | GPIO_ACTIVE_HIGH);
22-
} else if (pinMode == INPUT_PULLUP) { // input with internal pull-up
23-
gpio_pin_configure_dt(arduino_pins[pinNumber],
24-
GPIO_INPUT | GPIO_PULL_UP | GPIO_ACTIVE_HIGH);
25-
} else if (pinMode == INPUT_PULLDOWN) { // input with internal pull-down
26-
gpio_pin_configure_dt(arduino_pins[pinNumber],
27-
GPIO_INPUT | GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH);
28-
} else if (pinMode == OUTPUT) { // output mode
29-
gpio_pin_configure_dt(arduino_pins[pinNumber],
30-
GPIO_OUTPUT_LOW | GPIO_ACTIVE_HIGH);
31-
}
175+
gpio_flags_t pinstatus = 0;
176+
177+
#ifdef CONFIG_GPIO_GET_CONFIG
178+
/* preserve GPIO interrupt configuration */
179+
gpio_pin_get_config_dt(arduino_pins[pinNumber], &pinstatus);
180+
#endif
181+
182+
pinModeImpl(pinNumber, pinMode2flags(pinMode), nullptr, (pinstatus & ~GPIO_MODE_MASK));
32183
}
33184

34185
void digitalWrite(pin_size_t pinNumber, PinStatus status) {
@@ -49,3 +200,20 @@ unsigned long micros(void) {
49200

50201
unsigned long millis(void) { return k_uptime_get_32(); }
51202

203+
#ifdef CONFIG_GPIO_GET_CONFIG
204+
205+
void attachInterrupt(pin_size_t pinNumber, voidFuncPtr callback, PinStatus pinStatus)
206+
{
207+
gpio_flags_t pinmode = 0;
208+
209+
/* preserve GPIO configuration that configured by pinMode()*/
210+
gpio_pin_get_config_dt(arduino_pins[pinNumber], &pinmode);
211+
pinModeImpl(pinNumber, (pinmode & ~GPIO_INT_MASK), callback, pinStatus2flags(pinStatus));
212+
}
213+
214+
void detachInterrupt(pin_size_t pinNumber)
215+
{
216+
setInterruptHandler(pinNumber, nullptr);
217+
}
218+
219+
#endif

0 commit comments

Comments
 (0)