SdSpiDue.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /**
  2. * Copyright (c) 2011-2021 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #include "SdSpiDriver.h"
  26. #if defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_SAM_DUE)
  27. /* Use SAM3X DMAC if nonzero */
  28. #define USE_SAM3X_DMAC 1
  29. /* Use extra Bus Matrix arbitration fix if nonzero */
  30. #define USE_SAM3X_BUS_MATRIX_FIX 1
  31. /* Time in ms for DMA receive timeout */
  32. #define SAM3X_DMA_TIMEOUT 100
  33. /* chip select register number */
  34. #define SPI_CHIP_SEL 3
  35. /* DMAC receive channel */
  36. #define SPI_DMAC_RX_CH 1
  37. /* DMAC transmit channel */
  38. #define SPI_DMAC_TX_CH 0
  39. /* DMAC Channel HW Interface Number for SPI TX. */
  40. #define SPI_TX_IDX 1
  41. /* DMAC Channel HW Interface Number for SPI RX. */
  42. #define SPI_RX_IDX 2
  43. //------------------------------------------------------------------------------
  44. /* Disable DMA Controller. */
  45. static void dmac_disable() {
  46. DMAC->DMAC_EN &= (~DMAC_EN_ENABLE);
  47. }
  48. /* Enable DMA Controller. */
  49. static void dmac_enable() {
  50. DMAC->DMAC_EN = DMAC_EN_ENABLE;
  51. }
  52. /* Disable DMA Channel. */
  53. static void dmac_channel_disable(uint32_t ul_num) {
  54. DMAC->DMAC_CHDR = DMAC_CHDR_DIS0 << ul_num;
  55. }
  56. /* Enable DMA Channel. */
  57. static void dmac_channel_enable(uint32_t ul_num) {
  58. DMAC->DMAC_CHER = DMAC_CHER_ENA0 << ul_num;
  59. }
  60. /* Poll for transfer complete. */
  61. static bool dmac_channel_transfer_done(uint32_t ul_num) {
  62. return (DMAC->DMAC_CHSR & (DMAC_CHSR_ENA0 << ul_num)) ? false : true;
  63. }
  64. //------------------------------------------------------------------------------
  65. // start RX DMA
  66. static void spiDmaRX(uint8_t* dst, uint16_t count) {
  67. dmac_channel_disable(SPI_DMAC_RX_CH);
  68. DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_SADDR = (uint32_t)&SPI0->SPI_RDR;
  69. DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
  70. DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
  71. DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
  72. DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
  73. DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
  74. DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
  75. DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
  76. DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
  77. DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
  78. dmac_channel_enable(SPI_DMAC_RX_CH);
  79. }
  80. //------------------------------------------------------------------------------
  81. // start TX DMA
  82. static void spiDmaTX(const uint8_t* src, uint16_t count) {
  83. static uint8_t ff = 0XFF;
  84. uint32_t src_incr = DMAC_CTRLB_SRC_INCR_INCREMENTING;
  85. if (!src) {
  86. src = &ff;
  87. src_incr = DMAC_CTRLB_SRC_INCR_FIXED;
  88. }
  89. dmac_channel_disable(SPI_DMAC_TX_CH);
  90. DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_SADDR = (uint32_t)src;
  91. DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
  92. DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
  93. DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
  94. DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
  95. DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
  96. DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
  97. src_incr | DMAC_CTRLB_DST_INCR_FIXED;
  98. DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
  99. DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
  100. dmac_channel_enable(SPI_DMAC_TX_CH);
  101. }
  102. //------------------------------------------------------------------------------
  103. // initialize SPI controller
  104. void SdSpiArduinoDriver::activate() {
  105. SPI.beginTransaction(m_spiSettings);
  106. Spi* pSpi = SPI0;
  107. // Save the divisor
  108. uint32_t scbr = pSpi->SPI_CSR[SPI_CHIP_SEL] & 0XFF00;
  109. // Disable SPI
  110. pSpi->SPI_CR = SPI_CR_SPIDIS;
  111. // reset SPI
  112. pSpi->SPI_CR = SPI_CR_SWRST;
  113. // no mode fault detection, set master mode
  114. pSpi->SPI_MR = SPI_PCS(SPI_CHIP_SEL) | SPI_MR_MODFDIS | SPI_MR_MSTR;
  115. // mode 0, 8-bit,
  116. pSpi->SPI_CSR[SPI_CHIP_SEL] = scbr | SPI_CSR_CSAAT | SPI_CSR_NCPHA;
  117. // enable SPI
  118. pSpi->SPI_CR |= SPI_CR_SPIEN;
  119. }
  120. //------------------------------------------------------------------------------
  121. void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
  122. (void)spiConfig;
  123. SPI.begin();
  124. #if USE_SAM3X_DMAC
  125. pmc_enable_periph_clk(ID_DMAC);
  126. dmac_disable();
  127. DMAC->DMAC_GCFG = DMAC_GCFG_ARB_CFG_FIXED;
  128. dmac_enable();
  129. #if USE_SAM3X_BUS_MATRIX_FIX
  130. MATRIX->MATRIX_WPMR = 0x4d415400;
  131. MATRIX->MATRIX_MCFG[1] = 1;
  132. MATRIX->MATRIX_MCFG[2] = 1;
  133. MATRIX->MATRIX_SCFG[0] = 0x01000010;
  134. MATRIX->MATRIX_SCFG[1] = 0x01000010;
  135. MATRIX->MATRIX_SCFG[7] = 0x01000010;
  136. #endif // USE_SAM3X_BUS_MATRIX_FIX
  137. #endif // USE_SAM3X_DMAC
  138. }
  139. //------------------------------------------------------------------------------
  140. void SdSpiArduinoDriver::deactivate() {
  141. SPI.endTransaction();
  142. }
  143. //------------------------------------------------------------------------------
  144. void SdSpiArduinoDriver::end() {
  145. SPI.end();
  146. }
  147. //------------------------------------------------------------------------------
  148. static inline uint8_t spiTransfer(uint8_t b) {
  149. Spi* pSpi = SPI0;
  150. pSpi->SPI_TDR = b;
  151. while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
  152. b = pSpi->SPI_RDR;
  153. return b;
  154. }
  155. //------------------------------------------------------------------------------
  156. uint8_t SdSpiArduinoDriver::receive() {
  157. return spiTransfer(0XFF);
  158. }
  159. //------------------------------------------------------------------------------
  160. uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
  161. Spi* pSpi = SPI0;
  162. int rtn = 0;
  163. #if USE_SAM3X_DMAC
  164. // clear overrun error
  165. while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {pSpi->SPI_RDR;}
  166. spiDmaRX(buf, count);
  167. spiDmaTX(0, count);
  168. uint32_t m = millis();
  169. while (!dmac_channel_transfer_done(SPI_DMAC_RX_CH)) {
  170. if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
  171. dmac_channel_disable(SPI_DMAC_RX_CH);
  172. dmac_channel_disable(SPI_DMAC_TX_CH);
  173. rtn = 2;
  174. break;
  175. }
  176. }
  177. if (pSpi->SPI_SR & SPI_SR_OVRES) {
  178. rtn |= 1;
  179. }
  180. #else // USE_SAM3X_DMAC
  181. for (size_t i = 0; i < count; i++) {
  182. pSpi->SPI_TDR = 0XFF;
  183. while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
  184. buf[i] = pSpi->SPI_RDR;
  185. }
  186. #endif // USE_SAM3X_DMAC
  187. return rtn;
  188. }
  189. //------------------------------------------------------------------------------
  190. void SdSpiArduinoDriver::send(uint8_t data) {
  191. spiTransfer(data);
  192. }
  193. //------------------------------------------------------------------------------
  194. void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
  195. Spi* pSpi = SPI0;
  196. #if USE_SAM3X_DMAC
  197. spiDmaTX(buf, count);
  198. while (!dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {}
  199. #else // #if USE_SAM3X_DMAC
  200. while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
  201. for (size_t i = 0; i < count; i++) {
  202. pSpi->SPI_TDR = buf[i];
  203. while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {}
  204. }
  205. #endif // #if USE_SAM3X_DMAC
  206. while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
  207. // leave RDR empty
  208. while (pSpi->SPI_SR & (SPI_SR_OVRES | SPI_SR_RDRF)) {pSpi->SPI_RDR;}
  209. }
  210. #endif // defined(SD_USE_CUSTOM_SPI) && defined(ARDUINO_SAM_DUE)