Skip to content

Commit 0be7c98

Browse files
Support IRQ disabled SPI transactions (#1714)
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.
1 parent 0ed1f3d commit 0be7c98

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

libraries/SPI/keywords.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ SPI1 KEYWORD1
1414
#######################################
1515
begin KEYWORD2
1616
end KEYWORD2
17+
beginTransaction KEYWORD2
18+
endTransaction KEYWORD2
19+
SPISettings KEYWORD2
1720
transfer KEYWORD2
1821
setBitOrder KEYWORD2
1922
setDataMode KEYWORD2

libraries/SPI/src/SPI.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "SPI.h"
2222
#include <hardware/spi.h>
2323
#include <hardware/gpio.h>
24+
#include <hardware/structs/iobank0.h>
25+
#include <hardware/irq.h>
2426

2527
#ifdef USE_TINYUSB
2628
// For Serial when selecting TinyUSB. Can't include in the core because Arduino IDE
@@ -191,10 +193,33 @@ void SPIClassRP2040::beginTransaction(SPISettings settings) {
191193
DEBUGSPI("SPI: actual baudrate=%u\n", spi_get_baudrate(_spi));
192194
_initted = true;
193195
}
196+
// Disable any IRQs that are being used for SPI
197+
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
198+
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]);
199+
for (auto entry : _usingIRQs) {
200+
int gpio = entry.first;
201+
202+
// There is no gpio_get_irq, so manually twiddle the register
203+
io_rw_32 *en_reg = &irq_ctrl_base->inte[gpio / 8];
204+
uint32_t val = ((*en_reg) >> (4 * (gpio % 8))) & 0xf;
205+
_usingIRQs.insert_or_assign(gpio, val);
206+
DEBUGSPI("SPI: GPIO %d = %d\n", gpio, val);
207+
(*en_reg) ^= val << (4 * (gpio % 8));
208+
}
209+
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]);
194210
}
195211

196212
void SPIClassRP2040::endTransaction(void) {
197213
DEBUGSPI("SPI::endTransaction()\n");
214+
// Re-enablke IRQs
215+
for (auto entry : _usingIRQs) {
216+
int gpio = entry.first;
217+
int mode = entry.second;
218+
gpio_set_irq_enabled(gpio, mode, true);
219+
}
220+
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
221+
(void) irq_ctrl_base;
222+
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]);
198223
}
199224

200225
bool SPIClassRP2040::setRX(pin_size_t pin) {
@@ -292,6 +317,7 @@ void SPIClassRP2040::begin(bool hwCS) {
292317
gpio_set_function(_TX, GPIO_FUNC_SPI);
293318
// Give a default config in case user doesn't use beginTransaction
294319
beginTransaction(_spis);
320+
endTransaction();
295321
}
296322

297323
void SPIClassRP2040::end() {
@@ -312,11 +338,13 @@ void SPIClassRP2040::end() {
312338
void SPIClassRP2040::setBitOrder(BitOrder order) {
313339
_spis = SPISettings(_spis.getClockFreq(), order, _spis.getDataMode());
314340
beginTransaction(_spis);
341+
endTransaction();
315342
}
316343

317344
void SPIClassRP2040::setDataMode(uint8_t uc_mode) {
318345
_spis = SPISettings(_spis.getClockFreq(), _spis.getBitOrder(), uc_mode);
319346
beginTransaction(_spis);
347+
endTransaction();
320348
}
321349

322350
void SPIClassRP2040::setClockDivider(uint8_t uc_div) {

libraries/SPI/src/SPI.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <Arduino.h>
2424
#include <api/HardwareSPI.h>
2525
#include <hardware/spi.h>
26+
#include <map>
2627

2728
class SPIClassRP2040 : public arduino::HardwareSPI {
2829
public:
@@ -62,10 +63,10 @@ class SPIClassRP2040 : public arduino::HardwareSPI {
6263

6364
// Unimplemented
6465
virtual void usingInterrupt(int interruptNumber) override {
65-
(void) interruptNumber;
66+
_usingIRQs.insert({interruptNumber, 0});
6667
}
6768
virtual void notUsingInterrupt(int interruptNumber) override {
68-
(void) interruptNumber;
69+
_usingIRQs.erase(interruptNumber);
6970
}
7071
virtual void attachInterrupt() override { /* noop */ }
7172
virtual void detachInterrupt() override { /* noop */ }
@@ -83,6 +84,8 @@ class SPIClassRP2040 : public arduino::HardwareSPI {
8384
bool _hwCS;
8485
bool _running; // SPI port active
8586
bool _initted; // Transaction begun
87+
88+
std::map<int, int> _usingIRQs;
8689
};
8790

8891
extern SPIClassRP2040 SPI;

0 commit comments

Comments
 (0)