You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 7 години
преди 10 години
преди 10 години
преди 9 години
преди 9 години
преди 9 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 7 години
преди 7 години
преди 5 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 9 години
преди 10 години
преди 10 години
преди 9 години
преди 10 години
преди 9 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  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_