Teensy 4.1 core updated for C++20
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

1108 Zeilen
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 detachInterrupt(void) {
  491. NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel);
  492. }
  493. void clearInterrupt(void) {
  494. DMA_CINT = channel;
  495. }
  496. /***************************************/
  497. /** Enable / Disable **/
  498. /***************************************/
  499. void enable(void) {
  500. DMA_SERQ = channel;
  501. }
  502. void disable(void) {
  503. DMA_CERQ = channel;
  504. }
  505. /***************************************/
  506. /** Status **/
  507. /***************************************/
  508. bool complete(void) {
  509. if (TCD->CSR & DMA_TCD_CSR_DONE) return true;
  510. return false;
  511. }
  512. void clearComplete(void) {
  513. DMA_CDNE = channel;
  514. }
  515. bool error(void) {
  516. if (DMA_ERR & (1<<channel)) return true;
  517. return false;
  518. }
  519. void clearError(void) {
  520. DMA_CERR = channel;
  521. }
  522. void * sourceAddress(void) {
  523. return (void *)(TCD->SADDR);
  524. }
  525. void * destinationAddress(void) {
  526. return (void *)(TCD->DADDR);
  527. }
  528. /***************************************/
  529. /** Direct Hardware Access **/
  530. /***************************************/
  531. // For complex and unusual configurations not possible with the above
  532. // functions, the Transfer Control Descriptor (TCD) and channel number
  533. // can be used directly. This leads to less portable and less readable
  534. // code, but direct control of all parameters is possible.
  535. uint8_t channel;
  536. // TCD is accessible due to inheritance from DMABaseClass
  537. };
  538. // arrange the relative priority of 2 or more DMA channels
  539. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2);
  540. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3);
  541. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4);
  542. /****************************************************************/
  543. /** Teensy-LC **/
  544. /****************************************************************/
  545. #elif defined(KINETISL)
  546. class DMABaseClass {
  547. public:
  548. typedef struct __attribute__((packed, aligned(4))) {
  549. volatile const void * volatile SAR;
  550. volatile void * volatile DAR;
  551. volatile uint32_t DSR_BCR;
  552. volatile uint32_t DCR;
  553. } CFG_t;
  554. CFG_t *CFG;
  555. /***************************************/
  556. /** Data Transfer **/
  557. /***************************************/
  558. // Use a single variable as the data source. Typically a register
  559. // for receiving data from one of the hardware peripherals is used.
  560. void source(volatile const signed char &p) { source(*(volatile const uint8_t *)&p); }
  561. void source(volatile const unsigned char &p) {
  562. CFG->SAR = &p;
  563. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1);
  564. }
  565. void source(volatile const signed short &p) { source(*(volatile const uint16_t *)&p); }
  566. void source(volatile const unsigned short &p) {
  567. CFG->SAR = &p;
  568. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2);
  569. }
  570. void source(volatile const signed int &p) { source(*(volatile const uint32_t *)&p); }
  571. void source(volatile const unsigned int &p) { source(*(volatile const uint32_t *)&p); }
  572. void source(volatile const signed long &p) { source(*(volatile const uint32_t *)&p); }
  573. void source(volatile const unsigned long &p) {
  574. CFG->SAR = &p;
  575. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0);
  576. }
  577. // Use a buffer (array of data) as the data source. Typically a
  578. // buffer for transmitting data is used.
  579. void sourceBuffer(volatile const signed char p[], unsigned int len) {
  580. sourceBuffer((volatile const uint8_t *)p, len); }
  581. void sourceBuffer(volatile const unsigned char p[], unsigned int len) {
  582. if (len > 0xFFFFF) return;
  583. CFG->SAR = p;
  584. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC;
  585. CFG->DSR_BCR = len;
  586. }
  587. void sourceBuffer(volatile const signed short p[], unsigned int len) {
  588. sourceBuffer((volatile const uint16_t *)p, len); }
  589. void sourceBuffer(volatile const unsigned short p[], unsigned int len) {
  590. if (len > 0xFFFFF) return;
  591. CFG->SAR = p;
  592. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC;
  593. CFG->DSR_BCR = len;
  594. }
  595. void sourceBuffer(volatile const signed int p[], unsigned int len) {
  596. sourceBuffer((volatile const uint32_t *)p, len); }
  597. void sourceBuffer(volatile const unsigned int p[], unsigned int len) {
  598. sourceBuffer((volatile const uint32_t *)p, len); }
  599. void sourceBuffer(volatile const signed long p[], unsigned int len) {
  600. sourceBuffer((volatile const uint32_t *)p, len); }
  601. void sourceBuffer(volatile const unsigned long p[], unsigned int len) {
  602. if (len > 0xFFFFF) return;
  603. CFG->SAR = p;
  604. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC;
  605. CFG->DSR_BCR = len;
  606. }
  607. // Use a circular buffer as the data source
  608. void sourceCircular(volatile const signed char p[], unsigned int len) {
  609. sourceCircular((volatile const uint8_t *)p, len); }
  610. void sourceCircular(volatile const unsigned char p[], unsigned int len) {
  611. uint32_t mod = len2mod(len);
  612. if (mod == 0) return;
  613. CFG->SAR = p;
  614. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(1) | DMA_DCR_SINC
  615. | DMA_DCR_SMOD(mod);
  616. CFG->DSR_BCR = len;
  617. }
  618. void sourceCircular(volatile const signed short p[], unsigned int len) {
  619. sourceCircular((volatile const uint16_t *)p, len); }
  620. void sourceCircular(volatile const unsigned short p[], unsigned int len) {
  621. uint32_t mod = len2mod(len);
  622. if (mod == 0) return;
  623. CFG->SAR = p;
  624. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(2) | DMA_DCR_SINC
  625. | DMA_DCR_SMOD(mod);
  626. CFG->DSR_BCR = len;
  627. }
  628. void sourceCircular(volatile const signed int p[], unsigned int len) {
  629. sourceCircular((volatile const uint32_t *)p, len); }
  630. void sourceCircular(volatile const unsigned int p[], unsigned int len) {
  631. sourceCircular((volatile const uint32_t *)p, len); }
  632. void sourceCircular(volatile const signed long p[], unsigned int len) {
  633. sourceCircular((volatile const uint32_t *)p, len); }
  634. void sourceCircular(volatile const unsigned long p[], unsigned int len) {
  635. uint32_t mod = len2mod(len);
  636. if (mod == 0) return;
  637. CFG->SAR = p;
  638. CFG->DCR = (CFG->DCR & 0xF08E0FFF) | DMA_DCR_SSIZE(0) | DMA_DCR_SINC
  639. | DMA_DCR_SMOD(mod);
  640. CFG->DSR_BCR = len;
  641. }
  642. // Use a single variable as the data destination. Typically a register
  643. // for transmitting data to one of the hardware peripherals is used.
  644. void destination(volatile signed char &p) { destination(*(volatile uint8_t *)&p); }
  645. void destination(volatile unsigned char &p) {
  646. CFG->DAR = &p;
  647. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1);
  648. }
  649. void destination(volatile signed short &p) { destination(*(volatile uint16_t *)&p); }
  650. void destination(volatile unsigned short &p) {
  651. CFG->DAR = &p;
  652. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2);
  653. }
  654. void destination(volatile signed int &p) { destination(*(volatile uint32_t *)&p); }
  655. void destination(volatile unsigned int &p) { destination(*(volatile uint32_t *)&p); }
  656. void destination(volatile signed long &p) { destination(*(volatile uint32_t *)&p); }
  657. void destination(volatile unsigned long &p) {
  658. CFG->DAR = &p;
  659. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0);
  660. }
  661. // Use a buffer (array of data) as the data destination. Typically a
  662. // buffer for receiving data is used.
  663. void destinationBuffer(volatile signed char p[], unsigned int len) {
  664. destinationBuffer((volatile uint8_t *)p, len); }
  665. void destinationBuffer(volatile unsigned char p[], unsigned int len) {
  666. CFG->DAR = p;
  667. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC;
  668. CFG->DSR_BCR = len;
  669. }
  670. void destinationBuffer(volatile signed short p[], unsigned int len) {
  671. destinationBuffer((volatile uint16_t *)p, len); }
  672. void destinationBuffer(volatile unsigned short p[], unsigned int len) {
  673. CFG->DAR = p;
  674. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2) | DMA_DCR_DINC;
  675. CFG->DSR_BCR = len;
  676. }
  677. void destinationBuffer(volatile signed int p[], unsigned int len) {
  678. destinationBuffer((volatile uint32_t *)p, len); }
  679. void destinationBuffer(volatile unsigned int p[], unsigned int len) {
  680. destinationBuffer((volatile uint32_t *)p, len); }
  681. void destinationBuffer(volatile signed long p[], unsigned int len) {
  682. destinationBuffer((volatile uint32_t *)p, len); }
  683. void destinationBuffer(volatile unsigned long p[], unsigned int len) {
  684. CFG->DAR = p;
  685. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0) | DMA_DCR_DINC;
  686. CFG->DSR_BCR = len;
  687. }
  688. // Use a circular buffer as the data destination
  689. void destinationCircular(volatile signed char p[], unsigned int len) {
  690. destinationCircular((volatile uint8_t *)p, len); }
  691. void destinationCircular(volatile unsigned char p[], unsigned int len) {
  692. uint32_t mod = len2mod(len);
  693. if (mod == 0) return;
  694. CFG->DAR = p;
  695. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(1) | DMA_DCR_DINC
  696. | DMA_DCR_DMOD(mod);
  697. CFG->DSR_BCR = len;
  698. }
  699. void destinationCircular(volatile signed short p[], unsigned int len) {
  700. destinationCircular((volatile uint16_t *)p, len); }
  701. void destinationCircular(volatile unsigned short p[], unsigned int len) {
  702. uint32_t mod = len2mod(len);
  703. if (mod == 0) return;
  704. CFG->DAR = p;
  705. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(2) | DMA_DCR_DINC
  706. | DMA_DCR_DMOD(mod);
  707. CFG->DSR_BCR = len;
  708. }
  709. void destinationCircular(volatile signed int p[], unsigned int len) {
  710. destinationCircular((volatile uint32_t *)p, len); }
  711. void destinationCircular(volatile unsigned int p[], unsigned int len) {
  712. destinationCircular((volatile uint32_t *)p, len); }
  713. void destinationCircular(volatile signed long p[], unsigned int len) {
  714. destinationCircular((volatile uint32_t *)p, len); }
  715. void destinationCircular(volatile unsigned long p[], unsigned int len) {
  716. uint32_t mod = len2mod(len);
  717. if (mod == 0) return;
  718. CFG->DAR = p;
  719. CFG->DCR = (CFG->DCR & 0xF0F0F0FF) | DMA_DCR_DSIZE(0) | DMA_DCR_DINC
  720. | DMA_DCR_DMOD(mod);
  721. CFG->DSR_BCR = len;
  722. }
  723. /*************************************************/
  724. /** Quantity of Data to Transfer **/
  725. /*************************************************/
  726. // Set the data size used for each triggered transfer
  727. void transferSize(unsigned int len) {
  728. uint32_t dcr = CFG->DCR & 0xF0C8FFFF;
  729. if (len == 4) {
  730. CFG->DCR = dcr | DMA_DCR_SSIZE(0) | DMA_DCR_DSIZE(0);
  731. } else if (len == 2) {
  732. CFG->DCR = dcr | DMA_DCR_SSIZE(2) | DMA_DCR_DSIZE(2);
  733. } else {
  734. CFG->DCR = dcr | DMA_DCR_SSIZE(1) | DMA_DCR_DSIZE(1);
  735. }
  736. }
  737. // Set the number of transfers (number of triggers until complete)
  738. void transferCount(unsigned int len) {
  739. uint32_t s, d, n = 0; // 0 = 8 bit, 1 = 16 bit, 2 = 32 bit
  740. uint32_t dcr = CFG->DCR;
  741. s = (dcr >> 20) & 3;
  742. d = (dcr >> 17) & 3;
  743. if (s == 0 || d == 0) n = 2;
  744. else if (s == 2 || d == 2) n = 1;
  745. CFG->DSR_BCR = len << n;
  746. }
  747. /*************************************************/
  748. /** Special Options / Features **/
  749. /*************************************************/
  750. void interruptAtCompletion(void) {
  751. CFG->DCR |= DMA_DCR_EINT;
  752. }
  753. void disableOnCompletion(void) {
  754. CFG->DCR |= DMA_DCR_D_REQ;
  755. }
  756. // Kinetis-L DMA does not have these features :-(
  757. //
  758. // void interruptAtHalf(void) {}
  759. // void replaceSettingsOnCompletion(const DMABaseClass &settings) {};
  760. // TODO: can a 2nd linked channel be used to emulate this?
  761. protected:
  762. // users should not be able to create instances of DMABaseClass, which
  763. // require the inheriting class to initialize the TCD pointer.
  764. DMABaseClass() {}
  765. static inline void copy_cfg(CFG_t *dst, const CFG_t *src) {
  766. dst->SAR = src->SAR;
  767. dst->DAR = src->DAR;
  768. dst->DSR_BCR = src->DSR_BCR;
  769. dst->DCR = src->DCR;
  770. }
  771. private:
  772. static inline uint32_t len2mod(uint32_t len) {
  773. if (len < 16) return 0;
  774. if (len < 32) return 1;
  775. if (len < 64) return 2;
  776. if (len < 128) return 3;
  777. if (len < 256) return 4;
  778. if (len < 512) return 5;
  779. if (len < 1024) return 6;
  780. if (len < 2048) return 7;
  781. if (len < 4096) return 8;
  782. if (len < 8192) return 9;
  783. if (len < 16384) return 10;
  784. if (len < 32768) return 11;
  785. if (len < 65536) return 12;
  786. if (len < 131072) return 13;
  787. if (len < 262144) return 14;
  788. return 15;
  789. }
  790. };
  791. // DMASetting represents settings stored only in memory, which can be
  792. // applied to any DMA channel.
  793. class DMASetting : public DMABaseClass {
  794. public:
  795. DMASetting() {
  796. cfgdata.SAR = NULL;
  797. cfgdata.DAR = NULL;
  798. cfgdata.DSR_BCR = 0;
  799. cfgdata.DCR = DMA_DCR_CS;
  800. CFG = &cfgdata;
  801. }
  802. DMASetting(const DMASetting &c) {
  803. CFG = &cfgdata;
  804. *this = c;
  805. }
  806. DMASetting(const DMABaseClass &c) {
  807. CFG = &cfgdata;
  808. *this = c;
  809. }
  810. DMASetting & operator = (const DMABaseClass &rhs) {
  811. copy_cfg(CFG, rhs.CFG);
  812. return *this;
  813. }
  814. private:
  815. CFG_t cfgdata __attribute__((aligned(4)));
  816. };
  817. // DMAChannel reprents an actual DMA channel and its current settings
  818. class DMAChannel : public DMABaseClass {
  819. public:
  820. /*************************************************/
  821. /** Channel Allocation **/
  822. /*************************************************/
  823. DMAChannel() {
  824. begin();
  825. }
  826. DMAChannel(const DMAChannel &c) {
  827. CFG = c.CFG;
  828. channel = c.channel;
  829. }
  830. DMAChannel(const DMASetting &c) {
  831. begin();
  832. copy_cfg(CFG, c.CFG);
  833. }
  834. DMAChannel(bool allocate) {
  835. if (allocate) begin();
  836. }
  837. DMAChannel & operator = (const DMAChannel &rhs) {
  838. if (channel != rhs.channel) {
  839. release();
  840. CFG = rhs.CFG;
  841. channel = rhs.channel;
  842. }
  843. return *this;
  844. }
  845. DMAChannel & operator = (const DMASetting &rhs) {
  846. copy_cfg(CFG, rhs.CFG);
  847. return *this;
  848. }
  849. ~DMAChannel() {
  850. release();
  851. }
  852. void begin(bool force_initialization = false);
  853. private:
  854. void release(void);
  855. public:
  856. /***************************************/
  857. /** Triggering **/
  858. /***************************************/
  859. // Triggers cause the DMA channel to actually move data. Each
  860. // trigger moves a single data unit, which is typically 8, 16 or
  861. // 32 bits. If a channel is configured for 200 transfers
  862. // Use a hardware trigger to make the DMA channel run
  863. void triggerAtHardwareEvent(uint8_t source) {
  864. volatile uint8_t *mux;
  865. CFG->DCR |= DMA_DCR_CS;
  866. mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
  867. *mux = 0;
  868. *mux = (source & 63) | DMAMUX_ENABLE;
  869. }
  870. // Use another DMA channel as the trigger, causing this
  871. // channel to trigger after each transfer is makes, including
  872. // the its last transfer. This effectively makes the 2
  873. // channels run in parallel. Note, on Teensy 3.0 & 3.1,
  874. // this feature triggers on every transfer except the last.
  875. // On Teensy-LC, it triggers on every one, including the last.
  876. void triggerAtTransfersOf(DMABaseClass &ch) {
  877. uint32_t dcr = ch.CFG->DCR;
  878. uint32_t linkcc = (dcr >> 4) & 3;
  879. if (linkcc == 0 || linkcc == 2) {
  880. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  881. DMA_DCR_LINKCC(2) | DMA_DCR_LCH1(channel);
  882. } else if (linkcc == 1) {
  883. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  884. DMA_DCR_LCH1(channel);
  885. } else {
  886. uint32_t lch1 = (dcr >> 2) & 3;
  887. ch.CFG->DCR = (dcr
  888. & ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3) | DMA_DCR_LCH1(3)))
  889. | DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(lch1) | DMA_DCR_LCH1(channel);
  890. }
  891. }
  892. // Use another DMA channel as the trigger, causing this
  893. // channel to trigger when the other channel completes.
  894. void triggerAtCompletionOf(DMABaseClass &ch) {
  895. uint32_t dcr = ch.CFG->DCR;
  896. uint32_t linkcc = (dcr >> 4) & 3;
  897. if (linkcc == 0 || linkcc == 3) {
  898. ch.CFG->DCR = (dcr & ~DMA_DCR_LCH1(3)) |
  899. DMA_DCR_LINKCC(3) | DMA_DCR_LCH1(channel);
  900. } else {
  901. ch.CFG->DCR = (dcr
  902. & ~(DMA_DCR_LINKCC(3) | DMA_DCR_LCH2(3)))
  903. | DMA_DCR_LINKCC(1) | DMA_DCR_LCH2(channel);
  904. }
  905. }
  906. // Cause this DMA channel to be continuously triggered, so
  907. // it will move data as rapidly as possible, without waiting.
  908. // Normally this would be used with disableOnCompletion().
  909. void triggerContinuously(void) {
  910. uint32_t dcr = CFG->DCR;
  911. dcr &= ~(DMA_DCR_ERQ | DMA_DCR_CS);
  912. CFG->DCR = dcr;
  913. CFG->DCR = dcr | DMA_DCR_START;
  914. }
  915. // Manually trigger the DMA channel.
  916. void triggerManual(void) {
  917. CFG->DCR = (CFG->DCR & ~DMA_DCR_ERQ) | (DMA_DCR_CS | DMA_DCR_START);
  918. }
  919. /***************************************/
  920. /** Interrupts **/
  921. /***************************************/
  922. // An interrupt routine can be run when the DMA channel completes
  923. // the entire transfer, and also optionally when half of the
  924. // transfer is completed.
  925. void attachInterrupt(void (*isr)(void)) {
  926. _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
  927. NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel);
  928. }
  929. void detachInterrupt(void) {
  930. NVIC_DISABLE_IRQ(IRQ_DMA_CH0 + channel);
  931. }
  932. void clearInterrupt(void) {
  933. CFG->DSR_BCR = DMA_DSR_BCR_DONE;
  934. }
  935. /***************************************/
  936. /** Enable / Disable **/
  937. /***************************************/
  938. void enable(void) {
  939. CFG->DCR |= DMA_DCR_ERQ;
  940. }
  941. void disable(void) {
  942. CFG->DCR &= ~DMA_DCR_ERQ;
  943. }
  944. /***************************************/
  945. /** Status **/
  946. /***************************************/
  947. bool complete(void) {
  948. if (CFG->DSR_BCR & DMA_DSR_BCR_DONE) return true;
  949. return false;
  950. }
  951. void clearComplete(void) {
  952. CFG->DSR_BCR |= DMA_DSR_BCR_DONE;
  953. }
  954. bool error(void) {
  955. if (CFG->DSR_BCR &
  956. (DMA_DSR_BCR_CE | DMA_DSR_BCR_BES | DMA_DSR_BCR_BED)) return true;
  957. return false;
  958. }
  959. void clearError(void) {
  960. CFG->DSR_BCR |= DMA_DSR_BCR_DONE;
  961. }
  962. void * sourceAddress(void) {
  963. return (void *)(CFG->SAR);
  964. }
  965. void * destinationAddress(void) {
  966. return (void *)(CFG->DAR);
  967. }
  968. /***************************************/
  969. /** Direct Hardware Access **/
  970. /***************************************/
  971. uint8_t channel;
  972. // CFG is accessible due to inheritance from DMABaseClass
  973. };
  974. // arrange the relative priority of 2 or more DMA channels
  975. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2);
  976. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3);
  977. void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2, DMAChannel &ch3, DMAChannel &ch4);
  978. #endif // KINETISL
  979. #endif // __cplusplus
  980. #endif // DMAChannel_h_