You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 7 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 7 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 7 година
пре 10 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 10 година
пре 10 година
пре 10 година
пре 7 година
пре 7 година
пре 7 година
пре 10 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 10 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 7 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 7 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367
  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. #if defined(__arm__) && defined(TEENSYDUINO)
  16. #if defined(__has_include) && __has_include(<EventResponder.h>)
  17. // SPI_HAS_TRANSFER_ASYNC - Defined to say that the SPI supports an ASYNC version
  18. // of the SPI_HAS_TRANSFER_BUF
  19. #define SPI_HAS_TRANSFER_ASYNC 1
  20. #include <DMAChannel.h>
  21. #include <EventResponder.h>
  22. #endif
  23. #endif
  24. // SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
  25. // usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
  26. #define SPI_HAS_TRANSACTION 1
  27. // Uncomment this line to add detection of mismatched begin/end transactions.
  28. // A mismatch occurs if other libraries fail to use SPI.endTransaction() for
  29. // each SPI.beginTransaction(). Connect a LED to this pin. The LED will turn
  30. // on if any mismatch is ever detected.
  31. //#define SPI_TRANSACTION_MISMATCH_LED 5
  32. // SPI_HAS_TRANSFER_BUF - is defined to signify that this library supports
  33. // a version of transfer which allows you to pass in both TX and RX buffer
  34. // pointers, either of which could be NULL
  35. #define SPI_HAS_TRANSFER_BUF 1
  36. #ifndef LSBFIRST
  37. #define LSBFIRST 0
  38. #endif
  39. #ifndef MSBFIRST
  40. #define MSBFIRST 1
  41. #endif
  42. #define SPI_MODE0 0x00
  43. #define SPI_MODE1 0x04
  44. #define SPI_MODE2 0x08
  45. #define SPI_MODE3 0x0C
  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. #define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
  54. #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
  55. #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
  56. /**********************************************************/
  57. /* 8 bit AVR-based boards */
  58. /**********************************************************/
  59. #if defined(__AVR__)
  60. #define SPI_ATOMIC_VERSION 1
  61. // define SPI_AVR_EIMSK for AVR boards with external interrupt pins
  62. #if defined(EIMSK)
  63. #define SPI_AVR_EIMSK EIMSK
  64. #elif defined(GICR)
  65. #define SPI_AVR_EIMSK GICR
  66. #elif defined(GIMSK)
  67. #define SPI_AVR_EIMSK GIMSK
  68. #endif
  69. class SPISettings {
  70. public:
  71. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  72. if (__builtin_constant_p(clock)) {
  73. init_AlwaysInline(clock, bitOrder, dataMode);
  74. } else {
  75. init_MightInline(clock, bitOrder, dataMode);
  76. }
  77. }
  78. SPISettings() {
  79. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  80. }
  81. private:
  82. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  83. init_AlwaysInline(clock, bitOrder, dataMode);
  84. }
  85. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  86. __attribute__((__always_inline__)) {
  87. // Clock settings are defined as follows. Note that this shows SPI2X
  88. // inverted, so the bits form increasing numbers. Also note that
  89. // fosc/64 appears twice
  90. // SPR1 SPR0 ~SPI2X Freq
  91. // 0 0 0 fosc/2
  92. // 0 0 1 fosc/4
  93. // 0 1 0 fosc/8
  94. // 0 1 1 fosc/16
  95. // 1 0 0 fosc/32
  96. // 1 0 1 fosc/64
  97. // 1 1 0 fosc/64
  98. // 1 1 1 fosc/128
  99. // We find the fastest clock that is less than or equal to the
  100. // given clock rate. The clock divider that results in clock_setting
  101. // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
  102. // slowest (128 == 2 ^^ 7, so clock_div = 6).
  103. uint8_t clockDiv;
  104. // When the clock is known at compiletime, use this if-then-else
  105. // cascade, which the compiler knows how to completely optimize
  106. // away. When clock is not known, use a loop instead, which generates
  107. // shorter code.
  108. if (__builtin_constant_p(clock)) {
  109. if (clock >= F_CPU / 2) {
  110. clockDiv = 0;
  111. } else if (clock >= F_CPU / 4) {
  112. clockDiv = 1;
  113. } else if (clock >= F_CPU / 8) {
  114. clockDiv = 2;
  115. } else if (clock >= F_CPU / 16) {
  116. clockDiv = 3;
  117. } else if (clock >= F_CPU / 32) {
  118. clockDiv = 4;
  119. } else if (clock >= F_CPU / 64) {
  120. clockDiv = 5;
  121. } else {
  122. clockDiv = 6;
  123. }
  124. } else {
  125. uint32_t clockSetting = F_CPU / 2;
  126. clockDiv = 0;
  127. while (clockDiv < 6 && clock < clockSetting) {
  128. clockSetting /= 2;
  129. clockDiv++;
  130. }
  131. }
  132. // Compensate for the duplicate fosc/64
  133. if (clockDiv == 6)
  134. clockDiv = 7;
  135. // Invert the SPI2X bit
  136. clockDiv ^= 0x1;
  137. // Pack into the SPISettings class
  138. spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
  139. (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
  140. spsr = clockDiv & SPI_2XCLOCK_MASK;
  141. }
  142. uint8_t spcr;
  143. uint8_t spsr;
  144. friend class SPIClass;
  145. };
  146. class SPIClass { // AVR
  147. public:
  148. // Initialize the SPI library
  149. static void begin();
  150. // If SPI is used from within an interrupt, this function registers
  151. // that interrupt with the SPI library, so beginTransaction() can
  152. // prevent conflicts. The input interruptNumber is the number used
  153. // with attachInterrupt. If SPI is used from a different interrupt
  154. // (eg, a timer), interruptNumber should be 255.
  155. static void usingInterrupt(uint8_t interruptNumber);
  156. // Before using SPI.transfer() or asserting chip select pins,
  157. // this function is used to gain exclusive access to the SPI bus
  158. // and configure the correct settings.
  159. inline static void beginTransaction(SPISettings settings) {
  160. if (interruptMode > 0) {
  161. #ifdef SPI_AVR_EIMSK
  162. if (interruptMode == 1) {
  163. interruptSave = SPI_AVR_EIMSK;
  164. SPI_AVR_EIMSK &= ~interruptMask;
  165. } else
  166. #endif
  167. {
  168. uint8_t tmp = SREG;
  169. cli();
  170. interruptSave = tmp;
  171. }
  172. }
  173. #ifdef SPI_TRANSACTION_MISMATCH_LED
  174. if (inTransactionFlag) {
  175. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  176. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  177. }
  178. inTransactionFlag = 1;
  179. #endif
  180. SPCR = settings.spcr;
  181. SPSR = settings.spsr;
  182. }
  183. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  184. inline static uint8_t transfer(uint8_t data) {
  185. SPDR = data;
  186. asm volatile("nop");
  187. while (!(SPSR & _BV(SPIF))) ; // wait
  188. return SPDR;
  189. }
  190. inline static uint16_t transfer16(uint16_t data) {
  191. union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
  192. in.val = data;
  193. if ((SPCR & _BV(DORD))) {
  194. SPDR = in.lsb;
  195. asm volatile("nop");
  196. while (!(SPSR & _BV(SPIF))) ;
  197. out.lsb = SPDR;
  198. SPDR = in.msb;
  199. asm volatile("nop");
  200. while (!(SPSR & _BV(SPIF))) ;
  201. out.msb = SPDR;
  202. } else {
  203. SPDR = in.msb;
  204. asm volatile("nop");
  205. while (!(SPSR & _BV(SPIF))) ;
  206. out.msb = SPDR;
  207. SPDR = in.lsb;
  208. asm volatile("nop");
  209. while (!(SPSR & _BV(SPIF))) ;
  210. out.lsb = SPDR;
  211. }
  212. return out.val;
  213. }
  214. inline static void transfer(void *buf, size_t count) {
  215. if (count == 0) return;
  216. uint8_t *p = (uint8_t *)buf;
  217. SPDR = *p;
  218. while (--count > 0) {
  219. uint8_t out = *(p + 1);
  220. while (!(SPSR & _BV(SPIF))) ;
  221. uint8_t in = SPDR;
  222. SPDR = out;
  223. *p++ = in;
  224. }
  225. while (!(SPSR & _BV(SPIF))) ;
  226. *p = SPDR;
  227. }
  228. static void setTransferWriteFill(uint8_t ch ) {_transferWriteFill = ch;}
  229. static void transfer(const void * buf, void * retbuf, uint32_t count);
  230. // After performing a group of transfers and releasing the chip select
  231. // signal, this function allows others to access the SPI bus
  232. inline static void endTransaction(void) {
  233. #ifdef SPI_TRANSACTION_MISMATCH_LED
  234. if (!inTransactionFlag) {
  235. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  236. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  237. }
  238. inTransactionFlag = 0;
  239. #endif
  240. if (interruptMode > 0) {
  241. #ifdef SPI_AVR_EIMSK
  242. if (interruptMode == 1) {
  243. SPI_AVR_EIMSK = interruptSave;
  244. } else
  245. #endif
  246. {
  247. SREG = interruptSave;
  248. }
  249. }
  250. }
  251. // Disable the SPI bus
  252. static void end();
  253. // This function is deprecated. New applications should use
  254. // beginTransaction() to configure SPI settings.
  255. inline static void setBitOrder(uint8_t bitOrder) {
  256. if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
  257. else SPCR &= ~(_BV(DORD));
  258. }
  259. // This function is deprecated. New applications should use
  260. // beginTransaction() to configure SPI settings.
  261. inline static void setDataMode(uint8_t dataMode) {
  262. SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
  263. }
  264. // This function is deprecated. New applications should use
  265. // beginTransaction() to configure SPI settings.
  266. inline static void setClockDivider(uint8_t clockDiv) {
  267. SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
  268. SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
  269. }
  270. // These undocumented functions should not be used. SPI.transfer()
  271. // polls the hardware flag which is automatically cleared as the
  272. // AVR responds to SPI's interrupt
  273. inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
  274. inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
  275. private:
  276. static uint8_t interruptMode; // 0=none, 1=mask, 2=global
  277. static uint8_t interruptMask; // which interrupts to mask
  278. static uint8_t interruptSave; // temp storage, to restore state
  279. #ifdef SPI_TRANSACTION_MISMATCH_LED
  280. static uint8_t inTransactionFlag;
  281. #endif
  282. static uint8_t _transferWriteFill;
  283. };
  284. /**********************************************************/
  285. /* 32 bit Teensy 3.x */
  286. /**********************************************************/
  287. #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISK)
  288. #define SPI_HAS_NOTUSINGINTERRUPT 1
  289. #define SPI_ATOMIC_VERSION 1
  290. class SPISettings {
  291. public:
  292. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  293. if (__builtin_constant_p(clock)) {
  294. init_AlwaysInline(clock, bitOrder, dataMode);
  295. } else {
  296. init_MightInline(clock, bitOrder, dataMode);
  297. }
  298. }
  299. SPISettings() {
  300. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  301. }
  302. private:
  303. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  304. init_AlwaysInline(clock, bitOrder, dataMode);
  305. }
  306. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  307. __attribute__((__always_inline__)) {
  308. uint32_t t, c = SPI_CTAR_FMSZ(7);
  309. if (bitOrder == LSBFIRST) c |= SPI_CTAR_LSBFE;
  310. if (__builtin_constant_p(clock)) {
  311. if (clock >= F_BUS / 2) {
  312. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  313. | SPI_CTAR_CSSCK(0);
  314. } else if (clock >= F_BUS / 3) {
  315. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  316. | SPI_CTAR_CSSCK(0);
  317. } else if (clock >= F_BUS / 4) {
  318. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  319. } else if (clock >= F_BUS / 5) {
  320. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
  321. | SPI_CTAR_CSSCK(0);
  322. } else if (clock >= F_BUS / 6) {
  323. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  324. } else if (clock >= F_BUS / 8) {
  325. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  326. } else if (clock >= F_BUS / 10) {
  327. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  328. } else if (clock >= F_BUS / 12) {
  329. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  330. } else if (clock >= F_BUS / 16) {
  331. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  332. } else if (clock >= F_BUS / 20) {
  333. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(0);
  334. } else if (clock >= F_BUS / 24) {
  335. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  336. } else if (clock >= F_BUS / 32) {
  337. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(3);
  338. } else if (clock >= F_BUS / 40) {
  339. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  340. } else if (clock >= F_BUS / 56) {
  341. t = SPI_CTAR_PBR(3) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2);
  342. } else if (clock >= F_BUS / 64) {
  343. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4);
  344. } else if (clock >= F_BUS / 96) {
  345. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4);
  346. } else if (clock >= F_BUS / 128) {
  347. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5);
  348. } else if (clock >= F_BUS / 192) {
  349. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5);
  350. } else if (clock >= F_BUS / 256) {
  351. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  352. } else if (clock >= F_BUS / 384) {
  353. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  354. } else if (clock >= F_BUS / 512) {
  355. t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
  356. } else if (clock >= F_BUS / 640) {
  357. t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
  358. } else { /* F_BUS / 768 */
  359. t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
  360. }
  361. } else {
  362. for (uint32_t i=0; i<23; i++) {
  363. t = ctar_clock_table[i];
  364. if (clock >= F_BUS / ctar_div_table[i]) break;
  365. }
  366. }
  367. if (dataMode & 0x08) {
  368. c |= SPI_CTAR_CPOL;
  369. }
  370. if (dataMode & 0x04) {
  371. c |= SPI_CTAR_CPHA;
  372. t = (t & 0xFFFF0FFF) | ((t & 0xF000) >> 4);
  373. }
  374. ctar = c | t;
  375. }
  376. static const uint16_t ctar_div_table[23];
  377. static const uint32_t ctar_clock_table[23];
  378. uint32_t ctar;
  379. friend class SPIClass;
  380. };
  381. class SPIClass { // Teensy 3.x
  382. public:
  383. #if defined(__MK20DX128__) || defined(__MK20DX256__)
  384. static const uint8_t CNT_MISO_PINS = 2;
  385. static const uint8_t CNT_MOSI_PINS = 2;
  386. static const uint8_t CNT_SCK_PINS = 2;
  387. static const uint8_t CNT_CS_PINS = 9;
  388. #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
  389. static const uint8_t CNT_MISO_PINS = 4;
  390. static const uint8_t CNT_MOSI_PINS = 4;
  391. static const uint8_t CNT_SCK_PINS = 3;
  392. static const uint8_t CNT_CS_PINS = 11;
  393. #endif
  394. typedef struct {
  395. volatile uint32_t &clock_gate_register;
  396. uint32_t clock_gate_mask;
  397. uint8_t queue_size;
  398. uint8_t spi_irq;
  399. uint32_t max_dma_count;
  400. uint8_t tx_dma_channel;
  401. uint8_t rx_dma_channel;
  402. void (*dma_rxisr)();
  403. uint8_t miso_pin[CNT_MISO_PINS];
  404. uint32_t miso_mux[CNT_MISO_PINS];
  405. uint8_t mosi_pin[CNT_MOSI_PINS];
  406. uint32_t mosi_mux[CNT_MOSI_PINS];
  407. uint8_t sck_pin[CNT_SCK_PINS];
  408. uint32_t sck_mux[CNT_SCK_PINS];
  409. uint8_t cs_pin[CNT_CS_PINS];
  410. uint32_t cs_mux[CNT_CS_PINS];
  411. uint8_t cs_mask[CNT_CS_PINS];
  412. } SPI_Hardware_t;
  413. static const SPI_Hardware_t spi0_hardware;
  414. static const SPI_Hardware_t spi1_hardware;
  415. static const SPI_Hardware_t spi2_hardware;
  416. enum DMAState { notAllocated, idle, active, completed};
  417. public:
  418. constexpr SPIClass(uintptr_t myport, uintptr_t myhardware)
  419. : port_addr(myport), hardware_addr(myhardware) {
  420. }
  421. // Initialize the SPI library
  422. void begin();
  423. // If SPI is to used from within an interrupt, this function registers
  424. // that interrupt with the SPI library, so beginTransaction() can
  425. // prevent conflicts. The input interruptNumber is the number used
  426. // with attachInterrupt. If SPI is used from a different interrupt
  427. // (eg, a timer), interruptNumber should be 255.
  428. void usingInterrupt(uint8_t n) {
  429. if (n == 3 || n == 4 || n == 24 || n == 33) {
  430. usingInterrupt(IRQ_PORTA);
  431. } else if (n == 0 || n == 1 || (n >= 16 && n <= 19) || n == 25 || n == 32) {
  432. usingInterrupt(IRQ_PORTB);
  433. } else if ((n >= 9 && n <= 13) || n == 15 || n == 22 || n == 23
  434. || (n >= 27 && n <= 30)) {
  435. usingInterrupt(IRQ_PORTC);
  436. } else if (n == 2 || (n >= 5 && n <= 8) || n == 14 || n == 20 || n == 21) {
  437. usingInterrupt(IRQ_PORTD);
  438. } else if (n == 26 || n == 31) {
  439. usingInterrupt(IRQ_PORTE);
  440. }
  441. }
  442. void usingInterrupt(IRQ_NUMBER_t interruptName);
  443. void notUsingInterrupt(IRQ_NUMBER_t interruptName);
  444. // Before using SPI.transfer() or asserting chip select pins,
  445. // this function is used to gain exclusive access to the SPI bus
  446. // and configure the correct settings.
  447. void beginTransaction(SPISettings settings) {
  448. if (interruptMasksUsed) {
  449. __disable_irq();
  450. if (interruptMasksUsed & 0x01) {
  451. interruptSave[0] = NVIC_ICER0 & interruptMask[0];
  452. NVIC_ICER0 = interruptSave[0];
  453. }
  454. #if NVIC_NUM_INTERRUPTS > 32
  455. if (interruptMasksUsed & 0x02) {
  456. interruptSave[1] = NVIC_ICER1 & interruptMask[1];
  457. NVIC_ICER1 = interruptSave[1];
  458. }
  459. #endif
  460. #if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
  461. if (interruptMasksUsed & 0x04) {
  462. interruptSave[2] = NVIC_ICER2 & interruptMask[2];
  463. NVIC_ICER2 = interruptSave[2];
  464. }
  465. #endif
  466. #if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
  467. if (interruptMasksUsed & 0x08) {
  468. interruptSave[3] = NVIC_ICER3 & interruptMask[3];
  469. NVIC_ICER3 = interruptSave[3];
  470. }
  471. #endif
  472. __enable_irq();
  473. }
  474. #ifdef SPI_TRANSACTION_MISMATCH_LED
  475. if (inTransactionFlag) {
  476. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  477. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  478. }
  479. inTransactionFlag = 1;
  480. #endif
  481. if (port().CTAR0 != settings.ctar) {
  482. port().MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x3F);
  483. port().CTAR0 = settings.ctar;
  484. port().CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
  485. port().MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x3F);
  486. }
  487. }
  488. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  489. uint8_t transfer(uint8_t data) {
  490. port().SR = SPI_SR_TCF;
  491. port().PUSHR = data;
  492. while (!(port().SR & SPI_SR_TCF)) ; // wait
  493. return port().POPR;
  494. }
  495. uint16_t transfer16(uint16_t data) {
  496. port().SR = SPI_SR_TCF;
  497. port().PUSHR = data | SPI_PUSHR_CTAS(1);
  498. while (!(port().SR & SPI_SR_TCF)) ; // wait
  499. return port().POPR;
  500. }
  501. void inline transfer(void *buf, size_t count) {transfer(buf, buf, count);}
  502. void setTransferWriteFill(uint8_t ch ) {_transferWriteFill = ch;}
  503. void transfer(const void * buf, void * retbuf, size_t count);
  504. // Asynch support (DMA )
  505. #ifdef SPI_HAS_TRANSFER_ASYNC
  506. bool transfer(const void *txBuffer, void *rxBuffer, size_t count, EventResponderRef event_responder);
  507. friend void _spi_dma_rxISR0(void);
  508. friend void _spi_dma_rxISR1(void);
  509. friend void _spi_dma_rxISR2(void);
  510. inline void dma_rxisr(void);
  511. #endif
  512. // After performing a group of transfers and releasing the chip select
  513. // signal, this function allows others to access the SPI bus
  514. void endTransaction(void) {
  515. #ifdef SPI_TRANSACTION_MISMATCH_LED
  516. if (!inTransactionFlag) {
  517. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  518. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  519. }
  520. inTransactionFlag = 0;
  521. #endif
  522. if (interruptMasksUsed) {
  523. if (interruptMasksUsed & 0x01) {
  524. NVIC_ISER0 = interruptSave[0];
  525. }
  526. #if NVIC_NUM_INTERRUPTS > 32
  527. if (interruptMasksUsed & 0x02) {
  528. NVIC_ISER1 = interruptSave[1];
  529. }
  530. #endif
  531. #if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
  532. if (interruptMasksUsed & 0x04) {
  533. NVIC_ISER2 = interruptSave[2];
  534. }
  535. #endif
  536. #if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
  537. if (interruptMasksUsed & 0x08) {
  538. NVIC_ISER3 = interruptSave[3];
  539. }
  540. #endif
  541. }
  542. }
  543. // Disable the SPI bus
  544. void end();
  545. // This function is deprecated. New applications should use
  546. // beginTransaction() to configure SPI settings.
  547. void setBitOrder(uint8_t bitOrder);
  548. // This function is deprecated. New applications should use
  549. // beginTransaction() to configure SPI settings.
  550. void setDataMode(uint8_t dataMode);
  551. // This function is deprecated. New applications should use
  552. // beginTransaction() to configure SPI settings.
  553. void setClockDivider(uint8_t clockDiv) {
  554. if (clockDiv == SPI_CLOCK_DIV2) {
  555. setClockDivider_noInline(SPISettings(12000000, MSBFIRST, SPI_MODE0).ctar);
  556. } else if (clockDiv == SPI_CLOCK_DIV4) {
  557. setClockDivider_noInline(SPISettings(4000000, MSBFIRST, SPI_MODE0).ctar);
  558. } else if (clockDiv == SPI_CLOCK_DIV8) {
  559. setClockDivider_noInline(SPISettings(2000000, MSBFIRST, SPI_MODE0).ctar);
  560. } else if (clockDiv == SPI_CLOCK_DIV16) {
  561. setClockDivider_noInline(SPISettings(1000000, MSBFIRST, SPI_MODE0).ctar);
  562. } else if (clockDiv == SPI_CLOCK_DIV32) {
  563. setClockDivider_noInline(SPISettings(500000, MSBFIRST, SPI_MODE0).ctar);
  564. } else if (clockDiv == SPI_CLOCK_DIV64) {
  565. setClockDivider_noInline(SPISettings(250000, MSBFIRST, SPI_MODE0).ctar);
  566. } else { /* clockDiv == SPI_CLOCK_DIV128 */
  567. setClockDivider_noInline(SPISettings(125000, MSBFIRST, SPI_MODE0).ctar);
  568. }
  569. }
  570. void setClockDivider_noInline(uint32_t clk);
  571. // These undocumented functions should not be used. SPI.transfer()
  572. // polls the hardware flag which is automatically cleared as the
  573. // AVR responds to SPI's interrupt
  574. void attachInterrupt() { }
  575. void detachInterrupt() { }
  576. // Teensy 3.x can use alternate pins for these 3 SPI signals.
  577. void setMOSI(uint8_t pin);
  578. void setMISO(uint8_t pin);
  579. void setSCK(uint8_t pin);
  580. // return true if "pin" has special chip select capability
  581. uint8_t pinIsChipSelect(uint8_t pin);
  582. bool pinIsMOSI(uint8_t pin);
  583. bool pinIsMISO(uint8_t pin);
  584. bool pinIsSCK(uint8_t pin);
  585. // return true if both pin1 and pin2 have independent chip select capability
  586. bool pinIsChipSelect(uint8_t pin1, uint8_t pin2);
  587. // configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
  588. // setCS() is a special function, not intended for use from normal Arduino
  589. // programs/sketches. See the ILI3941_t3 library for an example.
  590. uint8_t setCS(uint8_t pin);
  591. private:
  592. KINETISK_SPI_t & port() { return *(KINETISK_SPI_t *)port_addr; }
  593. const SPI_Hardware_t & hardware() { return *(const SPI_Hardware_t *)hardware_addr; }
  594. void updateCTAR(uint32_t ctar);
  595. uintptr_t port_addr;
  596. uintptr_t hardware_addr;
  597. uint8_t miso_pin_index = 0;
  598. uint8_t mosi_pin_index = 0;
  599. uint8_t sck_pin_index = 0;
  600. uint8_t interruptMasksUsed = 0;
  601. uint32_t interruptMask[(NVIC_NUM_INTERRUPTS+31)/32] = {};
  602. uint32_t interruptSave[(NVIC_NUM_INTERRUPTS+31)/32] = {};
  603. #ifdef SPI_TRANSACTION_MISMATCH_LED
  604. uint8_t inTransactionFlag = 0;
  605. #endif
  606. uint8_t _transferWriteFill = 0;
  607. // DMA Support
  608. #ifdef SPI_HAS_TRANSFER_ASYNC
  609. bool initDMAChannels();
  610. DMAState _dma_state = DMAState::notAllocated;
  611. uint32_t _dma_count_remaining = 0; // How many bytes left to output after current DMA completes
  612. DMAChannel *_dmaTX = nullptr;
  613. DMAChannel *_dmaRX = nullptr;
  614. EventResponder *_dma_event_responder = nullptr;
  615. #endif
  616. };
  617. /**********************************************************/
  618. /* 32 bit Teensy-LC */
  619. /**********************************************************/
  620. #elif defined(__arm__) && defined(TEENSYDUINO) && defined(KINETISL)
  621. #define SPI_ATOMIC_VERSION 1
  622. class SPISettings {
  623. public:
  624. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  625. if (__builtin_constant_p(clock)) {
  626. init_AlwaysInline(clock, bitOrder, dataMode);
  627. } else {
  628. init_MightInline(clock, bitOrder, dataMode);
  629. }
  630. }
  631. SPISettings() {
  632. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  633. }
  634. private:
  635. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  636. init_AlwaysInline(clock, bitOrder, dataMode);
  637. }
  638. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  639. __attribute__((__always_inline__)) {
  640. uint8_t c = SPI_C1_MSTR | SPI_C1_SPE;
  641. if (dataMode & 0x04) c |= SPI_C1_CPHA;
  642. if (dataMode & 0x08) c |= SPI_C1_CPOL;
  643. if (bitOrder == LSBFIRST) c |= SPI_C1_LSBFE;
  644. c1 = c;
  645. if (__builtin_constant_p(clock)) {
  646. if (clock >= F_BUS / 2) { c = SPI_BR_SPPR(0) | SPI_BR_SPR(0);
  647. } else if (clock >= F_BUS / 4) { c = SPI_BR_SPPR(1) | SPI_BR_SPR(0);
  648. } else if (clock >= F_BUS / 6) { c = SPI_BR_SPPR(2) | SPI_BR_SPR(0);
  649. } else if (clock >= F_BUS / 8) { c = SPI_BR_SPPR(3) | SPI_BR_SPR(0);
  650. } else if (clock >= F_BUS / 10) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(0);
  651. } else if (clock >= F_BUS / 12) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(0);
  652. } else if (clock >= F_BUS / 14) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(0);
  653. } else if (clock >= F_BUS / 16) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(0);
  654. } else if (clock >= F_BUS / 20) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(1);
  655. } else if (clock >= F_BUS / 24) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(1);
  656. } else if (clock >= F_BUS / 28) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(1);
  657. } else if (clock >= F_BUS / 32) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(1);
  658. } else if (clock >= F_BUS / 40) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(2);
  659. } else if (clock >= F_BUS / 48) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(2);
  660. } else if (clock >= F_BUS / 56) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(2);
  661. } else if (clock >= F_BUS / 64) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(2);
  662. } else if (clock >= F_BUS / 80) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(3);
  663. } else if (clock >= F_BUS / 96) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(3);
  664. } else if (clock >= F_BUS / 112) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(3);
  665. } else if (clock >= F_BUS / 128) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(3);
  666. } else if (clock >= F_BUS / 160) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(4);
  667. } else if (clock >= F_BUS / 192) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(4);
  668. } else if (clock >= F_BUS / 224) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(4);
  669. } else if (clock >= F_BUS / 256) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(4);
  670. } else if (clock >= F_BUS / 320) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(5);
  671. } else if (clock >= F_BUS / 384) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(5);
  672. } else if (clock >= F_BUS / 448) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(5);
  673. } else if (clock >= F_BUS / 512) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(5);
  674. } else if (clock >= F_BUS / 640) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(6);
  675. } else /* F_BUS / 768 */ { c = SPI_BR_SPPR(5) | SPI_BR_SPR(6);
  676. }
  677. } else {
  678. for (uint32_t i=0; i<30; i++) {
  679. c = br_clock_table[i];
  680. if (clock >= F_BUS / br_div_table[i]) break;
  681. }
  682. }
  683. br[0] = c;
  684. if (__builtin_constant_p(clock)) {
  685. if (clock >= (F_PLL/2) / 2) { c = SPI_BR_SPPR(0) | SPI_BR_SPR(0);
  686. } else if (clock >= (F_PLL/2) / 4) { c = SPI_BR_SPPR(1) | SPI_BR_SPR(0);
  687. } else if (clock >= (F_PLL/2) / 6) { c = SPI_BR_SPPR(2) | SPI_BR_SPR(0);
  688. } else if (clock >= (F_PLL/2) / 8) { c = SPI_BR_SPPR(3) | SPI_BR_SPR(0);
  689. } else if (clock >= (F_PLL/2) / 10) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(0);
  690. } else if (clock >= (F_PLL/2) / 12) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(0);
  691. } else if (clock >= (F_PLL/2) / 14) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(0);
  692. } else if (clock >= (F_PLL/2) / 16) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(0);
  693. } else if (clock >= (F_PLL/2) / 20) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(1);
  694. } else if (clock >= (F_PLL/2) / 24) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(1);
  695. } else if (clock >= (F_PLL/2) / 28) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(1);
  696. } else if (clock >= (F_PLL/2) / 32) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(1);
  697. } else if (clock >= (F_PLL/2) / 40) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(2);
  698. } else if (clock >= (F_PLL/2) / 48) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(2);
  699. } else if (clock >= (F_PLL/2) / 56) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(2);
  700. } else if (clock >= (F_PLL/2) / 64) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(2);
  701. } else if (clock >= (F_PLL/2) / 80) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(3);
  702. } else if (clock >= (F_PLL/2) / 96) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(3);
  703. } else if (clock >= (F_PLL/2) / 112) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(3);
  704. } else if (clock >= (F_PLL/2) / 128) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(3);
  705. } else if (clock >= (F_PLL/2) / 160) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(4);
  706. } else if (clock >= (F_PLL/2) / 192) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(4);
  707. } else if (clock >= (F_PLL/2) / 224) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(4);
  708. } else if (clock >= (F_PLL/2) / 256) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(4);
  709. } else if (clock >= (F_PLL/2) / 320) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(5);
  710. } else if (clock >= (F_PLL/2) / 384) { c = SPI_BR_SPPR(5) | SPI_BR_SPR(5);
  711. } else if (clock >= (F_PLL/2) / 448) { c = SPI_BR_SPPR(6) | SPI_BR_SPR(5);
  712. } else if (clock >= (F_PLL/2) / 512) { c = SPI_BR_SPPR(7) | SPI_BR_SPR(5);
  713. } else if (clock >= (F_PLL/2) / 640) { c = SPI_BR_SPPR(4) | SPI_BR_SPR(6);
  714. } else /* (F_PLL/2) / 768 */ { c = SPI_BR_SPPR(5) | SPI_BR_SPR(6);
  715. }
  716. } else {
  717. for (uint32_t i=0; i<30; i++) {
  718. c = br_clock_table[i];
  719. if (clock >= (F_PLL/2) / br_div_table[i]) break;
  720. }
  721. }
  722. br[1] = c;
  723. }
  724. static const uint8_t br_clock_table[30];
  725. static const uint16_t br_div_table[30];
  726. uint8_t c1, br[2];
  727. friend class SPIClass;
  728. };
  729. class SPIClass { // Teensy-LC
  730. public:
  731. static const uint8_t CNT_MISO_PINS = 2;
  732. static const uint8_t CNT_MMOSI_PINS = 2;
  733. static const uint8_t CNT_SCK_PINS = 2;
  734. static const uint8_t CNT_CS_PINS = 2;
  735. typedef struct {
  736. volatile uint32_t &clock_gate_register;
  737. uint32_t clock_gate_mask;
  738. uint8_t br_index;
  739. uint8_t tx_dma_channel;
  740. uint8_t rx_dma_channel;
  741. void (*dma_isr)();
  742. uint8_t miso_pin[CNT_MISO_PINS];
  743. uint32_t miso_mux[CNT_MISO_PINS];
  744. uint8_t mosi_pin[CNT_MMOSI_PINS];
  745. uint32_t mosi_mux[CNT_MMOSI_PINS];
  746. uint8_t sck_pin[CNT_SCK_PINS];
  747. uint32_t sck_mux[CNT_SCK_PINS];
  748. uint8_t cs_pin[CNT_CS_PINS];
  749. uint32_t cs_mux[CNT_CS_PINS];
  750. uint8_t cs_mask[CNT_CS_PINS];
  751. } SPI_Hardware_t;
  752. static const SPI_Hardware_t spi0_hardware;
  753. static const SPI_Hardware_t spi1_hardware;
  754. enum DMAState { notAllocated, idle, active, completed};
  755. public:
  756. constexpr SPIClass(uintptr_t myport, uintptr_t myhardware)
  757. : port_addr(myport), hardware_addr(myhardware) {
  758. }
  759. // Initialize the SPI library
  760. void begin();
  761. // If SPI is to used from within an interrupt, this function registers
  762. // that interrupt with the SPI library, so beginTransaction() can
  763. // prevent conflicts. The input interruptNumber is the number used
  764. // with attachInterrupt. If SPI is used from a different interrupt
  765. // (eg, a timer), interruptNumber should be 255.
  766. void usingInterrupt(uint8_t n) {
  767. if (n == 3 || n == 4) {
  768. usingInterrupt(IRQ_PORTA);
  769. } else if ((n >= 2 && n <= 15) || (n >= 20 && n <= 23)) {
  770. usingInterrupt(IRQ_PORTCD);
  771. }
  772. }
  773. void usingInterrupt(IRQ_NUMBER_t interruptName) {
  774. uint32_t n = (uint32_t)interruptName;
  775. if (n < NVIC_NUM_INTERRUPTS) interruptMask |= (1 << n);
  776. }
  777. void notUsingInterrupt(IRQ_NUMBER_t interruptName) {
  778. uint32_t n = (uint32_t)interruptName;
  779. if (n < NVIC_NUM_INTERRUPTS) interruptMask &= ~(1 << n);
  780. }
  781. // Before using SPI.transfer() or asserting chip select pins,
  782. // this function is used to gain exclusive access to the SPI bus
  783. // and configure the correct settings.
  784. void beginTransaction(SPISettings settings) {
  785. if (interruptMask) {
  786. __disable_irq();
  787. interruptSave = NVIC_ICER0 & interruptMask;
  788. NVIC_ICER0 = interruptSave;
  789. __enable_irq();
  790. }
  791. #ifdef SPI_TRANSACTION_MISMATCH_LED
  792. if (inTransactionFlag) {
  793. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  794. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  795. }
  796. inTransactionFlag = 1;
  797. #endif
  798. port().C1 = settings.c1;
  799. port().BR = settings.br[hardware().br_index];
  800. }
  801. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  802. uint8_t transfer(uint8_t data) {
  803. port().DL = data;
  804. while (!(port().S & SPI_S_SPRF)) ; // wait
  805. return port().DL;
  806. }
  807. uint16_t transfer16(uint16_t data) {
  808. port().C2 = SPI_C2_SPIMODE;
  809. port().S;
  810. port().DL = data;
  811. port().DH = data >> 8;
  812. while (!(port().S & SPI_S_SPRF)) ; // wait
  813. uint16_t r = port().DL | (port().DH << 8);
  814. port().C2 = 0;
  815. port().S;
  816. return r;
  817. }
  818. void transfer(void *buf, size_t count) {
  819. if (count == 0) return;
  820. uint8_t *p = (uint8_t *)buf;
  821. while (!(port().S & SPI_S_SPTEF)) ; // wait
  822. port().DL = *p;
  823. while (--count > 0) {
  824. uint8_t out = *(p + 1);
  825. while (!(port().S & SPI_S_SPTEF)) ; // wait
  826. __disable_irq();
  827. port().DL = out;
  828. while (!(port().S & SPI_S_SPRF)) ; // wait
  829. uint8_t in = port().DL;
  830. __enable_irq();
  831. *p++ = in;
  832. }
  833. while (!(port().S & SPI_S_SPRF)) ; // wait
  834. *p = port().DL;
  835. }
  836. void setTransferWriteFill(uint8_t ch ) {_transferWriteFill = ch;}
  837. void transfer(const void * buf, void * retbuf, size_t count);
  838. // Asynch support (DMA )
  839. #ifdef SPI_HAS_TRANSFER_ASYNC
  840. bool transfer(const void *txBuffer, void *rxBuffer, size_t count, EventResponderRef event_responder);
  841. friend void _spi_dma_rxISR0(void);
  842. friend void _spi_dma_rxISR1(void);
  843. inline void dma_isr(void);
  844. #endif
  845. // After performing a group of transfers and releasing the chip select
  846. // signal, this function allows others to access the SPI bus
  847. void endTransaction(void) {
  848. #ifdef SPI_TRANSACTION_MISMATCH_LED
  849. if (!inTransactionFlag) {
  850. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  851. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  852. }
  853. inTransactionFlag = 0;
  854. #endif
  855. if (interruptMask) {
  856. NVIC_ISER0 = interruptSave;
  857. }
  858. }
  859. // Disable the SPI bus
  860. void end();
  861. // This function is deprecated. New applications should use
  862. // beginTransaction() to configure SPI settings.
  863. void setBitOrder(uint8_t bitOrder) {
  864. uint8_t c = port().C1 | SPI_C1_SPE;
  865. if (bitOrder == LSBFIRST) c |= SPI_C1_LSBFE;
  866. else c &= ~SPI_C1_LSBFE;
  867. port().C1 = c;
  868. }
  869. // This function is deprecated. New applications should use
  870. // beginTransaction() to configure SPI settings.
  871. void setDataMode(uint8_t dataMode) {
  872. uint8_t c = port().C1 | SPI_C1_SPE;
  873. if (dataMode & 0x04) c |= SPI_C1_CPHA;
  874. else c &= ~SPI_C1_CPHA;
  875. if (dataMode & 0x08) c |= SPI_C1_CPOL;
  876. else c &= ~SPI_C1_CPOL;
  877. port().C1 = c;
  878. }
  879. // This function is deprecated. New applications should use
  880. // beginTransaction() to configure SPI settings.
  881. void setClockDivider(uint8_t clockDiv) {
  882. unsigned int i = hardware().br_index;
  883. if (clockDiv == SPI_CLOCK_DIV2) {
  884. port().BR = (SPISettings(12000000, MSBFIRST, SPI_MODE0).br[i]);
  885. } else if (clockDiv == SPI_CLOCK_DIV4) {
  886. port().BR = (SPISettings(4000000, MSBFIRST, SPI_MODE0).br[i]);
  887. } else if (clockDiv == SPI_CLOCK_DIV8) {
  888. port().BR = (SPISettings(2000000, MSBFIRST, SPI_MODE0).br[i]);
  889. } else if (clockDiv == SPI_CLOCK_DIV16) {
  890. port().BR = (SPISettings(1000000, MSBFIRST, SPI_MODE0).br[i]);
  891. } else if (clockDiv == SPI_CLOCK_DIV32) {
  892. port().BR = (SPISettings(500000, MSBFIRST, SPI_MODE0).br[i]);
  893. } else if (clockDiv == SPI_CLOCK_DIV64) {
  894. port().BR = (SPISettings(250000, MSBFIRST, SPI_MODE0).br[i]);
  895. } else { /* clockDiv == SPI_CLOCK_DIV128 */
  896. port().BR = (SPISettings(125000, MSBFIRST, SPI_MODE0).br[i]);
  897. }
  898. }
  899. // These undocumented functions should not be used. SPI.transfer()
  900. // polls the hardware flag which is automatically cleared as the
  901. // AVR responds to SPI's interrupt
  902. void attachInterrupt() { }
  903. void detachInterrupt() { }
  904. // Teensy LC can use alternate pins for these 3 SPI signals.
  905. void setMOSI(uint8_t pin);
  906. void setMISO(uint8_t pin);
  907. void setSCK(uint8_t pin);
  908. // return true if "pin" has special chip select capability
  909. bool pinIsChipSelect(uint8_t pin);
  910. bool pinIsMOSI(uint8_t pin);
  911. bool pinIsMISO(uint8_t pin);
  912. bool pinIsSCK(uint8_t pin);
  913. // return true if both pin1 and pin2 have independent chip select capability
  914. bool pinIsChipSelect(uint8_t pin1, uint8_t pin2) { return false; }
  915. // configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
  916. // setCS() is a special function, not intended for use from normal Arduino
  917. // programs/sketches. See the ILI3941_t3 library for an example.
  918. uint8_t setCS(uint8_t pin);
  919. private:
  920. KINETISL_SPI_t & port() { return *(KINETISL_SPI_t *)port_addr; }
  921. const SPI_Hardware_t & hardware() { return *(const SPI_Hardware_t *)hardware_addr; }
  922. uintptr_t port_addr;
  923. uintptr_t hardware_addr;
  924. uint32_t interruptMask = 0;
  925. uint32_t interruptSave = 0;
  926. uint8_t mosi_pin_index = 0;
  927. uint8_t miso_pin_index = 0;
  928. uint8_t sck_pin_index = 0;
  929. #ifdef SPI_TRANSACTION_MISMATCH_LED
  930. uint8_t inTransactionFlag = 0;
  931. #endif
  932. uint8_t _transferWriteFill = 0;
  933. #ifdef SPI_HAS_TRANSFER_ASYNC
  934. // DMA Support
  935. bool initDMAChannels();
  936. DMAState _dma_state = DMAState::notAllocated;
  937. uint32_t _dma_count_remaining = 0; // How many bytes left to output after current DMA completes
  938. DMAChannel *_dmaTX = nullptr;
  939. DMAChannel *_dmaRX = nullptr;
  940. EventResponder *_dma_event_responder = nullptr;
  941. #endif
  942. };
  943. /**********************************************************/
  944. /* 32 bit Teensy 4.x */
  945. /**********************************************************/
  946. #elif defined(__arm__) && defined(TEENSYDUINO) && (defined(__IMXRT1052__) || defined(__IMXRT1062__))
  947. #define SPI_ATOMIC_VERSION 1
  948. //#include "debug/printf.h"
  949. // TODO......
  950. #undef SPI_HAS_TRANSFER_ASYNC
  951. class SPISettings {
  952. public:
  953. SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  954. if (__builtin_constant_p(clock)) {
  955. init_AlwaysInline(clock, bitOrder, dataMode);
  956. } else {
  957. init_MightInline(clock, bitOrder, dataMode);
  958. }
  959. }
  960. SPISettings() {
  961. init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
  962. }
  963. private:
  964. void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
  965. init_AlwaysInline(clock, bitOrder, dataMode);
  966. }
  967. void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
  968. __attribute__((__always_inline__)) {
  969. // TODO: Need to check timings as related to chip selects?
  970. const uint32_t clk_sel[4] = {664615384, // PLL3 PFD1
  971. 720000000, // PLL3 PFD0
  972. 528000000, // PLL2
  973. 396000000}; // PLL2 PFD2
  974. uint32_t cbcmr = CCM_CBCMR;
  975. uint32_t clkhz = clk_sel[(cbcmr >> 4) & 0x03] / (((cbcmr >> 26 ) & 0x07 ) + 1); // LPSPI peripheral clock
  976. uint32_t d, div;
  977. if (clock == 0) clock =1;
  978. d= clkhz/clock;
  979. if (d && clkhz/d > clock) d++;
  980. if (d > 257) d= 257; // max div
  981. if (d > 2) {
  982. div = d-2;
  983. } else {
  984. div =0;
  985. }
  986. ccr = LPSPI_CCR_SCKDIV(div) | LPSPI_CCR_DBT(div/2);
  987. tcr = LPSPI_TCR_FRAMESZ(7); // TCR has polarity and bit order too
  988. // handle LSB setup
  989. if (bitOrder == LSBFIRST) tcr |= LPSPI_TCR_LSBF;
  990. // Handle Data Mode
  991. if (dataMode & 0x08) tcr |= LPSPI_TCR_CPOL;
  992. // Note: On T3.2 when we set CPHA it also updated the timing. It moved the
  993. // PCS to SCK Delay Prescaler into the After SCK Delay Prescaler
  994. if (dataMode & 0x04) tcr |= LPSPI_TCR_CPHA;
  995. }
  996. uint32_t ccr; // clock config, pg 2660 (RT1050 ref, rev 2)
  997. uint32_t tcr; // transmit command, pg 2664 (RT1050 ref, rev 2)
  998. friend class SPIClass;
  999. };
  1000. class SPIClass { // Teensy 4
  1001. public:
  1002. static const uint8_t CNT_MISO_PINS = 1;
  1003. static const uint8_t CNT_MOSI_PINS = 1;
  1004. static const uint8_t CNT_SCK_PINS = 1;
  1005. static const uint8_t CNT_CS_PINS = 1;
  1006. typedef struct {
  1007. volatile uint32_t &clock_gate_register;
  1008. const uint32_t clock_gate_mask;
  1009. const uint8_t miso_pin[CNT_MISO_PINS];
  1010. const uint32_t miso_mux[CNT_MISO_PINS];
  1011. const uint8_t mosi_pin[CNT_MOSI_PINS];
  1012. const uint32_t mosi_mux[CNT_MOSI_PINS];
  1013. const uint8_t sck_pin[CNT_SCK_PINS];
  1014. const uint32_t sck_mux[CNT_SCK_PINS];
  1015. const uint8_t cs_pin[CNT_CS_PINS];
  1016. const uint32_t cs_mux[CNT_CS_PINS];
  1017. } SPI_Hardware_t;
  1018. static const SPI_Hardware_t spiclass_lpspi4_hardware;
  1019. public:
  1020. constexpr SPIClass(uintptr_t myport, uintptr_t myhardware)
  1021. : port_addr(myport), hardware_addr(myhardware) {
  1022. }
  1023. // constexpr SPIClass(IMXRT_LPSPI_t *myport, const SPI_Hardware_t *myhardware)
  1024. // : port(myport), hardware(myhardware) {
  1025. // }
  1026. // Initialize the SPI library
  1027. void begin();
  1028. // If SPI is to used from within an interrupt, this function registers
  1029. // that interrupt with the SPI library, so beginTransaction() can
  1030. // prevent conflicts. The input interruptNumber is the number used
  1031. // with attachInterrupt. If SPI is used from a different interrupt
  1032. // (eg, a timer), interruptNumber should be 255.
  1033. void usingInterrupt(uint8_t n) {
  1034. if (n >= CORE_NUM_DIGITAL) return;
  1035. volatile uint32_t *gpio = portOutputRegister(n);
  1036. switch((uint32_t)gpio) {
  1037. case (uint32_t)&GPIO1_DR:
  1038. usingInterrupt(IRQ_GPIO1_0_15);
  1039. usingInterrupt(IRQ_GPIO1_16_31);
  1040. break;
  1041. case (uint32_t)&GPIO2_DR:
  1042. usingInterrupt(IRQ_GPIO2_0_15);
  1043. usingInterrupt(IRQ_GPIO2_16_31);
  1044. break;
  1045. case (uint32_t)&GPIO3_DR:
  1046. usingInterrupt(IRQ_GPIO3_0_15);
  1047. usingInterrupt(IRQ_GPIO3_16_31);
  1048. break;
  1049. case (uint32_t)&GPIO4_DR:
  1050. usingInterrupt(IRQ_GPIO4_0_15);
  1051. usingInterrupt(IRQ_GPIO4_16_31);
  1052. break;
  1053. }
  1054. }
  1055. void usingInterrupt(IRQ_NUMBER_t interruptName);
  1056. void notUsingInterrupt(IRQ_NUMBER_t interruptName);
  1057. // Before using SPI.transfer() or asserting chip select pins,
  1058. // this function is used to gain exclusive access to the SPI bus
  1059. // and configure the correct settings.
  1060. void beginTransaction(SPISettings settings) {
  1061. if (interruptMasksUsed) {
  1062. __disable_irq();
  1063. if (interruptMasksUsed & 0x01) {
  1064. interruptSave[0] = NVIC_ICER0 & interruptMask[0];
  1065. NVIC_ICER0 = interruptSave[0];
  1066. }
  1067. if (interruptMasksUsed & 0x02) {
  1068. interruptSave[1] = NVIC_ICER1 & interruptMask[1];
  1069. NVIC_ICER1 = interruptSave[1];
  1070. }
  1071. if (interruptMasksUsed & 0x04) {
  1072. interruptSave[2] = NVIC_ICER2 & interruptMask[2];
  1073. NVIC_ICER2 = interruptSave[2];
  1074. }
  1075. if (interruptMasksUsed & 0x08) {
  1076. interruptSave[3] = NVIC_ICER3 & interruptMask[3];
  1077. NVIC_ICER3 = interruptSave[3];
  1078. }
  1079. if (interruptMasksUsed & 0x10) {
  1080. interruptSave[4] = NVIC_ICER4 & interruptMask[4];
  1081. NVIC_ICER4 = interruptSave[4];
  1082. }
  1083. __enable_irq();
  1084. }
  1085. #ifdef SPI_TRANSACTION_MISMATCH_LED
  1086. if (inTransactionFlag) {
  1087. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  1088. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  1089. }
  1090. inTransactionFlag = 1;
  1091. #endif
  1092. //printf("trans\n");
  1093. port().CR = 0;
  1094. port().CFGR1 = LPSPI_CFGR1_MASTER | LPSPI_CFGR1_SAMPLE;
  1095. port().CCR = settings.ccr;
  1096. port().TCR = settings.tcr;
  1097. //port().CCR = LPSPI_CCR_SCKDIV(4);
  1098. //port().TCR = LPSPI_TCR_FRAMESZ(7);
  1099. port().CR = LPSPI_CR_MEN;
  1100. }
  1101. // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
  1102. uint8_t transfer(uint8_t data) {
  1103. // TODO: check for space in fifo?
  1104. port().TDR = data;
  1105. while (1) {
  1106. uint32_t fifo = (port().FSR >> 16) & 0x1F;
  1107. if (fifo > 0) return port().RDR;
  1108. }
  1109. //port().SR = SPI_SR_TCF;
  1110. //port().PUSHR = data;
  1111. //while (!(port().SR & SPI_SR_TCF)) ; // wait
  1112. //return port().POPR;
  1113. }
  1114. uint16_t transfer16(uint16_t data) {
  1115. uint32_t tcr = port().TCR;
  1116. port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ(15); // turn on 16 bit mode
  1117. port().TDR = data; // output 16 bit data.
  1118. while ((port().RSR & LPSPI_RSR_RXEMPTY)) ; // wait while the RSR fifo is empty...
  1119. port().TCR = tcr; // restore back
  1120. return port().RDR;
  1121. }
  1122. void inline transfer(void *buf, size_t count) {transfer(buf, buf, count);}
  1123. void setTransferWriteFill(uint8_t ch ) {_transferWriteFill = ch;}
  1124. void transfer(const void * buf, void * retbuf, size_t count);
  1125. // Asynch support (DMA )
  1126. #ifdef SPI_HAS_TRANSFER_ASYNC
  1127. bool transfer(const void *txBuffer, void *rxBuffer, size_t count, EventResponderRef event_responder);
  1128. friend void _spi_dma_rxISR0(void);
  1129. friend void _spi_dma_rxISR1(void);
  1130. friend void _spi_dma_rxISR2(void);
  1131. inline void dma_rxisr(void);
  1132. #endif
  1133. // After performing a group of transfers and releasing the chip select
  1134. // signal, this function allows others to access the SPI bus
  1135. void endTransaction(void) {
  1136. #ifdef SPI_TRANSACTION_MISMATCH_LED
  1137. if (!inTransactionFlag) {
  1138. pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
  1139. digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
  1140. }
  1141. inTransactionFlag = 0;
  1142. #endif
  1143. if (interruptMasksUsed) {
  1144. if (interruptMasksUsed & 0x01) NVIC_ISER0 = interruptSave[0];
  1145. if (interruptMasksUsed & 0x02) NVIC_ISER1 = interruptSave[1];
  1146. if (interruptMasksUsed & 0x04) NVIC_ISER2 = interruptSave[2];
  1147. if (interruptMasksUsed & 0x08) NVIC_ISER3 = interruptSave[3];
  1148. if (interruptMasksUsed & 0x10) NVIC_ISER4 = interruptSave[4];
  1149. }
  1150. }
  1151. // Disable the SPI bus
  1152. void end();
  1153. // This function is deprecated. New applications should use
  1154. // beginTransaction() to configure SPI settings.
  1155. void setBitOrder(uint8_t bitOrder);
  1156. // This function is deprecated. New applications should use
  1157. // beginTransaction() to configure SPI settings.
  1158. void setDataMode(uint8_t dataMode);
  1159. // This function is deprecated. New applications should use
  1160. // beginTransaction() to configure SPI settings.
  1161. void setClockDivider(uint8_t clockDiv) {
  1162. if (clockDiv == SPI_CLOCK_DIV2) {
  1163. //setClockDivider_noInline(SPISettings(12000000, MSBFIRST, SPI_MODE0).ctar);
  1164. } else if (clockDiv == SPI_CLOCK_DIV4) {
  1165. //setClockDivider_noInline(SPISettings(4000000, MSBFIRST, SPI_MODE0).ctar);
  1166. } else if (clockDiv == SPI_CLOCK_DIV8) {
  1167. //setClockDivider_noInline(SPISettings(2000000, MSBFIRST, SPI_MODE0).ctar);
  1168. } else if (clockDiv == SPI_CLOCK_DIV16) {
  1169. //setClockDivider_noInline(SPISettings(1000000, MSBFIRST, SPI_MODE0).ctar);
  1170. } else if (clockDiv == SPI_CLOCK_DIV32) {
  1171. //setClockDivider_noInline(SPISettings(500000, MSBFIRST, SPI_MODE0).ctar);
  1172. } else if (clockDiv == SPI_CLOCK_DIV64) {
  1173. //setClockDivider_noInline(SPISettings(250000, MSBFIRST, SPI_MODE0).ctar);
  1174. } else { /* clockDiv == SPI_CLOCK_DIV128 */
  1175. //setClockDivider_noInline(SPISettings(125000, MSBFIRST, SPI_MODE0).ctar);
  1176. }
  1177. }
  1178. void setClockDivider_noInline(uint32_t clk);
  1179. // These undocumented functions should not be used. SPI.transfer()
  1180. // polls the hardware flag which is automatically cleared as the
  1181. // AVR responds to SPI's interrupt
  1182. void attachInterrupt() { }
  1183. void detachInterrupt() { }
  1184. // Teensy 3.x can use alternate pins for these 3 SPI signals.
  1185. void setMOSI(uint8_t pin);
  1186. void setMISO(uint8_t pin);
  1187. void setSCK(uint8_t pin);
  1188. // return true if "pin" has special chip select capability
  1189. uint8_t pinIsChipSelect(uint8_t pin);
  1190. bool pinIsMOSI(uint8_t pin);
  1191. bool pinIsMISO(uint8_t pin);
  1192. bool pinIsSCK(uint8_t pin);
  1193. // return true if both pin1 and pin2 have independent chip select capability
  1194. bool pinIsChipSelect(uint8_t pin1, uint8_t pin2);
  1195. // configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
  1196. // setCS() is a special function, not intended for use from normal Arduino
  1197. // programs/sketches. See the ILI3941_t3 library for an example.
  1198. uint8_t setCS(uint8_t pin);
  1199. private:
  1200. private:
  1201. IMXRT_LPSPI_t & port() { return *(IMXRT_LPSPI_t *)port_addr; }
  1202. const SPI_Hardware_t & hardware() { return *(const SPI_Hardware_t *)hardware_addr; }
  1203. uintptr_t port_addr;
  1204. uintptr_t hardware_addr;
  1205. //KINETISK_SPI_t & port() { return *(KINETISK_SPI_t *)port_addr; }
  1206. // IMXRT_LPSPI_t * const port;
  1207. // const SPI_Hardware_t * const hardware;
  1208. void updateCTAR(uint32_t ctar);
  1209. uint8_t miso_pin_index = 0;
  1210. uint8_t mosi_pin_index = 0;
  1211. uint8_t sck_pin_index = 0;
  1212. uint8_t interruptMasksUsed = 0;
  1213. uint32_t interruptMask[(NVIC_NUM_INTERRUPTS+31)/32] = {};
  1214. uint32_t interruptSave[(NVIC_NUM_INTERRUPTS+31)/32] = {};
  1215. #ifdef SPI_TRANSACTION_MISMATCH_LED
  1216. uint8_t inTransactionFlag = 0;
  1217. #endif
  1218. uint8_t _transferWriteFill = 0;
  1219. // DMA Support
  1220. #ifdef SPI_HAS_TRANSFER_ASYNC
  1221. bool initDMAChannels();
  1222. DMAState _dma_state = DMAState::notAllocated;
  1223. uint32_t _dma_count_remaining = 0; // How many bytes left to output after current DMA completes
  1224. DMAChannel *_dmaTX = nullptr;
  1225. DMAChannel *_dmaRX = nullptr;
  1226. EventResponder *_dma_event_responder = nullptr;
  1227. #endif
  1228. };
  1229. #endif
  1230. extern SPIClass SPI;
  1231. #if defined(__MKL26Z64__)
  1232. extern SPIClass SPI1;
  1233. #endif
  1234. #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
  1235. extern SPIClass SPI1;
  1236. extern SPIClass SPI2;
  1237. #endif
  1238. #endif