Skip to content

Commit 0f28388

Browse files
facchinmpennam
authored andcommitted
core: add dynamic peripheral init for pinmux switching
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>
1 parent 5146532 commit 0f28388

6 files changed

Lines changed: 40 additions & 0 deletions

File tree

cores/arduino/zephyrCommon.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@
99

1010
#include <zephyr/spinlock.h>
1111

12+
// create an array of arduino_pins with functions to reinitialize pins if needed
13+
static const struct device *pinmux_array[DT_PROP_LEN(DT_PATH(zephyr_user), digital_pin_gpios)] = {
14+
nullptr};
15+
16+
void _reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev) {
17+
if (pinmux_array[pin] != dev) {
18+
pinmux_array[pin] = dev;
19+
if (dev != NULL) {
20+
dev->ops.init(dev);
21+
}
22+
}
23+
}
24+
1225
static const struct gpio_dt_spec arduino_pins[] = {
1326
DT_FOREACH_PROP_ELEM_SEP(
1427
DT_PATH(zephyr_user), digital_pin_gpios, GPIO_DT_SPEC_GET_BY_IDX, (, ))};
@@ -215,6 +228,7 @@ void yield(void) {
215228
* A high physical level will be interpreted as value 1
216229
*/
217230
void pinMode(pin_size_t pinNumber, PinMode pinMode) {
231+
_reinit_peripheral_if_needed(pinNumber, NULL);
218232
if (pinMode == INPUT) { // input mode
219233
gpio_pin_configure_dt(&arduino_pins[pinNumber], GPIO_INPUT | GPIO_ACTIVE_HIGH);
220234
} else if (pinMode == INPUT_PULLUP) { // input with internal pull-up
@@ -407,6 +421,7 @@ void analogWrite(pin_size_t pinNumber, int value) {
407421
return;
408422
}
409423

424+
_reinit_peripheral_if_needed(pinNumber, arduino_pwm[idx].dev);
410425
value = CLAMP(value, 0, maxInput);
411426

412427
const uint32_t pulse = map64(value, 0, maxInput, 0, arduino_pwm[idx].period);
@@ -435,6 +450,9 @@ void analogWrite(enum dacPins dacName, int value) {
435450
return;
436451
}
437452

453+
// TODO: add reverse map to find pin name from DAC* define
454+
// In the meantime, consider A0 == DAC0
455+
_reinit_peripheral_if_needed((pin_size_t)(dacName + A0), dac_dev);
438456
ret = dac_channel_setup(dac_dev, &dac_ch_cfg[dacName]);
439457
if (ret != 0) {
440458
return;
@@ -497,6 +515,8 @@ int analogRead(pin_size_t pinNumber) {
497515
return -ENOTSUP;
498516
}
499517

518+
_reinit_peripheral_if_needed(pinNumber, arduino_adc[idx].dev);
519+
500520
err = adc_channel_setup(arduino_adc[idx].dev, &arduino_adc[idx].channel_cfg);
501521
if (err < 0) {
502522
return err;

cores/arduino/zephyrInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern "C" {
1414

1515
void enableInterrupt(pin_size_t);
1616
void disableInterrupt(pin_size_t);
17+
void _reinit_peripheral_if_needed(pin_size_t pin, const struct device *dev);
1718

1819
#ifdef __cplusplus
1920
} // extern "C"

cores/arduino/zephyrSerial.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ void arduino::ZephyrSerial::begin(unsigned long baud, uint16_t conf) {
5858
.flow_ctrl = UART_CFG_FLOW_CTRL_NONE,
5959
};
6060

61+
uart->ops.init(uart);
62+
6163
uart_configure(uart, &config);
6264
uart_irq_callback_user_data_set(uart, arduino::ZephyrSerial::IrqDispatch, this);
6365
uart_irq_rx_enable(uart);

cores/arduino/zephyrSerial.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ class ZephyrSerial : public HardwareSerial {
7676
}
7777

7878
void end() {
79+
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
80+
if (uart->ops.deinit) {
81+
uart->ops.deinit(uart);
82+
}
83+
#endif
7984
}
8085

8186
size_t write(const uint8_t *buffer, size_t size);

libraries/SPI/SPI.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,15 @@ void arduino::ZephyrSPI::detachInterrupt() {
118118
}
119119

120120
void arduino::ZephyrSPI::begin() {
121+
spi_dev->ops.init(spi_dev);
121122
}
122123

123124
void arduino::ZephyrSPI::end() {
125+
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
126+
if (spi_dev->ops.deinit) {
127+
spi_dev->ops.deinit(spi_dev);
128+
}
129+
#endif
124130
}
125131

126132
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), spis)

libraries/Wire/Wire.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,18 @@ arduino::ZephyrI2C::ZephyrI2C(const struct device *i2c) : i2c_dev(i2c) {
1515

1616
void arduino::ZephyrI2C::begin() {
1717
ring_buf_init(&rxRingBuffer.rb, sizeof(rxRingBuffer.buffer), rxRingBuffer.buffer);
18+
i2c_dev->ops.init(i2c_dev);
1819
}
1920

2021
void arduino::ZephyrI2C::begin(uint8_t slaveAddr) {
2122
}
2223

2324
void arduino::ZephyrI2C::end() {
25+
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
26+
if (i2c_dev->ops.deinit) {
27+
i2c_dev->ops.deinit(i2c_dev);
28+
}
29+
#endif
2430
}
2531

2632
void arduino::ZephyrI2C::setClock(uint32_t freq) {

0 commit comments

Comments
 (0)