SPI.h
Go to the documentation of this file.
1 /*
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)
6  * SPI Master library for arduino.
7  *
8  * This file is free software; you can redistribute it and/or modify
9  * it under the terms of either the GNU General Public License version 2
10  * or the GNU Lesser General Public License version 2.1, both as
11  * published by the Free Software Foundation.
12  */
13 
14 #ifndef _SPI_H_INCLUDED
15 #define _SPI_H_INCLUDED
16 
17 #include <Arduino.h>
18 
19 // SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
20 // usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
21 #define SPI_HAS_TRANSACTION 1
22 
23 // SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
24 #define SPI_HAS_NOTUSINGINTERRUPT 1
25 
26 // SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
27 // This way when there is a bug fix you can check this define to alert users
28 // of your code if it uses better version of this library.
29 // This also implies everything that SPI_HAS_TRANSACTION as documented above is
30 // available too.
31 #define SPI_ATOMIC_VERSION 1
32 
33 // Uncomment this line to add detection of mismatched begin/end transactions.
34 // A mismatch occurs if other libraries fail to use SPI.endTransaction() for
35 // each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
36 // on if any mismatch is ever detected.
37 //#define SPI_TRANSACTION_MISMATCH_LED 5
38 
39 #ifndef LSBFIRST
40 #define LSBFIRST 0
41 #endif
42 #ifndef MSBFIRST
43 #define MSBFIRST 1
44 #endif
45 
46 #define SPI_CLOCK_DIV4 0x00
47 #define SPI_CLOCK_DIV16 0x01
48 #define SPI_CLOCK_DIV64 0x02
49 #define SPI_CLOCK_DIV128 0x03
50 #define SPI_CLOCK_DIV2 0x04
51 #define SPI_CLOCK_DIV8 0x05
52 #define SPI_CLOCK_DIV32 0x06
53 
54 #define SPI_MODE0 0x00
55 #define SPI_MODE1 0x04
56 #define SPI_MODE2 0x08
57 #define SPI_MODE3 0x0C
58 
59 #define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
60 #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
61 #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
62 
63 // define SPI_AVR_EIMSK for AVR boards with external interrupt pins
64 #if defined(EIMSK)
65  #define SPI_AVR_EIMSK EIMSK
66 #elif defined(GICR)
67  #define SPI_AVR_EIMSK GICR
68 #elif defined(GIMSK)
69  #define SPI_AVR_EIMSK GIMSK
70 #endif
71 
72 class SPISettings {
73 public:
74  SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
75  if (__builtin_constant_p(clock)) {
76  init_AlwaysInline(clock, bitOrder, dataMode);
77  } else {
78  init_MightInline(clock, bitOrder, dataMode);
79  }
80  }
83  }
84 private:
85  void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
86  init_AlwaysInline(clock, bitOrder, dataMode);
87  }
88  void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
89  __attribute__((__always_inline__)) {
90  // Clock settings are defined as follows. Note that this shows SPI2X
91  // inverted, so the bits form increasing numbers. Also note that
92  // fosc/64 appears twice
93  // SPR1 SPR0 ~SPI2X Freq
94  // 0 0 0 fosc/2
95  // 0 0 1 fosc/4
96  // 0 1 0 fosc/8
97  // 0 1 1 fosc/16
98  // 1 0 0 fosc/32
99  // 1 0 1 fosc/64
100  // 1 1 0 fosc/64
101  // 1 1 1 fosc/128
102 
103  // We find the fastest clock that is less than or equal to the
104  // given clock rate. The clock divider that results in clock_setting
105  // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
106  // slowest (128 == 2 ^^ 7, so clock_div = 6).
107  uint8_t clockDiv;
108 
109  // When the clock is known at compiletime, use this if-then-else
110  // cascade, which the compiler knows how to completely optimize
111  // away. When clock is not known, use a loop instead, which generates
112  // shorter code.
113  if (__builtin_constant_p(clock)) {
114  if (clock >= F_CPU / 2) {
115  clockDiv = 0;
116  } else if (clock >= F_CPU / 4) {
117  clockDiv = 1;
118  } else if (clock >= F_CPU / 8) {
119  clockDiv = 2;
120  } else if (clock >= F_CPU / 16) {
121  clockDiv = 3;
122  } else if (clock >= F_CPU / 32) {
123  clockDiv = 4;
124  } else if (clock >= F_CPU / 64) {
125  clockDiv = 5;
126  } else {
127  clockDiv = 6;
128  }
129  } else {
130  uint32_t clockSetting = F_CPU / 2;
131  clockDiv = 0;
132  while (clockDiv < 6 && clock < clockSetting) {
133  clockSetting /= 2;
134  clockDiv++;
135  }
136  }
137 
138  // Compensate for the duplicate fosc/64
139  if (clockDiv == 6)
140  clockDiv = 7;
141 
142  // Invert the SPI2X bit
143  clockDiv ^= 0x1;
144 
145  // Pack into the SPISettings class
146  spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
147  (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
148  spsr = clockDiv & SPI_2XCLOCK_MASK;
149  }
150  uint8_t spcr;
151  uint8_t spsr;
152  friend class SPIClass;
153 };
154 
155 
156 class SPIClass {
157 public:
158  // Initialize the SPI library
159  static void begin();
160 
161  // If SPI is used from within an interrupt, this function registers
162  // that interrupt with the SPI library, so beginTransaction() can
163  // prevent conflicts. The input interruptNumber is the number used
164  // with attachInterrupt. If SPI is used from a different interrupt
165  // (eg, a timer), interruptNumber should be 255.
166  static void usingInterrupt(uint8_t interruptNumber);
167  // And this does the opposite.
168  static void notUsingInterrupt(uint8_t interruptNumber);
169  // Note: the usingInterrupt and notUsingInterrupt functions should
170  // not to be called from ISR context or inside a transaction.
171  // For details see:
172  // https://github.com/arduino/Arduino/pull/2381
173  // https://github.com/arduino/Arduino/pull/2449
174 
175  // Before using SPI.transfer() or asserting chip select pins,
176  // this function is used to gain exclusive access to the SPI bus
177  // and configure the correct settings.
178  inline static void beginTransaction(SPISettings settings) {
179  if (interruptMode > 0) {
180  uint8_t sreg = SREG;
181  noInterrupts();
182 
183  #ifdef SPI_AVR_EIMSK
184  if (interruptMode == 1) {
185  interruptSave = SPI_AVR_EIMSK;
186  SPI_AVR_EIMSK &= ~interruptMask;
187  SREG = sreg;
188  } else
189  #endif
190  {
191  interruptSave = sreg;
192  }
193  }
194 
195  #ifdef SPI_TRANSACTION_MISMATCH_LED
196  if (inTransactionFlag) {
197  pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
198  digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
199  }
200  inTransactionFlag = 1;
201  #endif
202 
203  SPCR = settings.spcr;
204  SPSR = settings.spsr;
205  }
206 
207  // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
208  inline static uint8_t transfer(uint8_t data) {
209  SPDR = data;
210  /*
211  * The following NOP introduces a small delay that can prevent the wait
212  * loop form iterating when running at the maximum speed. This gives
213  * about 10% more speed, even if it seems counter-intuitive. At lower
214  * speeds it is unnoticed.
215  */
216  asm volatile("nop");
217  while (!(SPSR & _BV(SPIF))) ; // wait
218  return SPDR;
219  }
220  inline static uint16_t transfer16(uint16_t data) {
221  union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
222  in.val = data;
223  if (!(SPCR & _BV(DORD))) {
224  SPDR = in.msb;
225  asm volatile("nop"); // See transfer(uint8_t) function
226  while (!(SPSR & _BV(SPIF))) ;
227  out.msb = SPDR;
228  SPDR = in.lsb;
229  asm volatile("nop");
230  while (!(SPSR & _BV(SPIF))) ;
231  out.lsb = SPDR;
232  } else {
233  SPDR = in.lsb;
234  asm volatile("nop");
235  while (!(SPSR & _BV(SPIF))) ;
236  out.lsb = SPDR;
237  SPDR = in.msb;
238  asm volatile("nop");
239  while (!(SPSR & _BV(SPIF))) ;
240  out.msb = SPDR;
241  }
242  return out.val;
243  }
244  inline static void transfer(void *buf, size_t count) {
245  if (count == 0) return;
246  uint8_t *p = (uint8_t *)buf;
247  SPDR = *p;
248  while (--count > 0) {
249  uint8_t out = *(p + 1);
250  while (!(SPSR & _BV(SPIF))) ;
251  uint8_t in = SPDR;
252  SPDR = out;
253  *p++ = in;
254  }
255  while (!(SPSR & _BV(SPIF))) ;
256  *p = SPDR;
257  }
258  // After performing a group of transfers and releasing the chip select
259  // signal, this function allows others to access the SPI bus
260  inline static void endTransaction(void) {
261  #ifdef SPI_TRANSACTION_MISMATCH_LED
262  if (!inTransactionFlag) {
263  pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
264  digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
265  }
266  inTransactionFlag = 0;
267  #endif
268 
269  if (interruptMode > 0) {
270  #ifdef SPI_AVR_EIMSK
271  uint8_t sreg = SREG;
272  #endif
273  noInterrupts();
274  #ifdef SPI_AVR_EIMSK
275  if (interruptMode == 1) {
276  SPI_AVR_EIMSK = interruptSave;
277  SREG = sreg;
278  } else
279  #endif
280  {
281  SREG = interruptSave;
282  }
283  }
284  }
285 
286  // Disable the SPI bus
287  static void end();
288 
289  // This function is deprecated. New applications should use
290  // beginTransaction() to configure SPI settings.
291  inline static void setBitOrder(uint8_t bitOrder) {
292  if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
293  else SPCR &= ~(_BV(DORD));
294  }
295  // This function is deprecated. New applications should use
296  // beginTransaction() to configure SPI settings.
297  inline static void setDataMode(uint8_t dataMode) {
298  SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
299  }
300  // This function is deprecated. New applications should use
301  // beginTransaction() to configure SPI settings.
302  inline static void setClockDivider(uint8_t clockDiv) {
303  SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
304  SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
305  }
306  // These undocumented functions should not be used. SPI.transfer()
307  // polls the hardware flag which is automatically cleared as the
308  // AVR responds to SPI's interrupt
309  inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
310  inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
311 
312 private:
313  static uint8_t initialized;
314  static uint8_t interruptMode; // 0=none, 1=mask, 2=global
315  static uint8_t interruptMask; // which interrupts to mask
316  static uint8_t interruptSave; // temp storage, to restore state
317  #ifdef SPI_TRANSACTION_MISMATCH_LED
318  static uint8_t inTransactionFlag;
319  #endif
320 };
321 
322 extern SPIClass SPI;
323 
324 #endif
SPIClass SPI
Definition: SPI.cpp:16
static uint16_t transfer16(uint16_t data)
Definition: SPI.h:220
void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) __attribute__((__always_inline__))
Definition: SPI.h:88
void pinMode(uint8_t, uint8_t)
#define noInterrupts()
Definition: Arduino.h:102
static uint8_t interruptMode
Definition: SPI.h:314
static void detachInterrupt()
Definition: SPI.h:310
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
Definition: SPI.h:74
static uint8_t interruptSave
Definition: SPI.h:316
#define MSBFIRST
Definition: SPI.h:43
EIGEN_STRONG_INLINE iterator begin()
static void setBitOrder(uint8_t bitOrder)
Definition: SPI.h:291
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
Definition: SPI.h:85
uint8_t spsr
Definition: SPI.h:151
static uint8_t transfer(uint8_t data)
Definition: SPI.h:208
GLuint in
unsigned int uint32_t
static void transfer(void *buf, size_t count)
Definition: SPI.h:244
#define SPI_MODE_MASK
Definition: SPI.h:59
GLuint GLuint end
#define OUTPUT
Definition: Arduino.h:44
#define HIGH
Definition: Arduino.h:40
#define SPI_CLOCK_MASK
Definition: SPI.h:60
static void setDataMode(uint8_t dataMode)
Definition: SPI.h:297
SPISettings()
Definition: SPI.h:81
#define LSBFIRST
Definition: SPI.h:40
static void endTransaction(void)
Definition: SPI.h:260
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
uint8_t spcr
Definition: SPI.h:150
GLfloat GLfloat p
Definition: SPI.h:156
rp::arch::net::raw_serial __attribute__
static uint8_t initialized
Definition: SPI.h:313
void digitalWrite(uint8_t, uint8_t)
GLuint GLuint GLsizei count
static void beginTransaction(SPISettings settings)
Definition: SPI.h:178
static void attachInterrupt()
Definition: SPI.h:309
static uint8_t interruptMask
Definition: SPI.h:315
GLuint GLfloat * val
#define SPI_2XCLOCK_MASK
Definition: SPI.h:61
#define SPI_MODE0
Definition: SPI.h:54
static void setClockDivider(uint8_t clockDiv)
Definition: SPI.h:302


arduino_daq
Author(s):
autogenerated on Mon Jun 10 2019 12:46:03