Support "file-less" configuration#151
Conversation
30e80c9 to
2157ae2
Compare
d14bab2 to
769f878
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a "file-less" configuration system that automatically configures boards using Arduino-compatible header definitions from the device tree, eliminating the need for board-specific overlay files. The system detects supported connector types (arduino_header, arduino_mkr_header, etc.) and automatically maps GPIO pins, enabling support for 200+ Zephyr-supported boards including the Nucleo series.
Changes:
- Added automatic board detection using device tree connector labels (arduino_header, pico_header, etc.)
- Introduced GPIO port/pin abstraction layer with constexpr helper functions for compile-time pin mapping
- Modified tone/noTone implementation to support dynamic timer allocation by tracking pin assignments
- Updated PWM and ADC pin mappings to support both legacy and new connector-based configurations
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 21 comments.
| File | Description |
|---|---|
| cores/arduino/Arduino.h | Adds macro definitions for automatic connector detection (ZARD_CONNECTOR, ZARD_ADC_CONNECTOR, ZARD_PWM_CONNECTOR) and updates digital/analog pin enums to support both legacy and connector-based configurations |
| cores/arduino/zephyrCommon.cpp | Implements GPIO abstraction layer with constexpr functions for pin mapping, updates all GPIO operations to use new abstraction, and modifies tone/noTone for improved timer management |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
165377e to
aa5f7a5
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
9d23221 to
293076c
Compare
|
This PR looks quite interesting, will be on my next list of things to review! |
293076c to
7e1fd4c
Compare
dd32c52 to
dc41a17
Compare
55ac529 to
33935c2
Compare
|
@soburi any reaosn to keep this DNM? What's the wait for? |
There are several patches I want to synchronize with the Arduino. |
33935c2 to
34d02a8
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 21 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // create an array of arduino_pins with functions to reinitialize pins if needed | ||
| static const struct device *pinmux_array[DT_PROP_LEN(DT_PATH(zephyr_user), digital_pin_gpios)] = { | ||
| nullptr}; |
There was a problem hiding this comment.
pinmux_array uses DT_PROP_LEN(DT_PATH(zephyr_user), digital_pin_gpios) unconditionally. If /zephyr,user does not define digital-pin-gpios (the connector-derived / “file-less” mode described in this PR), DT_PROP_LEN will not compile. Use DT_PROP_LEN_OR(..., 0) and/or guard the whole pinmux_array/reinit machinery behind DT_NODE_HAS_PROP(..., digital_pin_gpios) (or size it from the connector map length / max pin number).
| static int _analog_write_resolution = 8; | ||
|
|
||
| void analogWriteResolution(int bits) { | ||
| _analog_write_resolution = bits; | ||
| } | ||
|
|
||
| int analogWriteResolution() { | ||
| return _analog_write_resolution; | ||
| } | ||
| #endif | ||
|
|
||
| #ifdef CONFIG_PWM | ||
|
|
||
| static uint32_t map64(uint32_t x, uint32_t in_min, uint32_t in_max, uint32_t out_min, | ||
| uint32_t out_max) { | ||
| return ((uint64_t)(x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min); | ||
| } | ||
|
|
||
| void analogWrite(pin_size_t pinNumber, int value) { | ||
| const int maxInput = BIT(_analog_write_resolution) - 1U; | ||
| size_t idx = pwm_pin_index(pinNumber); |
There was a problem hiding this comment.
analogWriteResolution(int bits) stores bits without validation, but analogWrite() later does BIT(_analog_write_resolution); values <= 0 or >= word size can cause undefined behavior (shift overflow) and incorrect clamping/mapping. Clamp bits to a safe range (e.g., 1..16 or 1..32 depending on desired support) and ensure maxInput is computed safely for edge cases.
|
|
||
| void enableInterrupt(pin_size_t); | ||
| void disableInterrupt(pin_size_t); | ||
| void _reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev); |
There was a problem hiding this comment.
_reinit_peripheral_if_needed is a global C symbol that begins with a leading underscore. Identifiers with a leading underscore at global scope are reserved for the implementation in C/C++, so this name risks conflicts/undefined behavior. Please rename it to a non-reserved identifier (e.g., zarduino_reinit_peripheral_if_needed or similar).
| void _reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev); | |
| void zarduino_reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev); |
| void arduino::ZephyrSPI::begin() { | ||
| spi_dev->ops.init(spi_dev); | ||
| } |
There was a problem hiding this comment.
Calling spi_dev->ops.init() directly reaches into Zephyr internal device ops and may double-initialize the device (or break across Zephyr updates). Prefer relying on standard device init (boot) and/or Zephyr PM/runtime-PM APIs; at minimum, check device_is_ready(spi_dev) before use.
| uart->ops.init(uart); | ||
|
|
||
| uart_configure(uart, &config); |
There was a problem hiding this comment.
Calling uart->ops.init(uart) directly uses Zephyr internal device ops and may cause double initialization or incompatibilities across Zephyr versions. If the goal is to re-enable a UART after end(), consider using Zephyr’s supported device PM/runtime-PM APIs (or avoid manual init entirely) and guard with device_is_ready(uart)/null checks as needed.
| // Note: We can not update the arduino_adc structure as it is read only... | ||
| static int read_resolution = 10; | ||
|
|
||
| void analogReadResolution(int bits) { | ||
| read_resolution = bits; | ||
| } | ||
|
|
||
| int analogReadResolution() { | ||
| return read_resolution; | ||
| } | ||
|
|
There was a problem hiding this comment.
analogReadResolution(int bits) stores bits without validation, but analogRead() later shifts by (read_resolution - seq.resolution). Large values (or <= 0) can lead to undefined behavior due to oversized shifts and nonsensical scaling. Clamp bits to a sensible range (and consider matching Arduino’s typical 1..16 behavior).
| // Allow namespace-less operations if Arduino.h is included | ||
| using namespace arduino; | ||
|
|
There was a problem hiding this comment.
using namespace arduino; in a widely-included public header can unexpectedly pollute the global namespace for all consumers and create name collisions/ambiguity in user sketches and libraries. Prefer exposing only the needed symbols (or provide wrapper typedefs/functions) instead of a global using namespace in the header.
| // Allow namespace-less operations if Arduino.h is included | |
| using namespace arduino; |
| #if DT_NODE_EXISTS(DT_NODELABEL(arduino_header)) && \ | ||
| DT_NODE_HAS_COMPAT(DT_NODELABEL(arduino_header), arduino_header_r3) | ||
| #include "arduino_header_r3.h" | ||
| #else | ||
| #error "Only arduino-header-r3 connector is supported" | ||
| #endif |
There was a problem hiding this comment.
connector.h hard-fails the build with #error when arduino_header is absent or not arduino-header-r3. This prevents the intended “works on any board” / numeric-pin (Level 0) behavior and will break boards that don’t have an Arduino header. Consider making connector support optional (e.g., only enable connector-derived pin mapping when the connector exists; otherwise compile with only numeric/global GPIO APIs and without D/A enums).
| #ifndef __INLINES_H__ | ||
| #define __INLINES_H__ | ||
|
|
There was a problem hiding this comment.
The include guard macro __INLINES_H__ uses a double-underscore identifier, which is reserved in C/C++. Please rename the guard to a non-reserved macro (e.g., ARDUINO_INLINES_H), or use #pragma once for consistency with other headers in this PR.
| void arduino::ZephyrSPI::end() { | ||
| #ifdef CONFIG_DEVICE_DEINIT_SUPPORT | ||
| if (spi_dev->ops.deinit) { | ||
| spi_dev->ops.deinit(spi_dev); | ||
| } | ||
| #endif |
There was a problem hiding this comment.
As with Wire, calling spi_dev->ops.deinit() directly relies on internal Zephyr device details. Please consider switching to a supported deinit/PM API or isolating this behind a core helper so it’s easier to keep compatible with Zephyr device lifecycle changes.
34d02a8 to
949f58a
Compare
d754f16 to
d13186a
Compare
edaf5de to
900de85
Compare
Allow Arduino APIs to switch a pin between GPIO and peripheral functions by re-running the selected device init path when the requested owner changes. This is an interim pinmux handoff mechanism for boards where sketches may move a pin back and forth between serial/GPIO/PWM-style use. Co-Authored-by: Martino Facchin <m.facchin@arduino.cc> Co-Authored-by: pennam <m.pennasilico@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
900de85 to
5e4800f
Compare
Define `invalid_pin_number` and replace `pin_size_t(-1)`. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
In preparation for improvements to allow the use of GPIOs without device tree definitions, the interface will be changed to specify port and pin instead of `gpio_dt_spec`. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Like digital pins, ADCs and PWMs are also defined from connectors. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Add guide for adding new board configuration and configuration reference. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
A new configuration method has been adopted, allowing support to be added with less configuration than before. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
5e4800f to
d7b3c5b
Compare
Replace {0} with {} for port_callback, set dac_channel_cfg::internal
explicitly, and expand the adc_sequence initialization to make default
values explicit and avoid C++ initializer warnings.
Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Move constexpr-specified constants and functions used for compile-time calculations from zephyrCommon.cpp to wiring_private.h. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Split zephyrCommon.cpp into smaller source files. wiring_digital.cpp: - pinMode - digitalWrite - digitalRead wiring_analog.cpp: - analogRead - analogWrite - analogReference - analogReadResolution - analogWriteResolution wiring_pulse.cpp: - pulseIn WInterrupts.cpp: - attachInterrupt - detachInterrupt - interrupts - noInterrupts - digitalPinToInterrupt WMath.cpp: - randomSeed - random Tone.cpp: - tone - noTone Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Move the constant array derived from devicetree to wiring_private.h and convert it to constexpr. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
This PR introduce new configuration system without variants/[board].overlay.
Boards that has arduino like connector mostly has define
arduino-header.We can use this information to configure automatically for each boards.
We can support all zephyr supported that has
arduino-header.That means, we make it works for more 200 boards, including Nucleo series.
However, only Blinky works out of the box, and ADC and PWM channels are required.
These should be made into snippets in the future.
Fix #11
Fix #90