Teensy 4.1 core updated for C++20
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.

199 lines
4.5KB

  1. #include "DMAChannel.h"
  2. #if DMA_NUM_CHANNELS > 16
  3. #undef DMA_NUM_CHANNELS
  4. #define DMA_NUM_CHANNELS 16
  5. #endif
  6. // The channel allocation bitmask is accessible from "C" namespace,
  7. // so C-only code can reserve DMA channels
  8. uint16_t dma_channel_allocated_mask = 0;
  9. /****************************************************************/
  10. /** Teensy 3.0 & 3.1 **/
  11. /****************************************************************/
  12. #if defined(KINETISK)
  13. void DMAChannel::begin(bool force_initialization)
  14. {
  15. uint32_t ch = 0;
  16. __disable_irq();
  17. if (!force_initialization && TCD && channel < DMA_NUM_CHANNELS
  18. && (dma_channel_allocated_mask & (1 << channel))
  19. && (uint32_t)TCD == (uint32_t)(0x40009000 + channel * 32)) {
  20. // DMA channel already allocated
  21. __enable_irq();
  22. return;
  23. }
  24. while (1) {
  25. if (!(dma_channel_allocated_mask & (1 << ch))) {
  26. dma_channel_allocated_mask |= (1 << ch);
  27. __enable_irq();
  28. break;
  29. }
  30. if (++ch >= DMA_NUM_CHANNELS) {
  31. __enable_irq();
  32. TCD = (TCD_t *)0;
  33. channel = DMA_NUM_CHANNELS;
  34. return; // no more channels available
  35. // attempts to use this object will hardfault
  36. }
  37. }
  38. channel = ch;
  39. SIM_SCGC7 |= SIM_SCGC7_DMA;
  40. SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
  41. DMA_CR = DMA_CR_EMLM | DMA_CR_EDBG ; // minor loop mapping is available
  42. DMA_CERQ = ch;
  43. DMA_CERR = ch;
  44. DMA_CEEI = ch;
  45. DMA_CINT = ch;
  46. TCD = (TCD_t *)(0x40009000 + ch * 32);
  47. uint32_t *p = (uint32_t *)TCD;
  48. *p++ = 0;
  49. *p++ = 0;
  50. *p++ = 0;
  51. *p++ = 0;
  52. *p++ = 0;
  53. *p++ = 0;
  54. *p++ = 0;
  55. *p++ = 0;
  56. }
  57. void DMAChannel::release(void)
  58. {
  59. if (channel >= DMA_NUM_CHANNELS) return;
  60. DMA_CERQ = channel;
  61. __disable_irq();
  62. dma_channel_allocated_mask &= ~(1 << channel);
  63. __enable_irq();
  64. channel = DMA_NUM_CHANNELS;
  65. TCD = (TCD_t *)0;
  66. }
  67. static uint32_t priority(const DMAChannel &c)
  68. {
  69. uint32_t n;
  70. n = *(uint32_t *)((uint32_t)&DMA_DCHPRI3 + (c.channel & 0xFC));
  71. n = __builtin_bswap32(n);
  72. return (n >> ((c.channel & 0x03) << 3)) & 0x0F;
  73. }
  74. static void swap(DMAChannel &c1, DMAChannel &c2)
  75. {
  76. uint8_t c;
  77. DMABaseClass::TCD_t *t;
  78. c = c1.channel;
  79. c1.channel = c2.channel;
  80. c2.channel = c;
  81. t = c1.TCD;
  82. c1.TCD = c2.TCD;
  83. c2.TCD = t;
  84. }
  85. /****************************************************************/
  86. /** Teensy-LC **/
  87. /****************************************************************/
  88. #elif defined(KINETISL)
  89. void DMAChannel::begin(bool force_initialization)
  90. {
  91. uint32_t ch = 0;
  92. __disable_irq();
  93. if (!force_initialization && CFG && channel < DMA_NUM_CHANNELS
  94. && (dma_channel_allocated_mask & (1 << channel))
  95. && (uint32_t)CFG == (uint32_t)(0x40008100 + channel * 16)) {
  96. // DMA channel already allocated
  97. __enable_irq();
  98. return;
  99. }
  100. while (1) {
  101. if (!(dma_channel_allocated_mask & (1 << ch))) {
  102. dma_channel_allocated_mask |= (1 << ch);
  103. __enable_irq();
  104. break;
  105. }
  106. if (++ch >= DMA_NUM_CHANNELS) {
  107. __enable_irq();
  108. CFG = (CFG_t *)0;
  109. channel = DMA_NUM_CHANNELS;
  110. return; // no more channels available
  111. // attempts to use this object will hardfault
  112. }
  113. }
  114. channel = ch;
  115. SIM_SCGC7 |= SIM_SCGC7_DMA;
  116. SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
  117. CFG = (CFG_t *)(0x40008100 + ch * 16);
  118. CFG->DSR_BCR = DMA_DSR_BCR_DONE;
  119. CFG->DCR = DMA_DCR_CS;
  120. CFG->SAR = NULL;
  121. CFG->DAR = NULL;
  122. }
  123. void DMAChannel::release(void)
  124. {
  125. if (channel >= DMA_NUM_CHANNELS) return;
  126. CFG->DSR_BCR = DMA_DSR_BCR_DONE;
  127. __disable_irq();
  128. dma_channel_allocated_mask &= ~(1 << channel);
  129. __enable_irq();
  130. channel = 16;
  131. CFG = (CFG_t *)0;
  132. }
  133. static uint32_t priority(const DMAChannel &c)
  134. {
  135. return 3 - c.channel;
  136. }
  137. static void swap(DMAChannel &c1, DMAChannel &c2)
  138. {
  139. uint8_t c;
  140. DMABaseClass::CFG_t *t;
  141. c = c1.channel;
  142. c1.channel = c2.channel;
  143. c2.channel = c;
  144. t = c1.CFG;
  145. c1.CFG = c2.CFG;
  146. c2.CFG = t;
  147. }
  148. #endif
  149. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2)
  150. {
  151. if (priority(ch1) < priority(ch2)) swap(ch1, ch2);
  152. }
  153. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3)
  154. {
  155. if (priority(ch2) < priority(ch3)) swap(ch2, ch3);
  156. if (priority(ch1) < priority(ch2)) swap(ch1, ch2);
  157. if (priority(ch2) < priority(ch3)) swap(ch2, ch3);
  158. }
  159. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4)
  160. {
  161. if (priority(ch3) < priority(ch4)) swap(ch3, ch4);
  162. if (priority(ch2) < priority(ch3)) swap(ch2, ch3);
  163. if (priority(ch1) < priority(ch2)) swap(ch1, ch2);
  164. if (priority(ch3) < priority(ch4)) swap(ch2, ch3);
  165. if (priority(ch2) < priority(ch3)) swap(ch1, ch2);
  166. if (priority(ch3) < priority(ch4)) swap(ch2, ch3);
  167. }