Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

547 lines
17KB

  1. /*
  2. * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
  3. * Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
  4. * Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings)
  5. * SPI Master library for arduino.
  6. *
  7. * This file is free software; you can redistribute it and/or modify
  8. * it under the terms of either the GNU General Public License version 2
  9. * or the GNU Lesser General Public License version 2.1, both as
  10. * published by the Free Software Foundation.
  11. */
  12. #ifndef _SPI_H_INCLUDED
  13. #define _SPI_H_INCLUDED
  14. #include <Arduino.h>
  15. // SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
  16. // usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
  17. #define SPI_HAS_TRANSACTION 1
  18. #ifndef LSBFIRST
  19. #define LSBFIRST 0
  20. #endif
  21. #ifndef MSBFIRST
  22. #define MSBFIRST 1
  23. #endif
  24. #define SPI_MODE0 0x00
  25. #define SPI_MODE1 0x04
  26. #define SPI_MODE2 0x08
  27. #define SPI_MODE3 0x0C
  28. #define SPI_CLOCK_DIV4 0x00
  29. #define SPI_CLOCK_DIV16 0x01
  30. #define SPI_CLOCK_DIV64 0x02
  31. #define SPI_CLOCK_DIV128 0x03
  32. #define SPI_CLOCK_DIV2 0x04
  33. #define SPI_CLOCK_DIV8 0x05
  34. #define SPI_CLOCK_DIV32 0x06
  35. #define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
  36. #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
  37. #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
  38. /**********************************************************/
  39. /* 8 bit AVR-based boards */
  40. /**********************************************************/
  41. #if defined(__AVR__)
  42. // define SPI_AVR_EIMSK for AVR boards with external interrupt pins
  43. #if defined(EIMSK)
  44. #define SPI_AVR_EIMSK EIMSK
  45. #elif defined(GICR)
  46. #define SPI_AVR_EIMSK GICR
  47. #elif defined(GIMSK)
  48. #define SPI_AVR_EIMSK GIMSK
  49. #endif
  50. class SPISettings {
  51. public:
  52. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  53. if (__builtin_constant_p(clock)) {
  54. init_AlwaysInline(clock, bitOrder, dataMode);
  55. } else {
  56. init_MightInline(clock, bitOrder, dataMode);
  57. }
  58. }
  59. SPISettings() {
  60. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  61. }
  62. private:
  63. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  64. init_AlwaysInline(clock, bitOrder, dataMode);
  65. }
  66. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  67. __attribute__((__always_inline__)) {
  68. // Clock settings are defined as follows. Note that this shows SPI2X
  69. // inverted, so the bits form increasing numbers. Also note that
  70. // fosc/64 appears twice
  71. // SPR1 SPR0 ~SPI2X Freq
  72. // 0 0 0 fosc/2
  73. // 0 0 1 fosc/4
  74. // 0 1 0 fosc/8
  75. // 0 1 1 fosc/16
  76. // 1 0 0 fosc/32
  77. // 1 0 1 fosc/64
  78. // 1 1 0 fosc/64
  79. // 1 1 1 fosc/128
  80. // We find the fastest clock that is less than or equal to the
  81. // given clock rate. The clock divider that results in clock_setting
  82. // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
  83. // slowest (128 == 2 ^^ 7, so clock_div = 6).
  84. uint8_t clockDiv;
  85. // When the clock is known at compiletime, use this if-then-else
  86. // cascade, which the compiler knows how to completely optimize
  87. // away. When clock is not known, use a loop instead, which generates
  88. // shorter code.
  89. if (__builtin_constant_p(clock)) {
  90. if (clock >= F_CPU / 2) {
  91. clockDiv = 0;
  92. } else if (clock >= F_CPU / 4) {
  93. clockDiv = 1;
  94. } else if (clock >= F_CPU / 8) {
  95. clockDiv = 2;
  96. } else if (clock >= F_CPU / 16) {
  97. clockDiv = 3;
  98. } else if (clock >= F_CPU / 32) {
  99. clockDiv = 4;
  100. } else if (clock >= F_CPU / 64) {
  101. clockDiv = 5;
  102. } else {
  103. clockDiv = 6;
  104. }
  105. } else {
  106. uint32_t clockSetting = F_CPU / 2;
  107. clockDiv = 0;
  108. while (clockDiv < 6 && clock < clockSetting) {
  109. clockSetting /= 2;
  110. clockDiv++;
  111. }
  112. }
  113. // Compensate for the duplicate fosc/64
  114. if (clockDiv == 6)
  115. clockDiv = 7;
  116. // Invert the SPI2X bit
  117. clockDiv ^= 0x1;
  118. // Pack into the SPISettings class
  119. spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
  120. (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
  121. spsr = clockDiv & SPI_2XCLOCK_MASK;
  122. }
  123. uint8_t spcr;
  124. uint8_t spsr;
  125. friend class SPIClass;
  126. };
  127. class SPIClass {
  128. public:
  129. // Initialize the SPI library
  130. static void begin();
  131. // If SPI is to used from within an interrupt, this function registers
  132. // that interrupt with the SPI library, so beginTransaction() can
  133. // prevent conflicts. The input interruptNumber is the number used
  134. // with attachInterrupt. If SPI is used from a different interrupt
  135. // (eg, a timer), interruptNumber should be 255.
  136. static void usingInterrupt(uint8_t interruptNumber);
  137. // Before using SPI.transfer() or asserting chip select pins,
  138. // this function is used to gain exclusive access to the SPI bus
  139. // and configure the correct settings.
  140. inline static void beginTransaction(SPISettings settings) {
  141. if (interruptMode > 0) {
  142. #ifdef SPI_AVR_EIMSK
  143. if (interruptMode == 1) {
  144. interruptSave = SPI_AVR_EIMSK;
  145. SPI_AVR_EIMSK &= ~interruptMask;
  146. } else
  147. #endif
  148. {
  149. interruptSave = SREG;
  150. cli();
  151. }
  152. }
  153. SPCR = settings.spcr;
  154. SPSR = settings.spsr;
  155. }
  156. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  157. inline static uint8_t transfer(uint8_t data) {
  158. SPDR = data;
  159. asm volatile("nop");
  160. while (!(SPSR & _BV(SPIF))) ; // wait
  161. return SPDR;
  162. }
  163. inline static uint16_t transfer16(uint16_t data) {
  164. union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
  165. in.val = data;
  166. if (!(SPCR & _BV(DORD))) {
  167. SPDR = in.msb;
  168. while (!(SPSR & _BV(SPIF))) ;
  169. out.msb = SPDR;
  170. SPDR = in.lsb;
  171. while (!(SPSR & _BV(SPIF))) ;
  172. out.lsb = SPDR;
  173. } else {
  174. SPDR = in.lsb;
  175. while (!(SPSR & _BV(SPIF))) ;
  176. out.lsb = SPDR;
  177. SPDR = in.msb;
  178. while (!(SPSR & _BV(SPIF))) ;
  179. out.msb = SPDR;
  180. }
  181. return out.val;
  182. }
  183. inline static void transfer(void *buf, size_t count) {
  184. if (count == 0) return;
  185. uint8_t *p = (uint8_t *)buf;
  186. SPDR = *p;
  187. while (--count > 0) {
  188. uint8_t out = *(p + 1);
  189. while (!(SPSR & _BV(SPIF))) ;
  190. uint8_t in = SPDR;
  191. SPDR = out;
  192. *p++ = in;
  193. }
  194. while (!(SPSR & _BV(SPIF))) ;
  195. *p = SPDR;
  196. }
  197. // After performing a group of transfers and releasing the chip select
  198. // signal, this function allows others to access the SPI bus
  199. inline static void endTransaction(void) {
  200. if (interruptMode > 0) {
  201. #ifdef SPI_AVR_EIMSK
  202. if (interruptMode == 1) {
  203. SPI_AVR_EIMSK = interruptSave;
  204. } else
  205. #endif
  206. {
  207. SREG = interruptSave;
  208. }
  209. }
  210. }
  211. // Disable the SPI bus
  212. static void end();
  213. // This function is deprecated. New applications should use
  214. // beginTransaction() to configure SPI settings.
  215. inline static void setBitOrder(uint8_t bitOrder) {
  216. if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
  217. else SPCR &= ~(_BV(DORD));
  218. }
  219. // This function is deprecated. New applications should use
  220. // beginTransaction() to configure SPI settings.
  221. inline static void setDataMode(uint8_t dataMode) {
  222. SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
  223. }
  224. // This function is deprecated. New applications should use
  225. // beginTransaction() to configure SPI settings.
  226. inline static void setClockDivider(uint8_t clockDiv) {
  227. SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
  228. SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
  229. }
  230. // These undocumented functions should not be used. SPI.transfer()
  231. // polls the hardware flag which is automatically cleared as the
  232. // AVR responds to SPI's interrupt
  233. inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
  234. inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
  235. private:
  236. static uint8_t interruptMode; // 0=none, 1=mask, 2=global
  237. static uint8_t interruptMask; // which interrupts to mask
  238. static uint8_t interruptSave; // temp storage, to restore state
  239. };
  240. // mapping of interrupt numbers to bits within SPI_AVR_EIMSK
  241. #if defined(__AVR_ATmega32U4__)
  242. #define SPI_INT0_MASK (1<<INT0)
  243. #define SPI_INT1_MASK (1<<INT1)
  244. #define SPI_INT2_MASK (1<<INT2)
  245. #define SPI_INT3_MASK (1<<INT3)
  246. #define SPI_INT4_MASK (1<<INT6)
  247. #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
  248. #define SPI_INT0_MASK (1<<INT0)
  249. #define SPI_INT1_MASK (1<<INT1)
  250. #define SPI_INT2_MASK (1<<INT2)
  251. #define SPI_INT3_MASK (1<<INT3)
  252. #define SPI_INT4_MASK (1<<INT4)
  253. #define SPI_INT5_MASK (1<<INT5)
  254. #define SPI_INT6_MASK (1<<INT6)
  255. #define SPI_INT7_MASK (1<<INT7)
  256. #elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
  257. #define SPI_INT0_MASK (1<<INT4)
  258. #define SPI_INT1_MASK (1<<INT5)
  259. #define SPI_INT2_MASK (1<<INT0)
  260. #define SPI_INT3_MASK (1<<INT1)
  261. #define SPI_INT4_MASK (1<<INT2)
  262. #define SPI_INT5_MASK (1<<INT3)
  263. #define SPI_INT6_MASK (1<<INT6)
  264. #define SPI_INT7_MASK (1<<INT7)
  265. #else
  266. #ifdef INT0
  267. #define SPI_INT0_MASK (1<<INT0)
  268. #endif
  269. #ifdef INT1
  270. #define SPI_INT1_MASK (1<<INT1)
  271. #endif
  272. #ifdef INT2
  273. #define SPI_INT2_MASK (1<<INT2)
  274. #endif
  275. #endif
  276. /**********************************************************/
  277. /* 32 bit Teensy 3.0 and 3.1 */
  278. /**********************************************************/
  279. #elif defined(__arm__) && defined(TEENSYDUINO)
  280. class SPISettings {
  281. public:
  282. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  283. if (__builtin_constant_p(clock)) {
  284. init_AlwaysInline(clock, bitOrder, dataMode);
  285. } else {
  286. init_MightInline(clock, bitOrder, dataMode);
  287. }
  288. }
  289. SPISettings() {
  290. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  291. }
  292. private:
  293. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  294. init_AlwaysInline(clock, bitOrder, dataMode);
  295. }
  296. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  297. __attribute__((__always_inline__)) {
  298. uint32_t t, c = SPI_CTAR_FMSZ(7);
  299. if (bitOrder == LSBFIRST) c |= SPI_CTAR_LSBFE;
  300. if (__builtin_constant_p(clock)) {
  301. if (clock >= F_BUS / 2) {
  302. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  303. | SPI_CTAR_CSSCK(0);
  304. } else if (clock >= F_BUS / 3) {
  305. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  306. | SPI_CTAR_CSSCK(0);
  307. } else if (clock >= F_BUS / 4) {
  308. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  309. } else if (clock >= F_BUS / 5) {
  310. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  311. | SPI_CTAR_CSSCK(0);
  312. } else if (clock >= F_BUS / 6) {
  313. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  314. } else if (clock >= F_BUS / 8) {
  315. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  316. } else if (clock >= F_BUS / 10) {
  317. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  318. } else if (clock >= F_BUS / 12) {
  319. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  320. } else if (clock >= F_BUS / 16) {
  321. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  322. } else if (clock >= F_BUS / 20) {
  323. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(0);
  324. } else if (clock >= F_BUS / 24) {
  325. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  326. } else if (clock >= F_BUS / 32) {
  327. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(3);
  328. } else if (clock >= F_BUS / 40) {
  329. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  330. } else if (clock >= F_BUS / 56) {
  331. t = SPI_CTAR_PBR(3) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  332. } else if (clock >= F_BUS / 64) {
  333. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4);
  334. } else if (clock >= F_BUS / 96) {
  335. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4);
  336. } else if (clock >= F_BUS / 128) {
  337. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5);
  338. } else if (clock >= F_BUS / 192) {
  339. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5);
  340. } else if (clock >= F_BUS / 256) {
  341. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  342. } else if (clock >= F_BUS / 384) {
  343. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  344. } else if (clock >= F_BUS / 512) {
  345. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
  346. } else if (clock >= F_BUS / 640) {
  347. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  348. } else { /* F_BUS / 768 */
  349. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
  350. }
  351. } else {
  352. for (uint32_t i=0; i<23; i++) {
  353. t = ctar_clock_table[i];
  354. if (clock >= F_BUS / ctar_div_table[i]) break;
  355. }
  356. }
  357. if (dataMode & 0x08) {
  358. c |= SPI_CTAR_CPOL;
  359. }
  360. if (dataMode & 0x04) {
  361. c |= SPI_CTAR_CPHA;
  362. t = (t & 0xFFFF0FFF) | ((t & 0xF000) >> 4);
  363. }
  364. ctar = c | t;
  365. }
  366. static const uint16_t ctar_div_table[23];
  367. static const uint32_t ctar_clock_table[23];
  368. uint32_t ctar;
  369. friend class SPIClass;
  370. };
  371. class SPIClass {
  372. public:
  373. // Initialize the SPI library
  374. static void begin();
  375. // If SPI is to used from within an interrupt, this function registers
  376. // that interrupt with the SPI library, so beginTransaction() can
  377. // prevent conflicts. The input interruptNumber is the number used
  378. // with attachInterrupt. If SPI is used from a different interrupt
  379. // (eg, a timer), interruptNumber should be 255.
  380. static void usingInterrupt(uint8_t interruptNumber);
  381. static void usingInterrupt(IRQ_NUMBER_t interruptName);
  382. // Before using SPI.transfer() or asserting chip select pins,
  383. // this function is used to gain exclusive access to the SPI bus
  384. // and configure the correct settings.
  385. inline static void beginTransaction(SPISettings settings) {
  386. if (interruptMode > 0) {
  387. #ifdef SPI_AVR_EIMSK
  388. if (interruptMode == 1) {
  389. interruptSave = SPI_AVR_EIMSK;
  390. SPI_AVR_EIMSK &= ~interruptMask;
  391. } else
  392. #endif
  393. {
  394. interruptSave = SREG;
  395. cli();
  396. }
  397. }
  398. if (SPI0_CTAR0 != settings.ctar) {
  399. SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  400. SPI0_CTAR0 = settings.ctar;
  401. SPI0_CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
  402. SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
  403. }
  404. }
  405. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  406. inline static uint8_t transfer(uint8_t data) {
  407. SPDR = data;
  408. while (!(SPSR & _BV(SPIF))) ; // wait
  409. return SPDR;
  410. }
  411. inline static void transfer(void *buf, size_t count) {
  412. if (count == 0) return;
  413. uint8_t *p = (uint8_t *)buf;
  414. SPDR = *p;
  415. while (--count > 0) {
  416. uint8_t out = *(p + 1);
  417. while (!(SPSR & _BV(SPIF))) ;
  418. uint8_t in = SPDR;
  419. SPDR = out;
  420. *p++ = in;
  421. }
  422. while (!(SPSR & _BV(SPIF))) ;
  423. *p = SPDR;
  424. }
  425. // After performing a group of transfers and releasing the chip select
  426. // signal, this function allows others to access the SPI bus
  427. inline static void endTransaction(void) {
  428. if (interruptMode > 0) {
  429. #ifdef SPI_AVR_EIMSK
  430. if (interruptMode == 1) {
  431. SPI_AVR_EIMSK = interruptSave;
  432. } else
  433. #endif
  434. {
  435. SREG = interruptSave;
  436. }
  437. }
  438. }
  439. // Disable the SPI bus
  440. static void end();
  441. // This function is deprecated. New applications should use
  442. // beginTransaction() to configure SPI settings.
  443. static void setBitOrder(uint8_t bitOrder);
  444. // This function is deprecated. New applications should use
  445. // beginTransaction() to configure SPI settings.
  446. static void setDataMode(uint8_t dataMode);
  447. // This function is deprecated. New applications should use
  448. // beginTransaction() to configure SPI settings.
  449. inline static void setClockDivider(uint8_t clockDiv) {
  450. if (clockDiv == SPI_CLOCK_DIV2) {
  451. setClockDivider_noInline(SPISettings(8000000, MSBFIRST, SPI_MODE0).ctar);
  452. } else if (clockDiv == SPI_CLOCK_DIV4) {
  453. setClockDivider_noInline(SPISettings(4000000, MSBFIRST, SPI_MODE0).ctar);
  454. } else if (clockDiv == SPI_CLOCK_DIV8) {
  455. setClockDivider_noInline(SPISettings(2000000, MSBFIRST, SPI_MODE0).ctar);
  456. } else if (clockDiv == SPI_CLOCK_DIV16) {
  457. setClockDivider_noInline(SPISettings(1000000, MSBFIRST, SPI_MODE0).ctar);
  458. } else if (clockDiv == SPI_CLOCK_DIV32) {
  459. setClockDivider_noInline(SPISettings(500000, MSBFIRST, SPI_MODE0).ctar);
  460. } else if (clockDiv == SPI_CLOCK_DIV64) {
  461. setClockDivider_noInline(SPISettings(250000, MSBFIRST, SPI_MODE0).ctar);
  462. } else { /* clockDiv == SPI_CLOCK_DIV128 */
  463. setClockDivider_noInline(SPISettings(125000, MSBFIRST, SPI_MODE0).ctar);
  464. }
  465. }
  466. static void setClockDivider_noInline(uint32_t clk);
  467. // These undocumented functions should not be used. SPI.transfer()
  468. // polls the hardware flag which is automatically cleared as the
  469. // AVR responds to SPI's interrupt
  470. inline static void attachInterrupt() { }
  471. inline static void detachInterrupt() { }
  472. // Teensy 3.x can use alternate pins for these 3 SPI signals.
  473. inline static void setMOSI(uint8_t pin) __attribute__((always_inline)) {
  474. SPCR.setMOSI(pin);
  475. }
  476. inline static void setMISO(uint8_t pin) __attribute__((always_inline)) {
  477. SPCR.setMISO(pin);
  478. }
  479. inline static void setSCK(uint8_t pin) __attribute__((always_inline)) {
  480. SPCR.setSCK(pin);
  481. }
  482. // return true if "pin" has special chip select capability
  483. static bool pinIsChipSelect(uint8_t pin);
  484. // return true if both pin1 and pin2 have independent chip select capability
  485. static bool pinIsChipSelect(uint8_t pin1, uint8_t pin2);
  486. // configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
  487. static uint8_t setCS(uint8_t pin);
  488. private:
  489. static uint8_t interruptMode; // 0=none, 1=mask, 2=global
  490. static uint8_t interruptMask; // which interrupts to mask
  491. static uint8_t interruptSave; // temp storage, to restore state
  492. };
  493. #endif
  494. extern SPIClass SPI;
  495. #endif