From b068fc0202caa7f8317fdc91cd7dff738c8b467b Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 17 Nov 2025 17:19:29 +0100 Subject: [PATCH 1/2] core: pinmux: implement rough solution 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 --- cores/arduino/zephyrCommon.cpp | 20 ++++++++++++++++++++ cores/arduino/zephyrInternal.h | 1 + cores/arduino/zephyrSerial.cpp | 2 ++ cores/arduino/zephyrSerial.h | 3 +++ libraries/SPI/SPI.cpp | 4 ++++ libraries/Wire/Wire.cpp | 4 ++++ loader/prj.conf | 2 ++ 7 files changed, 36 insertions(+) diff --git a/cores/arduino/zephyrCommon.cpp b/cores/arduino/zephyrCommon.cpp index 64a0f712a..cb3358157 100644 --- a/cores/arduino/zephyrCommon.cpp +++ b/cores/arduino/zephyrCommon.cpp @@ -7,6 +7,19 @@ #include #include "zephyrInternal.h" +// 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}; + +void _reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev) { + if (pinmux_array[pin] != dev) { + pinmux_array[pin] = dev; + if (dev != NULL) { + dev->ops.init(dev); + } + } +} + static const struct gpio_dt_spec arduino_pins[] = { DT_FOREACH_PROP_ELEM_SEP( DT_PATH(zephyr_user), digital_pin_gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))}; @@ -209,6 +222,7 @@ void yield(void) { * A high physical level will be interpreted as value 1 */ void pinMode(pin_size_t pinNumber, PinMode pinMode) { + _reinit_peripheral_if_needed(pinNumber, NULL); if (pinMode == INPUT) { // input mode gpio_pin_configure_dt(&arduino_pins[pinNumber], GPIO_INPUT | GPIO_ACTIVE_HIGH); } else if (pinMode == INPUT_PULLUP) { // input with internal pull-up @@ -320,6 +334,7 @@ void analogWrite(pin_size_t pinNumber, int value) { return; } + _reinit_peripheral_if_needed(pinNumber, arduino_pwm[idx].dev); value = map(value, 0, 1 << _analog_write_resolution, 0, arduino_pwm[idx].period); if (((uint32_t)value) > arduino_pwm[idx].period) { @@ -343,6 +358,9 @@ void analogWrite(enum dacPins dacName, int value) { return; } + // TODO: add reverse map to find pin name from DAC* define + // In the meantime, consider A0 == DAC0 + _reinit_peripheral_if_needed((pin_size_t)(dacName + A0), dac_dev); dac_channel_setup(dac_dev, &dac_ch_cfg[dacName]); const int max_dac_value = 1U << dac_ch_cfg[dacName].resolution; @@ -393,6 +411,8 @@ int analogRead(pin_size_t pinNumber) { return -ENOTSUP; } + _reinit_peripheral_if_needed(pinNumber, arduino_adc[idx].dev); + err = adc_channel_setup(arduino_adc[idx].dev, &arduino_adc[idx].channel_cfg); if (err < 0) { return err; diff --git a/cores/arduino/zephyrInternal.h b/cores/arduino/zephyrInternal.h index b07e1bd9c..e3938e603 100644 --- a/cores/arduino/zephyrInternal.h +++ b/cores/arduino/zephyrInternal.h @@ -14,6 +14,7 @@ extern "C" { void enableInterrupt(pin_size_t); void disableInterrupt(pin_size_t); +void _reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev); #ifdef __cplusplus } // extern "C" diff --git a/cores/arduino/zephyrSerial.cpp b/cores/arduino/zephyrSerial.cpp index 2ebece7b9..a9e0b2951 100644 --- a/cores/arduino/zephyrSerial.cpp +++ b/cores/arduino/zephyrSerial.cpp @@ -59,6 +59,8 @@ void arduino::ZephyrSerial::begin(unsigned long baud, uint16_t conf) { .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, }; + uart->ops.init(uart); + uart_configure(uart, &config); uart_irq_callback_user_data_set(uart, arduino::ZephyrSerial::IrqDispatch, this); k_sem_take(&rx.sem, K_FOREVER); diff --git a/cores/arduino/zephyrSerial.h b/cores/arduino/zephyrSerial.h index 5e1d15fe7..46ee1b1d7 100644 --- a/cores/arduino/zephyrSerial.h +++ b/cores/arduino/zephyrSerial.h @@ -75,6 +75,9 @@ class ZephyrSerial : public HardwareSerial { void flush(); void end() { + if (uart->ops.deinit) { + uart->ops.deinit(uart); + } } size_t write(const uint8_t *buffer, size_t size); diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index 1a0b39115..77caa2e7a 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -115,9 +115,13 @@ void arduino::ZephyrSPI::detachInterrupt() { } void arduino::ZephyrSPI::begin() { + spi_dev->ops.init(spi_dev); } void arduino::ZephyrSPI::end() { + if (spi_dev->ops.deinit) { + spi_dev->ops.deinit(spi_dev); + } } #if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), spis) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index 18ec6140c..d8cc06e5d 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -54,6 +54,7 @@ arduino::ZephyrI2C::ZephyrI2C(const struct device *i2c) : i2c_dev(i2c), i2c_cfg( } void arduino::ZephyrI2C::begin() { + i2c_dev->ops.init(i2c_dev); } void arduino::ZephyrI2C::begin(uint8_t slaveAddr) { @@ -70,6 +71,9 @@ void arduino::ZephyrI2C::end() { i2c_target_unregister(i2c_dev, &i2c_cfg); memset(&i2c_cfg, 0, sizeof(i2c_cfg)); } + if (i2c_dev->ops.deinit) { + i2c_dev->ops.deinit(i2c_dev); + } } void arduino::ZephyrI2C::setClock(uint32_t freq) { diff --git a/loader/prj.conf b/loader/prj.conf index 99c2c7172..399ceccc7 100644 --- a/loader/prj.conf +++ b/loader/prj.conf @@ -30,6 +30,8 @@ CONFIG_LLEXT_EDK_FORMAT_TAR_ZSTD=y CONFIG_GPIO=y CONFIG_PINCTRL=y +CONFIG_PINCTRL_DYNAMIC=y +CONFIG_DEVICE_DEINIT_SUPPORT=y CONFIG_I2C=y CONFIG_SPI=y From 505c6f6c2168fa0e4cbc2427ed7c290a5789ca15 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 17 Nov 2025 17:22:41 +0100 Subject: [PATCH 2/2] unoq: restore conflicting PWMs and DACs --- .../arduino_uno_q_stm32u585xx.overlay | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/variants/arduino_uno_q_stm32u585xx/arduino_uno_q_stm32u585xx.overlay b/variants/arduino_uno_q_stm32u585xx/arduino_uno_q_stm32u585xx.overlay index b37c40282..65639c739 100644 --- a/variants/arduino_uno_q_stm32u585xx/arduino_uno_q_stm32u585xx.overlay +++ b/variants/arduino_uno_q_stm32u585xx/arduino_uno_q_stm32u585xx.overlay @@ -75,15 +75,13 @@ status = "okay"; /* tim1_etr_pa12 is not available for PWM */ /* Currently only the pins marked with ~ on the pin headers are enabled */ - /* pinctrl-0 = <&tim1_ch4_pa11 &tim1_ch3n_pb15 &tim1_ch1n_pb13 &tim1_ch2n_pb14>; */ - pinctrl-0 = <&tim1_ch4_pa11>; + pinctrl-0 = <&tim1_ch4_pa11 &tim1_ch3n_pb15 &tim1_ch1n_pb13 &tim1_ch2n_pb14>; pinctrl-names = "default"; }; }; /* Currently only the pins marked with ~ on the pin headers are enabled */ /* PB10 and PB11 conflict with I2C configuation */ -/* &timers2 { status = "okay"; st,prescaler = <4>; @@ -94,7 +92,6 @@ pinctrl-names = "default"; }; }; -*/ &timers3 { status = "okay"; @@ -103,8 +100,7 @@ pwm3: pwm { status = "okay"; /* Currently only the pins marked with ~ on the pin headers are enabled */ - /* pinctrl-0 = <&tim3_ch3_pb0 &tim3_ch4_pb1 &tim3_ch1_pb4>; */ - pinctrl-0 = <&tim3_ch3_pb0 &tim3_ch4_pb1>; + pinctrl-0 = <&tim3_ch3_pb0 &tim3_ch4_pb1 &tim3_ch1_pb4>; pinctrl-names = "default"; }; }; @@ -117,8 +113,7 @@ status = "okay"; /* PB6 PB7 not usable for PWM until dynamic pin muxing works */ /* Currently only the pins marked with ~ on the pin headers are enabled */ - /* pinctrl-0 = <&tim4_ch3_pb8 &tim4_ch4_pb9 &tim4_ch1_pb6 &tim4_ch2_pb7>; */ - pinctrl-0 = <&tim4_ch3_pb8 &tim4_ch4_pb9>; + pinctrl-0 = <&tim4_ch3_pb8 &tim4_ch4_pb9 &tim4_ch1_pb6 &tim4_ch2_pb7>; pinctrl-names = "default"; }; }; @@ -135,7 +130,6 @@ }; /* Currently only the pins marked with ~ on the pin headers are enabled */ -/* &timers8 { status = "okay"; st,prescaler = <4>; @@ -146,7 +140,6 @@ pinctrl-names = "default"; }; }; -*/ &timers16 { status = "okay"; @@ -258,25 +251,25 @@ /* PWM pin mapping - Digital pins with their timer channels */ /* Currently only the pins marked with ~ on the pin headers are enabled */ - pwm-pin-gpios = - /* <&gpiob 6 0>, */ /* D1/PB6 - TIM4_CH1 */ - /* <&gpiob 3 0>, */ /* D2/PB3 - TIM2_CH2 */ - /* <&gpiob 3 0>, */ /* D2/PB3 - TIM2_CH2 */ - <&gpiob 0 0>, /* D3/PB0 - TIM3_CH3 */ - <&gpioa 11 0>, /* D5/PA11 - TIM1_CH4 */ - <&gpiob 1 0>, /* D6/PB1 - TIM3_CH4 */ - /* <&gpiob 2 0>, */ /* D7/PB2 - TIM8_CH4N */ - /* <&gpiob 4 0>, */ /* D8/PB4 - TIM3_CH1 */ - <&gpiob 8 0>, /* D9/PB8 - TIM4_CH3 */ - <&gpiob 9 0>, /* D10/PB9 - TIM4_CH4 */ - /* <&gpiob 15 0>, */ /* D11/PB15 - TIM1_CH3N */ - /* <&gpiob 14 0>, */ /* D12/PB14 - TIM1_CH2N */ - /* <&gpiob 13 0>, */ /* D13/PB13 - TIM1_CH1N */ - /* <&gpiob 11 0>, */ /* D20/PB11 - TIM2_CH4 */ - /* <&gpiob 10 0>; */ /* D21/PB10 - TIM2_CH3 */ - <&gpioh 10 0>, /* LED3_R - TIM5_CH1 */ - <&gpioh 11 0>, /* LED3_G - TIM5_CH2 */ - <&gpioh 12 0>; /* LED3_B - TIM5_CH3 */ + pwm-pin-gpios = + <&gpiob 7 0>, /* D0/PB6 - TIM4_CH2 */ + <&gpiob 6 0>, /* D1/PB6 - TIM4_CH1 */ + <&gpiob 3 0>, /* D2/PB3 - TIM2_CH2 */ + <&gpiob 0 0>, /* D3/PB0 - TIM3_CH3 */ + <&gpioa 11 0>, /* D5/PA11 - TIM1_CH4 */ + <&gpiob 1 0>, /* D6/PB1 - TIM3_CH4 */ + <&gpiob 2 0>, /* D7/PB2 - TIM8_CH4N */ + <&gpiob 4 0>, /* D8/PB4 - TIM3_CH1 */ + <&gpiob 8 0>, /* D9/PB8 - TIM4_CH3 */ + <&gpiob 9 0>, /* D10/PB9 - TIM4_CH4 */ + <&gpiob 15 0>, /* D11/PB15 - TIM1_CH3N */ + <&gpiob 14 0>, /* D12/PB14 - TIM1_CH2N */ + <&gpiob 13 0>, /* D13/PB13 - TIM1_CH1N */ + <&gpiob 11 0>, /* D20/PB11 - TIM2_CH4 */ + <&gpiob 10 0>, /* D21/PB10 - TIM2_CH3 */ + <&gpioh 10 0>, /* LED3_R - TIM5_CH1 */ + <&gpioh 11 0>, /* LED3_G - TIM5_CH2 */ + <&gpioh 12 0>; /* LED3_B - TIM5_CH3 */ adc-pin-gpios = <&gpioa 4 0>, <&gpioa 5 0>, @@ -290,22 +283,22 @@ spis = <&spi2>, <&spi3>; /* PWM mapping for the digital pins */ /* Currently only the pins marked with ~ on the pin headers are enabled */ - pwms = - /* <&pwm4 2 PWM_HZ(500) PWM_POLARITY_NORMAL>, */ /* D0/PB7 → TIM4_CH2 */ - /* <&pwm4 1 PWM_HZ(500) PWM_POLARITY_NORMAL>, */ /* D1/PB6 → TIM4_CH1 */ - /* <&pwm2 2 PWM_HZ(500) PWM_POLARITY_NORMAL>, */ /* D2/PB3 → TIM2_CH2 */ + pwms = + <&pwm4 2 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D0/PB7 → TIM4_CH2 */ + <&pwm4 1 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D1/PB6 → TIM4_CH1 */ + <&pwm2 2 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D2/PB3 → TIM2_CH2 */ <&pwm3 3 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D3/PB0 → TIM3_CH3 */ <&pwm1 4 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D5/PA11 → TIM1_CH4 */ <&pwm3 4 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D6/PB1 → TIM3_CH4 */ - /* <&pwm8 4 PWM_HZ(500) PWM_POLARITY_INVERTED>, */ /* D7/PB2 → TIM8_CH4N */ - /* <&pwm3 1 PWM_HZ(500) PWM_POLARITY_NORMAL>, */ /* D8/PB4 → TIM3_CH1 */ + <&pwm8 4 PWM_HZ(500) PWM_POLARITY_INVERTED>, /* D7/PB2 → TIM8_CH4N */ + <&pwm3 1 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D8/PB4 → TIM3_CH1 */ <&pwm4 3 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D9/PB8 → TIM4_CH3 */ <&pwm4 4 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D10/PB9 → TIM4_CH4 */ - /* <&pwm1 3 PWM_HZ(500) PWM_POLARITY_INVERTED>, */ /* D11/PB15 → TIM1_CH3N */ - /* <&pwm1 2 PWM_HZ(500) PWM_POLARITY_INVERTED>, */ /* D12/PB14 → TIM1_CH2N */ - /* <&pwm1 1 PWM_HZ(500) PWM_POLARITY_INVERTED>, */ /* D13/PB13 → TIM1_CH1N */ - /* <&pwm2 4 PWM_HZ(500) PWM_POLARITY_NORMAL>, */ /* D20/PB11 → TIM2_CH4 */ - /* <&pwm2 3 PWM_HZ(500) PWM_POLARITY_NORMAL>; */ /* D21/PB10 → TIM2_CH3 */ + <&pwm1 3 PWM_HZ(500) PWM_POLARITY_INVERTED>, /* D11/PB15 → TIM1_CH3N */ + <&pwm1 2 PWM_HZ(500) PWM_POLARITY_INVERTED>, /* D12/PB14 → TIM1_CH2N */ + <&pwm1 1 PWM_HZ(500) PWM_POLARITY_INVERTED>, /* D13/PB13 → TIM1_CH1N */ + <&pwm2 4 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D20/PB11 → TIM2_CH4 */ + <&pwm2 3 PWM_HZ(500) PWM_POLARITY_NORMAL>, /* D21/PB10 → TIM2_CH3 */ <&pwm5 1 PWM_HZ(500) PWM_POLARITY_INVERTED>, /* LED3_R/PH10 → TIM5_CH1 */ <&pwm5 2 PWM_HZ(500) PWM_POLARITY_INVERTED>, /* LED3_G/PH11 → TIM5_CH2 */ <&pwm5 3 PWM_HZ(500) PWM_POLARITY_INVERTED>; /* LED3_B/PH12 → TIM5_CH3 */ @@ -320,6 +313,9 @@ <&adc1 2>, /* A4 - PC1 */ <&adc1 1>; /* A5 - PC0 */ + dac-pin-gpios = <&gpioa 4 0>, + <&gpioa 5 0>; + dac = <&dac1>; dac-channels = <1>, <2>; dac-resolution = <12>;