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.

SdSpi.h 9.9KB

10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. /**
  21. * \file
  22. * \brief SdSpi class for V2 SD/SDHC cards
  23. */
  24. #ifndef SdSpi_h
  25. #define SdSpi_h
  26. #include <Arduino.h>
  27. #include "SdFatConfig.h"
  28. //------------------------------------------------------------------------------
  29. /**
  30. * \class SdSpiBase
  31. * \brief Virtual SPI class for access to SD and SDHC flash memory cards.
  32. */
  33. class SdSpiBase {
  34. public:
  35. /** Initialize the SPI bus */
  36. virtual void begin() = 0;
  37. /** Set SPI options for access to SD/SDHC cards.
  38. *
  39. * \param[in] divisor SCK clock divider relative to the system clock.
  40. */
  41. virtual void init(uint8_t divisor);
  42. /** Receive a byte.
  43. *
  44. * \return The byte.
  45. */
  46. virtual uint8_t receive() = 0;
  47. /** Receive multiple bytes.
  48. *
  49. * \param[out] buf Buffer to receive the data.
  50. * \param[in] n Number of bytes to receive.
  51. *
  52. * \return Zero for no error or nonzero error code.
  53. */
  54. virtual uint8_t receive(uint8_t* buf, size_t n) = 0;
  55. /** Send a byte.
  56. *
  57. * \param[in] data Byte to send
  58. */
  59. virtual void send(uint8_t data) = 0;
  60. /** Send multiple bytes.
  61. *
  62. * \param[in] buf Buffer for data to be sent.
  63. * \param[in] n Number of bytes to send.
  64. */
  65. virtual void send(const uint8_t* buf, size_t n) = 0;
  66. /** \return true if hardware SPI else false */
  67. virtual bool useSpiTransactions() = 0;
  68. };
  69. //------------------------------------------------------------------------------
  70. /**
  71. * \class SdSpi
  72. * \brief SPI class for access to SD and SDHC flash memory cards.
  73. */
  74. #if SD_SPI_CONFIGURATION >= 3
  75. class SdSpi : public SdSpiBase {
  76. #else // SD_SPI_CONFIGURATION >= 3
  77. class SdSpi {
  78. #endif // SD_SPI_CONFIGURATION >= 3
  79. public:
  80. /** Initialize the SPI bus */
  81. void begin();
  82. /** Set SPI options for access to SD/SDHC cards.
  83. *
  84. * \param[in] divisor SCK clock divider relative to the system clock.
  85. */
  86. void init(uint8_t divisor);
  87. /** Receive a byte.
  88. *
  89. * \return The byte.
  90. */
  91. uint8_t receive();
  92. /** Receive multiple bytes.
  93. *
  94. * \param[out] buf Buffer to receive the data.
  95. * \param[in] n Number of bytes to receive.
  96. *
  97. * \return Zero for no error or nonzero error code.
  98. */
  99. uint8_t receive(uint8_t* buf, size_t n);
  100. /** Send a byte.
  101. *
  102. * \param[in] data Byte to send
  103. */
  104. void send(uint8_t data);
  105. /** Send multiple bytes.
  106. *
  107. * \param[in] buf Buffer for data to be sent.
  108. * \param[in] n Number of bytes to send.
  109. */
  110. void send(const uint8_t* buf, size_t n);
  111. /** \return true - uses SPI transactions */
  112. bool useSpiTransactions() {
  113. return true;
  114. }
  115. };
  116. //------------------------------------------------------------------------------
  117. /**
  118. * \class SdSpiLib
  119. * \brief Arduino SPI library class for access to SD and SDHC flash
  120. * memory cards.
  121. */
  122. #if SD_SPI_CONFIGURATION >= 3 || SD_SPI_CONFIGURATION == 1 || defined(DOXYGEN)
  123. #include <SPI.h>
  124. #if SD_SPI_CONFIGURATION >= 3
  125. class SdSpiLib : public SdSpiBase {
  126. #else // SD_SPI_CONFIGURATION >= 3
  127. class SdSpiLib {
  128. #endif // SD_SPI_CONFIGURATION >= 3
  129. public:
  130. /**
  131. * Initialize SPI pins.
  132. */
  133. void begin() {
  134. SPI.begin();
  135. }
  136. /** Set SPI options for access to SD/SDHC cards.
  137. *
  138. * \param[in] divisor SCK clock divider relative to the system clock.
  139. */
  140. void init(uint8_t divisor) {
  141. SPI.setBitOrder(MSBFIRST);
  142. SPI.setDataMode(SPI_MODE0);
  143. #ifndef SPI_CLOCK_DIV128
  144. SPI.setClockDivider(divisor);
  145. #else // SPI_CLOCK_DIV128
  146. int v;
  147. if (divisor <= 2) {
  148. v = SPI_CLOCK_DIV2;
  149. } else if (divisor <= 4) {
  150. v = SPI_CLOCK_DIV4;
  151. } else if (divisor <= 8) {
  152. v = SPI_CLOCK_DIV8;
  153. } else if (divisor <= 16) {
  154. v = SPI_CLOCK_DIV16;
  155. } else if (divisor <= 32) {
  156. v = SPI_CLOCK_DIV32;
  157. } else if (divisor <= 64) {
  158. v = SPI_CLOCK_DIV64;
  159. } else {
  160. v = SPI_CLOCK_DIV128;
  161. }
  162. SPI.setClockDivider(v);
  163. #endif // SPI_CLOCK_DIV128
  164. }
  165. /** Receive a byte.
  166. *
  167. * \return The byte.
  168. */
  169. uint8_t receive() {
  170. return SPI.transfer(0XFF);
  171. }
  172. /** Receive multiple bytes.
  173. *
  174. * \param[out] buf Buffer to receive the data.
  175. * \param[in] n Number of bytes to receive.
  176. *
  177. * \return Zero for no error or nonzero error code.
  178. */
  179. uint8_t receive(uint8_t* buf, size_t n) {
  180. for (size_t i = 0; i < n; i++) {
  181. buf[i] = SPI.transfer(0XFF);
  182. }
  183. return 0;
  184. }
  185. /** Send a byte.
  186. *
  187. * \param[in] b Byte to send
  188. */
  189. void send(uint8_t b) {
  190. SPI.transfer(b);
  191. }
  192. /** Send multiple bytes.
  193. *
  194. * \param[in] buf Buffer for data to be sent.
  195. * \param[in] n Number of bytes to send.
  196. */
  197. void send(const uint8_t* buf , size_t n) {
  198. for (size_t i = 0; i < n; i++) {
  199. SPI.transfer(buf[i]);
  200. }
  201. }
  202. /** \return true - uses SPI transactions */
  203. bool useSpiTransactions() {
  204. return true;
  205. }
  206. };
  207. #endif // SD_SPI_CONFIGURATION >= 3 || SD_SPI_CONFIGURATION == 1
  208. //------------------------------------------------------------------------------
  209. #if SD_SPI_CONFIGURATION > 1 || defined(DOXYGEN)
  210. #include "utility/SoftSPI.h"
  211. /**
  212. * \class SdSpiSoft
  213. * \brief Software SPI class for access to SD and SDHC flash memory cards.
  214. */
  215. template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
  216. class SdSpiSoft : public SdSpiBase {
  217. public:
  218. /**
  219. * initialize SPI pins
  220. */
  221. void begin() {
  222. m_spi.begin();
  223. }
  224. /**
  225. * Initialize hardware SPI - dummy for soft SPI
  226. * \param[in] divisor SCK divisor - ignored.
  227. */
  228. void init(uint8_t divisor) {}
  229. /** Receive a byte.
  230. *
  231. * \return The byte.
  232. */
  233. uint8_t receive() {
  234. return m_spi.receive();
  235. }
  236. /** Receive multiple bytes.
  237. *
  238. * \param[out] buf Buffer to receive the data.
  239. * \param[in] n Number of bytes to receive.
  240. *
  241. * \return Zero for no error or nonzero error code.
  242. */
  243. uint8_t receive(uint8_t* buf, size_t n) {
  244. for (size_t i = 0; i < n; i++) {
  245. buf[i] = receive();
  246. }
  247. return 0;
  248. }
  249. /** Send a byte.
  250. *
  251. * \param[in] data Byte to send
  252. */
  253. void send(uint8_t data) {
  254. m_spi.send(data);
  255. }
  256. /** Send multiple bytes.
  257. *
  258. * \param[in] buf Buffer for data to be sent.
  259. * \param[in] n Number of bytes to send.
  260. */
  261. void send(const uint8_t* buf , size_t n) {
  262. for (size_t i = 0; i < n; i++) {
  263. send(buf[i]);
  264. }
  265. }
  266. /** \return false - no SPI transactions */
  267. bool useSpiTransactions() {
  268. return false;
  269. }
  270. private:
  271. SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi;
  272. };
  273. #endif // SD_SPI_CONFIGURATION > 1 || defined(DOXYGEN)
  274. //------------------------------------------------------------------------------
  275. #if SD_SPI_CONFIGURATION == 0 || SD_SPI_CONFIGURATION >= 3
  276. /** Default is custom fast SPI. */
  277. typedef SdSpi SpiDefault_t;
  278. #elif SD_SPI_CONFIGURATION == 1
  279. /** Default is Arduino library SPI. */
  280. typedef SdSpiLib SpiDefault_t;
  281. #elif SD_SPI_CONFIGURATION == 2
  282. /** Default is software SPI. */
  283. typedef SdSpiSoft<SOFT_SPI_MISO_PIN, SOFT_SPI_MOSI_PIN, SOFT_SPI_SCK_PIN>
  284. SpiDefault_t;
  285. #else // SD_SPI_CONFIGURATION == 0 || SD_SPI_CONFIGURATION >= 3
  286. #error bad SD_SPI_CONFIGURATION
  287. #endif // SD_SPI_CONFIGURATION == 0 || SD_SPI_CONFIGURATION >= 3
  288. //------------------------------------------------------------------------------
  289. // Use of in-line for AVR to save flash.
  290. #ifdef __AVR__
  291. //------------------------------------------------------------------------------
  292. inline void SdSpi::begin() {
  293. #ifdef __AVR_ATmega328P__
  294. // Save a few bytes for 328 CPU - gcc optimizes single bit '|' to sbi.
  295. PORTB |= 1 << 2; // SS high
  296. DDRB |= 1 << 2; // SS output mode
  297. DDRB |= 1 << 3; // MOSI output mode
  298. DDRB |= 1 << 5; // SCK output mode
  299. #else // __AVR_ATmega328P__
  300. // set SS high - may be chip select for another SPI device
  301. digitalWrite(SS, HIGH);
  302. // SS must be in output mode even it is not chip select
  303. pinMode(SS, OUTPUT);
  304. pinMode(MOSI, OUTPUT);
  305. pinMode(SCK, OUTPUT);
  306. #endif // __AVR_ATmega328P__
  307. }
  308. //------------------------------------------------------------------------------
  309. inline void SdSpi::init(uint8_t divisor) {
  310. uint8_t b = 2;
  311. uint8_t r = 0;
  312. // See AVR processor documentation.
  313. for (; divisor > b && r < 7; b <<= 1, r += r < 5 ? 1 : 2) {}
  314. SPCR = (1 << SPE) | (1 << MSTR) | (r >> 1);
  315. SPSR = r & 1 ? 0 : 1 << SPI2X;
  316. }
  317. //------------------------------------------------------------------------------
  318. inline uint8_t SdSpi::receive() {
  319. SPDR = 0XFF;
  320. while (!(SPSR & (1 << SPIF))) {}
  321. return SPDR;
  322. }
  323. //------------------------------------------------------------------------------
  324. inline uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
  325. if (n-- == 0) {
  326. return 0;
  327. }
  328. SPDR = 0XFF;
  329. for (size_t i = 0; i < n; i++) {
  330. while (!(SPSR & (1 << SPIF))) {}
  331. uint8_t b = SPDR;
  332. SPDR = 0XFF;
  333. buf[i] = b;
  334. }
  335. while (!(SPSR & (1 << SPIF))) {}
  336. buf[n] = SPDR;
  337. return 0;
  338. }
  339. //------------------------------------------------------------------------------
  340. inline void SdSpi::send(uint8_t data) {
  341. SPDR = data;
  342. while (!(SPSR & (1 << SPIF))) {}
  343. }
  344. //------------------------------------------------------------------------------
  345. inline void SdSpi::send(const uint8_t* buf , size_t n) {
  346. if (n == 0) {
  347. return;
  348. }
  349. SPDR = buf[0];
  350. if (n > 1) {
  351. uint8_t b = buf[1];
  352. size_t i = 2;
  353. while (1) {
  354. while (!(SPSR & (1 << SPIF))) {}
  355. SPDR = b;
  356. if (i == n) {
  357. break;
  358. }
  359. b = buf[i++];
  360. }
  361. }
  362. while (!(SPSR & (1 << SPIF))) {}
  363. }
  364. #endif // __AVR__
  365. #endif // SdSpi_h