Teensy 4.1 core updated for C++20
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.

преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. #ifndef DMAChannel_h_
  2. #define DMAChannel_h_
  3. #include "mk20dx128.h"
  4. // This code is a work-in-progress. It's incomplete and not usable yet...
  5. //
  6. // http://forum.pjrc.com/threads/25778-Could-there-be-something-like-an-ISR-template-function/page3
  7. // known libraries with DMA usage (in need of porting to this new scheme):
  8. //
  9. // https://github.com/PaulStoffregen/Audio
  10. // https://github.com/PaulStoffregen/OctoWS2811
  11. // https://github.com/pedvide/ADC
  12. // https://github.com/duff2013/SerialEvent
  13. // https://github.com/pixelmatix/SmartMatrix
  14. // https://github.com/crteensy/DmaSpi
  15. #ifdef __cplusplus
  16. class DMAChannel {
  17. typedef struct __attribute__((packed)) {
  18. volatile const void * volatile SADDR;
  19. int16_t SOFF;
  20. union { uint16_t ATTR; struct { uint8_t ATTR_DST; uint8_t ATTR_SRC; }; };
  21. uint32_t NBYTES;
  22. int32_t SLAST;
  23. volatile void * volatile DADDR;
  24. int16_t DOFF;
  25. volatile uint16_t CITER;
  26. int32_t DLASTSGA;
  27. volatile uint16_t CSR;
  28. volatile uint16_t BITER;
  29. } TCD_t;
  30. public:
  31. /*************************************************/
  32. /** Channel Allocation **/
  33. /*************************************************/
  34. // Constructor - allocates which DMA channel each object actually uses
  35. DMAChannel(uint8_t channelRequest=0);
  36. // TODO: should the copy constructor be private?
  37. /***************************************/
  38. /** Triggering **/
  39. /***************************************/
  40. // Triggers cause the DMA channel to actually move data.
  41. // Use a hardware trigger to make the DMA channel run
  42. void attachTrigger(uint8_t source) {
  43. volatile uint8_t *mux;
  44. mux = (volatile uint8_t *)&(DMAMUX0_CHCFG0) + channel;
  45. *mux = 0;
  46. *mux = source | DMAMUX_ENABLE;
  47. }
  48. // Use another DMA channel as the trigger, causing this
  49. // channel to trigger every time it triggers. This
  50. // effectively makes the 2 channels run in parallel.
  51. void attachTrigger(DMAChannel &channel) {
  52. }
  53. // Use another DMA channel as the trigger, causing this
  54. // channel to trigger when the other channel completes.
  55. void attachTriggerOnCompletion(DMAChannel &channel) {
  56. }
  57. void attachTriggerContinuous(DMAChannel &channel) {
  58. }
  59. // Manually trigger the DMA channel.
  60. void trigger(void) {
  61. }
  62. /***************************************/
  63. /** Interrupts **/
  64. /***************************************/
  65. // An interrupt routine can be run when the DMA channel completes
  66. // the entire transfer.
  67. void attachInterrupt(void (*isr)(void)) {
  68. _VectorsRam[channel + IRQ_DMA_CH0 + 16] = isr;
  69. NVIC_ENABLE_IRQ(IRQ_DMA_CH0 + channel);
  70. }
  71. void interruptAtHalf(void) {
  72. }
  73. void clearInterrupt(void) {
  74. }
  75. /***************************************/
  76. /** Enable / Disable **/
  77. /***************************************/
  78. void enable(void) {
  79. }
  80. void disable(void) {
  81. }
  82. void disableOnCompletion(void) {
  83. }
  84. /***************************************/
  85. /** Data Transfer **/
  86. /***************************************/
  87. // Use a single variable as the data source. Typically a register
  88. // for receiving data from one of the hardware peripherals is used.
  89. void source(const signed char &p) { source(*(const uint8_t *)&p); }
  90. void source(const unsigned char &p) {
  91. TCD.SADDR = &p;
  92. TCD.SOFF = 0;
  93. TCD.ATTR_SRC = 0;
  94. if ((uint32_t)p < 0x40000000 || TCD.NBYTES == 0) TCD.NBYTES = 1;
  95. TCD.SLAST = 0;
  96. }
  97. void source(const signed short &p) { source(*(const uint16_t *)&p); }
  98. void source(const unsigned short &p) {
  99. TCD.SADDR = &p;
  100. TCD.SOFF = 0;
  101. TCD.ATTR_SRC = 1;
  102. if ((uint32_t)p < 0x40000000 || TCD.NBYTES == 0) TCD.NBYTES = 2;
  103. TCD.SLAST = 0;
  104. }
  105. void source(const signed int &p) { source(*(const uint32_t *)&p); }
  106. void source(const unsigned int &p) { source(*(const uint32_t *)&p); }
  107. void source(const signed long &p) { source(*(const uint32_t *)&p); }
  108. void source(const unsigned long &p) {
  109. TCD.SADDR = &p;
  110. TCD.SOFF = 0;
  111. TCD.ATTR_SRC = 2;
  112. if ((uint32_t)p < 0x40000000 || TCD.NBYTES == 0) TCD.NBYTES = 4;
  113. TCD.SLAST = 0;
  114. }
  115. // Use a buffer (array of data) as the data source. Typically a
  116. // buffer for transmitting data is used.
  117. void sourceBuffer(const signed char p[], unsigned int len) { sourceBuffer((uint8_t *)p, len); }
  118. void sourceBuffer(const unsigned char p[], unsigned int len) {
  119. TCD.SADDR = p;
  120. TCD.SOFF = 1;
  121. TCD.ATTR_SRC = 0;
  122. TCD.NBYTES = 1;
  123. TCD.SLAST = -len;
  124. TCD.BITER = len;
  125. TCD.CITER = len;
  126. }
  127. void sourceBuffer(const signed short p[], unsigned int len) { sourceBuffer((uint16_t *)p, len); }
  128. void sourceBuffer(const unsigned short p[], unsigned int len) {
  129. TCD.SADDR = p;
  130. TCD.SOFF = 2;
  131. TCD.ATTR_SRC = 1;
  132. TCD.NBYTES = 2;
  133. TCD.SLAST = -len;
  134. TCD.BITER = len / 2;
  135. TCD.CITER = len / 2;
  136. }
  137. void sourceBuffer(const signed int p[], unsigned int len) { sourceBuffer((uint32_t *)p, len); }
  138. void sourceBuffer(const unsigned int p[], unsigned int len) {sourceBuffer((uint32_t *)p, len); }
  139. void sourceBuffer(const signed long p[], unsigned int len) { sourceBuffer((uint32_t *)p, len); }
  140. void sourceBuffer(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(const signed char p[], unsigned int len) { sourceCircular((uint8_t *)p, len); }
  151. void sourceCircular(const unsigned char p[], unsigned int len) {
  152. TCD.SADDR = p;
  153. TCD.SOFF = 1;
  154. TCD.ATTR_SRC = ((31 - __builtin_clz(len)) << 3);
  155. TCD.NBYTES = 1;
  156. TCD.SLAST = 0;
  157. TCD.BITER = len;
  158. TCD.CITER = len;
  159. }
  160. void sourceCircular(const signed short p[], unsigned int len) { sourceCircular((uint16_t *)p, len); }
  161. void sourceCircular(const unsigned short p[], unsigned int len) {
  162. TCD.SADDR = p;
  163. TCD.SOFF = 2;
  164. TCD.ATTR_SRC = ((31 - __builtin_clz(len)) << 3) | 1;
  165. TCD.NBYTES = 2;
  166. TCD.SLAST = 0;
  167. TCD.BITER = len / 2;
  168. TCD.CITER = len / 2;
  169. }
  170. void sourceCircular(const signed int p[], unsigned int len) { sourceCircular((uint32_t *)p, len); }
  171. void sourceCircular(const unsigned int p[], unsigned int len) { sourceCircular((uint32_t *)p, len); }
  172. void sourceCircular(const signed long p[], unsigned int len) { sourceCircular((uint32_t *)p, len); }
  173. void sourceCircular(const unsigned long p[], unsigned int len) {
  174. TCD.SADDR = p;
  175. TCD.SOFF = 4;
  176. TCD.ATTR_SRC = ((31 - __builtin_clz(len)) << 3) | 2;
  177. TCD.NBYTES = 4;
  178. TCD.SLAST = 0;
  179. TCD.BITER = len / 4;
  180. TCD.CITER = len / 4;
  181. }
  182. // Use a single variable as the data destination. Typically a register
  183. // for transmitting data to one of the hardware peripherals is used.
  184. void destination(signed char &p) { destination(*(uint8_t *)&p); }
  185. void destination(unsigned char &p) {
  186. TCD.DADDR = &p;
  187. TCD.DOFF = 0;
  188. TCD.ATTR_DST = 0;
  189. if ((uint32_t)p < 0x40000000 || TCD.NBYTES == 0) TCD.NBYTES = 1;
  190. TCD.DLASTSGA = 0;
  191. }
  192. void destination(signed short &p) { destination(*(uint16_t *)&p); }
  193. void destination(unsigned short &p) {
  194. TCD.DADDR = &p;
  195. TCD.DOFF = 0;
  196. TCD.ATTR_DST = 1;
  197. if ((uint32_t)p < 0x40000000 || TCD.NBYTES == 0) TCD.NBYTES = 2;
  198. TCD.DLASTSGA = 0;
  199. }
  200. void destination(signed int &p) { destination(*(uint32_t *)&p); }
  201. void destination(unsigned int &p) { destination(*(uint32_t *)&p); }
  202. void destination(signed long &p) { destination(*(uint32_t *)&p); }
  203. void destination(unsigned long &p) {
  204. TCD.DADDR = &p;
  205. TCD.DOFF = 0;
  206. TCD.ATTR_DST = 2;
  207. if ((uint32_t)p < 0x40000000 || TCD.NBYTES == 0) TCD.NBYTES = 4;
  208. TCD.DLASTSGA = 0;
  209. }
  210. // Use a buffer (array of data) as the data destination. Typically a
  211. // buffer for receiving data is used.
  212. void destinationBuffer(signed char p[], unsigned int len) { destinationBuffer((uint8_t *)p, len); }
  213. void destinationBuffer(unsigned char p[], unsigned int len) {
  214. TCD.DADDR = p;
  215. TCD.DOFF = 1;
  216. TCD.ATTR_DST = 0;
  217. TCD.NBYTES = 1;
  218. TCD.DLASTSGA = -len;
  219. TCD.BITER = len;
  220. TCD.CITER = len;
  221. }
  222. void destinationBuffer(signed short p[], unsigned int len) { destinationBuffer((uint16_t *)p, len); }
  223. void destinationBuffer(unsigned short p[], unsigned int len) {
  224. TCD.DADDR = p;
  225. TCD.DOFF = 2;
  226. TCD.ATTR_DST = 1;
  227. TCD.NBYTES = 2;
  228. TCD.DLASTSGA = -len;
  229. TCD.BITER = len / 2;
  230. TCD.CITER = len / 2;
  231. }
  232. void destinationBuffer(signed int p[], unsigned int len) { destinationBuffer((uint32_t *)p, len); }
  233. void destinationBuffer(unsigned int p[], unsigned int len) { destinationBuffer((uint32_t *)p, len); }
  234. void destinationBuffer(signed long p[], unsigned int len) { destinationBuffer((uint32_t *)p, len); }
  235. void destinationBuffer(unsigned long p[], unsigned int len) {
  236. TCD.DADDR = p;
  237. TCD.DOFF = 4;
  238. TCD.ATTR_DST = 1;
  239. TCD.NBYTES = 4;
  240. TCD.DLASTSGA = -len;
  241. TCD.BITER = len / 4;
  242. TCD.CITER = len / 4;
  243. }
  244. // Use a circular buffer as the data destination
  245. void destinationCircular(signed char p[], unsigned int len) { destinationCircular((uint8_t *)p, len); }
  246. void destinationCircular(unsigned char p[], unsigned int len) {
  247. TCD.DADDR = p;
  248. TCD.DOFF = 1;
  249. TCD.ATTR_DST = ((31 - __builtin_clz(len)) << 3);
  250. TCD.NBYTES = 1;
  251. TCD.DLASTSGA = 0;
  252. TCD.BITER = len;
  253. TCD.CITER = len;
  254. }
  255. void destinationCircular(signed short p[], unsigned int len) { destinationCircular((uint16_t *)p, len); }
  256. void destinationCircular(unsigned short p[], unsigned int len) {
  257. TCD.DADDR = p;
  258. TCD.DOFF = 2;
  259. TCD.ATTR_DST = ((31 - __builtin_clz(len)) << 3) | 1;
  260. TCD.NBYTES = 2;
  261. TCD.DLASTSGA = 0;
  262. TCD.BITER = len / 2;
  263. TCD.CITER = len / 2;
  264. }
  265. void destinationCircular(signed int p[], unsigned int len) { destinationCircular((uint32_t *)p, len); }
  266. void destinationCircular(unsigned int p[], unsigned int len) { destinationCircular((uint32_t *)p, len); }
  267. void destinationCircular(signed long p[], unsigned int len) { destinationCircular((uint32_t *)p, len); }
  268. void destinationCircular(unsigned long p[], unsigned int len) {
  269. TCD.DADDR = p;
  270. TCD.DOFF = 4;
  271. TCD.ATTR_DST = ((31 - __builtin_clz(len)) << 3) | 2;
  272. TCD.NBYTES = 4;
  273. TCD.DLASTSGA = 0;
  274. TCD.BITER = len / 4;
  275. TCD.CITER = len / 4;
  276. }
  277. // Set the data size used for each triggered transfer
  278. void size(unsigned int len) {
  279. if (len == 4) {
  280. TCD.NBYTES = 4;
  281. if (TCD.SOFF != 0) TCD.SOFF = 4;
  282. if (TCD.DOFF != 0) TCD.DOFF = 4;
  283. TCD.ATTR = (TCD.ATTR & 0xF8F8) | 0x0202;
  284. } else if (len == 2) {
  285. TCD.NBYTES = 2;
  286. if (TCD.SOFF != 0) TCD.SOFF = 2;
  287. if (TCD.DOFF != 0) TCD.DOFF = 2;
  288. TCD.ATTR = (TCD.ATTR & 0xF8F8) | 0x0101;
  289. } else {
  290. TCD.NBYTES = 1;
  291. if (TCD.SOFF != 0) TCD.SOFF = 1;
  292. if (TCD.DOFF != 0) TCD.DOFF = 1;
  293. TCD.ATTR = TCD.ATTR & 0xF8F8;
  294. }
  295. }
  296. // Set the number of transfers (number of triggers until complete)
  297. void count(unsigned int len) {
  298. if (len > 32767) return;
  299. if (len >= 512) {
  300. TCD.BITER = len;
  301. TCD.CITER = len;
  302. } else {
  303. TCD.BITER = (TCD.BITER & 0xFE00) | len;
  304. TCD.CITER = (TCD.CITER & 0xFE00) | len;
  305. }
  306. }
  307. /***************************************/
  308. /** Status **/
  309. /***************************************/
  310. // TODO: "get" functions, to read important stuff, like SADDR & DADDR...
  311. // error status, etc
  312. /***************************************/
  313. /** Direct Hardware Access **/
  314. /***************************************/
  315. // For complex and unusual configurations not possible with the above
  316. // functions, the Transfer Control Descriptor (TCD) and channel number
  317. // can be used directly. This leads to less portable and less readable
  318. // code, but direct control of all parameters is possible.
  319. TCD_t &TCD;
  320. uint8_t channel;
  321. /* usage cases:
  322. ************************
  323. OctoWS2811:
  324. ************************
  325. // enable clocks to the DMA controller and DMAMUX
  326. SIM_SCGC7 |= SIM_SCGC7_DMA;
  327. SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
  328. DMA_CR = 0;
  329. DMA_CERQ = 1;
  330. DMA_CERQ = 2;
  331. DMA_CERQ = 3;
  332. // DMA channel #1 sets WS2811 high at the beginning of each cycle
  333. DMA_TCD1_SADDR = &ones;
  334. DMA_TCD1_SOFF = 0;
  335. DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0);
  336. DMA_TCD1_NBYTES_MLNO = 1;
  337. DMA_TCD1_SLAST = 0;
  338. DMA_TCD1_DADDR = &GPIOD_PSOR;
  339. DMA_TCD1_DOFF = 0;
  340. DMA_TCD1_CITER_ELINKNO = bufsize;
  341. DMA_TCD1_DLASTSGA = 0;
  342. DMA_TCD1_CSR = DMA_TCD_CSR_DREQ;
  343. DMA_TCD1_BITER_ELINKNO = bufsize;
  344. dma1.source(ones);
  345. dma1.destination(GPIOD_PSOR);
  346. dma1.size(1);
  347. dma1.count(bufsize);
  348. // DMA channel #2 writes the pixel data at 20% of the cycle
  349. DMA_TCD2_SADDR = frameBuffer;
  350. DMA_TCD2_SOFF = 1;
  351. DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0);
  352. DMA_TCD2_NBYTES_MLNO = 1;
  353. DMA_TCD2_SLAST = -bufsize;
  354. DMA_TCD2_DADDR = &GPIOD_PDOR;
  355. DMA_TCD2_DOFF = 0;
  356. DMA_TCD2_CITER_ELINKNO = bufsize;
  357. DMA_TCD2_DLASTSGA = 0;
  358. DMA_TCD2_CSR = DMA_TCD_CSR_DREQ;
  359. DMA_TCD2_BITER_ELINKNO = bufsize;
  360. dma2.source(frameBuffer, sizeof(frameBuffer));
  361. dma2.destination(GPIOD_PDOR);
  362. // DMA channel #3 clear all the pins low at 48% of the cycle
  363. DMA_TCD3_SADDR = &ones;
  364. DMA_TCD3_SOFF = 0;
  365. DMA_TCD3_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0);
  366. DMA_TCD3_NBYTES_MLNO = 1;
  367. DMA_TCD3_SLAST = 0;
  368. DMA_TCD3_DADDR = &GPIOD_PCOR;
  369. DMA_TCD3_DOFF = 0;
  370. DMA_TCD3_CITER_ELINKNO = bufsize;
  371. DMA_TCD3_DLASTSGA = 0;
  372. DMA_TCD3_CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_INTMAJOR;
  373. DMA_TCD3_BITER_ELINKNO = bufsize;
  374. ************************
  375. Audio, DAC
  376. ************************
  377. DMA_CR = 0;
  378. DMA_TCD4_SADDR = dac_buffer;
  379. DMA_TCD4_SOFF = 2;
  380. DMA_TCD4_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
  381. DMA_TCD4_NBYTES_MLNO = 2;
  382. DMA_TCD4_SLAST = -sizeof(dac_buffer);
  383. DMA_TCD4_DADDR = &DAC0_DAT0L;
  384. DMA_TCD4_DOFF = 0;
  385. DMA_TCD4_CITER_ELINKNO = sizeof(dac_buffer) / 2;
  386. DMA_TCD4_DLASTSGA = 0;
  387. DMA_TCD4_BITER_ELINKNO = sizeof(dac_buffer) / 2;
  388. DMA_TCD4_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
  389. DMAMUX0_CHCFG4 = DMAMUX_DISABLE;
  390. DMAMUX0_CHCFG4 = DMAMUX_SOURCE_PDB | DMAMUX_ENABLE;
  391. ************************
  392. Audio, I2S
  393. ************************
  394. DMA_CR = 0;
  395. DMA_TCD0_SADDR = i2s_tx_buffer;
  396. DMA_TCD0_SOFF = 2;
  397. DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
  398. DMA_TCD0_NBYTES_MLNO = 2;
  399. DMA_TCD0_SLAST = -sizeof(i2s_tx_buffer);
  400. DMA_TCD0_DADDR = &I2S0_TDR0;
  401. DMA_TCD0_DOFF = 0;
  402. DMA_TCD0_CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
  403. DMA_TCD0_DLASTSGA = 0;
  404. DMA_TCD0_BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
  405. DMA_TCD0_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
  406. DMAMUX0_CHCFG0 = DMAMUX_DISABLE;
  407. DMAMUX0_CHCFG0 = DMAMUX_SOURCE_I2S0_TX | DMAMUX_ENABLE;
  408. ************************
  409. ADC lib, Pedro Villanueva
  410. ************************
  411. DMA_CR = 0; // normal mode of operation
  412. *DMAMUX0_CHCFG = DMAMUX_DISABLE; // disable before changing
  413. *DMA_TCD_ATTR = DMA_TCD_ATTR_SSIZE(DMA_TCD_ATTR_SIZE_16BIT) |
  414. DMA_TCD_ATTR_DSIZE(DMA_TCD_ATTR_SIZE_16BIT) |
  415. DMA_TCD_ATTR_DMOD(4); // src and dst data is 16 bit (2 bytes), buffer size 2^^4 bytes = 8 values
  416. *DMA_TCD_NBYTES_MLNO = 2; // Minor Byte Transfer Count 2 bytes = 16 bits (we transfer 2 bytes each minor loop)
  417. *DMA_TCD_SADDR = ADC_RA; // source address
  418. *DMA_TCD_SOFF = 0; // don't change the address when minor loop finishes
  419. *DMA_TCD_SLAST = 0; // don't change src address after major loop completes
  420. *DMA_TCD_DADDR = elems; // destination address
  421. *DMA_TCD_DOFF = 2; // increment 2 bytes each minor loop
  422. *DMA_TCD_DLASTSGA = 0; // modulus feature takes care of going back to first element
  423. *DMA_TCD_CITER_ELINKNO = 1; // Current Major Iteration Count with channel linking disabled
  424. *DMA_TCD_BITER_ELINKNO = 1; // Starting Major Iteration Count with channel linking disabled
  425. *DMA_TCD_CSR = DMA_TCD_CSR_INTMAJOR; // Control and status: interrupt when major counter is complete
  426. DMA_CERQ = DMA_CERQ_CERQ(DMA_channel); // clear all past request
  427. DMA_CINT = DMA_channel; // clear interrupts
  428. uint8_t DMAMUX_SOURCE_ADC = DMAMUX_SOURCE_ADC0;
  429. if(ADC_number==1){
  430. DMAMUX_SOURCE_ADC = DMAMUX_SOURCE_ADC1;
  431. }
  432. *DMAMUX0_CHCFG = DMAMUX_SOURCE_ADC | DMAMUX_ENABLE; // enable mux and set channel DMA_channel to ADC0
  433. DMA_SERQ = DMA_SERQ_SERQ(DMA_channel); // enable DMA request
  434. NVIC_ENABLE_IRQ(IRQ_DMA_CH); // enable interrupts
  435. ************************
  436. SmartMatrix
  437. ************************
  438. // enable minor loop mapping so addresses can get reset after minor loops
  439. DMA_CR = 1 << 7;
  440. // DMA channel #0 - on latch rising edge, read address from fixed address temporary buffer, and output address on GPIO
  441. // using combo of writes to set+clear registers, to only modify the address pins and not other GPIO pins
  442. // address temporary buffer is refreshed before each DMA trigger (by DMA channel #2)
  443. // only use single major loop, never disable channel
  444. #define ADDRESS_ARRAY_REGISTERS_TO_UPDATE 2
  445. DMA_TCD0_SADDR = &gpiosync.gpio_pcor;
  446. DMA_TCD0_SOFF = (int)&gpiosync.gpio_psor - (int)&gpiosync.gpio_pcor;
  447. DMA_TCD0_SLAST = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&ADDX_GPIO_CLEAR_REGISTER - (int)&ADDX_GPIO_SET_REGISTER));
  448. DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
  449. // Destination Minor Loop Offset Enabled - transfer appropriate number of bytes per minor loop, and put DADDR back to original value when minor loop is complete
  450. // Source Minor Loop Offset Enabled - source buffer is same size and offset as destination so values reset after each minor loop
  451. DMA_TCD0_NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE | DMA_TCD_NBYTES_DMLOE |
  452. ((ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&ADDX_GPIO_CLEAR_REGISTER - (int)&ADDX_GPIO_SET_REGISTER)) << 10) |
  453. (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * sizeof(gpiosync.gpio_psor));
  454. // start on higher value of two registers, and make offset decrement to avoid negative number in NBYTES_MLOFFYES (TODO: can switch order by masking negative offset)
  455. DMA_TCD0_DADDR = &ADDX_GPIO_CLEAR_REGISTER;
  456. // update destination address so the second update per minor loop is ADDX_GPIO_SET_REGISTER
  457. DMA_TCD0_DOFF = (int)&ADDX_GPIO_SET_REGISTER - (int)&ADDX_GPIO_CLEAR_REGISTER;
  458. DMA_TCD0_DLASTSGA = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&ADDX_GPIO_CLEAR_REGISTER - (int)&ADDX_GPIO_SET_REGISTER));
  459. // single major loop
  460. DMA_TCD0_CITER_ELINKNO = 1;
  461. DMA_TCD0_BITER_ELINKNO = 1;
  462. // link channel 1, enable major channel-to-channel linking, don't clear enable on major loop complete
  463. DMA_TCD0_CSR = (1 << 8) | (1 << 5);
  464. DMAMUX0_CHCFG0 = DMAMUX_SOURCE_LATCH_RISING_EDGE | DMAMUX_ENABLE;
  465. // DMA channel #1 - copy address values from current position in array to buffer to temporarily hold row values for the next timer cycle
  466. // only use single major loop, never disable channel
  467. DMA_TCD1_SADDR = &matrixUpdateBlocks[0][0].addressValues;
  468. DMA_TCD1_SOFF = sizeof(uint16_t);
  469. DMA_TCD1_SLAST = sizeof(matrixUpdateBlock) - (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * sizeof(uint16_t));
  470. DMA_TCD1_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
  471. // 16-bit = 2 bytes transferred
  472. // transfer two 16-bit values, reset destination address back after each minor loop
  473. DMA_TCD1_NBYTES_MLOFFNO = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * sizeof(uint16_t));
  474. // start with the register that's the highest location in memory and make offset decrement to avoid negative number in NBYTES_MLOFFYES register (TODO: can switch order by masking negative offset)
  475. DMA_TCD1_DADDR = &gpiosync.gpio_pcor;
  476. DMA_TCD1_DOFF = (int)&gpiosync.gpio_psor - (int)&gpiosync.gpio_pcor;
  477. DMA_TCD1_DLASTSGA = (ADDRESS_ARRAY_REGISTERS_TO_UPDATE * ((int)&gpiosync.gpio_pcor - (int)&gpiosync.gpio_psor));
  478. // no minor loop linking, single major loop, single minor loop, don't clear enable after major loop complete
  479. DMA_TCD1_CITER_ELINKNO = 1;
  480. DMA_TCD1_BITER_ELINKNO = 1;
  481. DMA_TCD1_CSR = 0;
  482. // DMA channel #2 - on latch falling edge, load FTM1_CV1 and FTM1_MOD with with next values from current block
  483. // only use single major loop, never disable channel
  484. // link to channel 3 when complete
  485. #define TIMER_REGISTERS_TO_UPDATE 2
  486. DMA_TCD2_SADDR = &matrixUpdateBlocks[0][0].timerValues.timer_oe;
  487. DMA_TCD2_SOFF = sizeof(uint16_t);
  488. DMA_TCD2_SLAST = sizeof(matrixUpdateBlock) - (TIMER_REGISTERS_TO_UPDATE * sizeof(uint16_t));
  489. DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
  490. // 16-bit = 2 bytes transferred
  491. DMA_TCD2_NBYTES_MLOFFNO = TIMER_REGISTERS_TO_UPDATE * sizeof(uint16_t);
  492. DMA_TCD2_DADDR = &FTM1_C1V;
  493. DMA_TCD2_DOFF = (int)&FTM1_MOD - (int)&FTM1_C1V;
  494. DMA_TCD2_DLASTSGA = TIMER_REGISTERS_TO_UPDATE * ((int)&FTM1_C1V - (int)&FTM1_MOD);
  495. // no minor loop linking, single major loop
  496. DMA_TCD2_CITER_ELINKNO = 1;
  497. DMA_TCD2_BITER_ELINKNO = 1;
  498. // link channel 3, enable major channel-to-channel linking, don't clear enable after major loop complete
  499. DMA_TCD2_CSR = (3 << 8) | (1 << 5);
  500. DMAMUX0_CHCFG2 = DMAMUX_SOURCE_LATCH_FALLING_EDGE | DMAMUX_ENABLE;
  501. #define DMA_TCD_MLOFF_MASK (0x3FFFFC00)
  502. // DMA channel #3 - repeatedly load gpio_array into GPIOD_PDOR, stop and int on major loop complete
  503. DMA_TCD3_SADDR = matrixUpdateData[0][0];
  504. DMA_TCD3_SOFF = sizeof(matrixUpdateData[0][0]) / 2;
  505. // SADDR will get updated by ISR, no need to set SLAST
  506. DMA_TCD3_SLAST = 0;
  507. DMA_TCD3_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0);
  508. // after each minor loop, set source to point back to the beginning of this set of data,
  509. // but advance by 1 byte to get the next significant bits data
  510. DMA_TCD3_NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
  511. (((1 - sizeof(matrixUpdateData[0])) << 10) & DMA_TCD_MLOFF_MASK) |
  512. (MATRIX_WIDTH * DMA_UPDATES_PER_CLOCK);
  513. DMA_TCD3_DADDR = &GPIOD_PDOR;
  514. DMA_TCD3_DOFF = 0;
  515. DMA_TCD3_DLASTSGA = 0;
  516. DMA_TCD3_CITER_ELINKNO = LATCHES_PER_ROW;
  517. DMA_TCD3_BITER_ELINKNO = LATCHES_PER_ROW;
  518. // int after major loop is complete
  519. DMA_TCD3_CSR = DMA_TCD_CSR_INTMAJOR;
  520. // for debugging - enable bandwidth control (space out GPIO updates so they can be seen easier on a low-bandwidth logic analyzer)
  521. //DMA_TCD3_CSR |= (0x02 << 14);
  522. // enable a done interrupt when all DMA operations are complete
  523. NVIC_ENABLE_IRQ(IRQ_DMA_CH3);
  524. // enable additional dma interrupt used as software interrupt
  525. NVIC_SET_PRIORITY(IRQ_DMA_CH1, 0xFF); // 0xFF = lowest priority
  526. NVIC_ENABLE_IRQ(IRQ_DMA_CH1);
  527. // enable channels 0, 1, 2, 3
  528. DMA_ERQ = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3);
  529. // at the end after everything is set up: enable timer from system clock, with appropriate prescale
  530. FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(LATCH_TIMER_PRESCALE);
  531. */
  532. };
  533. extern "C" {
  534. #endif
  535. extern uint16_t dma_channel_allocated_mask;
  536. #ifdef __cplusplus
  537. }
  538. #endif
  539. #endif