Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

964 lines
33KB

  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 AVR)
  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. // Uncomment this line to add detection of mismatched begin/end transactions.
  19. // A mismatch occurs if other libraries fail to use SPI.endTransaction() for
  20. // each SPI.beginTransaction(). Connect a LED to this pin. The LED will turn
  21. // on if any mismatch is ever detected.
  22. //#define SPI_TRANSACTION_MISMATCH_LED 5
  23. #ifndef LSBFIRST
  24. #define LSBFIRST 0
  25. #endif
  26. #ifndef MSBFIRST
  27. #define MSBFIRST 1
  28. #endif
  29. #define SPI_MODE0 0x00
  30. #define SPI_MODE1 0x04
  31. #define SPI_MODE2 0x08
  32. #define SPI_MODE3 0x0C
  33. #define SPI_CLOCK_DIV4 0x00
  34. #define SPI_CLOCK_DIV16 0x01
  35. #define SPI_CLOCK_DIV64 0x02
  36. #define SPI_CLOCK_DIV128 0x03
  37. #define SPI_CLOCK_DIV2 0x04
  38. #define SPI_CLOCK_DIV8 0x05
  39. #define SPI_CLOCK_DIV32 0x06
  40. #define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
  41. #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
  42. #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
  43. /**********************************************************/
  44. /* 8 bit AVR-based boards */
  45. /**********************************************************/
  46. #if defined(__AVR__)
  47. // define SPI_AVR_EIMSK for AVR boards with external interrupt pins
  48. #if defined(EIMSK)
  49. #define SPI_AVR_EIMSK EIMSK
  50. #elif defined(GICR)
  51. #define SPI_AVR_EIMSK GICR
  52. #elif defined(GIMSK)
  53. #define SPI_AVR_EIMSK GIMSK
  54. #endif
  55. class SPISettings {
  56. public:
  57. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  58. if (__builtin_constant_p(clock)) {
  59. init_AlwaysInline(clock, bitOrder, dataMode);
  60. } else {
  61. init_MightInline(clock, bitOrder, dataMode);
  62. }
  63. }
  64. SPISettings() {
  65. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  66. }
  67. private:
  68. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  69. init_AlwaysInline(clock, bitOrder, dataMode);
  70. }
  71. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  72. __attribute__((__always_inline__)) {
  73. // Clock settings are defined as follows. Note that this shows SPI2X
  74. // inverted, so the bits form increasing numbers. Also note that
  75. // fosc/64 appears twice
  76. // SPR1 SPR0 ~SPI2X Freq
  77. // 0 0 0 fosc/2
  78. // 0 0 1 fosc/4
  79. // 0 1 0 fosc/8
  80. // 0 1 1 fosc/16
  81. // 1 0 0 fosc/32
  82. // 1 0 1 fosc/64
  83. // 1 1 0 fosc/64
  84. // 1 1 1 fosc/128
  85. // We find the fastest clock that is less than or equal to the
  86. // given clock rate. The clock divider that results in clock_setting
  87. // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
  88. // slowest (128 == 2 ^^ 7, so clock_div = 6).
  89. uint8_t clockDiv;
  90. // When the clock is known at compiletime, use this if-then-else
  91. // cascade, which the compiler knows how to completely optimize
  92. // away. When clock is not known, use a loop instead, which generates
  93. // shorter code.
  94. if (__builtin_constant_p(clock)) {
  95. if (clock >= F_CPU / 2) {
  96. clockDiv = 0;
  97. } else if (clock >= F_CPU / 4) {
  98. clockDiv = 1;
  99. } else if (clock >= F_CPU / 8) {
  100. clockDiv = 2;
  101. } else if (clock >= F_CPU / 16) {
  102. clockDiv = 3;
  103. } else if (clock >= F_CPU / 32) {
  104. clockDiv = 4;
  105. } else if (clock >= F_CPU / 64) {
  106. clockDiv = 5;
  107. } else {
  108. clockDiv = 6;
  109. }
  110. } else {
  111. uint32_t clockSetting = F_CPU / 2;
  112. clockDiv = 0;
  113. while (clockDiv < 6 && clock < clockSetting) {
  114. clockSetting /= 2;
  115. clockDiv++;
  116. }
  117. }
  118. // Compensate for the duplicate fosc/64
  119. if (clockDiv == 6)
  120. clockDiv = 7;
  121. // Invert the SPI2X bit
  122. clockDiv ^= 0x1;
  123. // Pack into the SPISettings class
  124. spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
  125. (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
  126. spsr = clockDiv & SPI_2XCLOCK_MASK;
  127. }
  128. uint8_t spcr;
  129. uint8_t spsr;
  130. friend class SPIClass;
  131. };
  132. class SPIClass { // AVR
  133. public:
  134. // Initialize the SPI library
  135. static void begin();
  136. // If SPI is used from within an interrupt, this function registers
  137. // that interrupt with the SPI library, so beginTransaction() can
  138. // prevent conflicts. The input interruptNumber is the number used
  139. // with attachInterrupt. If SPI is used from a different interrupt
  140. // (eg, a timer), interruptNumber should be 255.
  141. static void usingInterrupt(uint8_t interruptNumber);
  142. // Before using SPI.transfer() or asserting chip select pins,
  143. // this function is used to gain exclusive access to the SPI bus
  144. // and configure the correct settings.
  145. inline static void beginTransaction(SPISettings settings) {
  146. if (interruptMode > 0) {
  147. #ifdef SPI_AVR_EIMSK
  148. if (interruptMode == 1) {
  149. interruptSave = SPI_AVR_EIMSK;
  150. SPI_AVR_EIMSK &= ~interruptMask;
  151. } else
  152. #endif
  153. {
  154. uint8_t tmp = SREG;
  155. cli();
  156. interruptSave = tmp;
  157. }
  158. }
  159. #ifdef SPI_TRANSACTION_MISMATCH_LED
  160. if (inTransactionFlag) {
  161. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  162. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  163. }
  164. inTransactionFlag = 1;
  165. #endif
  166. SPCR = settings.spcr;
  167. SPSR = settings.spsr;
  168. }
  169. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  170. inline static uint8_t transfer(uint8_t data) {
  171. SPDR = data;
  172. asm volatile("nop");
  173. while (!(SPSR & _BV(SPIF))) ; // wait
  174. return SPDR;
  175. }
  176. inline static uint16_t transfer16(uint16_t data) {
  177. union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
  178. in.val = data;
  179. if ((SPCR & _BV(DORD))) {
  180. SPDR = in.lsb;
  181. asm volatile("nop");
  182. while (!(SPSR & _BV(SPIF))) ;
  183. out.lsb = SPDR;
  184. SPDR = in.msb;
  185. asm volatile("nop");
  186. while (!(SPSR & _BV(SPIF))) ;
  187. out.msb = SPDR;
  188. } else {
  189. SPDR = in.msb;
  190. asm volatile("nop");
  191. while (!(SPSR & _BV(SPIF))) ;
  192. out.msb = SPDR;
  193. SPDR = in.lsb;
  194. asm volatile("nop");
  195. while (!(SPSR & _BV(SPIF))) ;
  196. out.lsb = SPDR;
  197. }
  198. return out.val;
  199. }
  200. inline static void transfer(void *buf, size_t count) {
  201. if (count == 0) return;
  202. uint8_t *p = (uint8_t *)buf;
  203. SPDR = *p;
  204. while (--count > 0) {
  205. uint8_t out = *(p + 1);
  206. while (!(SPSR & _BV(SPIF))) ;
  207. uint8_t in = SPDR;
  208. SPDR = out;
  209. *p++ = in;
  210. }
  211. while (!(SPSR & _BV(SPIF))) ;
  212. *p = SPDR;
  213. }
  214. // After performing a group of transfers and releasing the chip select
  215. // signal, this function allows others to access the SPI bus
  216. inline static void endTransaction(void) {
  217. #ifdef SPI_TRANSACTION_MISMATCH_LED
  218. if (!inTransactionFlag) {
  219. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  220. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  221. }
  222. inTransactionFlag = 0;
  223. #endif
  224. if (interruptMode > 0) {
  225. #ifdef SPI_AVR_EIMSK
  226. if (interruptMode == 1) {
  227. SPI_AVR_EIMSK = interruptSave;
  228. } else
  229. #endif
  230. {
  231. SREG = interruptSave;
  232. }
  233. }
  234. }
  235. // Disable the SPI bus
  236. static void end();
  237. // This function is deprecated. New applications should use
  238. // beginTransaction() to configure SPI settings.
  239. inline static void setBitOrder(uint8_t bitOrder) {
  240. if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
  241. else SPCR &= ~(_BV(DORD));
  242. }
  243. // This function is deprecated. New applications should use
  244. // beginTransaction() to configure SPI settings.
  245. inline static void setDataMode(uint8_t dataMode) {
  246. SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
  247. }
  248. // This function is deprecated. New applications should use
  249. // beginTransaction() to configure SPI settings.
  250. inline static void setClockDivider(uint8_t clockDiv) {
  251. SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
  252. SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
  253. }
  254. // These undocumented functions should not be used. SPI.transfer()
  255. // polls the hardware flag which is automatically cleared as the
  256. // AVR responds to SPI's interrupt
  257. inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
  258. inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
  259. private:
  260. static uint8_t interruptMode; // 0=none, 1=mask, 2=global
  261. static uint8_t interruptMask; // which interrupts to mask
  262. static uint8_t interruptSave; // temp storage, to restore state
  263. #ifdef SPI_TRANSACTION_MISMATCH_LED
  264. static uint8_t inTransactionFlag;
  265. #endif
  266. };
  267. /**********************************************************/
  268. /* 32 bit Teensy 3.x */
  269. /**********************************************************/
  270. #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISK)
  271. #define SPI_HAS_NOTUSINGINTERRUPT 1
  272. class SPISettings {
  273. public:
  274. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  275. if (__builtin_constant_p(clock)) {
  276. init_AlwaysInline(clock, bitOrder, dataMode);
  277. } else {
  278. init_MightInline(clock, bitOrder, dataMode);
  279. }
  280. }
  281. SPISettings() {
  282. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  283. }
  284. private:
  285. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  286. init_AlwaysInline(clock, bitOrder, dataMode);
  287. }
  288. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  289. __attribute__((__always_inline__)) {
  290. uint32_t t, c = SPI_CTAR_FMSZ(7);
  291. if (bitOrder == LSBFIRST) c |= SPI_CTAR_LSBFE;
  292. if (__builtin_constant_p(clock)) {
  293. if (clock >= F_BUS / 2) {
  294. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  295. | SPI_CTAR_CSSCK(0);
  296. } else if (clock >= F_BUS / 3) {
  297. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  298. | SPI_CTAR_CSSCK(0);
  299. } else if (clock >= F_BUS / 4) {
  300. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  301. } else if (clock >= F_BUS / 5) {
  302. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  303. | SPI_CTAR_CSSCK(0);
  304. } else if (clock >= F_BUS / 6) {
  305. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  306. } else if (clock >= F_BUS / 8) {
  307. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  308. } else if (clock >= F_BUS / 10) {
  309. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  310. } else if (clock >= F_BUS / 12) {
  311. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  312. } else if (clock >= F_BUS / 16) {
  313. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  314. } else if (clock >= F_BUS / 20) {
  315. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(0);
  316. } else if (clock >= F_BUS / 24) {
  317. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  318. } else if (clock >= F_BUS / 32) {
  319. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(3);
  320. } else if (clock >= F_BUS / 40) {
  321. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  322. } else if (clock >= F_BUS / 56) {
  323. t = SPI_CTAR_PBR(3) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  324. } else if (clock >= F_BUS / 64) {
  325. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4);
  326. } else if (clock >= F_BUS / 96) {
  327. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4);
  328. } else if (clock >= F_BUS / 128) {
  329. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5);
  330. } else if (clock >= F_BUS / 192) {
  331. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5);
  332. } else if (clock >= F_BUS / 256) {
  333. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  334. } else if (clock >= F_BUS / 384) {
  335. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  336. } else if (clock >= F_BUS / 512) {
  337. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
  338. } else if (clock >= F_BUS / 640) {
  339. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  340. } else { /* F_BUS / 768 */
  341. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
  342. }
  343. } else {
  344. for (uint32_t i=0; i<23; i++) {
  345. t = ctar_clock_table[i];
  346. if (clock >= F_BUS / ctar_div_table[i]) break;
  347. }
  348. }
  349. if (dataMode & 0x08) {
  350. c |= SPI_CTAR_CPOL;
  351. }
  352. if (dataMode & 0x04) {
  353. c |= SPI_CTAR_CPHA;
  354. t = (t & 0xFFFF0FFF) | ((t & 0xF000) >> 4);
  355. }
  356. ctar = c | t;
  357. }
  358. static const uint16_t ctar_div_table[23];
  359. static const uint32_t ctar_clock_table[23];
  360. uint32_t ctar;
  361. friend class SPIClass;
  362. };
  363. class SPIClass { // Teensy 3.x
  364. public:
  365. #if defined(__MK20DX128__) || defined(__MK20DX256__)
  366. static const uint8_t CNT_MISO_PINS = 2;
  367. static const uint8_t CNT_MOSI_PINS = 2;
  368. static const uint8_t CNT_SCK_PINS = 2;
  369. static const uint8_t CNT_CS_PINS = 9;
  370. #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
  371. static const uint8_t CNT_MISO_PINS = 4;
  372. static const uint8_t CNT_MOSI_PINS = 4;
  373. static const uint8_t CNT_SCK_PINS = 3;
  374. static const uint8_t CNT_CS_PINS = 11;
  375. #endif
  376. typedef struct {
  377. volatile uint32_t &clock_gate_register;
  378. uint32_t clock_gate_mask;
  379. uint8_t queue_size;
  380. uint8_t spi_irq;
  381. uint32_t max_dma_count;
  382. uint8_t tx_dma_channel;
  383. uint8_t rx_dma_channel;
  384. void (*dma_rxisr)();
  385. uint8_t miso_pin[CNT_MISO_PINS];
  386. uint8_t miso_mux[CNT_MISO_PINS];
  387. uint8_t mosi_pin[CNT_MOSI_PINS];
  388. uint8_t mosi_mux[CNT_MOSI_PINS];
  389. uint8_t sck_pin[CNT_SCK_PINS];
  390. uint8_t sck_mux[CNT_SCK_PINS];
  391. uint8_t cs_pin[CNT_CS_PINS];
  392. uint8_t cs_mux[CNT_CS_PINS];
  393. uint8_t cs_mask[CNT_CS_PINS];
  394. } SPI_Hardware_t;
  395. static const SPI_Hardware_t spi0_hardware;
  396. static const SPI_Hardware_t spi1_hardware;
  397. static const SPI_Hardware_t spi2_hardware;
  398. public:
  399. constexpr SPIClass(uintptr_t myport, uintptr_t myhardware)
  400. : port_addr(myport), hardware_addr(myhardware) {
  401. }
  402. // Initialize the SPI library
  403. void begin();
  404. // If SPI is to used from within an interrupt, this function registers
  405. // that interrupt with the SPI library, so beginTransaction() can
  406. // prevent conflicts. The input interruptNumber is the number used
  407. // with attachInterrupt. If SPI is used from a different interrupt
  408. // (eg, a timer), interruptNumber should be 255.
  409. void usingInterrupt(uint8_t n) {
  410. if (n == 3 || n == 4 || n == 24 || n == 33) {
  411. usingInterrupt(IRQ_PORTA);
  412. } else if (n == 0 || n == 1 || (n >= 16 && n <= 19) || n == 25 || n == 32) {
  413. usingInterrupt(IRQ_PORTB);
  414. } else if ((n >= 9 && n <= 13) || n == 15 || n == 22 || n == 23
  415. || (n >= 27 && n <= 30)) {
  416. usingInterrupt(IRQ_PORTC);
  417. } else if (n == 2 || (n >= 5 && n <= 8) || n == 14 || n == 20 || n == 21) {
  418. usingInterrupt(IRQ_PORTD);
  419. } else if (n == 26 || n == 31) {
  420. usingInterrupt(IRQ_PORTE);
  421. }
  422. }
  423. void usingInterrupt(IRQ_NUMBER_t interruptName);
  424. void notUsingInterrupt(IRQ_NUMBER_t interruptName);
  425. // Before using SPI.transfer() or asserting chip select pins,
  426. // this function is used to gain exclusive access to the SPI bus
  427. // and configure the correct settings.
  428. void beginTransaction(SPISettings settings) {
  429. if (interruptMasksUsed) {
  430. __disable_irq();
  431. if (interruptMasksUsed & 0x01) {
  432. interruptSave[0] = NVIC_ICER0 & interruptMask[0];
  433. NVIC_ICER0 = interruptSave[0];
  434. }
  435. #if NVIC_NUM_INTERRUPTS > 32
  436. if (interruptMasksUsed & 0x02) {
  437. interruptSave[1] = NVIC_ICER1 & interruptMask[1];
  438. NVIC_ICER1 = interruptSave[1];
  439. }
  440. #endif
  441. #if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
  442. if (interruptMasksUsed & 0x04) {
  443. interruptSave[2] = NVIC_ICER2 & interruptMask[2];
  444. NVIC_ICER2 = interruptSave[2];
  445. }
  446. #endif
  447. #if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
  448. if (interruptMasksUsed & 0x08) {
  449. interruptSave[3] = NVIC_ICER3 & interruptMask[3];
  450. NVIC_ICER3 = interruptSave[3];
  451. }
  452. #endif
  453. __enable_irq();
  454. }
  455. #ifdef SPI_TRANSACTION_MISMATCH_LED
  456. if (inTransactionFlag) {
  457. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  458. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  459. }
  460. inTransactionFlag = 1;
  461. #endif
  462. if (port().CTAR0 != settings.ctar) {
  463. port().MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  464. port().CTAR0 = settings.ctar;
  465. port().CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
  466. port().MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
  467. }
  468. }
  469. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  470. uint8_t transfer(uint8_t data) {
  471. port().SR = SPI_SR_TCF;
  472. port().PUSHR = data;
  473. while (!(port().SR & SPI_SR_TCF)) ; // wait
  474. return port().POPR;
  475. }
  476. uint16_t transfer16(uint16_t data) {
  477. port().SR = SPI_SR_TCF;
  478. port().PUSHR = data | SPI_PUSHR_CTAS(1);
  479. while (!(port().SR & SPI_SR_TCF)) ; // wait
  480. return port().POPR;
  481. }
  482. void transfer(void *buf, size_t count);
  483. // After performing a group of transfers and releasing the chip select
  484. // signal, this function allows others to access the SPI bus
  485. void endTransaction(void) {
  486. #ifdef SPI_TRANSACTION_MISMATCH_LED
  487. if (!inTransactionFlag) {
  488. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  489. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  490. }
  491. inTransactionFlag = 0;
  492. #endif
  493. if (interruptMasksUsed) {
  494. if (interruptMasksUsed & 0x01) {
  495. NVIC_ISER0 = interruptSave[0];
  496. }
  497. #if NVIC_NUM_INTERRUPTS > 32
  498. if (interruptMasksUsed & 0x02) {
  499. NVIC_ISER1 = interruptSave[1];
  500. }
  501. #endif
  502. #if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
  503. if (interruptMasksUsed & 0x04) {
  504. NVIC_ISER2 = interruptSave[2];
  505. }
  506. #endif
  507. #if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
  508. if (interruptMasksUsed & 0x08) {
  509. NVIC_ISER3 = interruptSave[3];
  510. }
  511. #endif
  512. }
  513. }
  514. // Disable the SPI bus
  515. void end();
  516. // This function is deprecated. New applications should use
  517. // beginTransaction() to configure SPI settings.
  518. void setBitOrder(uint8_t bitOrder);
  519. // This function is deprecated. New applications should use
  520. // beginTransaction() to configure SPI settings.
  521. void setDataMode(uint8_t dataMode);
  522. // This function is deprecated. New applications should use
  523. // beginTransaction() to configure SPI settings.
  524. void setClockDivider(uint8_t clockDiv) {
  525. if (clockDiv == SPI_CLOCK_DIV2) {
  526. setClockDivider_noInline(SPISettings(12000000, MSBFIRST, SPI_MODE0).ctar);
  527. } else if (clockDiv == SPI_CLOCK_DIV4) {
  528. setClockDivider_noInline(SPISettings(4000000, MSBFIRST, SPI_MODE0).ctar);
  529. } else if (clockDiv == SPI_CLOCK_DIV8) {
  530. setClockDivider_noInline(SPISettings(2000000, MSBFIRST, SPI_MODE0).ctar);
  531. } else if (clockDiv == SPI_CLOCK_DIV16) {
  532. setClockDivider_noInline(SPISettings(1000000, MSBFIRST, SPI_MODE0).ctar);
  533. } else if (clockDiv == SPI_CLOCK_DIV32) {
  534. setClockDivider_noInline(SPISettings(500000, MSBFIRST, SPI_MODE0).ctar);
  535. } else if (clockDiv == SPI_CLOCK_DIV64) {
  536. setClockDivider_noInline(SPISettings(250000, MSBFIRST, SPI_MODE0).ctar);
  537. } else { /* clockDiv == SPI_CLOCK_DIV128 */
  538. setClockDivider_noInline(SPISettings(125000, MSBFIRST, SPI_MODE0).ctar);
  539. }
  540. }
  541. void setClockDivider_noInline(uint32_t clk);
  542. // These undocumented functions should not be used. SPI.transfer()
  543. // polls the hardware flag which is automatically cleared as the
  544. // AVR responds to SPI's interrupt
  545. void attachInterrupt() { }
  546. void detachInterrupt() { }
  547. // Teensy 3.x can use alternate pins for these 3 SPI signals.
  548. void setMOSI(uint8_t pin);
  549. void setMISO(uint8_t pin);
  550. void setSCK(uint8_t pin);
  551. // return true if "pin" has special chip select capability
  552. uint8_t pinIsChipSelect(uint8_t pin);
  553. bool pinIsMOSI(uint8_t pin);
  554. bool pinIsMISO(uint8_t pin);
  555. bool pinIsSCK(uint8_t pin);
  556. // return true if both pin1 and pin2 have independent chip select capability
  557. bool pinIsChipSelect(uint8_t pin1, uint8_t pin2);
  558. // configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
  559. // setCS() is a special function, not intended for use from normal Arduino
  560. // programs/sketches. See the ILI3941_t3 library for an example.
  561. uint8_t setCS(uint8_t pin);
  562. private:
  563. KINETISK_SPI_t & port() { return *(KINETISK_SPI_t *)port_addr; }
  564. const SPI_Hardware_t & hardware() { return *(const SPI_Hardware_t *)hardware_addr; }
  565. void updateCTAR(uint32_t ctar);
  566. uintptr_t port_addr;
  567. uintptr_t hardware_addr;
  568. uint8_t miso_pin_index = 0;
  569. uint8_t mosi_pin_index = 0;
  570. uint8_t sck_pin_index = 0;
  571. uint8_t interruptMasksUsed = 0;
  572. uint32_t interruptMask[(NVIC_NUM_INTERRUPTS+31)/32] = {};
  573. uint32_t interruptSave[(NVIC_NUM_INTERRUPTS+31)/32] = {};
  574. #ifdef SPI_TRANSACTION_MISMATCH_LED
  575. uint8_t inTransactionFlag = 0;
  576. #endif
  577. };
  578. /**********************************************************/
  579. /* 32 bit Teensy-LC */
  580. /**********************************************************/
  581. #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISL)
  582. class SPISettings {
  583. public:
  584. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  585. if (__builtin_constant_p(clock)) {
  586. init_AlwaysInline(clock, bitOrder, dataMode);
  587. } else {
  588. init_MightInline(clock, bitOrder, dataMode);
  589. }
  590. }
  591. SPISettings() {
  592. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  593. }
  594. private:
  595. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  596. init_AlwaysInline(clock, bitOrder, dataMode);
  597. }
  598. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  599. __attribute__((__always_inline__)) {
  600. uint8_t c = SPI_C1_MSTR | SPI_C1_SPE;
  601. if (dataMode & 0x04) c |= SPI_C1_CPHA;
  602. if (dataMode & 0x08) c |= SPI_C1_CPOL;
  603. if (bitOrder == LSBFIRST) c |= SPI_C1_LSBFE;
  604. c1 = c;
  605. if (__builtin_constant_p(clock)) {
  606. if (clock >= F_BUS / 2) { c = SPI_BR_SPPR(0) | SPI_BR_SPR(0);
  607. } else if (clock >= F_BUS / 4) { c = SPI_BR_SPPR(1) | SPI_BR_SPR(0);
  608. } else if (clock >= F_BUS / 6) { c = SPI_BR_SPPR(2) | SPI_BR_SPR(0);
  609. } else if (clock >= F_BUS / 8) { c = SPI_BR_SPPR(3) | SPI_BR_SPR(0);
  610. } else if (clock >= F_BUS / 10) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(0);
  611. } else if (clock >= F_BUS / 12) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(0);
  612. } else if (clock >= F_BUS / 14) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(0);
  613. } else if (clock >= F_BUS / 16) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(0);
  614. } else if (clock >= F_BUS / 20) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(1);
  615. } else if (clock >= F_BUS / 24) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(1);
  616. } else if (clock >= F_BUS / 28) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(1);
  617. } else if (clock >= F_BUS / 32) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(1);
  618. } else if (clock >= F_BUS / 40) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(2);
  619. } else if (clock >= F_BUS / 48) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(2);
  620. } else if (clock >= F_BUS / 56) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(2);
  621. } else if (clock >= F_BUS / 64) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(2);
  622. } else if (clock >= F_BUS / 80) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(3);
  623. } else if (clock >= F_BUS / 96) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(3);
  624. } else if (clock >= F_BUS / 112) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(3);
  625. } else if (clock >= F_BUS / 128) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(3);
  626. } else if (clock >= F_BUS / 160) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(4);
  627. } else if (clock >= F_BUS / 192) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(4);
  628. } else if (clock >= F_BUS / 224) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(4);
  629. } else if (clock >= F_BUS / 256) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(4);
  630. } else if (clock >= F_BUS / 320) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(5);
  631. } else if (clock >= F_BUS / 384) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(5);
  632. } else if (clock >= F_BUS / 448) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(5);
  633. } else if (clock >= F_BUS / 512) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(5);
  634. } else if (clock >= F_BUS / 640) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(6);
  635. } else /* F_BUS / 768 */ { c = SPI_BR_SPPR(5) | SPI_BR_SPR(6);
  636. }
  637. } else {
  638. for (uint32_t i=0; i<30; i++) {
  639. c = br_clock_table[i];
  640. if (clock >= F_BUS / br_div_table[i]) break;
  641. }
  642. }
  643. br[0] = c;
  644. if (__builtin_constant_p(clock)) {
  645. if (clock >= (F_PLL/2) / 2) { c = SPI_BR_SPPR(0) | SPI_BR_SPR(0);
  646. } else if (clock >= (F_PLL/2) / 4) { c = SPI_BR_SPPR(1) | SPI_BR_SPR(0);
  647. } else if (clock >= (F_PLL/2) / 6) { c = SPI_BR_SPPR(2) | SPI_BR_SPR(0);
  648. } else if (clock >= (F_PLL/2) / 8) { c = SPI_BR_SPPR(3) | SPI_BR_SPR(0);
  649. } else if (clock >= (F_PLL/2) / 10) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(0);
  650. } else if (clock >= (F_PLL/2) / 12) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(0);
  651. } else if (clock >= (F_PLL/2) / 14) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(0);
  652. } else if (clock >= (F_PLL/2) / 16) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(0);
  653. } else if (clock >= (F_PLL/2) / 20) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(1);
  654. } else if (clock >= (F_PLL/2) / 24) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(1);
  655. } else if (clock >= (F_PLL/2) / 28) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(1);
  656. } else if (clock >= (F_PLL/2) / 32) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(1);
  657. } else if (clock >= (F_PLL/2) / 40) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(2);
  658. } else if (clock >= (F_PLL/2) / 48) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(2);
  659. } else if (clock >= (F_PLL/2) / 56) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(2);
  660. } else if (clock >= (F_PLL/2) / 64) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(2);
  661. } else if (clock >= (F_PLL/2) / 80) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(3);
  662. } else if (clock >= (F_PLL/2) / 96) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(3);
  663. } else if (clock >= (F_PLL/2) / 112) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(3);
  664. } else if (clock >= (F_PLL/2) / 128) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(3);
  665. } else if (clock >= (F_PLL/2) / 160) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(4);
  666. } else if (clock >= (F_PLL/2) / 192) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(4);
  667. } else if (clock >= (F_PLL/2) / 224) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(4);
  668. } else if (clock >= (F_PLL/2) / 256) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(4);
  669. } else if (clock >= (F_PLL/2) / 320) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(5);
  670. } else if (clock >= (F_PLL/2) / 384) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(5);
  671. } else if (clock >= (F_PLL/2) / 448) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(5);
  672. } else if (clock >= (F_PLL/2) / 512) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(5);
  673. } else if (clock >= (F_PLL/2) / 640) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(6);
  674. } else /* (F_PLL/2) / 768 */ { c = SPI_BR_SPPR(5) | SPI_BR_SPR(6);
  675. }
  676. } else {
  677. for (uint32_t i=0; i<30; i++) {
  678. c = br_clock_table[i];
  679. if (clock >= (F_PLL/2) / br_div_table[i]) break;
  680. }
  681. }
  682. br[1] = c;
  683. }
  684. static const uint8_t br_clock_table[30];
  685. static const uint16_t br_div_table[30];
  686. uint8_t c1, br[2];
  687. friend class SPIClass;
  688. };
  689. class SPIClass { // Teensy-LC
  690. public:
  691. static const uint8_t CNT_MISO_PINS = 2;
  692. static const uint8_t CNT_MMOSI_PINS = 2;
  693. static const uint8_t CNT_SCK_PINS = 2;
  694. static const uint8_t CNT_CS_PINS = 2;
  695. typedef struct {
  696. volatile uint32_t &clock_gate_register;
  697. uint32_t clock_gate_mask;
  698. uint8_t br_index;
  699. uint8_t tx_dma_channel;
  700. uint8_t rx_dma_channel;
  701. void (*dma_isr)();
  702. uint8_t miso_pin[CNT_MISO_PINS];
  703. uint8_t miso_mux[CNT_MISO_PINS];
  704. uint8_t mosi_pin[CNT_MMOSI_PINS];
  705. uint8_t mosi_mux[CNT_MMOSI_PINS];
  706. uint8_t sck_pin[CNT_SCK_PINS];
  707. uint8_t sck_mux[CNT_SCK_PINS];
  708. uint8_t cs_pin[CNT_CS_PINS];
  709. uint8_t cs_mux[CNT_CS_PINS];
  710. uint8_t cs_mask[CNT_CS_PINS];
  711. } SPI_Hardware_t;
  712. static const SPI_Hardware_t spi0_hardware;
  713. static const SPI_Hardware_t spi1_hardware;
  714. public:
  715. constexpr SPIClass(uintptr_t myport, uintptr_t myhardware)
  716. : port_addr(myport), hardware_addr(myhardware) {
  717. }
  718. // Initialize the SPI library
  719. void begin();
  720. // If SPI is to used from within an interrupt, this function registers
  721. // that interrupt with the SPI library, so beginTransaction() can
  722. // prevent conflicts. The input interruptNumber is the number used
  723. // with attachInterrupt. If SPI is used from a different interrupt
  724. // (eg, a timer), interruptNumber should be 255.
  725. void usingInterrupt(uint8_t n) {
  726. if (n == 3 || n == 4) {
  727. usingInterrupt(IRQ_PORTA);
  728. } else if ((n >= 2 && n <= 15) || (n >= 20 && n <= 23)) {
  729. usingInterrupt(IRQ_PORTCD);
  730. }
  731. }
  732. void usingInterrupt(IRQ_NUMBER_t interruptName) {
  733. uint32_t n = (uint32_t)interruptName;
  734. if (n < NVIC_NUM_INTERRUPTS) interruptMask |= (1 << n);
  735. }
  736. void notUsingInterrupt(IRQ_NUMBER_t interruptName) {
  737. uint32_t n = (uint32_t)interruptName;
  738. if (n < NVIC_NUM_INTERRUPTS) interruptMask &= ~(1 << n);
  739. }
  740. // Before using SPI.transfer() or asserting chip select pins,
  741. // this function is used to gain exclusive access to the SPI bus
  742. // and configure the correct settings.
  743. void beginTransaction(SPISettings settings) {
  744. if (interruptMask) {
  745. __disable_irq();
  746. interruptSave = NVIC_ICER0 & interruptMask;
  747. NVIC_ICER0 = interruptSave;
  748. __enable_irq();
  749. }
  750. #ifdef SPI_TRANSACTION_MISMATCH_LED
  751. if (inTransactionFlag) {
  752. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  753. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  754. }
  755. inTransactionFlag = 1;
  756. #endif
  757. port().C1 = settings.c1;
  758. port().BR = settings.br[hardware().br_index];
  759. }
  760. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  761. uint8_t transfer(uint8_t data) {
  762. port().DL = data;
  763. while (!(port().S & SPI_S_SPRF)) ; // wait
  764. return port().DL;
  765. }
  766. uint16_t transfer16(uint16_t data) {
  767. port().C2 = SPI_C2_SPIMODE;
  768. port().S;
  769. port().DL = data;
  770. port().DH = data >> 8;
  771. while (!(port().S & SPI_S_SPRF)) ; // wait
  772. uint16_t r = port().DL | (port().DH << 8);
  773. port().C2 = 0;
  774. port().S;
  775. return r;
  776. }
  777. void transfer(void *buf, size_t count) {
  778. if (count == 0) return;
  779. uint8_t *p = (uint8_t *)buf;
  780. while (!(port().S & SPI_S_SPTEF)) ; // wait
  781. port().DL = *p;
  782. while (--count > 0) {
  783. uint8_t out = *(p + 1);
  784. while (!(port().S & SPI_S_SPTEF)) ; // wait
  785. __disable_irq();
  786. port().DL = out;
  787. while (!(port().S & SPI_S_SPRF)) ; // wait
  788. uint8_t in = port().DL;
  789. __enable_irq();
  790. *p++ = in;
  791. }
  792. while (!(port().S & SPI_S_SPRF)) ; // wait
  793. *p = port().DL;
  794. }
  795. // After performing a group of transfers and releasing the chip select
  796. // signal, this function allows others to access the SPI bus
  797. void endTransaction(void) {
  798. #ifdef SPI_TRANSACTION_MISMATCH_LED
  799. if (!inTransactionFlag) {
  800. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  801. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  802. }
  803. inTransactionFlag = 0;
  804. #endif
  805. if (interruptMask) {
  806. NVIC_ISER0 = interruptSave;
  807. }
  808. }
  809. // Disable the SPI bus
  810. void end();
  811. // This function is deprecated. New applications should use
  812. // beginTransaction() to configure SPI settings.
  813. void setBitOrder(uint8_t bitOrder) {
  814. uint8_t c = port().C1 | SPI_C1_SPE;
  815. if (bitOrder == LSBFIRST) c |= SPI_C1_LSBFE;
  816. else c &= ~SPI_C1_LSBFE;
  817. port().C1 = c;
  818. }
  819. // This function is deprecated. New applications should use
  820. // beginTransaction() to configure SPI settings.
  821. void setDataMode(uint8_t dataMode) {
  822. uint8_t c = port().C1 | SPI_C1_SPE;
  823. if (dataMode & 0x04) c |= SPI_C1_CPHA;
  824. else c &= ~SPI_C1_CPHA;
  825. if (dataMode & 0x08) c |= SPI_C1_CPOL;
  826. else c &= ~SPI_C1_CPOL;
  827. port().C1 = c;
  828. }
  829. // This function is deprecated. New applications should use
  830. // beginTransaction() to configure SPI settings.
  831. void setClockDivider(uint8_t clockDiv) {
  832. unsigned int i = hardware().br_index;
  833. if (clockDiv == SPI_CLOCK_DIV2) {
  834. port().BR = (SPISettings(12000000, MSBFIRST, SPI_MODE0).br[i]);
  835. } else if (clockDiv == SPI_CLOCK_DIV4) {
  836. port().BR = (SPISettings(4000000, MSBFIRST, SPI_MODE0).br[i]);
  837. } else if (clockDiv == SPI_CLOCK_DIV8) {
  838. port().BR = (SPISettings(2000000, MSBFIRST, SPI_MODE0).br[i]);
  839. } else if (clockDiv == SPI_CLOCK_DIV16) {
  840. port().BR = (SPISettings(1000000, MSBFIRST, SPI_MODE0).br[i]);
  841. } else if (clockDiv == SPI_CLOCK_DIV32) {
  842. port().BR = (SPISettings(500000, MSBFIRST, SPI_MODE0).br[i]);
  843. } else if (clockDiv == SPI_CLOCK_DIV64) {
  844. port().BR = (SPISettings(250000, MSBFIRST, SPI_MODE0).br[i]);
  845. } else { /* clockDiv == SPI_CLOCK_DIV128 */
  846. port().BR = (SPISettings(125000, MSBFIRST, SPI_MODE0).br[i]);
  847. }
  848. }
  849. // These undocumented functions should not be used. SPI.transfer()
  850. // polls the hardware flag which is automatically cleared as the
  851. // AVR responds to SPI's interrupt
  852. void attachInterrupt() { }
  853. void detachInterrupt() { }
  854. // Teensy LC can use alternate pins for these 3 SPI signals.
  855. void setMOSI(uint8_t pin);
  856. void setMISO(uint8_t pin);
  857. void setSCK(uint8_t pin);
  858. // return true if "pin" has special chip select capability
  859. bool pinIsChipSelect(uint8_t pin);
  860. bool pinIsMOSI(uint8_t pin);
  861. bool pinIsMISO(uint8_t pin);
  862. bool pinIsSCK(uint8_t pin);
  863. // return true if both pin1 and pin2 have independent chip select capability
  864. bool pinIsChipSelect(uint8_t pin1, uint8_t pin2) { return false; }
  865. // configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
  866. // setCS() is a special function, not intended for use from normal Arduino
  867. // programs/sketches. See the ILI3941_t3 library for an example.
  868. uint8_t setCS(uint8_t pin);
  869. private:
  870. KINETISL_SPI_t & port() { return *(KINETISL_SPI_t *)port_addr; }
  871. const SPI_Hardware_t & hardware() { return *(const SPI_Hardware_t *)hardware_addr; }
  872. uintptr_t port_addr;
  873. uintptr_t hardware_addr;
  874. uint32_t interruptMask = 0;
  875. uint32_t interruptSave = 0;
  876. uint8_t mosi_pin_index = 0;
  877. uint8_t miso_pin_index = 0;
  878. uint8_t sck_pin_index = 0;
  879. #ifdef SPI_TRANSACTION_MISMATCH_LED
  880. uint8_t inTransactionFlag = 0;
  881. #endif
  882. };
  883. #endif
  884. extern SPIClass SPI;
  885. #if defined(__MKL26Z64__)
  886. extern SPIClass SPI1;
  887. #endif
  888. #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
  889. extern SPIClass SPI1;
  890. extern SPIClass SPI2;
  891. #endif
  892. #endif