diff --git a/libraries/SPI/keywords.txt b/libraries/SPI/keywords.txt index c21a9ecc6..14ba8f17a 100644 --- a/libraries/SPI/keywords.txt +++ b/libraries/SPI/keywords.txt @@ -14,6 +14,9 @@ SPI1 KEYWORD1 ####################################### begin KEYWORD2 end KEYWORD2 +beginTransaction KEYWORD2 +endTransaction KEYWORD2 +SPISettings KEYWORD2 transfer KEYWORD2 setBitOrder KEYWORD2 setDataMode KEYWORD2 diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 3d0dd500c..fa526afb8 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -21,6 +21,8 @@ #include "SPI.h" #include #include +#include +#include #ifdef USE_TINYUSB // For Serial when selecting TinyUSB. Can't include in the core because Arduino IDE @@ -191,10 +193,33 @@ void SPIClassRP2040::beginTransaction(SPISettings settings) { DEBUGSPI("SPI: actual baudrate=%u\n", spi_get_baudrate(_spi)); _initted = true; } + // Disable any IRQs that are being used for SPI + io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl; + DEBUGSPI("SPI: IRQ masks before = %08x %08x %08x %08x\n", (unsigned)irq_ctrl_base->inte[0], (unsigned)irq_ctrl_base->inte[1], (unsigned)irq_ctrl_base->inte[2], (unsigned)irq_ctrl_base->inte[3]); + for (auto entry : _usingIRQs) { + int gpio = entry.first; + + // There is no gpio_get_irq, so manually twiddle the register + io_rw_32 *en_reg = &irq_ctrl_base->inte[gpio / 8]; + uint32_t val = ((*en_reg) >> (4 * (gpio % 8))) & 0xf; + _usingIRQs.insert_or_assign(gpio, val); + DEBUGSPI("SPI: GPIO %d = %d\n", gpio, val); + (*en_reg) ^= val << (4 * (gpio % 8)); + } + DEBUGSPI("SPI: IRQ masks after = %08x %08x %08x %08x\n", (unsigned)irq_ctrl_base->inte[0], (unsigned)irq_ctrl_base->inte[1], (unsigned)irq_ctrl_base->inte[2], (unsigned)irq_ctrl_base->inte[3]); } void SPIClassRP2040::endTransaction(void) { DEBUGSPI("SPI::endTransaction()\n"); + // Re-enablke IRQs + for (auto entry : _usingIRQs) { + int gpio = entry.first; + int mode = entry.second; + gpio_set_irq_enabled(gpio, mode, true); + } + io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl; + (void) irq_ctrl_base; + DEBUGSPI("SPI: IRQ masks = %08x %08x %08x %08x\n", (unsigned)irq_ctrl_base->inte[0], (unsigned)irq_ctrl_base->inte[1], (unsigned)irq_ctrl_base->inte[2], (unsigned)irq_ctrl_base->inte[3]); } bool SPIClassRP2040::setRX(pin_size_t pin) { @@ -292,6 +317,7 @@ void SPIClassRP2040::begin(bool hwCS) { gpio_set_function(_TX, GPIO_FUNC_SPI); // Give a default config in case user doesn't use beginTransaction beginTransaction(_spis); + endTransaction(); } void SPIClassRP2040::end() { @@ -312,11 +338,13 @@ void SPIClassRP2040::end() { void SPIClassRP2040::setBitOrder(BitOrder order) { _spis = SPISettings(_spis.getClockFreq(), order, _spis.getDataMode()); beginTransaction(_spis); + endTransaction(); } void SPIClassRP2040::setDataMode(uint8_t uc_mode) { _spis = SPISettings(_spis.getClockFreq(), _spis.getBitOrder(), uc_mode); beginTransaction(_spis); + endTransaction(); } void SPIClassRP2040::setClockDivider(uint8_t uc_div) { diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 44b1e8648..70daacbeb 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -23,6 +23,7 @@ #include #include #include +#include class SPIClassRP2040 : public arduino::HardwareSPI { public: @@ -62,10 +63,10 @@ class SPIClassRP2040 : public arduino::HardwareSPI { // Unimplemented virtual void usingInterrupt(int interruptNumber) override { - (void) interruptNumber; + _usingIRQs.insert({interruptNumber, 0}); } virtual void notUsingInterrupt(int interruptNumber) override { - (void) interruptNumber; + _usingIRQs.erase(interruptNumber); } virtual void attachInterrupt() override { /* noop */ } virtual void detachInterrupt() override { /* noop */ } @@ -83,6 +84,8 @@ class SPIClassRP2040 : public arduino::HardwareSPI { bool _hwCS; bool _running; // SPI port active bool _initted; // Transaction begun + + std::map _usingIRQs; }; extern SPIClassRP2040 SPI;