Skip to content

Commit 7c79f6a

Browse files
committed
cores: arduino: zephyrCommon: Generate config from connector definition
If digital-gpio-pins is not defined, the pin configuration will be generated using the connector definition. This allows ArduinoCore-Zephyr to be used on boards that have arduino-header defined, without requiring specific configuration in ArduinoCore-Zephyr. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
1 parent 0559914 commit 7c79f6a

File tree

5 files changed

+591
-14
lines changed

5 files changed

+591
-14
lines changed

cores/arduino/Arduino.h

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2022 Dhruva Gole
3+
* Copyright (c) 2026 TOKITA Hiroshi
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -14,6 +15,8 @@
1415
#include <zephyr/drivers/adc.h>
1516
#include <zephyr/drivers/i2c.h>
1617

18+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
19+
1720
#define DIGITAL_PIN_EXISTS(n, p, i, dev, num) \
1821
(((dev == DT_REG_ADDR(DT_PHANDLE_BY_IDX(n, p, i))) && \
1922
(num == DT_PHA_BY_IDX(n, p, i, pin))) \
@@ -74,12 +77,80 @@
7477

7578
#define DN_ENUMS(n, p, i) D##i = i
7679

80+
#else
81+
82+
#if DT_NODE_EXISTS(DT_NODELABEL(arduino_header))
83+
#define ZARD_CONNECTOR arduino_header
84+
#elif DT_NODE_EXISTS(DT_NODELABEL(arduino_mkr_header))
85+
#define ZARD_CONNECTOR arduino_mkr_header
86+
#elif DT_NODE_EXISTS(DT_NODELABEL(arduino_nano_header))
87+
#define ZARD_CONNECTOR arduino_nano_header
88+
#elif DT_NODE_EXISTS(DT_NODELABEL(pico_header))
89+
#define ZARD_CONNECTOR pico_header
90+
#elif DT_NODE_EXISTS(DT_NODELABEL(boosterpack_header))
91+
#define ZARD_CONNECTOR boosterpack_header
92+
#endif
93+
94+
#if DT_NODE_EXISTS(DT_NODELABEL(arduino_adc))
95+
#define ZARD_ADC_CONNECTOR arduino_adc
96+
#endif
97+
98+
#if DT_NODE_EXISTS(DT_NODELABEL(arduino_pwm))
99+
#define ZARD_PWM_CONNECTOR arduino_pwm
100+
#endif
101+
102+
#define ZARD_CHECK_GPIO_CTLR_OKAY(node_id) \
103+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(node_id), \
104+
(COND_CODE_1(DT_NODE_HAS_PROP(node_id, gpio_controller), (node_id,), ())), ())
105+
106+
#define ZARD_ALL_OKAY_GPIO_CTLR \
107+
GET_ARGS_FIRST_N(NUM_VA_ARGS_LESS_1(DT_FOREACH_NODE(ZARD_CHECK_GPIO_CTLR_OKAY)), \
108+
DT_FOREACH_NODE(ZARD_CHECK_GPIO_CTLR_OKAY))
109+
110+
#define ZARD_IDX_IF_MATCH(i, n) \
111+
COND_CODE_1(DT_SAME_NODE(n, GET_ARG_N(UTIL_INC(i), ZARD_ALL_OKAY_GPIO_CTLR)), (i), ())
112+
113+
#define ZARD_MATCH_IDX(n) \
114+
LISTIFY(NUM_VA_ARGS_LESS_1(ZARD_ALL_OKAY_GPIO_CTLR), ZARD_IDX_IF_MATCH, (), n)
115+
116+
#define ZARD_GET_NGPIOS(i, ...) DT_PROP(GET_ARG_N(UTIL_INC(i), __VA_ARGS__), ngpios)
117+
#define ZARD_SUM_NGPIOS(...) \
118+
LISTIFY(NUM_VA_ARGS_LESS_1(__VA_ARGS__), ZARD_GET_NGPIOS, (+), __VA_ARGS__)
119+
#define ZARD_GLOBAL_GPIO_NUM_(ph) \
120+
ZARD_SUM_NGPIOS(GET_ARGS_FIRST_N(ZARD_MATCH_IDX(ph), ZARD_ALL_OKAY_GPIO_CTLR))
121+
122+
#define ZARD_GLOBAL_GPIO_NUM(ph) \
123+
COND_CODE_1(IS_EQ(NUM_VA_ARGS(ZARD_GLOBAL_GPIO_NUM_(ph)), 0), \
124+
(0), (ZARD_GLOBAL_GPIO_NUM_(ph)))
125+
126+
#define ZARD_CONN_DN_ENUMS(n, p, i) \
127+
UTIL_CAT(D, DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 0)) = \
128+
ZARD_GLOBAL_GPIO_NUM(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)) + \
129+
DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 0)
130+
131+
#define ZARD_CONN_AN_ENUMS(n, p, i) \
132+
UTIL_CAT(A, DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 0)) = \
133+
ZARD_GLOBAL_GPIO_NUM( \
134+
DT_MAP_ENTRY_PARENT_BY_IDX(DT_NODELABEL(ZARD_CONNECTOR), gpio_map, i)) + \
135+
DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(DT_NODELABEL(ZARD_CONNECTOR), gpio_map, i, 0)
136+
137+
#if DT_NODE_EXISTS(DT_ALIAS(led0))
138+
#define ZARD_LED_BUILTIN \
139+
ZARD_GLOBAL_GPIO_NUM(DT_PHANDLE_BY_IDX(DT_ALIAS(led0), gpios, 0)) + \
140+
DT_PHA_BY_IDX(DT_ALIAS(led0), gpios, 0, pin)
141+
#endif
142+
#endif
143+
77144
/*
78145
* expand as
79146
* enum digitalPins { D0, D1, ... LED... NUM_OF_DIGITAL_PINS };
80147
*/
81148
enum digitalPins {
149+
#if DT_PROP_LEN_OR(DT_PATH(zephyr_user), digital_pin_gpios, 0) > 0
82150
DT_FOREACH_PROP_ELEM_SEP(DT_PATH(zephyr_user), digital_pin_gpios, DN_ENUMS, (, )),
151+
#elif defined(ZARD_CONNECTOR)
152+
DT_FOREACH_MAP_ENTRY_SEP(DT_NODELABEL(ZARD_CONNECTOR), gpio_map, ZARD_CONN_DN_ENUMS, (, )),
153+
#endif
83154
NUM_OF_DIGITAL_PINS
84155
};
85156

@@ -88,8 +159,21 @@ enum digitalPins {
88159
#define AN_ENUMS(n, p, i) A ## i = DIGITAL_PIN_GPIOS_FIND_PIN( \
89160
DT_REG_ADDR(DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), p, i)), \
90161
DT_PHA_BY_IDX(DT_PATH(zephyr_user), p, i, pin)),
91-
enum analogPins { DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user),
92-
adc_pin_gpios, AN_ENUMS) };
162+
#define ZARD_AN_ENUM_GLOBAL(n, p, i) \
163+
ZARD_GLOBAL_GPIO_NUM(DT_PHANDLE_BY_IDX(n, p, i)) + DT_PHA_BY_IDX(n, p, i, pin)
164+
enum analogPins {
165+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), adc_pin_gpios)
166+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
167+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), adc_pin_gpios, AN_ENUMS)
168+
#else
169+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), adc_pin_gpios, ZARD_AN_ENUM_GLOBAL)
170+
#endif
171+
#elif defined(ZARD_ADC_CONNECTOR)
172+
DT_FOREACH_MAP_ENTRY_SEP(DT_NODELABEL(ZARD_ADC_CONNECTOR), io_channel_map, ZARD_CONN_AN_ENUMS,
173+
(, )),
174+
#endif
175+
NUM_OF_ANALOG_PINS
176+
};
93177

94178
#endif
95179

cores/arduino/zephyrCommon.cpp

Lines changed: 151 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2022 Dhruva Gole
3+
* Copyright (c) 2026 TOKITA Hiroshi
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -9,8 +10,23 @@
910

1011
#include <zephyr/spinlock.h>
1112

13+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
1214
static constexpr struct gpio_dt_spec arduino_pins[] = {DT_FOREACH_PROP_ELEM_SEP(
1315
DT_PATH(zephyr_user), digital_pin_gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))};
16+
#else
17+
#define GET_GPIO_DEVICES(node_id) \
18+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(node_id), \
19+
(COND_CODE_1(DT_NODE_HAS_PROP(node_id, gpio_controller), \
20+
(DEVICE_DT_GET(node_id),), ())), ())
21+
22+
#define GET_GPIO_NGPIOS(node_id) \
23+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(node_id), \
24+
(COND_CODE_1(DT_NODE_HAS_PROP(node_id, gpio_controller), \
25+
(DT_PROP(node_id, ngpios),), ())), ())
26+
27+
static constexpr const struct device *gpio_ports[] = {DT_FOREACH_NODE(GET_GPIO_DEVICES)};
28+
static constexpr uint32_t gpio_ngpios[] = {DT_FOREACH_NODE(GET_GPIO_NGPIOS)};
29+
#endif
1430

1531
namespace {
1632

@@ -58,18 +74,77 @@ constexpr const size_t is_first_appearance(const size_t &idx, const size_t &at,
5874
tail...);
5975
}
6076

77+
#if !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
78+
constexpr inline const struct device *local_gpio_port(pin_size_t gpin);
79+
80+
constexpr inline const struct device *local_gpio_port_r(pin_size_t pin,
81+
const struct device *const *ctrl,
82+
const uint32_t accum, const uint32_t *end,
83+
size_t n) {
84+
return (n == 0) ? nullptr :
85+
(pin < accum + end[0]) ? ctrl[0] :
86+
local_gpio_port_r(pin, ctrl + 1, accum + end[0], end + 1, n - 1);
87+
}
88+
89+
constexpr inline size_t port_index_r(const struct device *target, const struct device *const *table,
90+
pin_size_t idx, size_t n) {
91+
return (n == 0) ? size_t(-1) :
92+
(target == table[0]) ? idx : port_index_r(target, table + 1, idx + 1, n - 1);
93+
}
94+
95+
constexpr inline pin_size_t port_idx(pin_size_t gpin) {
96+
return port_index_r(local_gpio_port(gpin), gpio_ports, 0, ARRAY_SIZE(gpio_ports));
97+
}
98+
99+
constexpr inline pin_size_t end_accum_r(const uint32_t accum, const uint32_t *end, size_t n) {
100+
return (n == 0) ? accum : end_accum_r(accum + end[0], end + 1, n - 1);
101+
}
102+
103+
constexpr inline pin_size_t end_accum(size_t n) {
104+
return end_accum_r(0, gpio_ngpios, n);
105+
}
106+
107+
constexpr inline pin_size_t global_gpio_pin_(size_t port_idx, pin_size_t lpin) {
108+
return port_idx == size_t(-1) ? size_t(-1) : end_accum(port_idx) + lpin;
109+
}
110+
111+
constexpr inline pin_size_t global_gpio_pin(const struct device *lport, pin_size_t lpin) {
112+
return global_gpio_pin_(port_index_r(lport, gpio_ports, 0, ARRAY_SIZE(gpio_ports)), lpin);
113+
}
114+
#endif
115+
61116
constexpr inline const struct device *local_gpio_port(pin_size_t gpin) {
117+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
62118
return arduino_pins[gpin].port;
119+
#else
120+
return local_gpio_port_r(gpin, gpio_ports, 0, gpio_ngpios, ARRAY_SIZE(gpio_ports));
121+
#endif
63122
}
64123

65124
constexpr inline pin_size_t local_gpio_pin(pin_size_t gpin) {
125+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
66126
return arduino_pins[gpin].pin;
127+
#else
128+
return port_idx(gpin) == pin_size_t(-1) ? pin_size_t(-1) : gpin - end_accum(port_idx(gpin));
129+
#endif
67130
}
68131

69132
inline int global_gpio_pin_configure(pin_size_t pinNumber, int flags) {
133+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
70134
return gpio_pin_configure_dt(&arduino_pins[pinNumber], flags);
135+
#else
136+
const struct device *port = local_gpio_port(pinNumber);
137+
138+
if (port) {
139+
return gpio_pin_configure(port, local_gpio_pin(pinNumber), flags);
140+
} else {
141+
return -1;
142+
}
143+
#endif
71144
}
72145

146+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
147+
#if DT_PROP_LEN_OR(DT_PATH(zephyr_user), digital_pin_gpios, 0) > 0
73148
#define GET_DEVICE_VARGS(n, p, i, _) DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(n, p, i))
74149
#define FIRST_APPEARANCE(n, p, i) \
75150
is_first_appearance(0, i, ((size_t)-1), DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(n, p, i)), \
@@ -81,6 +156,14 @@ const int port_num =
81156
#define GPIO_NGPIOS(n, p, i) DT_PROP(DT_GPIO_CTLR_BY_IDX(n, p, i), ngpios)
82157
const int max_ngpios = max_in_list(
83158
0, DT_FOREACH_PROP_ELEM_SEP(DT_PATH(zephyr_user), digital_pin_gpios, GPIO_NGPIOS, (, )));
159+
#else
160+
const int port_num = 1;
161+
const int max_ngpios = 0;
162+
#endif
163+
#else
164+
const int port_num = ARRAY_SIZE(gpio_ports);
165+
const int max_ngpios = max_in_list(DT_FOREACH_NODE(GET_GPIO_NGPIOS) 0);
166+
#endif
84167

85168
/*
86169
* GPIO callback implementation
@@ -100,6 +183,10 @@ struct gpio_port_callback {
100183

101184
struct gpio_port_callback *find_gpio_port_callback(const struct device *dev)
102185
{
186+
if (dev == nullptr) {
187+
return nullptr;
188+
}
189+
103190
for (size_t i = 0; i < ARRAY_SIZE(port_callback); i++) {
104191
if (port_callback[i].dev == dev) {
105192
return &port_callback[i];
@@ -140,13 +227,32 @@ void handleGpioCallback(const struct device *port, struct gpio_callback *cb, uin
140227
DIGITAL_PIN_GPIOS_FIND_PIN( \
141228
DT_REG_ADDR(DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), p, i)), \
142229
DT_PHA_BY_IDX(DT_PATH(zephyr_user), p, i, pin)),
143-
144-
const struct pwm_dt_spec arduino_pwm[] =
145-
{ DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), pwms, PWM_DT_SPEC) };
230+
#define PWM_CONN_CHANNEL_DT(n, p, i) \
231+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \
232+
({ .dev = DEVICE_DT_GET(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \
233+
.channel = DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 0), },), \
234+
())
235+
#define PWM_CONN_PINNUM(n, p, i) \
236+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \
237+
(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 0),), \
238+
())
239+
240+
const struct pwm_dt_spec arduino_pwm[] = {
241+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), adc_pin_gpios)
242+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), pwms, PWM_DT_SPEC)
243+
#elif defined(ZARD_PWM_CONNECTOR)
244+
DT_FOREACH_MAP_ENTRY(DT_NODELABEL(ZARD_PWM_CONNECTOR), pwm_map, PWM_CONN_CHANNEL_DT)
245+
#endif
246+
};
146247

147248
/* pwm-pins node provides a mapping digital pin numbers to pwm channels */
148-
const pin_size_t arduino_pwm_pins[] =
149-
{ DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), pwm_pin_gpios, PWM_PINS) };
249+
const pin_size_t arduino_pwm_pins[] = {
250+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), pwm_pin_gpios)
251+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), pwm_pin_gpios, PWM_PINS)
252+
#elif defined(ZARD_PWM_CONNECTOR)
253+
DT_FOREACH_MAP_ENTRY(DT_NODELABEL(ZARD_PWM_CONNECTOR), pwm_map, PWM_CONN_PINNUM)
254+
#endif
255+
};
150256

151257
size_t pwm_pin_index(pin_size_t pinNumber) {
152258
for(size_t i=0; i<ARRAY_SIZE(arduino_pwm_pins); i++) {
@@ -167,16 +273,45 @@ size_t pwm_pin_index(pin_size_t pinNumber) {
167273
DT_REG_ADDR(DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), p, i)), \
168274
DT_PHA_BY_IDX(DT_PATH(zephyr_user), p, i, pin)),
169275
#define ADC_CH_CFG(n,p,i) arduino_adc[i].channel_cfg,
170-
171-
const struct adc_dt_spec arduino_adc[] =
172-
{ DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, ADC_DT_SPEC) };
276+
#define ADC_CONN_CHANNEL_CFG(n, p, i) \
277+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \
278+
(ADC_CHANNEL_CFG_DT(ADC_CHANNEL_DT_NODE(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i), \
279+
DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 0))),), \
280+
())
281+
#define ADC_CONN_CHANNEL_DT(n, p, i) \
282+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \
283+
(ADC_DT_SPEC_STRUCT(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i), \
284+
DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 0)),), \
285+
())
286+
#define ADC_CONN_PINNUM(n, p, i) \
287+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \
288+
(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 0),), \
289+
())
290+
291+
const struct adc_dt_spec arduino_adc[] = {
292+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), adc_pin_gpios)
293+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, ADC_DT_SPEC)
294+
#elif defined(ZARD_ADC_CONNECTOR)
295+
DT_FOREACH_MAP_ENTRY(DT_NODELABEL(ZARD_ADC_CONNECTOR), io_channel_map, ADC_CONN_CHANNEL_DT)
296+
#endif
297+
};
173298

174299
/* io-channel-pins node provides a mapping digital pin numbers to adc channels */
175-
const pin_size_t arduino_analog_pins[] =
176-
{ DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), adc_pin_gpios, ADC_PINS) };
300+
const pin_size_t arduino_analog_pins[] = {
301+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), adc_pin_gpios)
302+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), adc_pin_gpios, ADC_PINS)
303+
#elif defined(ZARD_ADC_CONNECTOR)
304+
DT_FOREACH_MAP_ENTRY(DT_NODELABEL(ZARD_ADC_CONNECTOR), io_channel_map, ADC_CONN_PINNUM)
305+
#endif
306+
};
177307

178-
struct adc_channel_cfg channel_cfg[ARRAY_SIZE(arduino_analog_pins)] =
179-
{ DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, ADC_CH_CFG) };
308+
struct adc_channel_cfg channel_cfg[ARRAY_SIZE(arduino_analog_pins)] = {
309+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), adc_pin_gpios)
310+
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, ADC_CH_CFG)
311+
#elif defined(ZARD_ADC_CONNECTOR)
312+
DT_FOREACH_MAP_ENTRY(DT_NODELABEL(ZARD_ADC_CONNECTOR), io_channel_map, ADC_CONN_CHANNEL_CFG)
313+
#endif
314+
};
180315

181316
size_t analog_pin_index(pin_size_t pinNumber) {
182317
for(size_t i=0; i<ARRAY_SIZE(arduino_analog_pins); i++) {
@@ -237,7 +372,11 @@ PinStatus digitalRead(pin_size_t pinNumber) {
237372
}
238373

239374
#if CONFIG_ARDUINO_MAX_TONES < 0
375+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), digital_pin_gpios)
240376
#define MAX_TONE_PINS DT_PROP_LEN(DT_PATH(zephyr_user), digital_pin_gpios)
377+
#elif defined(ZARD_CONNECTOR)
378+
#define MAX_TONE_PINS DT_PROP_LEN(DT_NODELABEL(ZARD_CONNECTOR), gpio_map)
379+
#endif
241380
#else
242381
#define MAX_TONE_PINS CONFIG_ARDUINO_MAX_TONES
243382
#endif

0 commit comments

Comments
 (0)