diff --git a/cores/arduino/zephyrCommon.cpp b/cores/arduino/zephyrCommon.cpp index 9dfe2010..619c0bdf 100644 --- a/cores/arduino/zephyrCommon.cpp +++ b/cores/arduino/zephyrCommon.cpp @@ -5,6 +5,7 @@ */ #include +#include "zephyrInternal.h" namespace { @@ -68,9 +69,14 @@ const int max_ngpios = max_in_list( * GPIO callback implementation */ +struct arduino_callback { + voidFuncPtr handler; + bool enabled; +}; + struct gpio_port_callback { struct gpio_callback callback; - voidFuncPtr handlers[max_ngpios]; + struct arduino_callback handlers[max_ngpios]; gpio_port_pins_t pins; const struct device *dev; } port_callback[port_num] = {0}; @@ -95,7 +101,7 @@ void setInterruptHandler(pin_size_t pinNumber, voidFuncPtr func) struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port); if (pcb) { - pcb->handlers[BIT(arduino_pins[pinNumber].pin)] = func; + pcb->handlers[BIT(arduino_pins[pinNumber].pin)].handler = func; } } @@ -104,8 +110,8 @@ void handleGpioCallback(const struct device *port, struct gpio_callback *cb, uin struct gpio_port_callback *pcb = (struct gpio_port_callback *)cb; for (uint32_t i = 0; i < max_ngpios; i++) { - if (pins & BIT(i)) { - pcb->handlers[BIT(i)](); + if (pins & BIT(i) && pcb->handlers[BIT(i)].enabled) { + pcb->handlers[BIT(i)].handler(); } } } @@ -321,6 +327,7 @@ void attachInterrupt(pin_size_t pinNumber, voidFuncPtr callback, PinStatus pinSt pcb->pins |= BIT(arduino_pins[pinNumber].pin); setInterruptHandler(pinNumber, callback); + enableInterrupt(pinNumber); gpio_pin_interrupt_configure(arduino_pins[pinNumber].port, arduino_pins[pinNumber].pin, intmode); gpio_init_callback(&pcb->callback, handleGpioCallback, pcb->pins); @@ -330,6 +337,7 @@ void attachInterrupt(pin_size_t pinNumber, voidFuncPtr callback, PinStatus pinSt void detachInterrupt(pin_size_t pinNumber) { setInterruptHandler(pinNumber, nullptr); + disableInterrupt(pinNumber); } #ifndef CONFIG_MINIMAL_LIBC_RAND @@ -349,3 +357,19 @@ long random(long max) { } #endif + +void enableInterrupt(pin_size_t pinNumber) { + struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port); + + if (pcb) { + pcb->handlers[BIT(arduino_pins[pinNumber].pin)].enabled = true; + } +} + +void disableInterrupt(pin_size_t pinNumber) { + struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port); + + if (pcb) { + pcb->handlers[BIT(arduino_pins[pinNumber].pin)].enabled = false; + } +} diff --git a/cores/arduino/zephyrInternal.h b/cores/arduino/zephyrInternal.h new file mode 100644 index 00000000..b07e1bd9 --- /dev/null +++ b/cores/arduino/zephyrInternal.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Ayush Singh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void enableInterrupt(pin_size_t); +void disableInterrupt(pin_size_t); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index 1b2ed16e..29a18153 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -5,6 +5,7 @@ */ #include "SPI.h" +#include "zephyrInternal.h" #include /* Serial Peripheral Control Register */ @@ -75,9 +76,19 @@ void arduino::ZephyrSPI::transfer(void *buf, size_t count) { } } -void arduino::ZephyrSPI::usingInterrupt(int interruptNumber) {} +void arduino::ZephyrSPI::usingInterrupt(int interruptNumber) { + interrupt[interrupt_pos++] = interruptNumber; +} -void arduino::ZephyrSPI::notUsingInterrupt(int interruptNumber) {} +void arduino::ZephyrSPI::notUsingInterrupt(int interruptNumber) { + for (size_t i = 0; i < interrupt_pos; ++i) { + if (interrupt[i] == interruptNumber) { + memmove(&interrupt[i], &interrupt[i + 1], interrupt_pos - i - 1); + interrupt_pos--; + break; + } + } +} void arduino::ZephyrSPI::beginTransaction(SPISettings settings) { memset(&config, 0, sizeof(config)); @@ -85,13 +96,26 @@ void arduino::ZephyrSPI::beginTransaction(SPISettings settings) { config.operation = ((settings.getBitOrder() ^ 1) << 4) | (settings.getDataMode() << 1) | ((SPCR >> MSTR) & 1) | SPI_WORD_SET(8); + + detachInterrupt(); } -void arduino::ZephyrSPI::endTransaction(void) { spi_release(spi_dev, &config); } +void arduino::ZephyrSPI::endTransaction(void) { + spi_release(spi_dev, &config); + attachInterrupt(); +} -void arduino::ZephyrSPI::attachInterrupt() {} +void arduino::ZephyrSPI::attachInterrupt() { + for (size_t i = 0; i < interrupt_pos; ++i) { + enableInterrupt(interrupt[i]); + } +} -void arduino::ZephyrSPI::detachInterrupt() {} +void arduino::ZephyrSPI::detachInterrupt() { + for (size_t i = 0; i < interrupt_pos; ++i) { + disableInterrupt(interrupt[i]); + } +} void arduino::ZephyrSPI::begin() {} diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index c873156d..ff9d96ba 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -19,6 +19,12 @@ #define SPE 6 #define SPIE 7 +/* Count the number of GPIOs for limit of number of interrupts */ +#define INTERRUPT_HELPER(n, p, i) 1 +#define INTERRUPT_COUNT \ + DT_FOREACH_PROP_ELEM_SEP(DT_PATH(zephyr_user), digital_pin_gpios, \ + INTERRUPT_HELPER, (+)) + namespace arduino { class ZephyrSPI : public HardwareSPI { public: @@ -43,7 +49,9 @@ class ZephyrSPI : public HardwareSPI { private: const struct device *spi_dev; - struct spi_config config; + struct spi_config config; + int interrupt[INTERRUPT_COUNT]; + size_t interrupt_pos = 0; }; } // namespace arduino