Skip to content

Support "file-less" configuration#151

Draft
soburi wants to merge 28 commits intozephyrproject-rtos:nextfrom
soburi:configure_by_connector_def
Draft

Support "file-less" configuration#151
soburi wants to merge 28 commits intozephyrproject-rtos:nextfrom
soburi:configure_by_connector_def

Conversation

@soburi
Copy link
Copy Markdown
Member

@soburi soburi commented Feb 1, 2026

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

@soburi soburi force-pushed the configure_by_connector_def branch from 30e80c9 to 2157ae2 Compare February 1, 2026 15:38
@soburi soburi changed the title Configure by connector def Support **file-less** configuration Feb 1, 2026
@soburi soburi changed the title Support **file-less** configuration Support "file-less" configuration Feb 1, 2026
@soburi soburi force-pushed the configure_by_connector_def branch 2 times, most recently from d14bab2 to 769f878 Compare February 5, 2026 15:17
@soburi soburi marked this pull request as ready for review February 5, 2026 15:17
Copilot AI review requested due to automatic review settings February 5, 2026 15:17
@soburi soburi marked this pull request as draft February 5, 2026 15:17
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/Arduino.h Outdated
Comment thread cores/arduino/zephyrCommon.cpp
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread samples/tone_doremi/src/app.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/Arduino.h
Comment thread cores/arduino/zephyrCommon.cpp Outdated
Comment thread cores/arduino/zephyrCommon.cpp Outdated
@soburi soburi force-pushed the configure_by_connector_def branch 3 times, most recently from 9d23221 to 293076c Compare February 9, 2026 10:57
@DhruvaG2000
Copy link
Copy Markdown
Member

This PR looks quite interesting, will be on my next list of things to review!

@soburi soburi force-pushed the configure_by_connector_def branch from 293076c to 7e1fd4c Compare February 9, 2026 14:23
Comment thread variants/arduino_uno_r4_r7fa4m1ab3cfm/variant.h Outdated
@soburi soburi force-pushed the configure_by_connector_def branch 8 times, most recently from dd32c52 to dc41a17 Compare February 11, 2026 03:46
@soburi soburi requested a review from Copilot February 11, 2026 04:41
soburi and others added 19 commits April 25, 2026 14:34
…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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +13 to +15
// 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};
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment on lines +651 to 671
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);
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.

void enableInterrupt(pin_size_t);
void disableInterrupt(pin_size_t);
void _reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev);
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_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).

Suggested change
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);

Copilot uses AI. Check for mistakes.
Comment thread libraries/SPI/SPI.cpp
Comment on lines 120 to 122
void arduino::ZephyrSPI::begin() {
spi_dev->ops.init(spi_dev);
}
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +61 to 63
uart->ops.init(uart);

uart_configure(uart, &config);
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +750 to +760
// 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;
}

Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment thread cores/arduino/Arduino.h
Comment on lines +197 to +199
// Allow namespace-less operations if Arduino.h is included
using namespace arduino;

Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
// Allow namespace-less operations if Arduino.h is included
using namespace arduino;

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +14
#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
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment thread cores/arduino/inlines.h
Comment on lines +11 to +13
#ifndef __INLINES_H__
#define __INLINES_H__

Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment thread libraries/SPI/SPI.cpp
Comment on lines 124 to +129
void arduino::ZephyrSPI::end() {
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
if (spi_dev->ops.deinit) {
spi_dev->ops.deinit(spi_dev);
}
#endif
Copy link

Copilot AI Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
facchinm and others added 9 commits April 25, 2026 14:40
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>
@soburi soburi force-pushed the configure_by_connector_def branch from 34d02a8 to 949f58a Compare April 25, 2026 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DNM This PR should not be merged (Do Not Merge)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Builds fail if variant does not have any GPIOs Autogenerate board support

9 participants