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 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
  3. * SPI Master library for arduino.
  4. *
  5. * This file is free software; you can redistribute it and/or modify
  6. * it under the terms of either the GNU General Public License version 2
  7. * or the GNU Lesser General Public License version 2.1, both as
  8. * published by the Free Software Foundation.
  9. */
  10. #include "SPI.h"
  11. #include "pins_arduino.h"
  12. /**********************************************************/
  13. /* 8 bit AVR-based boards */
  14. /**********************************************************/
  15. #if defined(__AVR__)
  16. SPIClass SPI;
  17. uint8_t SPIClass::interruptMode = 0;
  18. uint8_t SPIClass::interruptMask = 0;
  19. uint8_t SPIClass::interruptSave = 0;
  20. void SPIClass::begin()
  21. {
  22. // Set SS to high so a connected chip will be "deselected" by default
  23. digitalWrite(SS, HIGH);
  24. // When the SS pin is set as OUTPUT, it can be used as
  25. // a general purpose output port (it doesn't influence
  26. // SPI operations).
  27. pinMode(SS, OUTPUT);
  28. // Warning: if the SS pin ever becomes a LOW INPUT then SPI
  29. // automatically switches to Slave, so the data direction of
  30. // the SS pin MUST be kept as OUTPUT.
  31. SPCR |= _BV(MSTR);
  32. SPCR |= _BV(SPE);
  33. // Set direction register for SCK and MOSI pin.
  34. // MISO pin automatically overrides to INPUT.
  35. // By doing this AFTER enabling SPI, we avoid accidentally
  36. // clocking in a single bit since the lines go directly
  37. // from "input" to SPI control.
  38. // http://code.google.com/p/arduino/issues/detail?id=888
  39. pinMode(SCK, OUTPUT);
  40. pinMode(MOSI, OUTPUT);
  41. }
  42. void SPIClass::end() {
  43. SPCR &= ~_BV(SPE);
  44. }
  45. // mapping of interrupt numbers to bits within SPI_AVR_EIMSK
  46. #if defined(__AVR_ATmega32U4__)
  47. #define SPI_INT0_MASK (1<<INT0)
  48. #define SPI_INT1_MASK (1<<INT1)
  49. #define SPI_INT2_MASK (1<<INT2)
  50. #define SPI_INT3_MASK (1<<INT3)
  51. #define SPI_INT4_MASK (1<<INT6)
  52. #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
  53. #define SPI_INT0_MASK (1<<INT0)
  54. #define SPI_INT1_MASK (1<<INT1)
  55. #define SPI_INT2_MASK (1<<INT2)
  56. #define SPI_INT3_MASK (1<<INT3)
  57. #define SPI_INT4_MASK (1<<INT4)
  58. #define SPI_INT5_MASK (1<<INT5)
  59. #define SPI_INT6_MASK (1<<INT6)
  60. #define SPI_INT7_MASK (1<<INT7)
  61. #elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
  62. #define SPI_INT0_MASK (1<<INT4)
  63. #define SPI_INT1_MASK (1<<INT5)
  64. #define SPI_INT2_MASK (1<<INT0)
  65. #define SPI_INT3_MASK (1<<INT1)
  66. #define SPI_INT4_MASK (1<<INT2)
  67. #define SPI_INT5_MASK (1<<INT3)
  68. #define SPI_INT6_MASK (1<<INT6)
  69. #define SPI_INT7_MASK (1<<INT7)
  70. #else
  71. #ifdef INT0
  72. #define SPI_INT0_MASK (1<<INT0)
  73. #endif
  74. #ifdef INT1
  75. #define SPI_INT1_MASK (1<<INT1)
  76. #endif
  77. #ifdef INT2
  78. #define SPI_INT2_MASK (1<<INT2)
  79. #endif
  80. #endif
  81. void SPIClass::usingInterrupt(uint8_t interruptNumber)
  82. {
  83. uint8_t mask;
  84. if (interruptMode > 1) return;
  85. noInterrupts();
  86. switch (interruptNumber) {
  87. #ifdef SPI_INT0_MASK
  88. case 0: mask = SPI_INT0_MASK; break;
  89. #endif
  90. #ifdef SPI_INT1_MASK
  91. case 1: mask = SPI_INT1_MASK; break;
  92. #endif
  93. #ifdef SPI_INT2_MASK
  94. case 2: mask = SPI_INT2_MASK; break;
  95. #endif
  96. #ifdef SPI_INT3_MASK
  97. case 3: mask = SPI_INT3_MASK; break;
  98. #endif
  99. #ifdef SPI_INT4_MASK
  100. case 4: mask = SPI_INT4_MASK; break;
  101. #endif
  102. #ifdef SPI_INT5_MASK
  103. case 5: mask = SPI_INT5_MASK; break;
  104. #endif
  105. #ifdef SPI_INT6_MASK
  106. case 6: mask = SPI_INT6_MASK; break;
  107. #endif
  108. #ifdef SPI_INT7_MASK
  109. case 7: mask = SPI_INT7_MASK; break;
  110. #endif
  111. default:
  112. interruptMode = 2;
  113. interrupts();
  114. return;
  115. }
  116. interruptMode = 1;
  117. interruptMask |= mask;
  118. interrupts();
  119. }
  120. /**********************************************************/
  121. /* 32 bit Teensy 3.0 and 3.1 */
  122. /**********************************************************/
  123. #elif defined(__arm__) && defined(TEENSYDUINO)
  124. SPIClass SPI;
  125. uint8_t SPIClass::interruptMode = 0;
  126. uint8_t SPIClass::interruptMask = 0;
  127. uint8_t SPIClass::interruptSave = 0;
  128. void SPIClass::begin()
  129. {
  130. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  131. SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  132. SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  133. SPI0_CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  134. SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
  135. SPCR.enable_pins(); // pins managed by SPCRemulation in avr_emulation.h
  136. }
  137. void SPIClass::end() {
  138. SPCR.disable_pins();
  139. SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  140. }
  141. void SPIClass::usingInterrupt(uint8_t interruptNumber)
  142. {
  143. // TODO: implement this...
  144. }
  145. void SPIClass::usingInterrupt(IRQ_NUMBER_t interruptName)
  146. {
  147. // TODO: implement this...
  148. }
  149. const uint16_t SPISettings::ctar_div_table[23] = {
  150. 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40,
  151. 56, 64, 96, 128, 192, 256, 384, 512, 640, 768
  152. };
  153. const uint32_t SPISettings::ctar_clock_table[23] = {
  154. SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
  155. SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
  156. SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
  157. SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
  158. SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
  159. SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
  160. SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
  161. SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
  162. SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  163. SPI_CTAR_PBR(2) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(0),
  164. SPI_CTAR_PBR(1) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  165. SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(3),
  166. SPI_CTAR_PBR(2) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  167. SPI_CTAR_PBR(3) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  168. SPI_CTAR_PBR(0) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
  169. SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
  170. SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
  171. SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
  172. SPI_CTAR_PBR(0) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
  173. SPI_CTAR_PBR(1) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
  174. SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7),
  175. SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
  176. SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7)
  177. };
  178. static void updateCTAR(uint32_t ctar)
  179. {
  180. if (SPI0_CTAR0 != ctar) {
  181. uint32_t mcr = SPI0_MCR;
  182. if (mcr & SPI_MCR_MDIS) {
  183. SPI0_CTAR0 = ctar;
  184. SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
  185. } else {
  186. SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  187. SPI0_CTAR0 = ctar;
  188. SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
  189. SPI0_MCR = mcr;
  190. }
  191. }
  192. }
  193. void SPIClass::setBitOrder(uint8_t bitOrder)
  194. {
  195. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  196. uint32_t ctar = SPI0_CTAR0;
  197. if (bitOrder == LSBFIRST) {
  198. ctar |= SPI_CTAR_LSBFE;
  199. } else {
  200. ctar &= ~SPI_CTAR_LSBFE;
  201. }
  202. updateCTAR(ctar);
  203. }
  204. void SPIClass::setDataMode(uint8_t dataMode)
  205. {
  206. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  207. // TODO: implement with native code
  208. SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
  209. }
  210. void SPIClass::setClockDivider_noInline(uint32_t clk)
  211. {
  212. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  213. uint32_t ctar = SPI0_CTAR0;
  214. ctar &= (SPI_CTAR_CPOL | SPI_CTAR_CPHA | SPI_CTAR_LSBFE);
  215. if (ctar & SPI_CTAR_CPHA) {
  216. clk = (clk & 0xFFFF0FFF) | ((clk & 0xF000) >> 4);
  217. }
  218. ctar |= clk;
  219. updateCTAR(ctar);
  220. }
  221. bool SPIClass::pinIsChipSelect(uint8_t pin)
  222. {
  223. if (pin == 10 || pin == 9 || pin == 6 || pin == 2 || pin == 15) return true;
  224. if (pin >= 20 && pin <= 23) return true;
  225. return false;
  226. }
  227. bool SPIClass::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
  228. {
  229. if (!pinIsChipSelect(pin1) || !pinIsChipSelect(pin2)) return false;
  230. if ((pin1 == 2 && pin2 == 10) || (pin1 == 10 && pin2 == 2)) return false;
  231. if ((pin1 == 6 && pin2 == 9) || (pin1 == 9 && pin2 == 6)) return false;
  232. if ((pin1 == 20 && pin2 == 23) || (pin1 == 23 && pin2 == 20)) return false;
  233. if ((pin1 == 21 && pin2 == 22) || (pin1 == 22 && pin2 == 21)) return false;
  234. return true;
  235. }
  236. uint8_t SPIClass::setCS(uint8_t pin)
  237. {
  238. switch (pin) {
  239. case 10: CORE_PIN10_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTC4
  240. case 2: CORE_PIN2_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTD0
  241. case 9: CORE_PIN9_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTC3
  242. case 6: CORE_PIN6_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTD4
  243. case 20: CORE_PIN20_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTD5
  244. case 23: CORE_PIN23_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTC2
  245. case 21: CORE_PIN21_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTD6
  246. case 22: CORE_PIN22_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTC1
  247. case 15: CORE_PIN15_CONFIG = PORT_PCR_MUX(2); return 0x10; // PTC0
  248. }
  249. return 0;
  250. }
  251. /**********************************************************/
  252. /* 32 bit Arduino Due */
  253. /**********************************************************/
  254. #elif defined(__arm__) && defined(__SAM3X8E__)
  255. #include "SPI.h"
  256. uint8_t SPIClass::interruptMode = 0;
  257. uint8_t SPIClass::interruptMask = 0;
  258. uint8_t SPIClass::interruptSave = 0;
  259. SPIClass::SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)) :
  260. spi(_spi), id(_id), initCb(_initCb), initialized(false)
  261. {
  262. // Empty
  263. }
  264. void SPIClass::begin() {
  265. init();
  266. // NPCS control is left to the user
  267. // Default speed set to 4Mhz
  268. setClockDivider(BOARD_SPI_DEFAULT_SS, 21);
  269. setDataMode(BOARD_SPI_DEFAULT_SS, SPI_MODE0);
  270. setBitOrder(BOARD_SPI_DEFAULT_SS, MSBFIRST);
  271. }
  272. void SPIClass::begin(uint8_t _pin) {
  273. init();
  274. uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin);
  275. PIO_Configure(
  276. g_APinDescription[spiPin].pPort,
  277. g_APinDescription[spiPin].ulPinType,
  278. g_APinDescription[spiPin].ulPin,
  279. g_APinDescription[spiPin].ulPinConfiguration);
  280. // Default speed set to 4Mhz
  281. setClockDivider(_pin, 21);
  282. setDataMode(_pin, SPI_MODE0);
  283. setBitOrder(_pin, MSBFIRST);
  284. }
  285. void SPIClass::init() {
  286. if (initialized)
  287. return;
  288. initCb();
  289. SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS);
  290. SPI_Enable(spi);
  291. initialized = true;
  292. }
  293. void SPIClass::usingInterrupt(uint8_t interruptNumber)
  294. {
  295. uint8_t irestore;
  296. irestore = interruptsStatus();
  297. noInterrupts();
  298. if (interruptMode < 2) {
  299. if (interruptNumber > NUM_DIGITAL_PINS) {
  300. interruptMode = 2;
  301. } else {
  302. uint8_t imask = interruptMask;
  303. Pio *pio = g_APinDescription[interruptNumber].pPort;
  304. if (pio == PIOA) {
  305. imask |= 1;
  306. } else if (pio == PIOB) {
  307. imask |= 2;
  308. } else if (pio == PIOC) {
  309. imask |= 4;
  310. } else if (pio == PIOD) {
  311. imask |= 8;
  312. }
  313. interruptMask = imask;
  314. interruptMode = 1;
  315. }
  316. }
  317. if (irestore) interrupts();
  318. }
  319. void SPIClass::beginTransaction(uint8_t pin, SPISettings settings)
  320. {
  321. if (interruptMode > 0) {
  322. if (interruptMode == 1) {
  323. uint8_t imask = interruptMask;
  324. if (imask & 1) NVIC_DisableIRQ(PIOA_IRQn);
  325. if (imask & 2) NVIC_DisableIRQ(PIOB_IRQn);
  326. if (imask & 4) NVIC_DisableIRQ(PIOC_IRQn);
  327. if (imask & 8) NVIC_DisableIRQ(PIOD_IRQn);
  328. } else {
  329. interruptSave = interruptsStatus();
  330. noInterrupts();
  331. }
  332. }
  333. uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin);
  334. bitOrder[ch] = settings.border;
  335. SPI_ConfigureNPCS(spi, ch, settings.config);
  336. }
  337. void SPIClass::endTransaction(void)
  338. {
  339. if (interruptMode > 0) {
  340. if (interruptMode == 1) {
  341. uint8_t imask = interruptMask;
  342. if (imask & 1) NVIC_EnableIRQ(PIOA_IRQn);
  343. if (imask & 2) NVIC_EnableIRQ(PIOB_IRQn);
  344. if (imask & 4) NVIC_EnableIRQ(PIOC_IRQn);
  345. if (imask & 8) NVIC_EnableIRQ(PIOD_IRQn);
  346. } else {
  347. if (interruptSave) interrupts();
  348. }
  349. }
  350. }
  351. void SPIClass::end(uint8_t _pin) {
  352. uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin);
  353. // Setting the pin as INPUT will disconnect it from SPI peripheral
  354. pinMode(spiPin, INPUT);
  355. }
  356. void SPIClass::end() {
  357. SPI_Disable(spi);
  358. initialized = false;
  359. }
  360. void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) {
  361. uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
  362. bitOrder[ch] = _bitOrder;
  363. }
  364. void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode) {
  365. uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
  366. mode[ch] = _mode | SPI_CSR_CSAAT;
  367. // SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed
  368. // transfer. Some device needs that for working properly.
  369. SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1));
  370. }
  371. void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider) {
  372. uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
  373. divider[ch] = _divider;
  374. // SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed
  375. // transfer. Some device needs that for working properly.
  376. SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1));
  377. }
  378. byte SPIClass::transfer(byte _pin, uint8_t _data, SPITransferMode _mode) {
  379. uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
  380. // Reverse bit order
  381. if (bitOrder[ch] == LSBFIRST)
  382. _data = __REV(__RBIT(_data));
  383. uint32_t d = _data | SPI_PCS(ch);
  384. if (_mode == SPI_LAST)
  385. d |= SPI_TDR_LASTXFER;
  386. // SPI_Write(spi, _channel, _data);
  387. while ((spi->SPI_SR & SPI_SR_TDRE) == 0)
  388. ;
  389. spi->SPI_TDR = d;
  390. // return SPI_Read(spi);
  391. while ((spi->SPI_SR & SPI_SR_RDRF) == 0)
  392. ;
  393. d = spi->SPI_RDR;
  394. // Reverse bit order
  395. if (bitOrder[ch] == LSBFIRST)
  396. d = __REV(__RBIT(d));
  397. return d & 0xFF;
  398. }
  399. void SPIClass::attachInterrupt(void) {
  400. // Should be enableInterrupt()
  401. }
  402. void SPIClass::detachInterrupt(void) {
  403. // Should be disableInterrupt()
  404. }
  405. #if SPI_INTERFACES_COUNT > 0
  406. static void SPI_0_Init(void) {
  407. PIO_Configure(
  408. g_APinDescription[PIN_SPI_MOSI].pPort,
  409. g_APinDescription[PIN_SPI_MOSI].ulPinType,
  410. g_APinDescription[PIN_SPI_MOSI].ulPin,
  411. g_APinDescription[PIN_SPI_MOSI].ulPinConfiguration);
  412. PIO_Configure(
  413. g_APinDescription[PIN_SPI_MISO].pPort,
  414. g_APinDescription[PIN_SPI_MISO].ulPinType,
  415. g_APinDescription[PIN_SPI_MISO].ulPin,
  416. g_APinDescription[PIN_SPI_MISO].ulPinConfiguration);
  417. PIO_Configure(
  418. g_APinDescription[PIN_SPI_SCK].pPort,
  419. g_APinDescription[PIN_SPI_SCK].ulPinType,
  420. g_APinDescription[PIN_SPI_SCK].ulPin,
  421. g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
  422. }
  423. SPIClass SPI(SPI_INTERFACE, SPI_INTERFACE_ID, SPI_0_Init);
  424. #endif
  425. #endif