Skip to content

Commit 8c31705

Browse files
Deduplicate SPI and SoftwareSPI routines (earlephilhower#2779)
1 parent acf81f4 commit 8c31705

File tree

7 files changed

+235
-229
lines changed

7 files changed

+235
-229
lines changed

libraries/SPI/src/SPI.cpp

Lines changed: 14 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -45,47 +45,6 @@ SPIClassRP2040::SPIClassRP2040(spi_inst_t *spi, pin_size_t rx, pin_size_t cs, pi
4545
_CS = cs;
4646
}
4747

48-
inline spi_cpol_t SPIClassRP2040::cpol() {
49-
switch (_spis.getDataMode()) {
50-
case SPI_MODE0:
51-
return SPI_CPOL_0;
52-
case SPI_MODE1:
53-
return SPI_CPOL_0;
54-
case SPI_MODE2:
55-
return SPI_CPOL_1;
56-
case SPI_MODE3:
57-
return SPI_CPOL_1;
58-
}
59-
// Error
60-
return SPI_CPOL_0;
61-
}
62-
63-
inline spi_cpha_t SPIClassRP2040::cpha() {
64-
switch (_spis.getDataMode()) {
65-
case SPI_MODE0:
66-
return SPI_CPHA_0;
67-
case SPI_MODE1:
68-
return SPI_CPHA_1;
69-
case SPI_MODE2:
70-
return SPI_CPHA_0;
71-
case SPI_MODE3:
72-
return SPI_CPHA_1;
73-
}
74-
// Error
75-
return SPI_CPHA_0;
76-
}
77-
78-
inline uint8_t SPIClassRP2040::reverseByte(uint8_t b) {
79-
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
80-
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
81-
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
82-
return b;
83-
}
84-
85-
inline uint16_t SPIClassRP2040::reverse16Bit(uint16_t w) {
86-
return (reverseByte(w & 0xff) << 8) | (reverseByte(w >> 8));
87-
}
88-
8948
// The HW can't do LSB first, only MSB first, so need to bitreverse
9049
void SPIClassRP2040::adjustBuffer(const void *s, void *d, size_t cnt, bool by16) {
9150
if (_spis.getBitOrder() == MSBFIRST) {
@@ -94,13 +53,13 @@ void SPIClassRP2040::adjustBuffer(const void *s, void *d, size_t cnt, bool by16)
9453
const uint8_t *src = (const uint8_t *)s;
9554
uint8_t *dst = (uint8_t *)d;
9655
for (size_t i = 0; i < cnt; i++) {
97-
*(dst++) = reverseByte(*(src++));
56+
*(dst++) = _helper.reverseByte(*(src++));
9857
}
9958
} else { /* by16 */
10059
const uint16_t *src = (const uint16_t *)s;
10160
uint16_t *dst = (uint16_t *)d;
10261
for (size_t i = 0; i < cnt; i++) {
103-
*(dst++) = reverse16Bit(*(src++));
62+
*(dst++) = _helper.reverse16Bit(*(src++));
10463
}
10564
}
10665
}
@@ -110,11 +69,11 @@ byte SPIClassRP2040::transfer(uint8_t data) {
11069
if (!_initted) {
11170
return 0;
11271
}
113-
data = (_spis.getBitOrder() == MSBFIRST) ? data : reverseByte(data);
114-
DEBUGSPI("SPI::transfer(%02x), cpol=%d, cpha=%d\n", data, cpol(), cpha());
72+
data = (_spis.getBitOrder() == MSBFIRST) ? data : _helper.reverseByte(data);
73+
DEBUGSPI("SPI::transfer(%02x), cpol=%d, cpha=%d\n", data, _helper.cpol(_spis), _helper.cpha(_spis));
11574
hw_write_masked(&spi_get_hw(_spi)->cr0, (8 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS); // Fast set to 8-bits
11675
spi_write_read_blocking(_spi, &data, &ret, 1);
117-
ret = (_spis.getBitOrder() == MSBFIRST) ? ret : reverseByte(ret);
76+
ret = (_spis.getBitOrder() == MSBFIRST) ? ret : _helper.reverseByte(ret);
11877
DEBUGSPI("SPI: read back %02x\n", ret);
11978
return ret;
12079
}
@@ -124,11 +83,11 @@ uint16_t SPIClassRP2040::transfer16(uint16_t data) {
12483
if (!_initted) {
12584
return 0;
12685
}
127-
data = (_spis.getBitOrder() == MSBFIRST) ? data : reverse16Bit(data);
128-
DEBUGSPI("SPI::transfer16(%04x), cpol=%d, cpha=%d\n", data, cpol(), cpha());
86+
data = (_spis.getBitOrder() == MSBFIRST) ? data : _helper.reverse16Bit(data);
87+
DEBUGSPI("SPI::transfer16(%04x), cpol=%d, cpha=%d\n", data, _helper.cpol(_spis), _helper.cpha(_spis));
12988
hw_write_masked(&spi_get_hw(_spi)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS); // Fast set to 16-bits
13089
spi_write16_read16_blocking(_spi, &data, &ret, 1);
131-
ret = (_spis.getBitOrder() == MSBFIRST) ? ret : reverse16Bit(ret);
90+
ret = (_spis.getBitOrder() == MSBFIRST) ? ret : _helper.reverse16Bit(ret);
13291
DEBUGSPI("SPI: read back %02x\n", ret);
13392
return ret;
13493
}
@@ -172,21 +131,14 @@ void SPIClassRP2040::transfer(const void *txbuf, void *rxbuf, size_t count) {
172131
// If its LSB this isn't nearly as fun, we'll just let transfer(x) do it :(
173132
for (size_t i = 0; i < count; i++) {
174133
*rxbuff = transfer(*txbuff);
175-
*rxbuff = (_spis.getBitOrder() == MSBFIRST) ? *rxbuff : reverseByte(*rxbuff);
134+
*rxbuff = (_spis.getBitOrder() == MSBFIRST) ? *rxbuff : _helper.reverseByte(*rxbuff);
176135
txbuff++;
177136
rxbuff++;
178137
}
179138
DEBUGSPI("SPI::transfer completed\n");
180139
}
181140

182-
#ifdef PICO_RP2350B
183-
#define GPIOIRQREGS 6
184-
#else
185-
#define GPIOIRQREGS 4
186-
#endif
187-
188141
void SPIClassRP2040::beginTransaction(SPISettings settings) {
189-
noInterrupts(); // Avoid possible race conditions if IRQ comes in while main app is in middle of this
190142
DEBUGSPI("SPI::beginTransaction(clk=%lu, bo=%s)\n", settings.getClockFreq(), (settings.getBitOrder() == MSBFIRST) ? "MSB" : "LSB");
191143
if (_initted && settings == _spis) {
192144
DEBUGSPI("SPI: Reusing existing initted SPI\n");
@@ -202,39 +154,15 @@ void SPIClassRP2040::beginTransaction(SPISettings settings) {
202154
DEBUGSPI("SPI: actual baudrate=%u\n", spi_get_baudrate(_spi));
203155
}
204156
_spis = settings;
205-
spi_set_format(_spi, 8, cpol(), cpha(), SPI_MSB_FIRST);
157+
spi_set_format(_spi, 8, _helper.cpol(_spis), _helper.cpha(_spis), SPI_MSB_FIRST);
206158
_initted = true;
207159
}
208-
// Disable any IRQs that are being used for SPI
209-
io_bank0_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
210-
DEBUGSPI("SPI: IRQ masks before = %08x %08x %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], (GPIOIRQREGS > 4) ? (unsigned)irq_ctrl_base->inte[4] : 0, (GPIOIRQREGS > 5) ? (unsigned)irq_ctrl_base->inte[5] : 0);
211-
for (auto entry : _usingIRQs) {
212-
int gpio = entry.first;
213-
214-
// There is no gpio_get_irq, so manually twiddle the register
215-
io_rw_32 *en_reg = &irq_ctrl_base->inte[gpio / 8];
216-
uint32_t val = ((*en_reg) >> (4 * (gpio % 8))) & 0xf;
217-
_usingIRQs.insert_or_assign(gpio, val);
218-
DEBUGSPI("SPI: GPIO %d = %lu\n", gpio, val);
219-
(*en_reg) ^= val << (4 * (gpio % 8));
220-
}
221-
DEBUGSPI("SPI: IRQ masks after = %08x %08x %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], (GPIOIRQREGS > 4) ? (unsigned)irq_ctrl_base->inte[4] : 0, (GPIOIRQREGS > 5) ? (unsigned)irq_ctrl_base->inte[5] : 0);
222-
interrupts();
160+
_helper.maskInterrupts();
223161
}
224162

225163
void SPIClassRP2040::endTransaction(void) {
226-
noInterrupts(); // Avoid race condition so the GPIO IRQs won't come back until all state is restored
227164
DEBUGSPI("SPI::endTransaction()\n");
228-
// Re-enable IRQs
229-
for (auto entry : _usingIRQs) {
230-
int gpio = entry.first;
231-
int mode = entry.second;
232-
gpio_set_irq_enabled(gpio, mode, true);
233-
}
234-
io_bank0_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
235-
(void) irq_ctrl_base;
236-
DEBUGSPI("SPI: IRQ masks = %08x %08x %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], (GPIOIRQREGS > 4) ? (unsigned)irq_ctrl_base->inte[4] : 0, (GPIOIRQREGS > 5) ? (unsigned)irq_ctrl_base->inte[5] : 0);
237-
interrupts();
165+
_helper.unmaskInterrupts();
238166
}
239167

240168
bool SPIClassRP2040::transferAsync(const void *send, void *recv, size_t bytes) {
@@ -265,7 +193,7 @@ bool SPIClassRP2040::transferAsync(const void *send, void *recv, size_t bytes) {
265193
return false;
266194
}
267195
for (size_t i = 0; i < bytes; i++) {
268-
_dmaBuffer[i] = reverseByte(txbuff[i]);
196+
_dmaBuffer[i] = _helper.reverseByte(txbuff[i]);
269197
}
270198
}
271199
_dmaBytes = bytes;
@@ -312,7 +240,7 @@ bool SPIClassRP2040::finishedAsync() {
312240
spi_get_hw(_spi)->dmacr = 0;
313241
if (_spis.getBitOrder() != MSBFIRST) {
314242
for (int i = 0; i < _dmaBytes; i++) {
315-
_rxFinalBuffer[i] = reverseByte(_rxFinalBuffer[i]);
243+
_rxFinalBuffer[i] = _helper.reverseByte(_rxFinalBuffer[i]);
316244
}
317245
free(_dmaBuffer);
318246
_dmaBuffer = nullptr;

libraries/SPI/src/SPI.h

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

2828
class SPIClassRP2040 : public arduino::HardwareSPI {
2929
public:
@@ -76,19 +76,16 @@ class SPIClassRP2040 : public arduino::HardwareSPI {
7676

7777
// List of GPIO IRQs to disable during a transaction
7878
virtual void usingInterrupt(int interruptNumber) override {
79-
_usingIRQs.insert({interruptNumber, 0});
79+
_helper.usingInterrupt(interruptNumber);
8080
}
81+
8182
virtual void notUsingInterrupt(int interruptNumber) override {
82-
_usingIRQs.erase(interruptNumber);
83+
_helper.notUsingInterrupt(interruptNumber);
8384
}
8485
virtual void attachInterrupt() override { /* noop */ }
8586
virtual void detachInterrupt() override { /* noop */ }
8687

8788
private:
88-
spi_cpol_t cpol();
89-
spi_cpha_t cpha();
90-
uint8_t reverseByte(uint8_t b);
91-
uint16_t reverse16Bit(uint16_t w);
9289
void adjustBuffer(const void *s, void *d, size_t cnt, bool by16);
9390

9491
spi_inst_t *_spi;
@@ -98,15 +95,14 @@ class SPIClassRP2040 : public arduino::HardwareSPI {
9895
bool _running; // SPI port active
9996
bool _initted; // Transaction begun
10097

101-
std::map<int, int> _usingIRQs;
102-
10398
// DMA
10499
int _channelDMA;
105100
int _channelSendDMA;
106101
uint8_t *_dmaBuffer = nullptr;
107102
int _dmaBytes;
108103
uint8_t *_rxFinalBuffer;
109104
uint32_t _dummy;
105+
SPIHelper _helper;
110106
};
111107

112108
extern SPIClassRP2040 SPI;

0 commit comments

Comments
 (0)