Support "file-less" configuration#151
Support "file-less" configuration#151soburi wants to merge 28 commits intozephyrproject-rtos:nextfrom
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
…ecycle Rework tone/noTone internals to better match Arduino behavior while making concurrent tone usage configurable and safer. - Add CONFIG_ARDUINO_MAX_TONES (default: -1). - Negative values fall back to the digital pin count from devicetree. - Replace per-pin tone timer arrays with slot-based pin_timer entries. - Remove the timeout companion timer and finish finite tones by counting remaining toggles in tone_expiry_cb(). Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
experimental results here arduino#332 (comment) On boards with different clock speed, function call overhead etc. the results may vary but will likely be consistent, given that all the boards share CONFIG_SYS_CLOCK_TICKS_PER_SEC Co-authored-by: Martino Facchin <m.facchin@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Fixes compilation error found at https://www.cnx-software.com/2024/12/10/arduino-core-for-zephyr-beta-released/ Co-Authored-by: Martino Facchin <m.facchin@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Place the implementation for delay() and delayMicroseconds() in a separate header file, and include it from Arduino.h. This allows the functions to be properly inlined, which is important for performance, especially for delayMicroseconds(). Signed-off-by: Luca Burelli <l.burelli@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Explicitly state the license in all source files to comply with SPDX best practices. In addition, update the copyright notice to the new format. Note: Applied only cores/arduino/time_macros.h on cherry-pick time. Co-Authored-by: Luca Burelli <l.burelli@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Co-Authored-by: Martino Facchin <m.facchin@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Co-Authored-by: Kurt Eckhardt <kurte@rockisland.com> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Take into account the analog switch Co-Authored-by: Martino Facchin <m.facchin@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Co-Authored-by: Martino Facchin <m.facchin@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Co-Authored-by: Martino Facchin <m.facchin@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Formatting ADC/DAC codes. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
- Remove duplicated `analogReadResolution` declaration - Add the same #ifdef conditions used in the implementation to the `analogWriteResolution` as well. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
- Fixed input max value calculation (Needs to be -1 after shift) - Clamp calculations are performed first, eliminating cast Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
- Correct max value calculation - Add guard for DAC entry is not defined case - initialize only if DAC not initialized Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Co-Authored-by: Giovanni Bruno <g.bruno@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Explicitly state the license in all source files to comply with SPDX
best practices. In addition, update the copyright notice to the new
format.
Note: At the time of cherry-picking, this was applied only to
cores/arduino/time_macros.h and
cores/arduino/overloads.h.
Co-Authored-by: Luca Burelli <l.burelli@arduino.cc>
Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
While we prepare a cleaner solution, this patch allows back and forth between pinmuxes.
Tested on UNO Q with next patch in the series and this sketch
void loop() {
Serial.begin(115200);
Serial.println("helloooooo");
delay(20);
Serial.end();
delay(20);
pinMode(1, OUTPUT);
digitalWrite(1, HIGH);
delay(10);
digitalWrite(1, LOW);
delay(100);
analogWrite(1, 33);
}
Pin 1 correctly prints the string, muxes as GPIo and then produces the required PWM
Co-Authored-by: Martino Facchin <m.facchin@arduino.cc>
Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
…ifdefs Co-Authored-by: pennam <m.pennasilico@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
Passing -1 to digital I/O functions may happen when libraries do not properly sanitize their inputs, leading to undefined behavior. This commit adds a check to ensure that the pin number is valid before accessing the arduino_pins array. Signed-off-by: Luca Burelli <l.burelli@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
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.
Allows compatibility with a broad set of libraries, like Adafruit's NeoPixel Co-Authored-by: Martino Facchin <m.facchin@arduino.cc> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
On Arduino Uno Q, calling analogWrite() on any pin silently returns without doing anything in two cases: 1. When pwm_pin_index() cannot find the pin in the arduino_pwm_pins[] lookup table (idx >= ARRAY_SIZE(arduino_pwm)) 2. When pwm_is_ready_dt() returns false for the PWM device This causes analogWrite() to appear completely broken to users - no output, no error, no warning. The function just silently does nothing. The pwm-pin-gpios mapping in the Uno Q device tree overlay is missing some pins (D0, D1, D4 are absent or commented out). This means pwm_pin_index() returns (size_t)-1 for those pins, which is always >= ARRAY_SIZE(arduino_pwm), causing an immediate silent return. Added a digitalWrite() fallback in both early-return paths: - If PWM lookup fails → fall back to digitalWrite HIGH/LOW - If PWM device not ready → fall back to digitalWrite HIGH/LOW This ensures analogWrite() always produces some output even when hardware PWM is unavailable, which is consistent with how other Arduino cores handle non-PWM pins. Tested on Arduino Uno Q with: - Motor driver (SmartElex L298N integrated board) - Confirmed analogWrite() was completely silent before fix - Confirmed digitalWrite() fallback works correctly after fix - Pins tested: 3, 4, 5, 6, 7, 8, 9, 10 - No breaking changes - Existing PWM functionality unchanged - Non-PWM pins now behave like standard Arduino (HIGH if value > 127) - Fixes user confusion when analogWrite() silently does nothing Co-Authored-by: Satvik <145106491+vs11official@users.noreply.github.com> Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
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>
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>
…nition Like digital pins, PWMs are also defined from connectors. Signed-off-by: TOKITA Hiroshi <tokita.hiroshi@gmail.com>
…nition Like digital pins, ADCs 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>
34d02a8 to
949f58a
Compare
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