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.

253 lines
7.2KB

  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. SPIClass SPI;
  13. /**********************************************************/
  14. /* 8 bit AVR-based boards */
  15. /**********************************************************/
  16. #if defined(__AVR__)
  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. void SPIClass::usingInterrupt(uint8_t interruptNumber)
  46. {
  47. uint8_t mask;
  48. if (interruptMode > 1) return;
  49. noInterrupts();
  50. switch (interruptNumber) {
  51. #ifdef SPI_INT0_MASK
  52. case 0: mask = SPI_INT0_MASK; break;
  53. #endif
  54. #ifdef SPI_INT1_MASK
  55. case 1: mask = SPI_INT1_MASK; break;
  56. #endif
  57. #ifdef SPI_INT2_MASK
  58. case 2: mask = SPI_INT2_MASK; break;
  59. #endif
  60. #ifdef SPI_INT3_MASK
  61. case 3: mask = SPI_INT3_MASK; break;
  62. #endif
  63. #ifdef SPI_INT4_MASK
  64. case 4: mask = SPI_INT4_MASK; break;
  65. #endif
  66. #ifdef SPI_INT5_MASK
  67. case 5: mask = SPI_INT5_MASK; break;
  68. #endif
  69. #ifdef SPI_INT6_MASK
  70. case 6: mask = SPI_INT6_MASK; break;
  71. #endif
  72. #ifdef SPI_INT7_MASK
  73. case 7: mask = SPI_INT7_MASK; break;
  74. #endif
  75. default:
  76. interruptMode = 2;
  77. interrupts();
  78. return;
  79. }
  80. interruptMode = 1;
  81. interruptMask |= mask;
  82. interrupts();
  83. }
  84. /**********************************************************/
  85. /* 32 bit Teensy 3.0 and 3.1 */
  86. /**********************************************************/
  87. #elif defined(__arm__) && defined(TEENSYDUINO)
  88. uint8_t SPIClass::interruptMode = 0;
  89. uint8_t SPIClass::interruptMask = 0;
  90. uint8_t SPIClass::interruptSave = 0;
  91. void SPIClass::begin()
  92. {
  93. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  94. SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  95. SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  96. SPI0_CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  97. SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
  98. SPCR.enable_pins(); // pins managed by SPCRemulation in avr_emulation.h
  99. }
  100. void SPIClass::end() {
  101. SPCR.disable_pins();
  102. SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  103. }
  104. void SPIClass::usingInterrupt(uint8_t interruptNumber)
  105. {
  106. // TODO: implement this...
  107. }
  108. void SPIClass::usingInterrupt(IRQ_NUMBER_t interruptName)
  109. {
  110. // TODO: implement this...
  111. }
  112. const uint16_t SPISettings::ctar_div_table[23] = {
  113. 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40,
  114. 56, 64, 96, 128, 192, 256, 384, 512, 640, 768
  115. };
  116. const uint32_t SPISettings::ctar_clock_table[23] = {
  117. SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
  118. SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
  119. SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
  120. SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
  121. SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
  122. SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
  123. SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
  124. SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
  125. SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  126. SPI_CTAR_PBR(2) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(0),
  127. SPI_CTAR_PBR(1) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  128. SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(3),
  129. SPI_CTAR_PBR(2) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  130. SPI_CTAR_PBR(3) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
  131. SPI_CTAR_PBR(0) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
  132. SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
  133. SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
  134. SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
  135. SPI_CTAR_PBR(0) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
  136. SPI_CTAR_PBR(1) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
  137. SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7),
  138. SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
  139. SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7)
  140. };
  141. static void updateCTAR(uint32_t ctar)
  142. {
  143. if (SPI0_CTAR0 != ctar) {
  144. uint32_t mcr = SPI0_MCR;
  145. if (mcr & SPI_MCR_MDIS) {
  146. SPI0_CTAR0 = ctar;
  147. SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
  148. } else {
  149. SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  150. SPI0_CTAR0 = ctar;
  151. SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
  152. SPI0_MCR = mcr;
  153. }
  154. }
  155. }
  156. void SPIClass::setBitOrder(uint8_t bitOrder)
  157. {
  158. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  159. uint32_t ctar = SPI0_CTAR0;
  160. if (bitOrder == LSBFIRST) {
  161. ctar |= SPI_CTAR_LSBFE;
  162. } else {
  163. ctar &= ~SPI_CTAR_LSBFE;
  164. }
  165. updateCTAR(ctar);
  166. }
  167. void SPIClass::setDataMode(uint8_t dataMode)
  168. {
  169. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  170. // TODO: implement with native code
  171. SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
  172. }
  173. void SPIClass::setClockDivider_noInline(uint32_t clk)
  174. {
  175. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  176. uint32_t ctar = SPI0_CTAR0;
  177. ctar &= (SPI_CTAR_CPOL | SPI_CTAR_CPHA | SPI_CTAR_LSBFE);
  178. if (ctar & SPI_CTAR_CPHA) {
  179. clk = (clk & 0xFFFF0FFF) | ((clk & 0xF000) >> 4);
  180. }
  181. ctar |= clk;
  182. updateCTAR(ctar);
  183. }
  184. bool SPIClass::pinIsChipSelect(uint8_t pin)
  185. {
  186. if (pin == 10 || pin == 9 || pin == 6 || pin == 2 || pin == 15) return true;
  187. if (pin >= 20 && pin <= 23) return true;
  188. return false;
  189. }
  190. bool SPIClass::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
  191. {
  192. if (!pinIsChipSelect(pin1) || !pinIsChipSelect(pin2)) return false;
  193. if ((pin1 == 2 && pin2 == 10) || (pin1 == 10 && pin2 == 2)) return false;
  194. if ((pin1 == 6 && pin2 == 9) || (pin1 == 9 && pin2 == 6)) return false;
  195. if ((pin1 == 20 && pin2 == 23) || (pin1 == 23 && pin2 == 20)) return false;
  196. if ((pin1 == 21 && pin2 == 22) || (pin1 == 22 && pin2 == 21)) return false;
  197. return true;
  198. }
  199. uint8_t SPIClass::setCS(uint8_t pin)
  200. {
  201. switch (pin) {
  202. case 10: CORE_PIN10_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTC4
  203. case 2: CORE_PIN2_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTD0
  204. case 9: CORE_PIN9_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTC3
  205. case 6: CORE_PIN6_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTD4
  206. case 20: CORE_PIN20_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTD5
  207. case 23: CORE_PIN23_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTC2
  208. case 21: CORE_PIN21_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTD6
  209. case 22: CORE_PIN22_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTC1
  210. case 15: CORE_PIN15_CONFIG = PORT_PCR_MUX(2); return 0x10; // PTC0
  211. }
  212. return 0;
  213. }
  214. #endif