Skip to content

Commit 042fa0c

Browse files
committed
Backported SPI Transcations from 1.5.x
1 parent 060c1e7 commit 042fa0c

File tree

4 files changed

+462
-81
lines changed

4 files changed

+462
-81
lines changed

libraries/SPI/SPI.cpp

+164-37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/*
22
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
3+
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
4+
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
5+
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
36
* SPI Master library for arduino.
47
*
58
* This file is free software; you can redistribute it and/or modify
@@ -8,59 +11,183 @@
811
* published by the Free Software Foundation.
912
*/
1013

11-
#include "pins_arduino.h"
1214
#include "SPI.h"
1315

1416
SPIClass SPI;
1517

16-
void SPIClass::begin() {
18+
uint8_t SPIClass::initialized = 0;
19+
uint8_t SPIClass::interruptMode = 0;
20+
uint8_t SPIClass::interruptMask = 0;
21+
uint8_t SPIClass::interruptSave = 0;
22+
#ifdef SPI_TRANSACTION_MISMATCH_LED
23+
uint8_t SPIClass::inTransactionFlag = 0;
24+
#endif
1725

18-
// Set SS to high so a connected chip will be "deselected" by default
19-
digitalWrite(SS, HIGH);
26+
void SPIClass::begin()
27+
{
28+
uint8_t sreg = SREG;
29+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
30+
if (!initialized) {
31+
// Set SS to high so a connected chip will be "deselected" by default
32+
digitalWrite(SS, HIGH);
2033

21-
// When the SS pin is set as OUTPUT, it can be used as
22-
// a general purpose output port (it doesn't influence
23-
// SPI operations).
24-
pinMode(SS, OUTPUT);
34+
// When the SS pin is set as OUTPUT, it can be used as
35+
// a general purpose output port (it doesn't influence
36+
// SPI operations).
37+
pinMode(SS, OUTPUT);
2538

26-
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
27-
// automatically switches to Slave, so the data direction of
28-
// the SS pin MUST be kept as OUTPUT.
29-
SPCR |= _BV(MSTR);
30-
SPCR |= _BV(SPE);
39+
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
40+
// automatically switches to Slave, so the data direction of
41+
// the SS pin MUST be kept as OUTPUT.
42+
SPCR |= _BV(MSTR);
43+
SPCR |= _BV(SPE);
3144

32-
// Set direction register for SCK and MOSI pin.
33-
// MISO pin automatically overrides to INPUT.
34-
// By doing this AFTER enabling SPI, we avoid accidentally
35-
// clocking in a single bit since the lines go directly
36-
// from "input" to SPI control.
37-
// http://code.google.com/p/arduino/issues/detail?id=888
38-
pinMode(SCK, OUTPUT);
39-
pinMode(MOSI, OUTPUT);
45+
// Set direction register for SCK and MOSI pin.
46+
// MISO pin automatically overrides to INPUT.
47+
// By doing this AFTER enabling SPI, we avoid accidentally
48+
// clocking in a single bit since the lines go directly
49+
// from "input" to SPI control.
50+
// http://code.google.com/p/arduino/issues/detail?id=888
51+
pinMode(SCK, OUTPUT);
52+
pinMode(MOSI, OUTPUT);
53+
}
54+
initialized++; // reference count
55+
SREG = sreg;
4056
}
4157

42-
4358
void SPIClass::end() {
44-
SPCR &= ~_BV(SPE);
45-
}
46-
47-
void SPIClass::setBitOrder(uint8_t bitOrder)
48-
{
49-
if(bitOrder == LSBFIRST) {
50-
SPCR |= _BV(DORD);
51-
} else {
52-
SPCR &= ~(_BV(DORD));
59+
uint8_t sreg = SREG;
60+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
61+
// Decrease the reference counter
62+
if (initialized)
63+
initialized--;
64+
// If there are no more references disable SPI
65+
if (!initialized) {
66+
SPCR &= ~_BV(SPE);
67+
interruptMode = 0;
68+
#ifdef SPI_TRANSACTION_MISMATCH_LED
69+
inTransactionFlag = 0;
70+
#endif
5371
}
72+
SREG = sreg;
5473
}
5574

56-
void SPIClass::setDataMode(uint8_t mode)
75+
// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
76+
#if defined(__AVR_ATmega32U4__)
77+
#define SPI_INT0_MASK (1<<INT0)
78+
#define SPI_INT1_MASK (1<<INT1)
79+
#define SPI_INT2_MASK (1<<INT2)
80+
#define SPI_INT3_MASK (1<<INT3)
81+
#define SPI_INT4_MASK (1<<INT6)
82+
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
83+
#define SPI_INT0_MASK (1<<INT0)
84+
#define SPI_INT1_MASK (1<<INT1)
85+
#define SPI_INT2_MASK (1<<INT2)
86+
#define SPI_INT3_MASK (1<<INT3)
87+
#define SPI_INT4_MASK (1<<INT4)
88+
#define SPI_INT5_MASK (1<<INT5)
89+
#define SPI_INT6_MASK (1<<INT6)
90+
#define SPI_INT7_MASK (1<<INT7)
91+
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
92+
#define SPI_INT0_MASK (1<<INT4)
93+
#define SPI_INT1_MASK (1<<INT5)
94+
#define SPI_INT2_MASK (1<<INT0)
95+
#define SPI_INT3_MASK (1<<INT1)
96+
#define SPI_INT4_MASK (1<<INT2)
97+
#define SPI_INT5_MASK (1<<INT3)
98+
#define SPI_INT6_MASK (1<<INT6)
99+
#define SPI_INT7_MASK (1<<INT7)
100+
#else
101+
#ifdef INT0
102+
#define SPI_INT0_MASK (1<<INT0)
103+
#endif
104+
#ifdef INT1
105+
#define SPI_INT1_MASK (1<<INT1)
106+
#endif
107+
#ifdef INT2
108+
#define SPI_INT2_MASK (1<<INT2)
109+
#endif
110+
#endif
111+
112+
void SPIClass::usingInterrupt(uint8_t interruptNumber)
57113
{
58-
SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
114+
uint8_t mask = 0;
115+
uint8_t sreg = SREG;
116+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
117+
switch (interruptNumber) {
118+
#ifdef SPI_INT0_MASK
119+
case 0: mask = SPI_INT0_MASK; break;
120+
#endif
121+
#ifdef SPI_INT1_MASK
122+
case 1: mask = SPI_INT1_MASK; break;
123+
#endif
124+
#ifdef SPI_INT2_MASK
125+
case 2: mask = SPI_INT2_MASK; break;
126+
#endif
127+
#ifdef SPI_INT3_MASK
128+
case 3: mask = SPI_INT3_MASK; break;
129+
#endif
130+
#ifdef SPI_INT4_MASK
131+
case 4: mask = SPI_INT4_MASK; break;
132+
#endif
133+
#ifdef SPI_INT5_MASK
134+
case 5: mask = SPI_INT5_MASK; break;
135+
#endif
136+
#ifdef SPI_INT6_MASK
137+
case 6: mask = SPI_INT6_MASK; break;
138+
#endif
139+
#ifdef SPI_INT7_MASK
140+
case 7: mask = SPI_INT7_MASK; break;
141+
#endif
142+
default:
143+
interruptMode = 2;
144+
break;
145+
}
146+
interruptMask |= mask;
147+
if (!interruptMode)
148+
interruptMode = 1;
149+
SREG = sreg;
59150
}
60151

61-
void SPIClass::setClockDivider(uint8_t rate)
152+
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
62153
{
63-
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK);
64-
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK);
154+
// Once in mode 2 we can't go back to 0 without a proper reference count
155+
if (interruptMode == 2)
156+
return;
157+
uint8_t mask = 0;
158+
uint8_t sreg = SREG;
159+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
160+
switch (interruptNumber) {
161+
#ifdef SPI_INT0_MASK
162+
case 0: mask = SPI_INT0_MASK; break;
163+
#endif
164+
#ifdef SPI_INT1_MASK
165+
case 1: mask = SPI_INT1_MASK; break;
166+
#endif
167+
#ifdef SPI_INT2_MASK
168+
case 2: mask = SPI_INT2_MASK; break;
169+
#endif
170+
#ifdef SPI_INT3_MASK
171+
case 3: mask = SPI_INT3_MASK; break;
172+
#endif
173+
#ifdef SPI_INT4_MASK
174+
case 4: mask = SPI_INT4_MASK; break;
175+
#endif
176+
#ifdef SPI_INT5_MASK
177+
case 5: mask = SPI_INT5_MASK; break;
178+
#endif
179+
#ifdef SPI_INT6_MASK
180+
case 6: mask = SPI_INT6_MASK; break;
181+
#endif
182+
#ifdef SPI_INT7_MASK
183+
case 7: mask = SPI_INT7_MASK; break;
184+
#endif
185+
default:
186+
break;
187+
// this case can't be reached
188+
}
189+
interruptMask &= ~mask;
190+
if (!interruptMask)
191+
interruptMode = 0;
192+
SREG = sreg;
65193
}
66-

0 commit comments

Comments
 (0)