Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

183 lines
5.8KB

  1. /* Arduino SdSpi Library
  2. * Copyright (C) 2013 by William Greiman
  3. *
  4. * STM32F1 code for Maple and Maple Mini support, 2015 by Victor Perez
  5. *
  6. * This file is part of the Arduino SdSpi Library
  7. *
  8. * This Library is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This Library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with the Arduino SdSpi Library. If not, see
  20. * <http://www.gnu.org/licenses/>.
  21. */
  22. #if defined(__STM32F1__)
  23. #include "SdSpi.h"
  24. #include <libmaple/dma.h>
  25. /** Use STM32 DMAC if nonzero */
  26. #define USE_STM32F1_DMAC 1
  27. /** Time in ms for DMA receive timeout */
  28. #define STM32F1_DMA_TIMEOUT 100
  29. /** DMAC receive channel */
  30. #define SPI1_DMAC_RX_CH DMA_CH2
  31. /** DMAC transmit channel */
  32. #define SPI1_DMAC_TX_CH DMA_CH3
  33. volatile bool SPI_DMA_TX_Active = false;
  34. volatile bool SPI_DMA_RX_Active = false;
  35. /** ISR for DMA TX event. */
  36. inline void SPI_DMA_TX_Event() {
  37. SPI_DMA_TX_Active = false;
  38. dma_disable(DMA1, SPI_DMAC_TX_CH);
  39. }
  40. /** ISR for DMA RX event. */
  41. inline void SPI_DMA_RX_Event() {
  42. SPI_DMA_RX_Active = false;
  43. dma_disable(DMA1, SPI1_DMAC_RX_CH);
  44. }
  45. //------------------------------------------------------------------------------
  46. /** Disable DMA Channel. */
  47. static void dmac_channel_disable(dma_channel ul_num) {
  48. dma_disable(DMA1, ul_num);
  49. }
  50. /** Enable DMA Channel. */
  51. static void dmac_channel_enable(dma_channel ul_num) {
  52. dma_enable(DMA1, ul_num);
  53. }
  54. //------------------------------------------------------------------------------
  55. void SdSpi::begin(uint8_t chipSelectPin) {
  56. pinMode(chipSelectPin, OUTPUT);
  57. digitalWrite(chipSelectPin, HIGH);
  58. SPI.begin();
  59. }
  60. //------------------------------------------------------------------------------
  61. // start RX DMA
  62. static void spiDmaRX(uint8_t* dst, uint16_t count) {
  63. // spi_rx_dma_enable(SPI1);
  64. if (count < 1) return;
  65. dma_setup_transfer(DMA1, SPI1_DMAC_RX_CH, &SPI1->regs->DR, DMA_SIZE_8BITS,
  66. dst, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));
  67. dma_set_num_transfers(DMA1, SPI1_DMAC_RX_CH, count); // 2 bytes per pixel
  68. SPI_DMA_RX_Active = true;
  69. dma_enable(DMA1, SPI1_DMAC_RX_CH);
  70. }
  71. //------------------------------------------------------------------------------
  72. // start TX DMA
  73. static void spiDmaTX(const uint8_t* src, uint16_t count) {
  74. if (count < 1) return;
  75. static uint8_t ff = 0XFF;
  76. if (!src) {
  77. src = &ff;
  78. dma_setup_transfer(DMA1, SPI1_DMAC_TX_CH, &SPI1->regs->DR, DMA_SIZE_8BITS,
  79. const_cast<uint8_t*>(src), DMA_SIZE_8BITS,
  80. (DMA_FROM_MEM | DMA_TRNS_CMPLT));
  81. } else {
  82. dma_setup_transfer(DMA1, SPI1_DMAC_TX_CH, &SPI1->regs->DR, DMA_SIZE_8BITS,
  83. const_cast<uint8_t*>(src), DMA_SIZE_8BITS,
  84. (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));
  85. }
  86. dma_set_num_transfers(DMA1, SPI1_DMAC_TX_CH, count); // 2 bytes per pixel
  87. SPI_DMA_TX_Active = true;
  88. dma_enable(DMA1, SPI1_DMAC_TX_CH);
  89. }
  90. //------------------------------------------------------------------------------
  91. // initialize SPI controller STM32F1
  92. void SdSpi::beginTransaction(uint8_t sckDivisor) {
  93. #if ENABLE_SPI_TRANSACTIONS
  94. SPI.beginTransaction(SPISettings());
  95. #endif // ENABLE_SPI_TRANSACTIONS
  96. if (sckDivisor < SPI_CLOCK_DIV2 || sckDivisor > SPI_CLOCK_DIV256) {
  97. sckDivisor = SPI_CLOCK_DIV2; // may not be needed, testing.
  98. }
  99. SPI.setClockDivider(sckDivisor);
  100. SPI.setBitOrder(MSBFIRST);
  101. SPI.setDataMode(SPI_MODE0);
  102. #if USE_STM32F1_DMAC
  103. dma_init(DMA1);
  104. dma_attach_interrupt(DMA1, SPI1_DMAC_TX_CH, SPI_DMA_TX_Event);
  105. dma_attach_interrupt(DMA1, SPI1_DMAC_RX_CH, SPI_DMA_RX_Event);
  106. spi_tx_dma_enable(SPI1);
  107. spi_rx_dma_enable(SPI1);
  108. #endif // USE_STM32F1_DMAC
  109. }
  110. //------------------------------------------------------------------------------
  111. void SdSpi::endTransaction() {
  112. #if ENABLE_SPI_TRANSACTIONS
  113. SPI.endTransaction();
  114. #endif // ENABLE_SPI_TRANSACTIONS
  115. }
  116. //------------------------------------------------------------------------------
  117. // STM32
  118. static inline uint8_t spiTransfer(uint8_t b) {
  119. return SPI.transfer(b);
  120. }
  121. //------------------------------------------------------------------------------
  122. // should be valid for STM32
  123. /** SPI receive a byte */
  124. uint8_t SdSpi::receive() {
  125. return spiTransfer(0xFF);
  126. }
  127. //------------------------------------------------------------------------------
  128. /** SPI receive multiple bytes */
  129. // check and finish.
  130. uint8_t SdSpi::receive(uint8_t* buf, size_t n) {
  131. int rtn = 0;
  132. #if USE_STM32F1_DMAC
  133. spiDmaRX(buf, n);
  134. spiDmaTX(0, n);
  135. uint32_t m = millis();
  136. while (SPI_DMA_RX_Active) {
  137. if ((millis() - m) > STM32F1_DMA_TIMEOUT) {
  138. dmac_channel_disable(SPI_DMAC_RX_CH);
  139. dmac_channel_disable(SPI_DMAC_TX_CH);
  140. rtn = 2;
  141. break;
  142. }
  143. }
  144. #else // USE_STM32F1_DMAC
  145. for (size_t i = 0; i < n; i++) {
  146. buf[i] = SPI.transfer(0xFF);
  147. }
  148. #endif // USE_STM32F1_DMAC
  149. return rtn;
  150. }
  151. //------------------------------------------------------------------------------
  152. /** SPI send a byte */
  153. void SdSpi::send(uint8_t b) {
  154. spiTransfer(b);
  155. }
  156. //------------------------------------------------------------------------------
  157. void SdSpi::send(const uint8_t* buf , size_t n) {
  158. #if USE_STM32F1_DMAC
  159. spiDmaTX(buf, n);
  160. while (SPI_DMA_TX_Active) {}
  161. #else // #if USE_STM32F1_DMAC
  162. SPI.write(buf, n);
  163. #endif // #if USE_STM32F1_DMAC
  164. // leave RX register empty
  165. // while (spi_is_rx_nonempty(SPI1))
  166. uint8_t b = spi_rx_reg(SPI1);
  167. }
  168. #endif // USE_NATIVE_STM32F1_SPI