Skip to content

Commit 92c97e3

Browse files
committed
updated to latest arduino version with transaction support
1 parent 4e2f6ff commit 92c97e3

File tree

3 files changed

+463
-65
lines changed

3 files changed

+463
-65
lines changed

digistump-avr/libraries/SPI/SPI.cpp

+173-38
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/*
2-
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
2+
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
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,191 @@
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);
20-
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);
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+
uint8_t port = digitalPinToPort(SS);
33+
uint8_t bit = digitalPinToBitMask(SS);
34+
volatile uint8_t *reg = portModeRegister(port);
2535

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);
36+
// if the SS pin is not already configured as an output
37+
// then set it high (to enable the internal pull-up resistor)
38+
if(!(*reg & bit)){
39+
digitalWrite(SS, HIGH);
40+
}
3141

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);
40-
}
42+
// When the SS pin is set as OUTPUT, it can be used as
43+
// a general purpose output port (it doesn't influence
44+
// SPI operations).
45+
pinMode(SS, OUTPUT);
4146

47+
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
48+
// automatically switches to Slave, so the data direction of
49+
// the SS pin MUST be kept as OUTPUT.
50+
SPCR |= _BV(MSTR);
51+
SPCR |= _BV(SPE);
4252

43-
void SPIClass::end() {
44-
SPCR &= ~_BV(SPE);
53+
// Set direction register for SCK and MOSI pin.
54+
// MISO pin automatically overrides to INPUT.
55+
// By doing this AFTER enabling SPI, we avoid accidentally
56+
// clocking in a single bit since the lines go directly
57+
// from "input" to SPI control.
58+
// http://code.google.com/p/arduino/issues/detail?id=888
59+
pinMode(SCK, OUTPUT);
60+
pinMode(MOSI, OUTPUT);
61+
}
62+
initialized++; // reference count
63+
SREG = sreg;
4564
}
4665

47-
void SPIClass::setBitOrder(uint8_t bitOrder)
48-
{
49-
if(bitOrder == LSBFIRST) {
50-
SPCR |= _BV(DORD);
51-
} else {
52-
SPCR &= ~(_BV(DORD));
66+
void SPIClass::end() {
67+
uint8_t sreg = SREG;
68+
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
69+
// Decrease the reference counter
70+
if (initialized)
71+
initialized--;
72+
// If there are no more references disable SPI
73+
if (!initialized) {
74+
SPCR &= ~_BV(SPE);
75+
interruptMode = 0;
76+
#ifdef SPI_TRANSACTION_MISMATCH_LED
77+
inTransactionFlag = 0;
78+
#endif
5379
}
80+
SREG = sreg;
5481
}
5582

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

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

0 commit comments

Comments
 (0)