234 lines
6.0KB

  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2017 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. #include "DMAChannel.h"
  31. #if DMA_NUM_CHANNELS <= 16
  32. #define DMA_MAX_CHANNELS DMA_NUM_CHANNELS
  33. #else
  34. #define DMA_MAX_CHANNELS 16
  35. #endif
  36. // The channel allocation bitmask is accessible from "C" namespace,
  37. // so C-only code can reserve DMA channels
  38. uint16_t dma_channel_allocated_mask = 0;
  39. /****************************************************************/
  40. /** Teensy 3.0 & 3.1 **/
  41. /****************************************************************/
  42. #if defined(KINETISK)
  43. void DMAChannel::begin(bool force_initialization)
  44. {
  45. uint32_t ch = 0;
  46. __disable_irq();
  47. if (!force_initialization && TCD && channel < DMA_MAX_CHANNELS
  48. && (dma_channel_allocated_mask & (1 << channel))
  49. && (uint32_t)TCD == (uint32_t)(0x40009000 + channel * 32)) {
  50. // DMA channel already allocated
  51. __enable_irq();
  52. return;
  53. }
  54. while (1) {
  55. if (!(dma_channel_allocated_mask & (1 << ch))) {
  56. dma_channel_allocated_mask |= (1 << ch);
  57. __enable_irq();
  58. break;
  59. }
  60. if (++ch >= DMA_MAX_CHANNELS) {
  61. __enable_irq();
  62. TCD = (TCD_t *)0;
  63. channel = DMA_MAX_CHANNELS;
  64. return; // no more channels available
  65. // attempts to use this object will hardfault
  66. }
  67. }
  68. channel = ch;
  69. SIM_SCGC7 |= SIM_SCGC7_DMA;
  70. SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
  71. #if DMA_NUM_CHANNELS <= 16
  72. DMA_CR = DMA_CR_EMLM | DMA_CR_EDBG; // minor loop mapping is available
  73. #else
  74. DMA_CR = DMA_CR_GRP1PRI| DMA_CR_EMLM | DMA_CR_EDBG;
  75. #endif
  76. DMA_CERQ = ch;
  77. DMA_CERR = ch;
  78. DMA_CEEI = ch;
  79. DMA_CINT = ch;
  80. TCD = (TCD_t *)(0x40009000 + ch * 32);
  81. uint32_t *p = (uint32_t *)TCD;
  82. *p++ = 0;
  83. *p++ = 0;
  84. *p++ = 0;
  85. *p++ = 0;
  86. *p++ = 0;
  87. *p++ = 0;
  88. *p++ = 0;
  89. *p++ = 0;
  90. }
  91. void DMAChannel::release(void)
  92. {
  93. if (channel >= DMA_MAX_CHANNELS) return;
  94. DMA_CERQ = channel;
  95. __disable_irq();
  96. dma_channel_allocated_mask &= ~(1 << channel);
  97. __enable_irq();
  98. channel = DMA_MAX_CHANNELS;
  99. TCD = (TCD_t *)0;
  100. }
  101. static uint32_t priority(const DMAChannel &c)
  102. {
  103. uint32_t n;
  104. n = *(uint32_t *)((uint32_t)&DMA_DCHPRI3 + (c.channel & 0xFC));
  105. n = __builtin_bswap32(n);
  106. return (n >> ((c.channel & 0x03) << 3)) & 0x0F;
  107. }
  108. static void swap(DMAChannel &c1, DMAChannel &c2)
  109. {
  110. uint8_t c;
  111. DMABaseClass::TCD_t *t;
  112. c = c1.channel;
  113. c1.channel = c2.channel;
  114. c2.channel = c;
  115. t = c1.TCD;
  116. c1.TCD = c2.TCD;
  117. c2.TCD = t;
  118. }
  119. /****************************************************************/
  120. /** Teensy-LC **/
  121. /****************************************************************/
  122. #elif defined(KINETISL)
  123. void DMAChannel::begin(bool force_initialization)
  124. {
  125. uint32_t ch = 0;
  126. __disable_irq();
  127. if (!force_initialization && CFG && channel < DMA_MAX_CHANNELS
  128. && (dma_channel_allocated_mask & (1 << channel))
  129. && (uint32_t)CFG == (uint32_t)(0x40008100 + channel * 16)) {
  130. // DMA channel already allocated
  131. __enable_irq();
  132. return;
  133. }
  134. while (1) {
  135. if (!(dma_channel_allocated_mask & (1 << ch))) {
  136. dma_channel_allocated_mask |= (1 << ch);
  137. __enable_irq();
  138. break;
  139. }
  140. if (++ch >= DMA_MAX_CHANNELS) {
  141. __enable_irq();
  142. CFG = (CFG_t *)0;
  143. channel = DMA_MAX_CHANNELS;
  144. return; // no more channels available
  145. // attempts to use this object will hardfault
  146. }
  147. }
  148. channel = ch;
  149. SIM_SCGC7 |= SIM_SCGC7_DMA;
  150. SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
  151. CFG = (CFG_t *)(0x40008100 + ch * 16);
  152. CFG->DSR_BCR = DMA_DSR_BCR_DONE;
  153. CFG->DCR = DMA_DCR_CS;
  154. CFG->SAR = NULL;
  155. CFG->DAR = NULL;
  156. }
  157. void DMAChannel::release(void)
  158. {
  159. if (channel >= DMA_MAX_CHANNELS) return;
  160. CFG->DSR_BCR = DMA_DSR_BCR_DONE;
  161. __disable_irq();
  162. dma_channel_allocated_mask &= ~(1 << channel);
  163. __enable_irq();
  164. channel = 16;
  165. CFG = (CFG_t *)0;
  166. }
  167. static uint32_t priority(const DMAChannel &c)
  168. {
  169. return 3 - c.channel;
  170. }
  171. static void swap(DMAChannel &c1, DMAChannel &c2)
  172. {
  173. uint8_t c;
  174. DMABaseClass::CFG_t *t;
  175. c = c1.channel;
  176. c1.channel = c2.channel;
  177. c2.channel = c;
  178. t = c1.CFG;
  179. c1.CFG = c2.CFG;
  180. c2.CFG = t;
  181. }
  182. #endif
  183. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2)
  184. {
  185. if (priority(ch1) < priority(ch2)) swap(ch1, ch2);
  186. }
  187. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3)
  188. {
  189. if (priority(ch2) < priority(ch3)) swap(ch2, ch3);
  190. if (priority(ch1) < priority(ch2)) swap(ch1, ch2);
  191. if (priority(ch2) < priority(ch3)) swap(ch2, ch3);
  192. }
  193. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4)
  194. {
  195. if (priority(ch3) < priority(ch4)) swap(ch3, ch4);
  196. if (priority(ch2) < priority(ch3)) swap(ch2, ch3);
  197. if (priority(ch1) < priority(ch2)) swap(ch1, ch2);
  198. if (priority(ch3) < priority(ch4)) swap(ch2, ch3);
  199. if (priority(ch2) < priority(ch3)) swap(ch1, ch2);
  200. if (priority(ch3) < priority(ch4)) swap(ch2, ch3);
  201. }