Skip to content

Commit 6f71582

Browse files
committed
[avr] Fix to atomic-access on SPI Transactions (Andrew Kroll)
1 parent b6d0897 commit 6f71582

File tree

2 files changed

+48
-27
lines changed

2 files changed

+48
-27
lines changed

hardware/arduino/avr/libraries/SPI/SPI.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,9 @@ void SPIClass::end() {
103103

104104
void SPIClass::usingInterrupt(uint8_t interruptNumber)
105105
{
106-
uint8_t mask;
107-
108-
if (modeFlags.interruptMode > 1) return;
109-
110-
noInterrupts();
106+
uint8_t mask = 0;
107+
uint8_t sreg = SREG;
108+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
111109
switch (interruptNumber) {
112110
#ifdef SPI_INT0_MASK
113111
case 0: mask = SPI_INT0_MASK; break;
@@ -135,11 +133,11 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber)
135133
#endif
136134
default:
137135
modeFlags.interruptMode = 2;
138-
interrupts();
139-
return;
136+
break;
140137
}
141-
modeFlags.interruptMode = 1;
142138
interruptMask |= mask;
143-
interrupts();
139+
if (!modeFlags.interruptMode)
140+
modeFlags.interruptMode = 1;
141+
SREG = sreg;
144142
}
145143

hardware/arduino/avr/libraries/SPI/SPI.h

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
2121
#define SPI_HAS_TRANSACTION 1
2222

23+
// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
24+
// This way when there is a bug fix you can check this define to alert users
25+
// of your code if it uses better version of this library.
26+
// This also implies everything that SPI_HAS_TRANSACTION as documented above is
27+
// available too.
28+
#define SPI_ATOMIC_VERSION 1
29+
2330
// Uncomment this line to add detection of mismatched begin/end transactions.
2431
// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
2532
// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
@@ -167,25 +174,33 @@ class SPIClass {
167174
// this function is used to gain exclusive access to the SPI bus
168175
// and configure the correct settings.
169176
inline static void beginTransaction(SPISettings settings) {
170-
if (modeFlags.interruptMode > 0) {
171-
#ifdef SPI_AVR_EIMSK
172-
if (modeFlags.interruptMode == 1) {
173-
interruptSave = SPI_AVR_EIMSK;
174-
SPI_AVR_EIMSK &= ~interruptMask;
175-
} else
176-
#endif
177-
{
178-
interruptSave = SREG;
179-
cli();
180-
}
181-
}
177+
uint8_t sreg = SREG;
178+
noInterrupts();
182179
#ifdef SPI_TRANSACTION_MISMATCH_LED
183180
if (modeFlags.inTransaction) {
184181
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
185182
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
186183
}
187184
modeFlags.inTransaction = true;
188185
#endif
186+
187+
#ifndef SPI_AVR_EIMSK
188+
if (modeFlags.interruptMode) {
189+
interruptSave = sreg;
190+
}
191+
#else
192+
if (modeFlags.interruptMode == 2) {
193+
interruptSave = sreg;
194+
} else if (modeFlags.interruptMode == 1) {
195+
interruptSave = SPI_AVR_EIMSK;
196+
SPI_AVR_EIMSK &= ~interruptMask;
197+
SREG = sreg;
198+
}
199+
#endif
200+
else {
201+
SREG = sreg;
202+
}
203+
189204
SPCR = settings.spcr;
190205
SPSR = settings.spsr;
191206
}
@@ -238,23 +253,31 @@ class SPIClass {
238253
// After performing a group of transfers and releasing the chip select
239254
// signal, this function allows others to access the SPI bus
240255
inline static void endTransaction(void) {
256+
uint8_t sreg = SREG;
257+
noInterrupts();
241258
#ifdef SPI_TRANSACTION_MISMATCH_LED
242259
if (!modeFlags.inTransaction) {
243260
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
244261
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
245262
}
246263
modeFlags.inTransaction = false;
247264
#endif
248-
if (modeFlags.interruptMode > 0) {
249-
#ifdef SPI_AVR_EIMSK
265+
#ifndef SPI_AVR_EIMSK
266+
if (modeFlags.interruptMode) {
267+
SREG = interruptSave;
268+
} else {
269+
SREG = sreg;
270+
}
271+
#else
272+
if (modeFlags.interruptMode == 2) {
273+
SREG = interruptSave;
274+
} else {
250275
if (modeFlags.interruptMode == 1) {
251276
SPI_AVR_EIMSK = interruptSave;
252-
} else
253-
#endif
254-
{
255-
SREG = interruptSave;
256277
}
278+
SREG = sreg;
257279
}
280+
#endif
258281
}
259282

260283
// Disable the SPI bus

0 commit comments

Comments
 (0)