Skip to content

Commit cb722cf

Browse files
Claudio Indellicatibitron
Claudio Indellicati
authored andcommitted
Implemented SPI Transaction API.
1 parent 730ff49 commit cb722cf

File tree

2 files changed

+121
-27
lines changed

2 files changed

+121
-27
lines changed

libraries/SPI/SPI.cpp

+80-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
* SPI Master library for arduino.
3-
* Copyright (c) 2014 Arduino.
2+
* SPI Master library for Arduino.
3+
* Copyright (c) 2015 Arduino LLC
44
*
55
* This file is free software; you can redistribute it and/or modify
66
* it under the terms of either the GNU General Public License version 2
@@ -13,8 +13,15 @@
1313
#include "assert.h"
1414
#include "variant.h"
1515

16+
#define SPI_IMODE_NONE 0
17+
#define SPI_IMODE_EXTINT 1
18+
#define SPI_IMODE_GLOBAL 2
19+
20+
const SPISettings DEFAULT_SPI_SETTINGS = SPISettings();
21+
1622
SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI)
1723
{
24+
initialized = false;
1825
assert(p_sercom != NULL);
1926
_p_sercom = p_sercom;
2027

@@ -25,40 +32,100 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint
2532

2633
void SPIClass::begin()
2734
{
35+
init();
36+
2837
// PIO init
2938
pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
3039
pinPeripheral(_uc_pinSCK, g_APinDescription[_uc_pinSCK].ulPinType);
3140
pinPeripheral(_uc_pinMosi, g_APinDescription[_uc_pinMosi].ulPinType);
3241

33-
// Default speed set to 4Mhz, SPI mode set to MODE 0 and Bit order set to MSB first.
34-
_p_sercom->initSPI(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, MSB_FIRST);
35-
_p_sercom->initSPIClock(SERCOM_SPI_MODE_0, 4000000);
42+
config(DEFAULT_SPI_SETTINGS);
43+
}
44+
45+
void SPIClass::init()
46+
{
47+
if (initialized)
48+
return;
49+
interruptMode = SPI_IMODE_NONE;
50+
interruptSave = 0;
51+
interruptMask = 0;
52+
initialized = true;
53+
}
54+
55+
void SPIClass::config(SPISettings settings)
56+
{
57+
_p_sercom->disableSPI();
58+
59+
_p_sercom->initSPI(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, settings.bitOrder);
60+
_p_sercom->initSPIClock(settings.dataMode, settings.clockFreq);
3661

3762
_p_sercom->enableSPI();
3863
}
3964

4065
void SPIClass::end()
4166
{
4267
_p_sercom->resetSPI();
68+
initialized = false;
4369
}
4470

71+
#ifndef interruptsStatus
72+
#define interruptsStatus() __interruptsStatus()
73+
static inline unsigned char __interruptsStatus(void) __attribute__((always_inline, unused));
74+
static inline unsigned char __interruptsStatus(void)
75+
{
76+
// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDBIBGJ.html
77+
return (__get_PRIMASK() ? 0 : 1);
78+
}
79+
#endif
4580

46-
void SPIClass::usingInterrupt(uint8_t interruptNumber)
81+
void SPIClass::usingInterrupt(int interruptNumber)
4782
{
48-
// XXX: TODO
83+
if ((interruptNumber == NOT_AN_INTERRUPT) || (interruptNumber == EXTERNAL_INT_NMI))
84+
return;
85+
86+
uint8_t irestore = interruptsStatus();
87+
noInterrupts();
88+
89+
if (interruptNumber >= EXTERNAL_NUM_INTERRUPTS)
90+
interruptMode = SPI_IMODE_GLOBAL;
91+
else
92+
{
93+
interruptMode |= SPI_IMODE_EXTINT;
94+
interruptMask |= (1 << interruptNumber);
95+
}
96+
97+
if (irestore)
98+
interrupts();
4999
}
50100

51101
void SPIClass::beginTransaction(SPISettings settings)
52102
{
53-
// XXX: TODO
54-
setBitOrder(settings.bitOrder);
55-
setClockDivider(settings.clockDiv);
56-
setDataMode(settings.dataMode);
103+
if (interruptMode != SPI_IMODE_NONE)
104+
{
105+
if (interruptMode & SPI_IMODE_GLOBAL)
106+
{
107+
interruptSave = interruptsStatus();
108+
noInterrupts();
109+
}
110+
else if (interruptMode & SPI_IMODE_EXTINT)
111+
EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(interruptMask);
112+
}
113+
114+
config(settings);
57115
}
58116

59117
void SPIClass::endTransaction(void)
60118
{
61-
// XXX: TODO
119+
if (interruptMode != SPI_IMODE_NONE)
120+
{
121+
if (interruptMode & SPI_IMODE_GLOBAL)
122+
{
123+
if (interruptSave)
124+
interrupts();
125+
}
126+
else if (interruptMode & SPI_IMODE_EXTINT)
127+
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(interruptMask);
128+
}
62129
}
63130

64131
void SPIClass::setBitOrder(BitOrder order)
@@ -110,7 +177,7 @@ byte SPIClass::transfer(uint8_t data)
110177
_p_sercom->writeDataSPI(data);
111178

112179
// Read data
113-
return _p_sercom->readDataSPI();
180+
return _p_sercom->readDataSPI() & 0xFF;
114181
}
115182

116183
void SPIClass::attachInterrupt() {

libraries/SPI/SPI.h

+41-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
2+
* SPI Master library for Arduino.
23
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
3-
* SPI Master library for arduino.
4+
* Copyright (c) 2015 Arduino LLC
45
*
56
* This file is free software; you can redistribute it and/or modify
67
* it under the terms of either the GNU General Public License version 2
@@ -13,6 +14,13 @@
1314

1415
#include <Arduino.h>
1516

17+
// SPI_HAS_TRANSACTION means SPI has
18+
// - beginTransaction()
19+
// - endTransaction()
20+
// - usingInterrupt()
21+
// - SPISetting(clock, bitOrder, dataMode)
22+
#define SPI_HAS_TRANSACTION 1
23+
1624
#define SPI_MODE0 0x02
1725
#define SPI_MODE1 0x00
1826
#define SPI_MODE2 0x03
@@ -38,6 +46,7 @@ class SPISettings {
3846
}
3947
}
4048

49+
// Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first.
4150
SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); }
4251

4352
private:
@@ -46,21 +55,32 @@ class SPISettings {
4655
}
4756

4857
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) {
49-
uint8_t div;
50-
if (clock < (F_CPU / 255)) {
51-
div = 255;
52-
} else if (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER)) {
53-
div = SPI_MIN_CLOCK_DIVIDER;
54-
} else {
55-
div = (F_CPU / (clock + 1)) + 1;
58+
this->clockFreq = (clock >= (F_CPU / SPI_MIN_CLOCK_DIVIDER) ? F_CPU / SPI_MIN_CLOCK_DIVIDER : clock);
59+
60+
this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST);
61+
62+
switch (dataMode)
63+
{
64+
case SPI_MODE0:
65+
this->dataMode = SERCOM_SPI_MODE_0;
66+
67+
case SPI_MODE1:
68+
this->dataMode = SERCOM_SPI_MODE_1;
69+
70+
case SPI_MODE2:
71+
this->dataMode = SERCOM_SPI_MODE_2;
72+
73+
case SPI_MODE3:
74+
this->dataMode = SERCOM_SPI_MODE_3;
75+
76+
default:
77+
this->dataMode = SERCOM_SPI_MODE_0;
5678
}
57-
this->clockDiv = div;
58-
this->dataMode = dataMode;
59-
this->bitOrder = bitOrder;
6079
}
6180

62-
uint8_t clockDiv, dataMode;
63-
BitOrder bitOrder;
81+
uint32_t clockFreq;
82+
SercomSpiClockMode dataMode;
83+
SercomDataOrder bitOrder;
6484

6585
friend class SPIClass;
6686
};
@@ -73,7 +93,7 @@ class SPIClass {
7393
inline void transfer(void *buf, size_t count);
7494

7595
// Transaction Functions
76-
void usingInterrupt(uint8_t interruptNumber);
96+
void usingInterrupt(int interruptNumber);
7797
void beginTransaction(SPISettings settings);
7898
void endTransaction(void);
7999

@@ -89,10 +109,17 @@ class SPIClass {
89109
void setClockDivider(uint8_t uc_div);
90110

91111
private:
112+
void init();
113+
void config(SPISettings settings);
114+
92115
SERCOM *_p_sercom;
93116
uint8_t _uc_pinMiso;
94117
uint8_t _uc_pinMosi;
95118
uint8_t _uc_pinSCK;
119+
bool initialized;
120+
uint8_t interruptMode;
121+
char interruptSave;
122+
uint32_t interruptMask;
96123
};
97124

98125
void SPIClass::transfer(void *buf, size_t count)

0 commit comments

Comments
 (0)