source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/libraries/SPI/src/SPI.h @ 4837

Last change on this file since 4837 was 4837, checked in by daduve, 2 years ago

Adding new version

File size: 10.1 KB
Line 
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
72class SPISettings {
73public:
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  }
81  SPISettings() {
82    init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
83  }
84private:
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
156class SPIClass {
157public:
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
312private:
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
322extern SPIClass SPI;
323
324#endif
Note: See TracBrowser for help on using the repository browser.