Teensy 4.1 core updated for C++20
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

1076 lines
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 == 16) {
  269. TCD->NBYTES = 16;
  270. if (TCD->SOFF != 0) TCD->SOFF = 16;
  271. if (TCD->DOFF != 0) TCD->DOFF = 16;
  272. TCD->ATTR = (TCD->ATTR & 0xF8F8) | 0x0404;
  273. } else if (len == 4) {
  274. TCD->NBYTES = 4;
  275. if (TCD->SOFF != 0) TCD->SOFF = 4;
  276. if (TCD->DOFF != 0) TCD->DOFF = 4;
  277. TCD->ATTR = (TCD->ATTR & 0xF8F8) | 0x0202;
  278. } else if (len == 2) {
  279. TCD->NBYTES = 2;
  280. if (TCD->SOFF != 0) TCD->SOFF = 2;
  281. if (TCD->DOFF != 0) TCD->DOFF = 2;
  282. TCD->ATTR = (TCD->ATTR & 0xF8F8) | 0x0101;
  283. } else {
  284. TCD->NBYTES = 1;
  285. if (TCD->SOFF != 0) TCD->SOFF = 1;
  286. if (TCD->DOFF != 0) TCD->DOFF = 1;
  287. TCD->ATTR = TCD->ATTR & 0xF8F8;
  288. }
  289. }
  290. // Set the number of transfers (number of triggers until complete)
  291. void transferCount(unsigned int len) {
  292. if (len > 32767) return;
  293. if (len >= 512) {
  294. TCD->BITER = len;
  295. TCD->CITER = len;
  296. } else {
  297. TCD->BITER = (TCD->BITER & 0xFE00) | len;
  298. TCD->CITER = (TCD->CITER & 0xFE00) | len;
  299. }
  300. }
  301. /*************************************************/
  302. /** Special Options / Features **/
  303. /*************************************************/
  304. void interruptAtCompletion(void) {
  305. TCD->CSR |= DMA_TCD_CSR_INTMAJOR;
  306. }
  307. void interruptAtHalf(void) {
  308. TCD->CSR |= DMA_TCD_CSR_INTHALF;
  309. }
  310. void disableOnCompletion(void) {
  311. TCD->CSR |= DMA_TCD_CSR_DREQ;
  312. }
  313. void replaceSettingsOnCompletion(const DMABaseClass &settings) {
  314. TCD->DLASTSGA = (int32_t)(settings.TCD);
  315. TCD->CSR &= ~DMA_TCD_CSR_DONE;
  316. TCD->CSR |= DMA_TCD_CSR_ESG;
  317. }
  318. protected:
  319. // users should not be able to create instances of DMABaseClass, which
  320. // require the inheriting class to initialize the TCD pointer.
  321. DMABaseClass() {}
  322. static inline void copy_tcd(TCD_t *dst, const TCD_t *src) {
  323. const uint32_t *p = (const uint32_t *)src;
  324. uint32_t *q = (uint32_t *)dst;
  325. uint32_t t1, t2, t3, t4;
  326. t1 = *p++; t2 = *p++; t3 = *p++; t4 = *p++;
  327. *q++ = t1; *q++ = t2; *q++ = t3; *q++ = t4;
  328. t1 = *p++; t2 = *p++; t3 = *p++; t4 = *p++;
  329. *q++ = t1; *q++ = t2; *q++ = t3; *q++ = t4;
  330. }
  331. };
  332. // DMASetting represents settings stored only in memory, which can be
  333. // applied to any DMA channel.
  334. class DMASetting : public DMABaseClass {
  335. public:
  336. DMASetting() {
  337. TCD = &tcddata;
  338. }
  339. DMASetting(const DMASetting &c) {
  340. TCD = &tcddata;
  341. *this = c;
  342. }
  343. DMASetting(const DMABaseClass &c) {
  344. TCD = &tcddata;
  345. *this = c;
  346. }
  347. DMASetting & operator = (const DMABaseClass &rhs) {
  348. copy_tcd(TCD, rhs.TCD);
  349. return *this;
  350. }
  351. private:
  352. TCD_t tcddata __attribute__((aligned(32)));
  353. };
  354. // DMAChannel reprents an actual DMA channel and its current settings
  355. class DMAChannel : public DMABaseClass {
  356. public:
  357. /*************************************************/
  358. /** Channel Allocation **/
  359. /*************************************************/
  360. DMAChannel() {
  361. begin();
  362. }
  363. DMAChannel(const DMAChannel &c) {
  364. TCD = c.TCD;
  365. channel = c.channel;
  366. }
  367. DMAChannel(const DMASetting &c) {
  368. begin();
  369. copy_tcd(TCD, c.TCD);
  370. }
  371. DMAChannel(bool allocate) {
  372. if (allocate) begin();
  373. }
  374. DMAChannel & operator = (const DMAChannel &rhs) {
  375. if (channel != rhs.channel) {
  376. release();
  377. TCD = rhs.TCD;
  378. channel = rhs.channel;
  379. }
  380. return *this;
  381. }
  382. DMAChannel & operator = (const DMASetting &rhs) {
  383. copy_tcd(TCD, rhs.TCD);
  384. return *this;
  385. }
  386. ~DMAChannel() {
  387. release();
  388. }
  389. void begin(bool force_initialization = false);
  390. private:
  391. void release(void);
  392. public:
  393. /***************************************/
  394. /** Triggering **/
  395. /***************************************/
  396. // Triggers cause the DMA channel to actually move data. Each
  397. // trigger moves a single data unit, which is typically 8, 16 or
  398. // 32 bits. If a channel is configured for 200 transfers
  399. // Use a hardware trigger to make the DMA channel run
  400. void triggerAtHardwareEvent(uint8_t source) {
  401. volatile uint8_t *mux;
  402. mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
  403. *mux = 0;
  404. *mux = (source & 63) | DMAMUX_ENABLE;
  405. }
  406. // Use another DMA channel as the trigger, causing this
  407. // channel to trigger after each transfer is makes, except
  408. // the its last transfer. This effectively makes the 2
  409. // channels run in parallel until the last transfer
  410. void triggerAtTransfersOf(DMABaseClass &ch) {
  411. ch.TCD->BITER = (ch.TCD->BITER & ~DMA_TCD_BITER_ELINKYES_LINKCH_MASK)
  412. | DMA_TCD_BITER_ELINKYES_LINKCH(channel) | DMA_TCD_BITER_ELINKYES_ELINK;
  413. ch.TCD->CITER = ch.TCD->BITER ;
  414. }
  415. // Use another DMA channel as the trigger, causing this
  416. // channel to trigger when the other channel completes.
  417. void triggerAtCompletionOf(DMABaseClass &ch) {
  418. ch.TCD->CSR = (ch.TCD->CSR & ~(DMA_TCD_CSR_MAJORLINKCH_MASK|DMA_TCD_CSR_DONE))
  419. | DMA_TCD_CSR_MAJORLINKCH(channel) | DMA_TCD_CSR_MAJORELINK;
  420. }
  421. // Cause this DMA channel to be continuously triggered, so
  422. // it will move data as rapidly as possible, without waiting.
  423. // Normally this would be used with disableOnCompletion().
  424. void triggerContinuously(void) {
  425. volatile uint8_t *mux = (volatile uint8_t *)&DMAMUX0_CHCFG0;
  426. mux[channel] = 0;
  427. #if DMAMUX_NUM_SOURCE_ALWAYS >= DMA_NUM_CHANNELS
  428. mux[channel] = DMAMUX_SOURCE_ALWAYS0 + channel;
  429. #else
  430. // search for an unused "always on" source
  431. unsigned int i = DMAMUX_SOURCE_ALWAYS0;
  432. for (i = DMAMUX_SOURCE_ALWAYS0;
  433. i < DMAMUX_SOURCE_ALWAYS0 + DMAMUX_NUM_SOURCE_ALWAYS; i++) {
  434. unsigned int ch;
  435. for (ch=0; ch < DMA_NUM_CHANNELS; ch++) {
  436. if (mux[ch] == i) break;
  437. }
  438. if (ch >= DMA_NUM_CHANNELS) {
  439. mux[channel] = (i | DMAMUX_ENABLE);
  440. return;
  441. }
  442. }
  443. #endif
  444. }
  445. // Manually trigger the DMA channel.
  446. void triggerManual(void) {
  447. DMA_SSRT = channel;
  448. }
  449. /***************************************/
  450. /** Interrupts **/
  451. /***************************************/
  452. // An interrupt routine can be run when the DMA channel completes
  453. // the entire transfer, and also optionally when half of the
  454. // transfer is completed.
  455. void attachInterrupt(void (*isr)(void)) {
  456. _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
  457. NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel);
  458. }
  459. void detachInterrupt(void) {
  460. NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel);
  461. }
  462. void clearInterrupt(void) {
  463. DMA_CINT = channel;
  464. }
  465. /***************************************/
  466. /** Enable / Disable **/
  467. /***************************************/
  468. void enable(void) {
  469. DMA_SERQ = channel;
  470. }
  471. void disable(void) {
  472. DMA_CERQ = channel;
  473. }
  474. /***************************************/
  475. /** Status **/
  476. /***************************************/
  477. bool complete(void) {
  478. if (TCD->CSR & DMA_TCD_CSR_DONE) return true;
  479. return false;
  480. }
  481. void clearComplete(void) {
  482. DMA_CDNE = channel;
  483. }
  484. bool error(void) {
  485. if (DMA_ERR & (1<<channel)) return true;
  486. return false;
  487. }
  488. void clearError(void) {
  489. DMA_CERR = channel;
  490. }
  491. void * sourceAddress(void) {
  492. return (void *)(TCD->SADDR);
  493. }
  494. void * destinationAddress(void) {
  495. return (void *)(TCD->DADDR);
  496. }
  497. /***************************************/
  498. /** Direct Hardware Access **/
  499. /***************************************/
  500. // For complex and unusual configurations not possible with the above
  501. // functions, the Transfer Control Descriptor (TCD) and channel number
  502. // can be used directly. This leads to less portable and less readable
  503. // code, but direct control of all parameters is possible.
  504. uint8_t channel;
  505. // TCD is accessible due to inheritance from DMABaseClass
  506. };
  507. // arrange the relative priority of 2 or more DMA channels
  508. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2);
  509. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3);
  510. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4);
  511. /****************************************************************/
  512. /** Teensy-LC **/
  513. /****************************************************************/
  514. #elif defined(KINETISL)
  515. class DMABaseClass {
  516. public:
  517. typedef struct __attribute__((packed)) {
  518. volatile const void * volatile SAR;
  519. volatile void * volatile DAR;
  520. volatile uint32_t DSR_BCR;
  521. volatile uint32_t DCR;
  522. } CFG_t;
  523. CFG_t *CFG;
  524. /***************************************/
  525. /** Data Transfer **/
  526. /***************************************/
  527. // Use a single variable as the data source. Typically a register
  528. // for receiving data from one of the hardware peripherals is used.
  529. void source(volatile const signed char &p) { source(*(volatile const uint8_t *)&p); }
  530. void source(volatile const unsigned char &p) {
  531. CFG->SAR = &p;
  532. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1);
  533. }
  534. void source(volatile const signed short &p) { source(*(volatile const uint16_t *)&p); }
  535. void source(volatile const unsigned short &p) {
  536. CFG->SAR = &p;
  537. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2);
  538. }
  539. void source(volatile const signed int &p) { source(*(volatile const uint32_t *)&p); }
  540. void source(volatile const unsigned int &p) { source(*(volatile const uint32_t *)&p); }
  541. void source(volatile const signed long &p) { source(*(volatile const uint32_t *)&p); }
  542. void source(volatile const unsigned long &p) {
  543. CFG->SAR = &p;
  544. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0);
  545. }
  546. // Use a buffer (array of data) as the data source. Typically a
  547. // buffer for transmitting data is used.
  548. void sourceBuffer(volatile const signed char p[], unsigned int len) {
  549. sourceBuffer((volatile const uint8_t *)p, len); }
  550. void sourceBuffer(volatile const unsigned char p[], unsigned int len) {
  551. if (len > 0xFFFFF) return;
  552. CFG->SAR = p;
  553. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC;
  554. CFG->DSR_BCR = len;
  555. }
  556. void sourceBuffer(volatile const signed short p[], unsigned int len) {
  557. sourceBuffer((volatile const uint16_t *)p, len); }
  558. void sourceBuffer(volatile const unsigned short p[], unsigned int len) {
  559. if (len > 0xFFFFF) return;
  560. CFG->SAR = p;
  561. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC;
  562. CFG->DSR_BCR = len;
  563. }
  564. void sourceBuffer(volatile const signed int p[], unsigned int len) {
  565. sourceBuffer((volatile const uint32_t *)p, len); }
  566. void sourceBuffer(volatile const unsigned int p[], unsigned int len) {
  567. sourceBuffer((volatile const uint32_t *)p, len); }
  568. void sourceBuffer(volatile const signed long p[], unsigned int len) {
  569. sourceBuffer((volatile const uint32_t *)p, len); }
  570. void sourceBuffer(volatile const unsigned long p[], unsigned int len) {
  571. if (len > 0xFFFFF) return;
  572. CFG->SAR = p;
  573. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC;
  574. CFG->DSR_BCR = len;
  575. }
  576. // Use a circular buffer as the data source
  577. void sourceCircular(volatile const signed char p[], unsigned int len) {
  578. sourceCircular((volatile const uint8_t *)p, len); }
  579. void sourceCircular(volatile const unsigned char p[], unsigned int len) {
  580. uint32_t mod = len2mod(len);
  581. if (mod == 0) return;
  582. CFG->SAR = p;
  583. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC
  584. | DMA_DCR_SMOD(mod);
  585. CFG->DSR_BCR = len;
  586. }
  587. void sourceCircular(volatile const signed short p[], unsigned int len) {
  588. sourceCircular((volatile const uint16_t *)p, len); }
  589. void sourceCircular(volatile const unsigned short p[], unsigned int len) {
  590. uint32_t mod = len2mod(len);
  591. if (mod == 0) return;
  592. CFG->SAR = p;
  593. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC
  594. | DMA_DCR_SMOD(mod);
  595. CFG->DSR_BCR = len;
  596. }
  597. void sourceCircular(volatile const signed int p[], unsigned int len) {
  598. sourceCircular((volatile const uint32_t *)p, len); }
  599. void sourceCircular(volatile const unsigned int p[], unsigned int len) {
  600. sourceCircular((volatile const uint32_t *)p, len); }
  601. void sourceCircular(volatile const signed long p[], unsigned int len) {
  602. sourceCircular((volatile const uint32_t *)p, len); }
  603. void sourceCircular(volatile const unsigned long p[], unsigned int len) {
  604. uint32_t mod = len2mod(len);
  605. if (mod == 0) return;
  606. CFG->SAR = p;
  607. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC
  608. | DMA_DCR_SMOD(mod);
  609. CFG->DSR_BCR = len;
  610. }
  611. // Use a single variable as the data destination. Typically a register
  612. // for transmitting data to one of the hardware peripherals is used.
  613. void destination(volatile signed char &p) { destination(*(volatile uint8_t *)&p); }
  614. void destination(volatile unsigned char &p) {
  615. CFG->DAR = &p;
  616. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1);
  617. }
  618. void destination(volatile signed short &p) { destination(*(volatile uint16_t *)&p); }
  619. void destination(volatile unsigned short &p) {
  620. CFG->DAR = &p;
  621. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2);
  622. }
  623. void destination(volatile signed int &p) { destination(*(volatile uint32_t *)&p); }
  624. void destination(volatile unsigned int &p) { destination(*(volatile uint32_t *)&p); }
  625. void destination(volatile signed long &p) { destination(*(volatile uint32_t *)&p); }
  626. void destination(volatile unsigned long &p) {
  627. CFG->DAR = &p;
  628. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0);
  629. }
  630. // Use a buffer (array of data) as the data destination. Typically a
  631. // buffer for receiving data is used.
  632. void destinationBuffer(volatile signed char p[], unsigned int len) {
  633. destinationBuffer((volatile uint8_t *)p, len); }
  634. void destinationBuffer(volatile unsigned char p[], unsigned int len) {
  635. CFG->DAR = p;
  636. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC;
  637. CFG->DSR_BCR = len;
  638. }
  639. void destinationBuffer(volatile signed short p[], unsigned int len) {
  640. destinationBuffer((volatile uint16_t *)p, len); }
  641. void destinationBuffer(volatile unsigned short p[], unsigned int len) {
  642. CFG->DAR = p;
  643. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2) | DMA_DCR_DINC;
  644. CFG->DSR_BCR = len;
  645. }
  646. void destinationBuffer(volatile signed int p[], unsigned int len) {
  647. destinationBuffer((volatile uint32_t *)p, len); }
  648. void destinationBuffer(volatile unsigned int p[], unsigned int len) {
  649. destinationBuffer((volatile uint32_t *)p, len); }
  650. void destinationBuffer(volatile signed long p[], unsigned int len) {
  651. destinationBuffer((volatile uint32_t *)p, len); }
  652. void destinationBuffer(volatile unsigned long p[], unsigned int len) {
  653. CFG->DAR = p;
  654. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0) | DMA_DCR_DINC;
  655. CFG->DSR_BCR = len;
  656. }
  657. // Use a circular buffer as the data destination
  658. void destinationCircular(volatile signed char p[], unsigned int len) {
  659. destinationCircular((volatile uint8_t *)p, len); }
  660. void destinationCircular(volatile unsigned char p[], unsigned int len) {
  661. uint32_t mod = len2mod(len);
  662. if (mod == 0) return;
  663. CFG->DAR = p;
  664. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC
  665. | DMA_DCR_DMOD(mod);
  666. CFG->DSR_BCR = len;
  667. }
  668. void destinationCircular(volatile signed short p[], unsigned int len) {
  669. destinationCircular((volatile uint16_t *)p, len); }
  670. void destinationCircular(volatile unsigned short p[], unsigned int len) {
  671. uint32_t mod = len2mod(len);
  672. if (mod == 0) return;
  673. CFG->DAR = p;
  674. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC
  675. | DMA_DCR_DMOD(mod);
  676. CFG->DSR_BCR = len;
  677. }
  678. void destinationCircular(volatile signed int p[], unsigned int len) {
  679. destinationCircular((volatile uint32_t *)p, len); }
  680. void destinationCircular(volatile unsigned int p[], unsigned int len) {
  681. destinationCircular((volatile uint32_t *)p, len); }
  682. void destinationCircular(volatile signed long p[], unsigned int len) {
  683. destinationCircular((volatile uint32_t *)p, len); }
  684. void destinationCircular(volatile unsigned long p[], unsigned int len) {
  685. uint32_t mod = len2mod(len);
  686. if (mod == 0) return;
  687. CFG->DAR = p;
  688. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC
  689. | DMA_DCR_DMOD(mod);
  690. CFG->DSR_BCR = len;
  691. }
  692. /*************************************************/
  693. /** Quantity of Data to Transfer **/
  694. /*************************************************/
  695. // Set the data size used for each triggered transfer
  696. void transferSize(unsigned int len) {
  697. uint32_t dcr = CFG->DCR & 0xF0C8FFFF;
  698. if (len == 4) {
  699. CFG->DCR = dcr | DMA_DCR_DSIZE(0) | DMA_DCR_DSIZE(0);
  700. } else if (len == 2) {
  701. CFG->DCR = dcr | DMA_DCR_DSIZE(2) | DMA_DCR_DSIZE(2);
  702. } else {
  703. CFG->DCR = dcr | DMA_DCR_DSIZE(1) | DMA_DCR_DSIZE(1);
  704. }
  705. }
  706. // Set the number of transfers (number of triggers until complete)
  707. void transferCount(unsigned int len) {
  708. uint32_t s, d, n = 0; // 0 = 8 bit, 1 = 16 bit, 2 = 32 bit
  709. uint32_t dcr = CFG->DCR;
  710. s = (dcr >> 20) & 3;
  711. d = (dcr >> 17) & 3;
  712. if (s == 0 || d == 0) n = 2;
  713. else if (s == 2 || d == 2) n = 1;
  714. CFG->DSR_BCR = len << n;
  715. }
  716. /*************************************************/
  717. /** Special Options / Features **/
  718. /*************************************************/
  719. void interruptAtCompletion(void) {
  720. CFG->DCR |= DMA_DCR_EINT;
  721. }
  722. void disableOnCompletion(void) {
  723. CFG->DCR |= DMA_DCR_D_REQ;
  724. }
  725. // Kinetis-L DMA does not have these features :-(
  726. //
  727. // void interruptAtHalf(void) {}
  728. // void replaceSettingsOnCompletion(const DMABaseClass &settings) {};
  729. // TODO: can a 2nd linked channel be used to emulate this?
  730. protected:
  731. // users should not be able to create instances of DMABaseClass, which
  732. // require the inheriting class to initialize the TCD pointer.
  733. DMABaseClass() {}
  734. static inline void copy_cfg(CFG_t *dst, const CFG_t *src) {
  735. dst->SAR = src->SAR;
  736. dst->DAR = src->DAR;
  737. dst->DSR_BCR = src->DSR_BCR;
  738. dst->DCR = src->DCR;
  739. }
  740. private:
  741. static inline uint32_t len2mod(uint32_t len) {
  742. if (len < 16) return 0;
  743. if (len < 32) return 1;
  744. if (len < 64) return 2;
  745. if (len < 128) return 3;
  746. if (len < 256) return 4;
  747. if (len < 512) return 5;
  748. if (len < 1024) return 6;
  749. if (len < 2048) return 7;
  750. if (len < 4096) return 8;
  751. if (len < 8192) return 9;
  752. if (len < 16384) return 10;
  753. if (len < 32768) return 11;
  754. if (len < 65536) return 12;
  755. if (len < 131072) return 13;
  756. if (len < 262144) return 14;
  757. return 15;
  758. }
  759. };
  760. // DMASetting represents settings stored only in memory, which can be
  761. // applied to any DMA channel.
  762. class DMASetting : public DMABaseClass {
  763. public:
  764. DMASetting() {
  765. cfgdata.SAR = NULL;
  766. cfgdata.DAR = NULL;
  767. cfgdata.DSR_BCR = 0;
  768. cfgdata.DCR = DMA_DCR_CS;
  769. CFG = &cfgdata;
  770. }
  771. DMASetting(const DMASetting &c) {
  772. CFG = &cfgdata;
  773. *this = c;
  774. }
  775. DMASetting(const DMABaseClass &c) {
  776. CFG = &cfgdata;
  777. *this = c;
  778. }
  779. DMASetting & operator = (const DMABaseClass &rhs) {
  780. copy_cfg(CFG, rhs.CFG);
  781. return *this;
  782. }
  783. private:
  784. CFG_t cfgdata __attribute__((aligned(4)));
  785. };
  786. // DMAChannel reprents an actual DMA channel and its current settings
  787. class DMAChannel : public DMABaseClass {
  788. public:
  789. /*************************************************/
  790. /** Channel Allocation **/
  791. /*************************************************/
  792. DMAChannel() {
  793. begin();
  794. }
  795. DMAChannel(const DMAChannel &c) {
  796. CFG = c.CFG;
  797. channel = c.channel;
  798. }
  799. DMAChannel(const DMASetting &c) {
  800. begin();
  801. copy_cfg(CFG, c.CFG);
  802. }
  803. DMAChannel(bool allocate) {
  804. if (allocate) begin();
  805. }
  806. DMAChannel & operator = (const DMAChannel &rhs) {
  807. if (channel != rhs.channel) {
  808. release();
  809. CFG = rhs.CFG;
  810. channel = rhs.channel;
  811. }
  812. return *this;
  813. }
  814. DMAChannel & operator = (const DMASetting &rhs) {
  815. copy_cfg(CFG, rhs.CFG);
  816. return *this;
  817. }
  818. ~DMAChannel() {
  819. release();
  820. }
  821. void begin(bool force_initialization = false);
  822. private:
  823. void release(void);
  824. public:
  825. /***************************************/
  826. /** Triggering **/
  827. /***************************************/
  828. // Triggers cause the DMA channel to actually move data. Each
  829. // trigger moves a single data unit, which is typically 8, 16 or
  830. // 32 bits. If a channel is configured for 200 transfers
  831. // Use a hardware trigger to make the DMA channel run
  832. void triggerAtHardwareEvent(uint8_t source) {
  833. volatile uint8_t *mux;
  834. CFG->DCR |= DMA_DCR_CS;
  835. mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
  836. *mux = 0;
  837. *mux = (source & 63) | DMAMUX_ENABLE;
  838. }
  839. // Use another DMA channel as the trigger, causing this
  840. // channel to trigger after each transfer is makes, including
  841. // the its last transfer. This effectively makes the 2
  842. // channels run in parallel. Note, on Teensy 3.0 & 3.1,
  843. // this feature triggers on every transfer except the last.
  844. // On Teensy-LC, it triggers on every one, including the last.
  845. void triggerAtTransfersOf(DMABaseClass &ch) {
  846. uint32_t dcr = ch.CFG->DCR;
  847. uint32_t linkcc = (dcr >> 4) & 3;
  848. if (linkcc == 0 || linkcc == 2) {
  849. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  850. DMA_DCR_LINKCC(2) | DMA_DCR_LCH1(channel);
  851. } else if (linkcc == 1) {
  852. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  853. DMA_DCR_LCH1(channel);
  854. } else {
  855. uint32_t lch1 = (dcr >> 2) & 3;
  856. ch.CFG->DCR = (dcr
  857. & ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3) | DMA_DCR_LCH1(3)))
  858. | DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(lch1) | DMA_DCR_LCH1(channel);
  859. }
  860. }
  861. // Use another DMA channel as the trigger, causing this
  862. // channel to trigger when the other channel completes.
  863. void triggerAtCompletionOf(DMABaseClass &ch) {
  864. uint32_t dcr = ch.CFG->DCR;
  865. uint32_t linkcc = (dcr >> 4) & 3;
  866. if (linkcc == 0 || linkcc == 3) {
  867. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  868. DMA_DCR_LINKCC(3) | DMA_DCR_LCH1(channel);
  869. } else {
  870. ch.CFG->DCR = (dcr
  871. & ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3)))
  872. | DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(channel);
  873. }
  874. }
  875. // Cause this DMA channel to be continuously triggered, so
  876. // it will move data as rapidly as possible, without waiting.
  877. // Normally this would be used with disableOnCompletion().
  878. void triggerContinuously(void) {
  879. uint32_t dcr = CFG->DCR;
  880. dcr &= ~(DMA_DCR_ERQ | DMA_DCR_CS);
  881. CFG->DCR = dcr;
  882. CFG->DCR = dcr | DMA_DCR_START;
  883. }
  884. // Manually trigger the DMA channel.
  885. void triggerManual(void) {
  886. CFG->DCR = (CFG->DCR & ~DMA_DCR_ERQ) | (DMA_DCR_CS | DMA_DCR_START);
  887. }
  888. /***************************************/
  889. /** Interrupts **/
  890. /***************************************/
  891. // An interrupt routine can be run when the DMA channel completes
  892. // the entire transfer, and also optionally when half of the
  893. // transfer is completed.
  894. void attachInterrupt(void (*isr)(void)) {
  895. _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
  896. NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel);
  897. }
  898. void detachInterrupt(void) {
  899. NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel);
  900. }
  901. void clearInterrupt(void) {
  902. CFG->DSR_BCR = DMA_DSR_BCR_DONE;
  903. }
  904. /***************************************/
  905. /** Enable / Disable **/
  906. /***************************************/
  907. void enable(void) {
  908. CFG->DCR |= DMA_DCR_ERQ;
  909. }
  910. void disable(void) {
  911. CFG->DCR &= ~DMA_DCR_ERQ;
  912. }
  913. /***************************************/
  914. /** Status **/
  915. /***************************************/
  916. bool complete(void) {
  917. if (CFG->DSR_BCR & DMA_DSR_BCR_DONE) return true;
  918. return false;
  919. }
  920. void clearComplete(void) {
  921. CFG->DSR_BCR |= DMA_DSR_BCR_DONE;
  922. }
  923. bool error(void) {
  924. if (CFG->DSR_BCR &
  925. (DMA_DSR_BCR_CE | DMA_DSR_BCR_BES | DMA_DSR_BCR_BED)) return true;
  926. return false;
  927. }
  928. void clearError(void) {
  929. CFG->DSR_BCR |= DMA_DSR_BCR_DONE;
  930. }
  931. void * sourceAddress(void) {
  932. return (void *)(CFG->SAR);
  933. }
  934. void * destinationAddress(void) {
  935. return (void *)(CFG->DAR);
  936. }
  937. /***************************************/
  938. /** Direct Hardware Access **/
  939. /***************************************/
  940. uint8_t channel;
  941. // CFG is accessible due to inheritance from DMABaseClass
  942. };
  943. // arrange the relative priority of 2 or more DMA channels
  944. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2);
  945. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3);
  946. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4);
  947. #endif // KINETISL
  948. #endif // __cplusplus
  949. #endif // DMAChannel_h_