Skip to content

Commit ff35811

Browse files
committed
Initial porting of SPI library based on SAMD
1 parent e53363b commit ff35811

File tree

5 files changed

+426
-6
lines changed

5 files changed

+426
-6
lines changed

cores/arduino/wiring_digital.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#include "wiring_private.h"
2727
#include "pins_arduino.h"
2828

29-
bool isDoubleBondedActive(uint8_t pin) __attribute__((weak));
29+
__attribute__((weak)) bool isDoubleBondedActive(uint8_t pin) {};
3030

3131
void pinMode(uint8_t pin, PinMode mode)
3232
{

libraries/SPI/src/SPI.cpp

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* SPI Master library for Arduino Zero.
3+
* Copyright (c) 2015 Arduino LLC
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 2.1 of the License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include "SPI.h"
21+
#include <Arduino.h>
22+
23+
#define SPI_IMODE_NONE 0
24+
#define SPI_IMODE_EXTINT 1
25+
#define SPI_IMODE_GLOBAL 2
26+
27+
const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
28+
29+
SPIClass::SPIClass(uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, uint8_t uc_pinSS, uint8_t uc_mux)
30+
{
31+
initialized = false;
32+
33+
// pins
34+
_uc_mux = uc_mux;
35+
_uc_pinMiso = uc_pinMISO;
36+
_uc_pinSCK = uc_pinSCK;
37+
_uc_pinMosi = uc_pinMOSI;
38+
_uc_pinSS = uc_pinSS;
39+
}
40+
41+
void SPIClass::begin()
42+
{
43+
init();
44+
45+
PORTMUX.TWISPIROUTEA |= _uc_mux;
46+
47+
// We don't need HW SS since salve/master mode is selected via registers, so make it simply INPUT
48+
pinMode(_uc_pinSS, INPUT);
49+
pinMode(_uc_pinMosi, OUTPUT);
50+
pinMode(_uc_pinSCK, OUTPUT);
51+
// MISO is set to input by the controller
52+
53+
SPI0.CTRLB |= (SPI_SSD_bm);
54+
SPI0.CTRLA |= (SPI_ENABLE_bm | SPI_MASTER_bm);
55+
56+
config(DEFAULT_SPI_SETTINGS);
57+
}
58+
59+
void SPIClass::init()
60+
{
61+
if (initialized)
62+
return;
63+
interruptMode = SPI_IMODE_NONE;
64+
interruptSave = 0;
65+
interruptMask = 0;
66+
initialized = true;
67+
}
68+
69+
void SPIClass::config(SPISettings settings)
70+
{
71+
SPI0.CTRLA = settings.ctrla;
72+
SPI0.CTRLB = settings.ctrlb;
73+
}
74+
75+
void SPIClass::end()
76+
{
77+
SPI0.CTRLA &= ~(SPI_ENABLE_bm);
78+
initialized = false;
79+
}
80+
81+
void SPIClass::usingInterrupt(int interruptNumber)
82+
{
83+
if ((interruptNumber == NOT_AN_INTERRUPT))
84+
return;
85+
86+
if (interruptNumber >= EXTERNAL_NUM_INTERRUPTS)
87+
interruptMode = SPI_IMODE_GLOBAL;
88+
else
89+
{
90+
interruptMode |= SPI_IMODE_EXTINT;
91+
interruptMask |= (1 << interruptNumber);
92+
}
93+
}
94+
95+
void SPIClass::notUsingInterrupt(int interruptNumber)
96+
{
97+
if ((interruptNumber == NOT_AN_INTERRUPT))
98+
return;
99+
100+
if (interruptMode & SPI_IMODE_GLOBAL)
101+
return; // can't go back, as there is no reference count
102+
103+
interruptMask &= ~(1 << interruptNumber);
104+
105+
if (interruptMask == 0)
106+
interruptMode = SPI_IMODE_NONE;
107+
}
108+
109+
110+
void SPIClass::detachMaskedInterrupts() {
111+
}
112+
113+
void SPIClass::reattachMaskedInterrupts() {
114+
115+
}
116+
117+
void SPIClass::beginTransaction(SPISettings settings)
118+
{
119+
if (interruptMode != SPI_IMODE_NONE)
120+
{
121+
if (interruptMode & SPI_IMODE_GLOBAL)
122+
{
123+
noInterrupts();
124+
}
125+
else if (interruptMode & SPI_IMODE_EXTINT)
126+
{
127+
detachMaskedInterrupts();
128+
}
129+
config(settings);
130+
}
131+
}
132+
133+
void SPIClass::endTransaction(void)
134+
{
135+
if (interruptMode != SPI_IMODE_NONE)
136+
{
137+
if (interruptMode & SPI_IMODE_GLOBAL)
138+
{
139+
interrupts();
140+
}
141+
else if (interruptMode & SPI_IMODE_EXTINT)
142+
reattachMaskedInterrupts();
143+
}
144+
}
145+
146+
void SPIClass::setBitOrder(BitOrder order)
147+
{
148+
if (order == LSBFIRST)
149+
SPI0.CTRLA |= (SPI_DORD_bm);
150+
else
151+
SPI0.CTRLA &= ~(SPI_DORD_bm);
152+
}
153+
154+
void SPIClass::setDataMode(uint8_t mode)
155+
{
156+
SPI0.CTRLB = ((SPI0.CTRLB & (~SPI_MODE_gm)) | mode );
157+
}
158+
159+
void SPIClass::setClockDivider(uint8_t div)
160+
{
161+
SPI0.CTRLA = ((SPI0.CTRLA &
162+
((~SPI_PRESC_gm) | (~SPI_CLK2X_bm) )) // mask out values
163+
| div); // write value
164+
}
165+
166+
byte SPIClass::transfer(uint8_t data)
167+
{
168+
/*
169+
* The following NOP introduces a small delay that can prevent the wait
170+
* loop from iterating when running at the maximum speed. This gives
171+
* about 10% more speed, even if it seems counter-intuitive. At lower
172+
* speeds it is unnoticed.
173+
*/
174+
asm volatile("nop");
175+
176+
SPI0.DATA = data;
177+
while ((SPI0.INTFLAGS & SPI_RXCIF_bm) == 0); // wait for complete send
178+
return SPI0.DATA; // read data back
179+
}
180+
181+
uint16_t SPIClass::transfer16(uint16_t data) {
182+
union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } t;
183+
184+
t.val = data;
185+
186+
if ((SPI0.CTRLA & SPI_DORD_bm) == 0) {
187+
t.msb = transfer(t.msb);
188+
t.lsb = transfer(t.lsb);
189+
} else {
190+
t.lsb = transfer(t.lsb);
191+
t.msb = transfer(t.msb);
192+
}
193+
194+
return t.val;
195+
}
196+
197+
void SPIClass::transfer(void *buf, size_t count)
198+
{
199+
uint8_t *buffer = reinterpret_cast<uint8_t *>(buf);
200+
for (size_t i=0; i<count; i++) {
201+
*buffer = transfer(*buffer);
202+
buffer++;
203+
}
204+
}
205+
206+
#if SPI_INTERFACES_COUNT > 0
207+
SPIClass SPI (PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI, PIN_SPI_SS, MUX_SPI);
208+
#endif

0 commit comments

Comments
 (0)