Teensy 4.1 core updated for C++20
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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