Skip to content

Commit

Permalink
Support IRQ disabled SPI transactions (#1714)
Browse files Browse the repository at this point in the history
Fixes #1147

When SPI.beginTransaction() is called, disable all GPIO IRQs that were
registered using SPI.usingInterrupt().  On SPI.endTransaction(), restore
all the IRQs to their prior state.
  • Loading branch information
earlephilhower committed Sep 16, 2023
1 parent 0ed1f3d commit 0be7c98
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
3 changes: 3 additions & 0 deletions libraries/SPI/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ SPI1 KEYWORD1
#######################################
begin KEYWORD2
end KEYWORD2
beginTransaction KEYWORD2
endTransaction KEYWORD2
SPISettings KEYWORD2
transfer KEYWORD2
setBitOrder KEYWORD2
setDataMode KEYWORD2
Expand Down
28 changes: 28 additions & 0 deletions libraries/SPI/src/SPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "SPI.h"
#include <hardware/spi.h>
#include <hardware/gpio.h>
#include <hardware/structs/iobank0.h>
#include <hardware/irq.h>

#ifdef USE_TINYUSB
// For Serial when selecting TinyUSB. Can't include in the core because Arduino IDE
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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() {
Expand All @@ -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) {
Expand Down
7 changes: 5 additions & 2 deletions libraries/SPI/src/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <Arduino.h>
#include <api/HardwareSPI.h>
#include <hardware/spi.h>
#include <map>

class SPIClassRP2040 : public arduino::HardwareSPI {
public:
Expand Down Expand Up @@ -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 */ }
Expand All @@ -83,6 +84,8 @@ class SPIClassRP2040 : public arduino::HardwareSPI {
bool _hwCS;
bool _running; // SPI port active
bool _initted; // Transaction begun

std::map<int, int> _usingIRQs;
};

extern SPIClassRP2040 SPI;
Expand Down

0 comments on commit 0be7c98

Please sign in to comment.