Teensy 4.1 core updated for C++20
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

1120 lines
35KB

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