Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

224 Zeilen
6.7KB

  1. /* Arduino SdSpi Library
  2. * Copyright (C) 2013 by William Greiman
  3. *
  4. * This file is part of the Arduino SdSpi Library
  5. *
  6. * This Library is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This Library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Arduino SdSpi Library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include <SdSpi.h>
  21. #if USE_NATIVE_TEENSY3_SPI
  22. // Teensy 3.0 functions
  23. #include <mk20dx128.h>
  24. // use 16-bit frame if SPI_USE_8BIT_FRAME is zero
  25. #define SPI_USE_8BIT_FRAME 0
  26. // Limit initial fifo to three entries to avoid fifo overrun
  27. #define SPI_INITIAL_FIFO_DEPTH 3
  28. // define some symbols that are not in mk20dx128.h
  29. #ifndef SPI_SR_RXCTR
  30. #define SPI_SR_RXCTR 0XF0
  31. #endif // SPI_SR_RXCTR
  32. #ifndef SPI_PUSHR_CONT
  33. #define SPI_PUSHR_CONT 0X80000000
  34. #endif // SPI_PUSHR_CONT
  35. #ifndef SPI_PUSHR_CTAS
  36. #define SPI_PUSHR_CTAS(n) (((n) & 7) << 28)
  37. #endif // SPI_PUSHR_CTAS
  38. //------------------------------------------------------------------------------
  39. /**
  40. * initialize SPI pins
  41. */
  42. void SdSpi::begin() {
  43. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  44. }
  45. //------------------------------------------------------------------------------
  46. /**
  47. * Initialize hardware SPI
  48. *
  49. */
  50. void SdSpi::init(uint8_t sckDivisor) {
  51. uint32_t ctar, ctar0, ctar1;
  52. if (sckDivisor <= 2) {
  53. // 1/2 speed
  54. ctar = SPI_CTAR_DBR | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  55. } else if (sckDivisor <= 4) {
  56. // 1/4 speed
  57. ctar = SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
  58. } else if (sckDivisor <= 8) {
  59. // 1/8 speed
  60. ctar = SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
  61. } else if (sckDivisor <= 12) {
  62. // 1/12 speed
  63. ctar = SPI_CTAR_BR(2) | SPI_CTAR_CSSCK(2);
  64. } else if (sckDivisor <= 16) {
  65. // 1/16 speed
  66. ctar = SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(3);
  67. } else if (sckDivisor <= 32) {
  68. // 1/32 speed
  69. ctar = SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(4);
  70. } else if (sckDivisor <= 64) {
  71. // 1/64 speed
  72. ctar = SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(5);
  73. } else {
  74. // 1/128 speed
  75. ctar = SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(6);
  76. }
  77. // CTAR0 - 8 bit transfer
  78. ctar0 = ctar | SPI_CTAR_FMSZ(7);
  79. // CTAR1 - 16 bit transfer
  80. ctar1 = ctar | SPI_CTAR_FMSZ(15);
  81. if (SPI0_CTAR0 != ctar0 || SPI0_CTAR1 != ctar1) {
  82. SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  83. SPI0_CTAR0 = ctar0;
  84. SPI0_CTAR1 = ctar1;
  85. }
  86. SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
  87. CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
  88. CORE_PIN12_CONFIG = PORT_PCR_MUX(2);
  89. CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
  90. }
  91. //------------------------------------------------------------------------------
  92. /** SPI receive a byte */
  93. uint8_t SdSpi::receive() {
  94. SPI0_MCR |= SPI_MCR_CLR_RXF;
  95. SPI0_SR = SPI_SR_TCF;
  96. SPI0_PUSHR = 0xFF;
  97. while (!(SPI0_SR & SPI_SR_TCF)) {}
  98. return SPI0_POPR;
  99. }
  100. //------------------------------------------------------------------------------
  101. /** SPI receive multiple bytes */
  102. uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
  103. // clear any data in RX FIFO
  104. SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
  105. #if SPI_USE_8BIT_FRAME
  106. // initial number of bytes to push into TX FIFO
  107. int nf = n < SPI_INITIAL_FIFO_DEPTH ? n : SPI_INITIAL_FIFO_DEPTH;
  108. for (int i = 0; i < nf; i++) {
  109. SPI0_PUSHR = 0XFF;
  110. }
  111. // limit for pushing dummy data into TX FIFO
  112. uint8_t* limit = buf + n - nf;
  113. while (buf < limit) {
  114. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  115. SPI0_PUSHR = 0XFF;
  116. *buf++ = SPI0_POPR;
  117. }
  118. // limit for rest of RX data
  119. limit += nf;
  120. while (buf < limit) {
  121. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  122. *buf++ = SPI0_POPR;
  123. }
  124. #else // SPI_USE_8BIT_FRAME
  125. // use 16 bit frame to avoid TD delay between frames
  126. // get one byte if n is odd
  127. if (n & 1) {
  128. *buf++ = receive();
  129. n--;
  130. }
  131. // initial number of words to push into TX FIFO
  132. int nf = n/2 < SPI_INITIAL_FIFO_DEPTH ? n/2 : SPI_INITIAL_FIFO_DEPTH;
  133. for (int i = 0; i < nf; i++) {
  134. SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
  135. }
  136. uint8_t* limit = buf + n - 2*nf;
  137. while (buf < limit) {
  138. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  139. SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
  140. uint16_t w = SPI0_POPR;
  141. *buf++ = w >> 8;
  142. *buf++ = w & 0XFF;
  143. }
  144. // limit for rest of RX data
  145. limit += 2*nf;
  146. while (buf < limit) {
  147. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  148. uint16_t w = SPI0_POPR;
  149. *buf++ = w >> 8;
  150. *buf++ = w & 0XFF;
  151. }
  152. #endif // SPI_USE_8BIT_FRAME
  153. return 0;
  154. }
  155. //------------------------------------------------------------------------------
  156. /** SPI send a byte */
  157. void SdSpi::send(uint8_t b) {
  158. SPI0_MCR |= SPI_MCR_CLR_RXF;
  159. SPI0_SR = SPI_SR_TCF;
  160. SPI0_PUSHR = b;
  161. while (!(SPI0_SR & SPI_SR_TCF)) {}
  162. }
  163. //------------------------------------------------------------------------------
  164. /** SPI send multiple bytes */
  165. void SdSpi::send(const uint8_t* buf , size_t n) {
  166. // clear any data in RX FIFO
  167. SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
  168. #if SPI_USE_8BIT_FRAME
  169. // initial number of bytes to push into TX FIFO
  170. int nf = n < SPI_INITIAL_FIFO_DEPTH ? n : SPI_INITIAL_FIFO_DEPTH;
  171. // limit for pushing data into TX fifo
  172. const uint8_t* limit = buf + n;
  173. for (int i = 0; i < nf; i++) {
  174. SPI0_PUSHR = *buf++;
  175. }
  176. // write data to TX FIFO
  177. while (buf < limit) {
  178. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  179. SPI0_PUSHR = *buf++;
  180. SPI0_POPR;
  181. }
  182. // wait for data to be sent
  183. while (nf) {
  184. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  185. SPI0_POPR;
  186. nf--;
  187. }
  188. #else // SPI_USE_8BIT_FRAME
  189. // use 16 bit frame to avoid TD delay between frames
  190. // send one byte if n is odd
  191. if (n & 1) {
  192. send(*buf++);
  193. n--;
  194. }
  195. // initial number of words to push into TX FIFO
  196. int nf = n/2 < SPI_INITIAL_FIFO_DEPTH ? n/2 : SPI_INITIAL_FIFO_DEPTH;
  197. // limit for pushing data into TX fifo
  198. const uint8_t* limit = buf + n;
  199. for (int i = 0; i < nf; i++) {
  200. uint16_t w = (*buf++) << 8;
  201. w |= *buf++;
  202. SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
  203. }
  204. // write data to TX FIFO
  205. while (buf < limit) {
  206. uint16_t w = *buf++ << 8;
  207. w |= *buf++;
  208. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  209. SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
  210. SPI0_POPR;
  211. }
  212. // wait for data to be sent
  213. while (nf) {
  214. while (!(SPI0_SR & SPI_SR_RXCTR)) {}
  215. SPI0_POPR;
  216. nf--;
  217. }
  218. #endif // SPI_USE_8BIT_FRAME
  219. }
  220. #endif // USE_NATIVE_TEENSY3_SPI