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.

1071 line
33KB

  1. #ifndef DMAChannel_h_
  2. #define DMAChannel_h_
  3. #include "kinetis.h"
  4. // Discussion about DMAChannel is here:
  5. // http://forum.pjrc.com/threads/25778-Could-there-be-something-like-an-ISR-template-function/page3
  6. #define DMACHANNEL_HAS_BEGIN
  7. #define DMACHANNEL_HAS_BOOLEAN_CTOR
  8. // The channel allocation bitmask is accessible from "C" namespace,
  9. // so C-only code can reserve DMA channels
  10. #ifdef __cplusplus
  11. extern "C" {
  12. #endif
  13. extern uint16_t dma_channel_allocated_mask;
  14. #ifdef __cplusplus
  15. }
  16. #endif
  17. #ifdef __cplusplus
  18. // known libraries with DMA usage (in need of porting to this new scheme):
  19. //
  20. // https://github.com/PaulStoffregen/Audio
  21. // https://github.com/PaulStoffregen/OctoWS2811
  22. // https://github.com/pedvide/ADC
  23. // https://github.com/duff2013/SerialEvent
  24. // https://github.com/pixelmatix/SmartMatrix
  25. // https://github.com/crteensy/DmaSpi <-- DmaSpi has adopted this scheme
  26. /****************************************************************/
  27. /** Teensy 3.0 & 3.1 **/
  28. /****************************************************************/
  29. #if defined(KINETISK)
  30. class DMABaseClass {
  31. public:
  32. typedef struct __attribute__((packed)) {
  33. volatile const void * volatile SADDR;
  34. int16_t SOFF;
  35. union { uint16_t ATTR;
  36. struct { uint8_t ATTR_DST; uint8_t ATTR_SRC; }; };
  37. union { uint32_t NBYTES; uint32_t NBYTES_MLNO;
  38. uint32_t NBYTES_MLOFFNO; uint32_t NBYTES_MLOFFYES; };
  39. int32_t SLAST;
  40. volatile void * volatile DADDR;
  41. int16_t DOFF;
  42. union { volatile uint16_t CITER;
  43. volatile uint16_t CITER_ELINKYES; volatile uint16_t CITER_ELINKNO; };
  44. int32_t DLASTSGA;
  45. volatile uint16_t CSR;
  46. union { volatile uint16_t BITER;
  47. volatile uint16_t BITER_ELINKYES; volatile uint16_t BITER_ELINKNO; };
  48. } TCD_t;
  49. TCD_t *TCD;
  50. /***************************************/
  51. /** Data Transfer **/
  52. /***************************************/
  53. // Use a single variable as the data source. Typically a register
  54. // for receiving data from one of the hardware peripherals is used.
  55. void source(volatile const signed char &p) { source(*(volatile const uint8_t *)&p); }
  56. void source(volatile const unsigned char &p) {
  57. TCD->SADDR = &p;
  58. TCD->SOFF = 0;
  59. TCD->ATTR_SRC = 0;
  60. if ((uint32_t)&p < 0x40000000 || TCD->NBYTES == 0) TCD->NBYTES = 1;
  61. TCD->SLAST = 0;
  62. }
  63. void source(volatile const signed short &p) { source(*(volatile const uint16_t *)&p); }
  64. void source(volatile const unsigned short &p) {
  65. TCD->SADDR = &p;
  66. TCD->SOFF = 0;
  67. TCD->ATTR_SRC = 1;
  68. if ((uint32_t)&p < 0x40000000 || TCD->NBYTES == 0) TCD->NBYTES = 2;
  69. TCD->SLAST = 0;
  70. }
  71. void source(volatile const signed int &p) { source(*(volatile const uint32_t *)&p); }
  72. void source(volatile const unsigned int &p) { source(*(volatile const uint32_t *)&p); }
  73. void source(volatile const signed long &p) { source(*(volatile const uint32_t *)&p); }
  74. void source(volatile const unsigned long &p) {
  75. TCD->SADDR = &p;
  76. TCD->SOFF = 0;
  77. TCD->ATTR_SRC = 2;
  78. if ((uint32_t)&p < 0x40000000 || TCD->NBYTES == 0) TCD->NBYTES = 4;
  79. TCD->SLAST = 0;
  80. }
  81. // Use a buffer (array of data) as the data source. Typically a
  82. // buffer for transmitting data is used.
  83. void sourceBuffer(volatile const signed char p[], unsigned int len) {
  84. sourceBuffer((volatile const uint8_t *)p, len); }
  85. void sourceBuffer(volatile const unsigned char p[], unsigned int len) {
  86. TCD->SADDR = p;
  87. TCD->SOFF = 1;
  88. TCD->ATTR_SRC = 0;
  89. TCD->NBYTES = 1;
  90. TCD->SLAST = -len;
  91. TCD->BITER = len;
  92. TCD->CITER = len;
  93. }
  94. void sourceBuffer(volatile const signed short p[], unsigned int len) {
  95. sourceBuffer((volatile const uint16_t *)p, len); }
  96. void sourceBuffer(volatile const unsigned short p[], unsigned int len) {
  97. TCD->SADDR = p;
  98. TCD->SOFF = 2;
  99. TCD->ATTR_SRC = 1;
  100. TCD->NBYTES = 2;
  101. TCD->SLAST = -len;
  102. TCD->BITER = len / 2;
  103. TCD->CITER = len / 2;
  104. }
  105. void sourceBuffer(volatile const signed int p[], unsigned int len) {
  106. sourceBuffer((volatile const uint32_t *)p, len); }
  107. void sourceBuffer(volatile const unsigned int p[], unsigned int len) {
  108. sourceBuffer((volatile const uint32_t *)p, len); }
  109. void sourceBuffer(volatile const signed long p[], unsigned int len) {
  110. sourceBuffer((volatile const uint32_t *)p, len); }
  111. void sourceBuffer(volatile const unsigned long p[], unsigned int len) {
  112. TCD->SADDR = p;
  113. TCD->SOFF = 4;
  114. TCD->ATTR_SRC = 2;
  115. TCD->NBYTES = 4;
  116. TCD->SLAST = -len;
  117. TCD->BITER = len / 4;
  118. TCD->CITER = len / 4;
  119. }
  120. // Use a circular buffer as the data source
  121. void sourceCircular(volatile const signed char p[], unsigned int len) {
  122. sourceCircular((volatile const uint8_t *)p, len); }
  123. void sourceCircular(volatile const unsigned char p[], unsigned int len) {
  124. TCD->SADDR = p;
  125. TCD->SOFF = 1;
  126. TCD->ATTR_SRC = ((31 - __builtin_clz(len)) << 3);
  127. TCD->NBYTES = 1;
  128. TCD->SLAST = 0;
  129. TCD->BITER = len;
  130. TCD->CITER = len;
  131. }
  132. void sourceCircular(volatile const signed short p[], unsigned int len) {
  133. sourceCircular((volatile const uint16_t *)p, len); }
  134. void sourceCircular(volatile const unsigned short p[], unsigned int len) {
  135. TCD->SADDR = p;
  136. TCD->SOFF = 2;
  137. TCD->ATTR_SRC = ((31 - __builtin_clz(len)) << 3) | 1;
  138. TCD->NBYTES = 2;
  139. TCD->SLAST = 0;
  140. TCD->BITER = len / 2;
  141. TCD->CITER = len / 2;
  142. }
  143. void sourceCircular(volatile const signed int p[], unsigned int len) {
  144. sourceCircular((volatile const uint32_t *)p, len); }
  145. void sourceCircular(volatile const unsigned int p[], unsigned int len) {
  146. sourceCircular((volatile const uint32_t *)p, len); }
  147. void sourceCircular(volatile const signed long p[], unsigned int len) {
  148. sourceCircular((volatile const uint32_t *)p, len); }
  149. void sourceCircular(volatile const unsigned long p[], unsigned int len) {
  150. TCD->SADDR = p;
  151. TCD->SOFF = 4;
  152. TCD->ATTR_SRC = ((31 - __builtin_clz(len)) << 3) | 2;
  153. TCD->NBYTES = 4;
  154. TCD->SLAST = 0;
  155. TCD->BITER = len / 4;
  156. TCD->CITER = len / 4;
  157. }
  158. // Use a single variable as the data destination. Typically a register
  159. // for transmitting data to one of the hardware peripherals is used.
  160. void destination(volatile signed char &p) { destination(*(volatile uint8_t *)&p); }
  161. void destination(volatile unsigned char &p) {
  162. TCD->DADDR = &p;
  163. TCD->DOFF = 0;
  164. TCD->ATTR_DST = 0;
  165. if ((uint32_t)&p < 0x40000000 || TCD->NBYTES == 0) TCD->NBYTES = 1;
  166. TCD->DLASTSGA = 0;
  167. }
  168. void destination(volatile signed short &p) { destination(*(volatile uint16_t *)&p); }
  169. void destination(volatile unsigned short &p) {
  170. TCD->DADDR = &p;
  171. TCD->DOFF = 0;
  172. TCD->ATTR_DST = 1;
  173. if ((uint32_t)&p < 0x40000000 || TCD->NBYTES == 0) TCD->NBYTES = 2;
  174. TCD->DLASTSGA = 0;
  175. }
  176. void destination(volatile signed int &p) { destination(*(volatile uint32_t *)&p); }
  177. void destination(volatile unsigned int &p) { destination(*(volatile uint32_t *)&p); }
  178. void destination(volatile signed long &p) { destination(*(volatile uint32_t *)&p); }
  179. void destination(volatile unsigned long &p) {
  180. TCD->DADDR = &p;
  181. TCD->DOFF = 0;
  182. TCD->ATTR_DST = 2;
  183. if ((uint32_t)&p < 0x40000000 || TCD->NBYTES == 0) TCD->NBYTES = 4;
  184. TCD->DLASTSGA = 0;
  185. }
  186. // Use a buffer (array of data) as the data destination. Typically a
  187. // buffer for receiving data is used.
  188. void destinationBuffer(volatile signed char p[], unsigned int len) {
  189. destinationBuffer((volatile uint8_t *)p, len); }
  190. void destinationBuffer(volatile unsigned char p[], unsigned int len) {
  191. TCD->DADDR = p;
  192. TCD->DOFF = 1;
  193. TCD->ATTR_DST = 0;
  194. TCD->NBYTES = 1;
  195. TCD->DLASTSGA = -len;
  196. TCD->BITER = len;
  197. TCD->CITER = len;
  198. }
  199. void destinationBuffer(volatile signed short p[], unsigned int len) {
  200. destinationBuffer((volatile uint16_t *)p, len); }
  201. void destinationBuffer(volatile unsigned short p[], unsigned int len) {
  202. TCD->DADDR = p;
  203. TCD->DOFF = 2;
  204. TCD->ATTR_DST = 1;
  205. TCD->NBYTES = 2;
  206. TCD->DLASTSGA = -len;
  207. TCD->BITER = len / 2;
  208. TCD->CITER = len / 2;
  209. }
  210. void destinationBuffer(volatile signed int p[], unsigned int len) {
  211. destinationBuffer((volatile uint32_t *)p, len); }
  212. void destinationBuffer(volatile unsigned int p[], unsigned int len) {
  213. destinationBuffer((volatile uint32_t *)p, len); }
  214. void destinationBuffer(volatile signed long p[], unsigned int len) {
  215. destinationBuffer((volatile uint32_t *)p, len); }
  216. void destinationBuffer(volatile unsigned long p[], unsigned int len) {
  217. TCD->DADDR = p;
  218. TCD->DOFF = 4;
  219. TCD->ATTR_DST = 2;
  220. TCD->NBYTES = 4;
  221. TCD->DLASTSGA = -len;
  222. TCD->BITER = len / 4;
  223. TCD->CITER = len / 4;
  224. }
  225. // Use a circular buffer as the data destination
  226. void destinationCircular(volatile signed char p[], unsigned int len) {
  227. destinationCircular((volatile uint8_t *)p, len); }
  228. void destinationCircular(volatile unsigned char p[], unsigned int len) {
  229. TCD->DADDR = p;
  230. TCD->DOFF = 1;
  231. TCD->ATTR_DST = ((31 - __builtin_clz(len)) << 3);
  232. TCD->NBYTES = 1;
  233. TCD->DLASTSGA = 0;
  234. TCD->BITER = len;
  235. TCD->CITER = len;
  236. }
  237. void destinationCircular(volatile signed short p[], unsigned int len) {
  238. destinationCircular((volatile uint16_t *)p, len); }
  239. void destinationCircular(volatile unsigned short p[], unsigned int len) {
  240. TCD->DADDR = p;
  241. TCD->DOFF = 2;
  242. TCD->ATTR_DST = ((31 - __builtin_clz(len)) << 3) | 1;
  243. TCD->NBYTES = 2;
  244. TCD->DLASTSGA = 0;
  245. TCD->BITER = len / 2;
  246. TCD->CITER = len / 2;
  247. }
  248. void destinationCircular(volatile signed int p[], unsigned int len) {
  249. destinationCircular((volatile uint32_t *)p, len); }
  250. void destinationCircular(volatile unsigned int p[], unsigned int len) {
  251. destinationCircular((volatile uint32_t *)p, len); }
  252. void destinationCircular(volatile signed long p[], unsigned int len) {
  253. destinationCircular((volatile uint32_t *)p, len); }
  254. void destinationCircular(volatile unsigned long p[], unsigned int len) {
  255. TCD->DADDR = p;
  256. TCD->DOFF = 4;
  257. TCD->ATTR_DST = ((31 - __builtin_clz(len)) << 3) | 2;
  258. TCD->NBYTES = 4;
  259. TCD->DLASTSGA = 0;
  260. TCD->BITER = len / 4;
  261. TCD->CITER = len / 4;
  262. }
  263. /*************************************************/
  264. /** Quantity of Data to Transfer **/
  265. /*************************************************/
  266. // Set the data size used for each triggered transfer
  267. void transferSize(unsigned int len) {
  268. if (len == 4) {
  269. TCD->NBYTES = 4;
  270. if (TCD->SOFF != 0) TCD->SOFF = 4;
  271. if (TCD->DOFF != 0) TCD->DOFF = 4;
  272. TCD->ATTR = (TCD->ATTR & 0xF8F8) | 0x0202;
  273. } else if (len == 2) {
  274. TCD->NBYTES = 2;
  275. if (TCD->SOFF != 0) TCD->SOFF = 2;
  276. if (TCD->DOFF != 0) TCD->DOFF = 2;
  277. TCD->ATTR = (TCD->ATTR & 0xF8F8) | 0x0101;
  278. } else {
  279. TCD->NBYTES = 1;
  280. if (TCD->SOFF != 0) TCD->SOFF = 1;
  281. if (TCD->DOFF != 0) TCD->DOFF = 1;
  282. TCD->ATTR = TCD->ATTR & 0xF8F8;
  283. }
  284. }
  285. // Set the number of transfers (number of triggers until complete)
  286. void transferCount(unsigned int len) {
  287. if (len > 32767) return;
  288. if (len >= 512) {
  289. TCD->BITER = len;
  290. TCD->CITER = len;
  291. } else {
  292. TCD->BITER = (TCD->BITER & 0xFE00) | len;
  293. TCD->CITER = (TCD->CITER & 0xFE00) | len;
  294. }
  295. }
  296. /*************************************************/
  297. /** Special Options / Features **/
  298. /*************************************************/
  299. void interruptAtCompletion(void) {
  300. TCD->CSR |= DMA_TCD_CSR_INTMAJOR;
  301. }
  302. void interruptAtHalf(void) {
  303. TCD->CSR |= DMA_TCD_CSR_INTHALF;
  304. }
  305. void disableOnCompletion(void) {
  306. TCD->CSR |= DMA_TCD_CSR_DREQ;
  307. }
  308. void replaceSettingsOnCompletion(const DMABaseClass &settings) {
  309. TCD->DLASTSGA = (int32_t)(settings.TCD);
  310. TCD->CSR &= ~DMA_TCD_CSR_DONE;
  311. TCD->CSR |= DMA_TCD_CSR_ESG;
  312. }
  313. protected:
  314. // users should not be able to create instances of DMABaseClass, which
  315. // require the inheriting class to initialize the TCD pointer.
  316. DMABaseClass() {}
  317. static inline void copy_tcd(TCD_t *dst, const TCD_t *src) {
  318. const uint32_t *p = (const uint32_t *)src;
  319. uint32_t *q = (uint32_t *)dst;
  320. uint32_t t1, t2, t3, t4;
  321. t1 = *p++; t2 = *p++; t3 = *p++; t4 = *p++;
  322. *q++ = t1; *q++ = t2; *q++ = t3; *q++ = t4;
  323. t1 = *p++; t2 = *p++; t3 = *p++; t4 = *p++;
  324. *q++ = t1; *q++ = t2; *q++ = t3; *q++ = t4;
  325. }
  326. };
  327. // DMASetting represents settings stored only in memory, which can be
  328. // applied to any DMA channel.
  329. class DMASetting : public DMABaseClass {
  330. public:
  331. DMASetting() {
  332. TCD = &tcddata;
  333. }
  334. DMASetting(const DMASetting &c) {
  335. TCD = &tcddata;
  336. *this = c;
  337. }
  338. DMASetting(const DMABaseClass &c) {
  339. TCD = &tcddata;
  340. *this = c;
  341. }
  342. DMASetting & operator = (const DMABaseClass &rhs) {
  343. copy_tcd(TCD, rhs.TCD);
  344. return *this;
  345. }
  346. private:
  347. TCD_t tcddata __attribute__((aligned(32)));
  348. };
  349. // DMAChannel reprents an actual DMA channel and its current settings
  350. class DMAChannel : public DMABaseClass {
  351. public:
  352. /*************************************************/
  353. /** Channel Allocation **/
  354. /*************************************************/
  355. DMAChannel() {
  356. begin();
  357. }
  358. DMAChannel(const DMAChannel &c) {
  359. TCD = c.TCD;
  360. channel = c.channel;
  361. }
  362. DMAChannel(const DMASetting &c) {
  363. begin();
  364. copy_tcd(TCD, c.TCD);
  365. }
  366. DMAChannel(bool allocate) {
  367. if (allocate) begin();
  368. }
  369. DMAChannel & operator = (const DMAChannel &rhs) {
  370. if (channel != rhs.channel) {
  371. release();
  372. TCD = rhs.TCD;
  373. channel = rhs.channel;
  374. }
  375. return *this;
  376. }
  377. DMAChannel & operator = (const DMASetting &rhs) {
  378. copy_tcd(TCD, rhs.TCD);
  379. return *this;
  380. }
  381. ~DMAChannel() {
  382. release();
  383. }
  384. void begin(bool force_initialization = false);
  385. private:
  386. void release(void);
  387. public:
  388. /***************************************/
  389. /** Triggering **/
  390. /***************************************/
  391. // Triggers cause the DMA channel to actually move data. Each
  392. // trigger moves a single data unit, which is typically 8, 16 or
  393. // 32 bits. If a channel is configured for 200 transfers
  394. // Use a hardware trigger to make the DMA channel run
  395. void triggerAtHardwareEvent(uint8_t source) {
  396. volatile uint8_t *mux;
  397. mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
  398. *mux = 0;
  399. *mux = (source & 63) | DMAMUX_ENABLE;
  400. }
  401. // Use another DMA channel as the trigger, causing this
  402. // channel to trigger after each transfer is makes, except
  403. // the its last transfer. This effectively makes the 2
  404. // channels run in parallel until the last transfer
  405. void triggerAtTransfersOf(DMABaseClass &ch) {
  406. ch.TCD->BITER = (ch.TCD->BITER & ~DMA_TCD_BITER_ELINKYES_LINKCH_MASK)
  407. | DMA_TCD_BITER_ELINKYES_LINKCH(channel) | DMA_TCD_BITER_ELINKYES_ELINK;
  408. ch.TCD->CITER = ch.TCD->BITER ;
  409. }
  410. // Use another DMA channel as the trigger, causing this
  411. // channel to trigger when the other channel completes.
  412. void triggerAtCompletionOf(DMABaseClass &ch) {
  413. ch.TCD->CSR = (ch.TCD->CSR & ~(DMA_TCD_CSR_MAJORLINKCH_MASK|DMA_TCD_CSR_DONE))
  414. | DMA_TCD_CSR_MAJORLINKCH(channel) | DMA_TCD_CSR_MAJORELINK;
  415. }
  416. // Cause this DMA channel to be continuously triggered, so
  417. // it will move data as rapidly as possible, without waiting.
  418. // Normally this would be used with disableOnCompletion().
  419. void triggerContinuously(void) {
  420. volatile uint8_t *mux = (volatile uint8_t *)&DMAMUX0_CHCFG0;
  421. mux[channel] = 0;
  422. #if DMAMUX_NUM_SOURCE_ALWAYS >= DMA_NUM_CHANNELS
  423. mux[channel] = DMAMUX_SOURCE_ALWAYS0 + channel;
  424. #else
  425. // search for an unused "always on" source
  426. unsigned int i = DMAMUX_SOURCE_ALWAYS0;
  427. for (i = DMAMUX_SOURCE_ALWAYS0;
  428. i < DMAMUX_SOURCE_ALWAYS0 + DMAMUX_NUM_SOURCE_ALWAYS; i++) {
  429. unsigned int ch;
  430. for (ch=0; ch < DMA_NUM_CHANNELS; ch++) {
  431. if (mux[ch] == i) break;
  432. }
  433. if (ch >= DMA_NUM_CHANNELS) {
  434. mux[channel] = (i | DMAMUX_ENABLE);
  435. return;
  436. }
  437. }
  438. #endif
  439. }
  440. // Manually trigger the DMA channel.
  441. void triggerManual(void) {
  442. DMA_SSRT = channel;
  443. }
  444. /***************************************/
  445. /** Interrupts **/
  446. /***************************************/
  447. // An interrupt routine can be run when the DMA channel completes
  448. // the entire transfer, and also optionally when half of the
  449. // transfer is completed.
  450. void attachInterrupt(void (*isr)(void)) {
  451. _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
  452. NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel);
  453. }
  454. void detachInterrupt(void) {
  455. NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel);
  456. }
  457. void clearInterrupt(void) {
  458. DMA_CINT = channel;
  459. }
  460. /***************************************/
  461. /** Enable / Disable **/
  462. /***************************************/
  463. void enable(void) {
  464. DMA_SERQ = channel;
  465. }
  466. void disable(void) {
  467. DMA_CERQ = channel;
  468. }
  469. /***************************************/
  470. /** Status **/
  471. /***************************************/
  472. bool complete(void) {
  473. if (TCD->CSR & DMA_TCD_CSR_DONE) return true;
  474. return false;
  475. }
  476. void clearComplete(void) {
  477. DMA_CDNE = channel;
  478. }
  479. bool error(void) {
  480. if (DMA_ERR & (1<<channel)) return true;
  481. return false;
  482. }
  483. void clearError(void) {
  484. DMA_CERR = channel;
  485. }
  486. void * sourceAddress(void) {
  487. return (void *)(TCD->SADDR);
  488. }
  489. void * destinationAddress(void) {
  490. return (void *)(TCD->DADDR);
  491. }
  492. /***************************************/
  493. /** Direct Hardware Access **/
  494. /***************************************/
  495. // For complex and unusual configurations not possible with the above
  496. // functions, the Transfer Control Descriptor (TCD) and channel number
  497. // can be used directly. This leads to less portable and less readable
  498. // code, but direct control of all parameters is possible.
  499. uint8_t channel;
  500. // TCD is accessible due to inheritance from DMABaseClass
  501. };
  502. // arrange the relative priority of 2 or more DMA channels
  503. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2);
  504. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3);
  505. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4);
  506. /****************************************************************/
  507. /** Teensy-LC **/
  508. /****************************************************************/
  509. #elif defined(KINETISL)
  510. class DMABaseClass {
  511. public:
  512. typedef struct __attribute__((packed)) {
  513. volatile const void * volatile SAR;
  514. volatile void * volatile DAR;
  515. volatile uint32_t DSR_BCR;
  516. volatile uint32_t DCR;
  517. } CFG_t;
  518. CFG_t *CFG;
  519. /***************************************/
  520. /** Data Transfer **/
  521. /***************************************/
  522. // Use a single variable as the data source. Typically a register
  523. // for receiving data from one of the hardware peripherals is used.
  524. void source(volatile const signed char &p) { source(*(volatile const uint8_t *)&p); }
  525. void source(volatile const unsigned char &p) {
  526. CFG->SAR = &p;
  527. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1);
  528. }
  529. void source(volatile const signed short &p) { source(*(volatile const uint16_t *)&p); }
  530. void source(volatile const unsigned short &p) {
  531. CFG->SAR = &p;
  532. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2);
  533. }
  534. void source(volatile const signed int &p) { source(*(volatile const uint32_t *)&p); }
  535. void source(volatile const unsigned int &p) { source(*(volatile const uint32_t *)&p); }
  536. void source(volatile const signed long &p) { source(*(volatile const uint32_t *)&p); }
  537. void source(volatile const unsigned long &p) {
  538. CFG->SAR = &p;
  539. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0);
  540. }
  541. // Use a buffer (array of data) as the data source. Typically a
  542. // buffer for transmitting data is used.
  543. void sourceBuffer(volatile const signed char p[], unsigned int len) {
  544. sourceBuffer((volatile const uint8_t *)p, len); }
  545. void sourceBuffer(volatile const unsigned char p[], unsigned int len) {
  546. if (len > 0xFFFFF) return;
  547. CFG->SAR = p;
  548. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC;
  549. CFG->DSR_BCR = len;
  550. }
  551. void sourceBuffer(volatile const signed short p[], unsigned int len) {
  552. sourceBuffer((volatile const uint16_t *)p, len); }
  553. void sourceBuffer(volatile const unsigned short p[], unsigned int len) {
  554. if (len > 0xFFFFF) return;
  555. CFG->SAR = p;
  556. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC;
  557. CFG->DSR_BCR = len;
  558. }
  559. void sourceBuffer(volatile const signed int p[], unsigned int len) {
  560. sourceBuffer((volatile const uint32_t *)p, len); }
  561. void sourceBuffer(volatile const unsigned int p[], unsigned int len) {
  562. sourceBuffer((volatile const uint32_t *)p, len); }
  563. void sourceBuffer(volatile const signed long p[], unsigned int len) {
  564. sourceBuffer((volatile const uint32_t *)p, len); }
  565. void sourceBuffer(volatile const unsigned long p[], unsigned int len) {
  566. if (len > 0xFFFFF) return;
  567. CFG->SAR = p;
  568. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC;
  569. CFG->DSR_BCR = len;
  570. }
  571. // Use a circular buffer as the data source
  572. void sourceCircular(volatile const signed char p[], unsigned int len) {
  573. sourceCircular((volatile const uint8_t *)p, len); }
  574. void sourceCircular(volatile const unsigned char p[], unsigned int len) {
  575. uint32_t mod = len2mod(len);
  576. if (mod == 0) return;
  577. CFG->SAR = p;
  578. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC
  579. | DMA_DCR_SMOD(mod);
  580. CFG->DSR_BCR = len;
  581. }
  582. void sourceCircular(volatile const signed short p[], unsigned int len) {
  583. sourceCircular((volatile const uint16_t *)p, len); }
  584. void sourceCircular(volatile const unsigned short p[], unsigned int len) {
  585. uint32_t mod = len2mod(len);
  586. if (mod == 0) return;
  587. CFG->SAR = p;
  588. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC
  589. | DMA_DCR_SMOD(mod);
  590. CFG->DSR_BCR = len;
  591. }
  592. void sourceCircular(volatile const signed int p[], unsigned int len) {
  593. sourceCircular((volatile const uint32_t *)p, len); }
  594. void sourceCircular(volatile const unsigned int p[], unsigned int len) {
  595. sourceCircular((volatile const uint32_t *)p, len); }
  596. void sourceCircular(volatile const signed long p[], unsigned int len) {
  597. sourceCircular((volatile const uint32_t *)p, len); }
  598. void sourceCircular(volatile const unsigned long p[], unsigned int len) {
  599. uint32_t mod = len2mod(len);
  600. if (mod == 0) return;
  601. CFG->SAR = p;
  602. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC
  603. | DMA_DCR_SMOD(mod);
  604. CFG->DSR_BCR = len;
  605. }
  606. // Use a single variable as the data destination. Typically a register
  607. // for transmitting data to one of the hardware peripherals is used.
  608. void destination(volatile signed char &p) { destination(*(volatile uint8_t *)&p); }
  609. void destination(volatile unsigned char &p) {
  610. CFG->DAR = &p;
  611. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1);
  612. }
  613. void destination(volatile signed short &p) { destination(*(volatile uint16_t *)&p); }
  614. void destination(volatile unsigned short &p) {
  615. CFG->DAR = &p;
  616. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2);
  617. }
  618. void destination(volatile signed int &p) { destination(*(volatile uint32_t *)&p); }
  619. void destination(volatile unsigned int &p) { destination(*(volatile uint32_t *)&p); }
  620. void destination(volatile signed long &p) { destination(*(volatile uint32_t *)&p); }
  621. void destination(volatile unsigned long &p) {
  622. CFG->DAR = &p;
  623. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0);
  624. }
  625. // Use a buffer (array of data) as the data destination. Typically a
  626. // buffer for receiving data is used.
  627. void destinationBuffer(volatile signed char p[], unsigned int len) {
  628. destinationBuffer((volatile uint8_t *)p, len); }
  629. void destinationBuffer(volatile unsigned char p[], unsigned int len) {
  630. CFG->DAR = p;
  631. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC;
  632. CFG->DSR_BCR = len;
  633. }
  634. void destinationBuffer(volatile signed short p[], unsigned int len) {
  635. destinationBuffer((volatile uint16_t *)p, len); }
  636. void destinationBuffer(volatile unsigned short p[], unsigned int len) {
  637. CFG->DAR = p;
  638. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2) | DMA_DCR_DINC;
  639. CFG->DSR_BCR = len;
  640. }
  641. void destinationBuffer(volatile signed int p[], unsigned int len) {
  642. destinationBuffer((volatile uint32_t *)p, len); }
  643. void destinationBuffer(volatile unsigned int p[], unsigned int len) {
  644. destinationBuffer((volatile uint32_t *)p, len); }
  645. void destinationBuffer(volatile signed long p[], unsigned int len) {
  646. destinationBuffer((volatile uint32_t *)p, len); }
  647. void destinationBuffer(volatile unsigned long p[], unsigned int len) {
  648. CFG->DAR = p;
  649. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0) | DMA_DCR_DINC;
  650. CFG->DSR_BCR = len;
  651. }
  652. // Use a circular buffer as the data destination
  653. void destinationCircular(volatile signed char p[], unsigned int len) {
  654. destinationCircular((volatile uint8_t *)p, len); }
  655. void destinationCircular(volatile unsigned char p[], unsigned int len) {
  656. uint32_t mod = len2mod(len);
  657. if (mod == 0) return;
  658. CFG->DAR = p;
  659. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC
  660. | DMA_DCR_DMOD(mod);
  661. CFG->DSR_BCR = len;
  662. }
  663. void destinationCircular(volatile signed short p[], unsigned int len) {
  664. destinationCircular((volatile uint16_t *)p, len); }
  665. void destinationCircular(volatile unsigned short p[], unsigned int len) {
  666. uint32_t mod = len2mod(len);
  667. if (mod == 0) return;
  668. CFG->DAR = p;
  669. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC
  670. | DMA_DCR_DMOD(mod);
  671. CFG->DSR_BCR = len;
  672. }
  673. void destinationCircular(volatile signed int p[], unsigned int len) {
  674. destinationCircular((volatile uint32_t *)p, len); }
  675. void destinationCircular(volatile unsigned int p[], unsigned int len) {
  676. destinationCircular((volatile uint32_t *)p, len); }
  677. void destinationCircular(volatile signed long p[], unsigned int len) {
  678. destinationCircular((volatile uint32_t *)p, len); }
  679. void destinationCircular(volatile unsigned long p[], unsigned int len) {
  680. uint32_t mod = len2mod(len);
  681. if (mod == 0) return;
  682. CFG->DAR = p;
  683. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC
  684. | DMA_DCR_DMOD(mod);
  685. CFG->DSR_BCR = len;
  686. }
  687. /*************************************************/
  688. /** Quantity of Data to Transfer **/
  689. /*************************************************/
  690. // Set the data size used for each triggered transfer
  691. void transferSize(unsigned int len) {
  692. uint32_t dcr = CFG->DCR & 0xF0C8FFFF;
  693. if (len == 4) {
  694. CFG->DCR = dcr | DMA_DCR_DSIZE(0) | DMA_DCR_DSIZE(0);
  695. } else if (len == 2) {
  696. CFG->DCR = dcr | DMA_DCR_DSIZE(2) | DMA_DCR_DSIZE(2);
  697. } else {
  698. CFG->DCR = dcr | DMA_DCR_DSIZE(1) | DMA_DCR_DSIZE(1);
  699. }
  700. }
  701. // Set the number of transfers (number of triggers until complete)
  702. void transferCount(unsigned int len) {
  703. uint32_t s, d, n = 0; // 0 = 8 bit, 1 = 16 bit, 2 = 32 bit
  704. uint32_t dcr = CFG->DCR;
  705. s = (dcr >> 20) & 3;
  706. d = (dcr >> 17) & 3;
  707. if (s == 0 || d == 0) n = 2;
  708. else if (s == 2 || d == 2) n = 1;
  709. CFG->DSR_BCR = len >> n;
  710. }
  711. /*************************************************/
  712. /** Special Options / Features **/
  713. /*************************************************/
  714. void interruptAtCompletion(void) {
  715. CFG->DCR |= DMA_DCR_EINT;
  716. }
  717. void disableOnCompletion(void) {
  718. CFG->DCR |= DMA_DCR_D_REQ;
  719. }
  720. // Kinetis-L DMA does not have these features :-(
  721. //
  722. // void interruptAtHalf(void) {}
  723. // void replaceSettingsOnCompletion(const DMABaseClass &settings) {};
  724. // TODO: can a 2nd linked channel be used to emulate this?
  725. protected:
  726. // users should not be able to create instances of DMABaseClass, which
  727. // require the inheriting class to initialize the TCD pointer.
  728. DMABaseClass() {}
  729. static inline void copy_cfg(CFG_t *dst, const CFG_t *src) {
  730. dst->SAR = src->SAR;
  731. dst->DAR = src->DAR;
  732. dst->DSR_BCR = src->DSR_BCR;
  733. dst->DCR = src->DCR;
  734. }
  735. private:
  736. static inline uint32_t len2mod(uint32_t len) {
  737. if (len < 16) return 0;
  738. if (len < 32) return 1;
  739. if (len < 64) return 2;
  740. if (len < 128) return 3;
  741. if (len < 256) return 4;
  742. if (len < 512) return 5;
  743. if (len < 1024) return 6;
  744. if (len < 2048) return 7;
  745. if (len < 4096) return 8;
  746. if (len < 8192) return 9;
  747. if (len < 16384) return 10;
  748. if (len < 32768) return 11;
  749. if (len < 65536) return 12;
  750. if (len < 131072) return 13;
  751. if (len < 262144) return 14;
  752. return 15;
  753. }
  754. };
  755. // DMASetting represents settings stored only in memory, which can be
  756. // applied to any DMA channel.
  757. class DMASetting : public DMABaseClass {
  758. public:
  759. DMASetting() {
  760. cfgdata.SAR = NULL;
  761. cfgdata.DAR = NULL;
  762. cfgdata.DSR_BCR = 0;
  763. cfgdata.DCR = DMA_DCR_CS;
  764. CFG = &cfgdata;
  765. }
  766. DMASetting(const DMASetting &c) {
  767. CFG = &cfgdata;
  768. *this = c;
  769. }
  770. DMASetting(const DMABaseClass &c) {
  771. CFG = &cfgdata;
  772. *this = c;
  773. }
  774. DMASetting & operator = (const DMABaseClass &rhs) {
  775. copy_cfg(CFG, rhs.CFG);
  776. return *this;
  777. }
  778. private:
  779. CFG_t cfgdata __attribute__((aligned(4)));
  780. };
  781. // DMAChannel reprents an actual DMA channel and its current settings
  782. class DMAChannel : public DMABaseClass {
  783. public:
  784. /*************************************************/
  785. /** Channel Allocation **/
  786. /*************************************************/
  787. DMAChannel() {
  788. begin();
  789. }
  790. DMAChannel(const DMAChannel &c) {
  791. CFG = c.CFG;
  792. channel = c.channel;
  793. }
  794. DMAChannel(const DMASetting &c) {
  795. begin();
  796. copy_cfg(CFG, c.CFG);
  797. }
  798. DMAChannel(bool allocate) {
  799. if (allocate) begin();
  800. }
  801. DMAChannel & operator = (const DMAChannel &rhs) {
  802. if (channel != rhs.channel) {
  803. release();
  804. CFG = rhs.CFG;
  805. channel = rhs.channel;
  806. }
  807. return *this;
  808. }
  809. DMAChannel & operator = (const DMASetting &rhs) {
  810. copy_cfg(CFG, rhs.CFG);
  811. return *this;
  812. }
  813. ~DMAChannel() {
  814. release();
  815. }
  816. void begin(bool force_initialization = false);
  817. private:
  818. void release(void);
  819. public:
  820. /***************************************/
  821. /** Triggering **/
  822. /***************************************/
  823. // Triggers cause the DMA channel to actually move data. Each
  824. // trigger moves a single data unit, which is typically 8, 16 or
  825. // 32 bits. If a channel is configured for 200 transfers
  826. // Use a hardware trigger to make the DMA channel run
  827. void triggerAtHardwareEvent(uint8_t source) {
  828. volatile uint8_t *mux;
  829. CFG->DCR |= DMA_DCR_CS;
  830. mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
  831. *mux = 0;
  832. *mux = (source & 63) | DMAMUX_ENABLE;
  833. }
  834. // Use another DMA channel as the trigger, causing this
  835. // channel to trigger after each transfer is makes, including
  836. // the its last transfer. This effectively makes the 2
  837. // channels run in parallel. Note, on Teensy 3.0 & 3.1,
  838. // this feature triggers on every transfer except the last.
  839. // On Teensy-LC, it triggers on every one, including the last.
  840. void triggerAtTransfersOf(DMABaseClass &ch) {
  841. uint32_t dcr = ch.CFG->DCR;
  842. uint32_t linkcc = (dcr >> 4) & 3;
  843. if (linkcc == 0 || linkcc == 2) {
  844. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  845. DMA_DCR_LINKCC(2) | DMA_DCR_LCH1(channel);
  846. } else if (linkcc == 1) {
  847. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  848. DMA_DCR_LCH1(channel);
  849. } else {
  850. uint32_t lch1 = (dcr >> 2) & 3;
  851. ch.CFG->DCR = (dcr
  852. & ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3) | DMA_DCR_LCH1(3)))
  853. | DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(lch1) | DMA_DCR_LCH1(channel);
  854. }
  855. }
  856. // Use another DMA channel as the trigger, causing this
  857. // channel to trigger when the other channel completes.
  858. void triggerAtCompletionOf(DMABaseClass &ch) {
  859. uint32_t dcr = ch.CFG->DCR;
  860. uint32_t linkcc = (dcr >> 4) & 3;
  861. if (linkcc == 0 || linkcc == 3) {
  862. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  863. DMA_DCR_LINKCC(3) | DMA_DCR_LCH1(channel);
  864. } else {
  865. ch.CFG->DCR = (dcr
  866. & ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3)))
  867. | DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(channel);
  868. }
  869. }
  870. // Cause this DMA channel to be continuously triggered, so
  871. // it will move data as rapidly as possible, without waiting.
  872. // Normally this would be used with disableOnCompletion().
  873. void triggerContinuously(void) {
  874. uint32_t dcr = CFG->DCR;
  875. dcr &= ~(DMA_DCR_ERQ | DMA_DCR_CS);
  876. CFG->DCR = dcr;
  877. CFG->DCR = dcr | DMA_DCR_START;
  878. }
  879. // Manually trigger the DMA channel.
  880. void triggerManual(void) {
  881. CFG->DCR = (CFG->DCR & ~DMA_DCR_ERQ) | (DMA_DCR_CS | DMA_DCR_START);
  882. }
  883. /***************************************/
  884. /** Interrupts **/
  885. /***************************************/
  886. // An interrupt routine can be run when the DMA channel completes
  887. // the entire transfer, and also optionally when half of the
  888. // transfer is completed.
  889. void attachInterrupt(void (*isr)(void)) {
  890. _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
  891. NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel);
  892. }
  893. void detachInterrupt(void) {
  894. NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel);
  895. }
  896. void clearInterrupt(void) {
  897. CFG->DSR_BCR = DMA_DSR_BCR_DONE;
  898. }
  899. /***************************************/
  900. /** Enable / Disable **/
  901. /***************************************/
  902. void enable(void) {
  903. CFG->DCR |= DMA_DCR_ERQ;
  904. }
  905. void disable(void) {
  906. CFG->DCR &= ~DMA_DCR_ERQ;
  907. }
  908. /***************************************/
  909. /** Status **/
  910. /***************************************/
  911. bool complete(void) {
  912. if (CFG->DSR_BCR & DMA_DSR_BCR_DONE) return true;
  913. return false;
  914. }
  915. void clearComplete(void) {
  916. CFG->DSR_BCR |= DMA_DSR_BCR_DONE;
  917. }
  918. bool error(void) {
  919. if (CFG->DSR_BCR &
  920. (DMA_DSR_BCR_CE | DMA_DSR_BCR_BES | DMA_DSR_BCR_BED)) return true;
  921. return false;
  922. }
  923. void clearError(void) {
  924. CFG->DSR_BCR |= DMA_DSR_BCR_DONE;
  925. }
  926. void * sourceAddress(void) {
  927. return (void *)(CFG->SAR);
  928. }
  929. void * destinationAddress(void) {
  930. return (void *)(CFG->DAR);
  931. }
  932. /***************************************/
  933. /** Direct Hardware Access **/
  934. /***************************************/
  935. uint8_t channel;
  936. // CFG is accessible due to inheritance from DMABaseClass
  937. };
  938. // arrange the relative priority of 2 or more DMA channels
  939. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2);
  940. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3);
  941. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4);
  942. #endif // KINETISL
  943. #endif // __cplusplus
  944. #endif // DMAChannel_h_