1 /***************************************************************************//**
2 * @file
3 * @brief Direct memory access (DMA) module peripheral API
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include "em_dma.h"
32 #if defined(DMA_PRESENT)
33
34 #include "em_cmu.h"
35 #include "sl_assert.h"
36 #include "em_bus.h"
37
38 /***************************************************************************//**
39 * @addtogroup dma DMA - Direct Memory Access
40 * @brief Direct Memory Access (DMA) Peripheral API
41 * @details
42 * DMA access functions provide basic support for the following
43 * types of DMA cycles:
44 *
45 * @li @b Basic, used for transferring data between memory and peripherals.
46 * @li @b Auto-request, used for transferring data between memory locations.
47 * @li @b Ping-pong, used for for continuous transfer of data between memory
48 * and peripherals, automatically toggling between primary and alternate
49 * descriptors.
50 * @li @b Memory @b scatter-gather, used for transferring a number of buffers
51 * between memory locations.
52 * @li @b Peripheral @b scatter-gather, used for transferring a number of
53 * buffers between memory and peripherals.
54 *
55 * A basic understanding of the DMA controller is assumed. See
56 * the reference manual for more details.
57 *
58 * The term 'descriptor' is synonymous to the 'channel control data
59 * structure' term.
60 *
61 * To use the DMA controller, the initialization function must have
62 * been executed once (normally during the system initialization):
63 * @verbatim
64 * DMA_Init();
65 * @endverbatim
66 *
67 * Normally, a DMA channel is configured:
68 * @verbatim
69 * DMA_CfgChannel();
70 * @endverbatim
71 *
72 * The channel configuration only has to be done once if reusing the channel
73 * for the same purpose later.
74 *
75 * To set up a DMA cycle, the primary and/or alternate descriptor
76 * has to be set up as indicated below.
77 *
78 * For basic or auto-request cycles, use once on either primary or alternate
79 * descriptor:
80 * @verbatim
81 * DMA_CfgDescr();
82 * @endverbatim
83 *
84 * For ping-pong cycles, configure both primary or alternate descriptors:
85 * @verbatim
86 * DMA_CfgDescr(); // Primary descriptor config
87 * DMA_CfgDescr(); // Alternate descriptor config
88 * @endverbatim
89 *
90 * For scatter-gather cycles, program the alternate descriptor array:
91 * @verbatim
92 * // 'n' is the number of scattered buffers
93 * // 'descr' points to the start of the alternate descriptor array
94 *
95 * // Fill in 'cfg'
96 * DMA_CfgDescrScatterGather(descr, 0, cfg);
97 * // Fill in 'cfg'
98 * DMA_CfgDescrScatterGather(descr, 1, cfg);
99 * :
100 * // Fill in 'cfg'
101 * DMA_CfgDescrScatterGather(descr, n - 1, cfg);
102 * @endverbatim
103 *
104 * In many cases, the descriptor configuration only has to be done once if
105 * re-using the channel for the same type of DMA cycles later.
106 *
107 * To activate the DMA cycle, use the respective DMA_Activate...()
108 * function.
109 *
110 * For ping-pong DMA cycles, use DMA_RefreshPingPong() from the callback to
111 * prepare the completed descriptor for reuse. Notice that the refresh must
112 * be done prior to the other active descriptor completes, otherwise the
113 * ping-pong DMA cycle will halt.
114 * @{
115 ******************************************************************************/
116
117 /*******************************************************************************
118 ************************** LOCAL FUNCTIONS ********************************
119 ******************************************************************************/
120
121 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
122
123 /***************************************************************************//**
124 * @brief
125 * Prepare the descriptor for the DMA cycle.
126 *
127 * @details
128 * This function prepares the last parts of the configuration required to start a
129 * DMA cycle. Since the DMA controller itself modifies some parts of the
130 * descriptor during use, those parts need to be refreshed if reusing a
131 * descriptor configuration.
132 *
133 * @note
134 * If using this function on a descriptor already activated and in use by the
135 * DMA controller, the behavior is undefined.
136 *
137 * @param[in] channel
138 * The DMA channel to prepare for the DMA cycle.
139 *
140 * @param[in] cycleCtrl
141 * The DMA cycle type to prepare for.
142 *
143 * @param[in] primary
144 * @li true - prepare the primary descriptor
145 * @li false - prepare an alternate descriptor
146 *
147 * @param[in] useBurst
148 * The burst feature is only used on peripherals supporting DMA bursts.
149 * Bursts must not be used if the total length (as given by nMinus1) is
150 * less than the arbitration rate configured for the descriptor.
151 * See the reference manual for more details on burst usage.
152 *
153 * @param[in] dst
154 * An address to a start location to transfer data to. If NULL, leave setting in
155 * descriptor as is.
156 *
157 * @param[in] src
158 * An address to a start location to transfer data from. If NULL, leave setting in
159 * descriptor as is.
160 *
161 * @param[in] nMinus1
162 * A number of elements (minus 1) to transfer (<= 1023).
163 ******************************************************************************/
DMA_Prepare(unsigned int channel,DMA_CycleCtrl_TypeDef cycleCtrl,bool primary,bool useBurst,void * dst,const void * src,unsigned int nMinus1)164 static void DMA_Prepare(unsigned int channel,
165 DMA_CycleCtrl_TypeDef cycleCtrl,
166 bool primary,
167 bool useBurst,
168 void *dst,
169 const void *src,
170 unsigned int nMinus1)
171 {
172 DMA_DESCRIPTOR_TypeDef *descr;
173 DMA_DESCRIPTOR_TypeDef *primDescr;
174 DMA_CB_TypeDef *cb;
175 uint32_t inc;
176 uint32_t chBit;
177 uint32_t tmp;
178
179 primDescr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE)) + channel;
180
181 /* Find a descriptor to configure. */
182 if (primary) {
183 descr = primDescr;
184 } else {
185 descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)) + channel;
186 }
187
188 /* If callback is defined, update information on whether the callback is issued */
189 /* for primary or alternate descriptor. This is mainly needed for ping-pong */
190 /* cycles. */
191 cb = (DMA_CB_TypeDef *)(primDescr->USER);
192 if (cb) {
193 cb->primary = (uint8_t)primary;
194 }
195
196 if (src) {
197 inc = (descr->CTRL & _DMA_CTRL_SRC_INC_MASK) >> _DMA_CTRL_SRC_INC_SHIFT;
198 if (inc == _DMA_CTRL_SRC_INC_NONE) {
199 descr->SRCEND = (volatile void*)src;
200 } else {
201 descr->SRCEND = (void *)((uint32_t)src + (nMinus1 << inc));
202 }
203 }
204
205 if (dst) {
206 inc = (descr->CTRL & _DMA_CTRL_DST_INC_MASK) >> _DMA_CTRL_DST_INC_SHIFT;
207 if (inc == _DMA_CTRL_DST_INC_NONE) {
208 descr->DSTEND = dst;
209 } else {
210 descr->DSTEND = (void *)((uint32_t)dst + (nMinus1 << inc));
211 }
212 }
213
214 chBit = 1 << channel;
215 if (useBurst) {
216 DMA->CHUSEBURSTS = chBit;
217 } else {
218 DMA->CHUSEBURSTC = chBit;
219 }
220
221 if (primary) {
222 DMA->CHALTC = chBit;
223 } else {
224 DMA->CHALTS = chBit;
225 }
226
227 /* Set the cycle control. */
228 tmp = descr->CTRL & ~(_DMA_CTRL_CYCLE_CTRL_MASK | _DMA_CTRL_N_MINUS_1_MASK);
229 tmp |= nMinus1 << _DMA_CTRL_N_MINUS_1_SHIFT;
230 tmp |= (uint32_t)cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT;
231 descr->CTRL = tmp;
232 }
233
234 /** @endcond */
235
236 /*******************************************************************************
237 ************************ INTERRUPT FUNCTIONS ******************************
238 ******************************************************************************/
239
240 #ifndef EXCLUDE_DEFAULT_DMA_IRQ_HANDLER
241
242 /***************************************************************************//**
243 * @brief
244 * Interrupt handler for the DMA cycle completion handling.
245 *
246 * @details
247 * Clears any pending flags and calls registered callback (if any).
248 *
249 * If using the default interrupt vector table setup provided, this function
250 * is automatically placed in the IRQ table due to weak linking. If taking
251 * control over the interrupt vector table in some other way, this interrupt
252 * handler must be installed to support callback actions.
253 *
254 * For the user to implement a custom IRQ handler or run without
255 * a DMA IRQ handler, define EXCLUDE_DEFAULT_DMA_IRQ_HANDLER
256 * with a \#define statement or with the compiler option -D.
257 *
258 ******************************************************************************/
DMA_IRQHandler(void)259 void DMA_IRQHandler(void)
260 {
261 int channel;
262 DMA_CB_TypeDef *cb;
263 uint32_t pending;
264 uint32_t pendingPrio;
265 uint32_t prio;
266 uint32_t primaryCpy;
267 int i;
268
269 /* Get all pending and enabled interrupts. */
270 pending = DMA->IF;
271 pending &= DMA->IEN;
272
273 /* Assert on bus error. */
274 EFM_ASSERT(!(pending & DMA_IF_ERR));
275
276 /* Process all pending channel interrupts. First process channels */
277 /* defined with high priority, then those with default priority. */
278 prio = DMA->CHPRIS;
279 pendingPrio = pending & prio;
280 for (i = 0; i < 2; i++) {
281 channel = 0;
282 /* Process pending interrupts within high/default priority group */
283 /* honoring the priority within the group. */
284 while (pendingPrio) {
285 if (pendingPrio & 1) {
286 DMA_DESCRIPTOR_TypeDef *descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE);
287 uint32_t chmask = 1 << channel;
288
289 /* Clear a pending interrupt prior to invoking the callback, in case it */
290 /* sets up another DMA cycle. */
291 DMA->IFC = chmask;
292
293 /* Normally, no point in enabling interrupt without the callback, but */
294 /* check if the callback is defined anyway. Callback information is always */
295 /* located in the primary descriptor. */
296 cb = (DMA_CB_TypeDef *)(descr[channel].USER);
297 if (cb) {
298 /* Toggle next-descriptor indicator always prior to invoking */
299 /* callback (in case callback reconfigures something). */
300 primaryCpy = cb->primary;
301 cb->primary ^= 1;
302 if (cb->cbFunc) {
303 cb->cbFunc(channel, (bool)primaryCpy, cb->userPtr);
304 }
305 }
306 }
307
308 pendingPrio >>= 1;
309 channel++;
310 }
311
312 /* On second iteration, process default priority channels. */
313 pendingPrio = pending & ~prio;
314 }
315 }
316
317 #endif /* EXCLUDE_DEFAULT_DMA_IRQ_HANDLER */
318
319 /*******************************************************************************
320 ************************** GLOBAL FUNCTIONS *******************************
321 ******************************************************************************/
322
323 /***************************************************************************//**
324 * @brief
325 * Activate the DMA auto-request cycle (used for memory-memory transfers).
326 *
327 * @details
328 * Prior to activating the DMA cycle, the channel and descriptor to be used
329 * must have been properly configured.
330 *
331 * @note
332 * If using this function on a channel already activated and in use by the
333 * DMA controller, the behavior is undefined.
334 *
335 * @param[in] channel
336 * The DMA channel to activate the DMA cycle for.
337 *
338 * @param[in] primary
339 * @li true - activate using the primary descriptor
340 * @li false - activate using an alternate descriptor
341 *
342 * @param[in] dst
343 * An ddress to a start location to transfer data to. If NULL, leave setting in
344 * descriptor as is from a previous activation.
345 *
346 * @param[in] src
347 * An address to a start location to transfer data from. If NULL, leave setting in
348 * descriptor as is from a previous activation.
349 *
350 * @param[in] nMinus1
351 * A number of DMA transfer elements (minus 1) to transfer (<= 1023). The
352 * size of the DMA transfer element (1, 2 or 4 bytes) is configured with
353 * DMA_CfgDescr().
354 ******************************************************************************/
DMA_ActivateAuto(unsigned int channel,bool primary,void * dst,const void * src,unsigned int nMinus1)355 void DMA_ActivateAuto(unsigned int channel,
356 bool primary,
357 void *dst,
358 const void *src,
359 unsigned int nMinus1)
360 {
361 uint32_t chBit;
362
363 EFM_ASSERT(channel < DMA_CHAN_COUNT);
364 EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
365
366 DMA_Prepare(channel,
367 dmaCycleCtrlAuto,
368 primary,
369 false,
370 dst,
371 src,
372 nMinus1);
373
374 chBit = 1 << channel;
375 DMA->CHENS = chBit; /* Enable the channel. */
376 DMA->CHSWREQ = chBit; /* Activate with the software request. */
377 }
378
379 /***************************************************************************//**
380 * @brief
381 * Activate the DMA basic cycle (used for memory-peripheral transfers).
382 *
383 * @details
384 * Prior to activating the DMA cycle, the channel and descriptor to be used
385 * must have been properly configured.
386 *
387 * @note
388 * If using this function on a channel already activated and in use by the
389 * DMA controller, the behavior is undefined.
390 *
391 * @param[in] channel
392 * The DMA channel to activate the DMA cycle for.
393 *
394 * @param[in] primary
395 * @li true - activate using the primary descriptor
396 * @li false - activate using an alternate descriptor
397 *
398 * @param[in] useBurst
399 * The burst feature is only used on peripherals supporting DMA bursts.
400 * Bursts must not be used if the total length (as given by nMinus1) is
401 * less than the arbitration rate configured for the descriptor.
402 * See the reference manual for more details on burst usage.
403 *
404 * @param[in] dst
405 * An address to a start location to transfer data to. If NULL, leave setting in
406 * descriptor as is from a previous activation.
407 *
408 * @param[in] src
409 * An address to a start location to transfer data from. If NULL, leave setting in
410 * descriptor as is from a previous activation.
411 *
412 * @param[in] nMinus1
413 * A number of DMA transfer elements (minus 1) to transfer (<= 1023). The
414 * size of the DMA transfer element (1, 2 or 4 bytes) is configured with
415 * DMA_CfgDescr().
416 ******************************************************************************/
DMA_ActivateBasic(unsigned int channel,bool primary,bool useBurst,void * dst,const void * src,unsigned int nMinus1)417 void DMA_ActivateBasic(unsigned int channel,
418 bool primary,
419 bool useBurst,
420 void *dst,
421 const void *src,
422 unsigned int nMinus1)
423 {
424 EFM_ASSERT(channel < DMA_CHAN_COUNT);
425 EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
426
427 DMA_Prepare(channel,
428 dmaCycleCtrlBasic,
429 primary,
430 useBurst,
431 dst,
432 src,
433 nMinus1);
434
435 /* Enable channel, request signal is provided by the peripheral device. */
436 DMA->CHENS = 1 << channel;
437 }
438
439 /***************************************************************************//**
440 * @brief
441 * Activate a DMA ping-pong cycle (used for memory-peripheral transfers).
442 *
443 * @details
444 * Prior to activating the DMA cycle, the channel and both descriptors must
445 * have been properly configured. The primary descriptor is always the first
446 * descriptor to be used by the DMA controller.
447 *
448 * @note
449 * If using this function on a channel already activated and in use by the
450 * DMA controller, the behavior is undefined.
451 *
452 * @param[in] channel
453 * The DMA channel to activate DMA cycle for.
454 *
455 * @param[in] useBurst
456 * The burst feature is only used on peripherals supporting DMA bursts.
457 * Bursts must not be used if the total length (as given by nMinus1) is
458 * less than the arbitration rate configured for the descriptors.
459 * See the reference manual for more details on burst usage. Notice
460 * that this setting is used for both the primary and alternate descriptors.
461 *
462 * @param[in] primDst
463 * An address to a start location to transfer data to, for the primary descriptor.
464 * If NULL, leave setting in descriptor as is from a previous activation.
465 *
466 * @param[in] primSrc
467 * An address to a start location to transfer data from, for the primary descriptor.
468 * If NULL, leave setting in the descriptor as is from a previous activation.
469 *
470 * @param[in] primNMinus1
471 * A number of DMA transfer elements (minus 1) to transfer (<= 1023), for
472 * primary descriptor. The size of the DMA transfer element (1, 2 or 4 bytes)
473 * is configured with DMA_CfgDescr().
474 *
475 * @param[in] altDst
476 * An address to a start location to transfer data to, for an alternate descriptor.
477 * If NULL, leave setting in descriptor as is from a previous activation.
478 *
479 * @param[in] altSrc
480 * An address to a start location to transfer data from, for an alternate descriptor.
481 * If NULL, leave setting in descriptor as is from a previous activation.
482 *
483 * @param[in] altNMinus1
484 * A number of DMA transfer elements (minus 1) to transfer (<= 1023), for
485 * an alternate descriptor. The size of the DMA transfer element (1, 2 or 4 bytes)
486 * is configured with DMA_CfgDescr().
487 ******************************************************************************/
DMA_ActivatePingPong(unsigned int channel,bool useBurst,void * primDst,const void * primSrc,unsigned int primNMinus1,void * altDst,const void * altSrc,unsigned int altNMinus1)488 void DMA_ActivatePingPong(unsigned int channel,
489 bool useBurst,
490 void *primDst,
491 const void *primSrc,
492 unsigned int primNMinus1,
493 void *altDst,
494 const void *altSrc,
495 unsigned int altNMinus1)
496 {
497 EFM_ASSERT(channel < DMA_CHAN_COUNT);
498 EFM_ASSERT(primNMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
499 EFM_ASSERT(altNMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
500
501 /* Prepare alternate descriptor first */
502 DMA_Prepare(channel,
503 dmaCycleCtrlPingPong,
504 false,
505 useBurst,
506 altDst,
507 altSrc,
508 altNMinus1);
509
510 /* Prepare the primary descriptor last to start a cycle using it. */
511 DMA_Prepare(channel,
512 dmaCycleCtrlPingPong,
513 true,
514 useBurst,
515 primDst,
516 primSrc,
517 primNMinus1);
518
519 /* Enable the channel, the request signal is provided by the peripheral device. */
520 DMA->CHENS = 1 << channel;
521 }
522
523 /***************************************************************************//**
524 * @brief
525 * Activate the DMA scatter-gather cycle (used for either memory-peripheral
526 * or memory-memory transfers).
527 *
528 * @details
529 * Prior to activating the DMA cycle, the array with alternate descriptors
530 * must have been properly configured. This function can be reused without
531 * reconfiguring the alternate descriptors, as long as @p count is the same.
532 *
533 * @note
534 * If using this function on a channel already activated and in use by the
535 * DMA controller, the behavior is undefined.
536 *
537 * @param[in] channel
538 * The DMA channel to activate DMA cycle for.
539 *
540 * @param[in] useBurst
541 * The burst feature is only used on peripherals supporting DMA bursts
542 * (this parameter is ignored for memory scatter-gather cycles).
543 * This parameter determines if bursts should be enabled during DMA transfers
544 * using the alternate descriptors. Bursts must not be used if the total
545 * length (as given by nMinus1 for the alternate descriptor) is
546 * less than the arbitration rate configured for the descriptor.
547 * See the reference manual for more details on burst usage.
548 *
549 * @param[in,out] altDescr
550 * A pointer to a start of an array with prepared alternate descriptors. The last
551 * descriptor will have its cycle control type reprogrammed to a basic type.
552 *
553 * @param[in] count
554 * A number of alternate descriptors in @p altDescr array. The maximum number of
555 * alternate descriptors is 256.
556 ******************************************************************************/
DMA_ActivateScatterGather(unsigned int channel,bool useBurst,DMA_DESCRIPTOR_TypeDef * altDescr,unsigned int count)557 void DMA_ActivateScatterGather(unsigned int channel,
558 bool useBurst,
559 DMA_DESCRIPTOR_TypeDef *altDescr,
560 unsigned int count)
561 {
562 DMA_DESCRIPTOR_TypeDef *descr;
563 DMA_CB_TypeDef *cb;
564 uint32_t cycleCtrl;
565 uint32_t chBit;
566
567 EFM_ASSERT(channel < DMA_CHAN_COUNT);
568 EFM_ASSERT(altDescr);
569 EFM_ASSERT(count && (count <= 256));
570
571 /* Configure the primary descriptor properly to */
572 /* transfer one complete alternate descriptor from the alternate */
573 /* descriptor table into the actual alternate descriptor. */
574 descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE) + channel;
575
576 /* Set the source end address to point to the alternate descriptor array. */
577 descr->SRCEND = (uint32_t *)altDescr + (count * 4) - 1;
578
579 /* The destination end address in the primary descriptor MUST point */
580 /* to the corresponding alternate descriptor in scatter-gather mode. */
581 descr->DSTEND = (uint32_t *)((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)
582 + channel + 1) - 1;
583
584 /* The user field of the descriptor is used for the callback configuration */
585 /* and is already configured when the channel is configured. Do not modify it. */
586
587 /* Determine from alternate configuration whether this is a memory or a */
588 /* peripheral scatter-gather by looking at the first alternate descriptor. */
589 cycleCtrl = altDescr->CTRL & _DMA_CTRL_CYCLE_CTRL_MASK;
590 cycleCtrl &= ~(1 << _DMA_CTRL_CYCLE_CTRL_SHIFT);
591
592 EFM_ASSERT((cycleCtrl == dmaCycleCtrlMemScatterGather)
593 || (cycleCtrl == dmaCycleCtrlPerScatterGather));
594
595 /* Set the last alternate descriptor to basic or auto-request a cycle type in */
596 /* order to have dma_done signal asserted when complete. Otherwise, an interrupt */
597 /* will not be triggered when done. */
598 altDescr[count - 1].CTRL &= ~_DMA_CTRL_CYCLE_CTRL_MASK;
599 if (cycleCtrl == dmaCycleCtrlMemScatterGather) {
600 altDescr[count - 1].CTRL |= (uint32_t)dmaCycleCtrlAuto
601 << _DMA_CTRL_CYCLE_CTRL_SHIFT;
602 } else {
603 altDescr[count - 1].CTRL |= (uint32_t)dmaCycleCtrlBasic
604 << _DMA_CTRL_CYCLE_CTRL_SHIFT;
605 }
606
607 /* If the callback is defined, update the information on whether the callback is issued for */
608 /* primary or alternate descriptors. Not really useful for scatter-gather */
609 /* but there for consistency. Always set to alternate, since that is the last */
610 /* descriptor used. */
611 cb = (DMA_CB_TypeDef *)(descr->USER);
612 if (cb) {
613 cb->primary = false;
614 }
615
616 /* Configure the primary descriptor control word. */
617 descr->CTRL = ((uint32_t)dmaDataInc4 << _DMA_CTRL_DST_INC_SHIFT)
618 | ((uint32_t)dmaDataSize4 << _DMA_CTRL_DST_SIZE_SHIFT)
619 | ((uint32_t)dmaDataInc4 << _DMA_CTRL_SRC_INC_SHIFT)
620 | ((uint32_t)dmaDataSize4 << _DMA_CTRL_SRC_SIZE_SHIFT)
621 /* Use the same protection scheme as for alternate descriptors. */
622 | (altDescr->CTRL & _DMA_CTRL_SRC_PROT_CTRL_MASK)
623 | ((uint32_t)dmaArbitrate4 << _DMA_CTRL_R_POWER_SHIFT)
624 | (((count * 4) - 1) << _DMA_CTRL_N_MINUS_1_SHIFT)
625 | (((uint32_t)useBurst & 1) << _DMA_CTRL_NEXT_USEBURST_SHIFT)
626 | cycleCtrl;
627
628 chBit = 1 << channel;
629
630 /* Start with the primary descriptor. */
631 DMA->CHALTC = chBit;
632
633 /* Enable the channel. */
634 DMA->CHENS = chBit;
635
636 /* Send a request if memory scatter-gather. Otherwise, the request signal is */
637 /* provided by the peripheral. */
638 if (cycleCtrl == dmaCycleCtrlMemScatterGather) {
639 DMA->CHSWREQ = chBit;
640 }
641 }
642
643 /***************************************************************************//**
644 * @brief
645 * Configure a DMA channel.
646 *
647 * @details
648 * Configure miscellaneous issues for a DMA channel. This function is typically
649 * used once to set up a channel for a certain type of use.
650 *
651 * @note
652 * If using this function on a channel already in use by the DMA controller,
653 * the behavior is undefined.
654 *
655 * @param[in] channel
656 * The DMA channel to configure.
657 *
658 * @param[in] cfg
659 * The configuration to use.
660 ******************************************************************************/
DMA_CfgChannel(unsigned int channel,DMA_CfgChannel_TypeDef * cfg)661 void DMA_CfgChannel(unsigned int channel, DMA_CfgChannel_TypeDef *cfg)
662 {
663 DMA_DESCRIPTOR_TypeDef *descr;
664
665 EFM_ASSERT(channel < DMA_CHAN_COUNT);
666 EFM_ASSERT(cfg);
667
668 /* Always keep callback configuration reference in the primary descriptor. */
669 descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE);
670 descr[channel].USER = (uint32_t)(cfg->cb);
671
672 /* Set to a specified priority for a channel. */
673 if (cfg->highPri) {
674 DMA->CHPRIS = 1 << channel;
675 } else {
676 DMA->CHPRIC = 1 << channel;
677 }
678
679 /* Set the DMA signal source select. */
680 DMA->CH[channel].CTRL = cfg->select;
681
682 /* Enable/disable an interrupt as specified. */
683 if (cfg->enableInt) {
684 DMA->IFC = (1 << channel);
685 BUS_RegBitWrite(&(DMA->IEN), channel, 1);
686 } else {
687 BUS_RegBitWrite(&(DMA->IEN), channel, 0);
688 }
689 }
690
691 /***************************************************************************//**
692 * @brief
693 * Configure the DMA descriptor for auto-request, basic, or ping-pong DMA cycles.
694 *
695 * @details
696 * This function is used to configure a descriptor for the following
697 * DMA cycle types:
698 *
699 * @li auto-request - used for a memory/memory transfer
700 * @li basic - used for a peripheral/memory transfer
701 * @li ping-pong - used for a ping-pong-based peripheral/memory transfer
702 * style providing time to refresh one descriptor while the other is
703 * in use.
704 *
705 * The DMA cycle is not activated. See DMA_ActivateAuto(),
706 * DMA_ActivateBasic(), or DMA_ActivatePingPong() to activate the DMA cycle.
707 * In many cases, the configuration only has to be done once, and all
708 * subsequent cycles may be activated with the activate function.
709 *
710 * For ping-pong DMA cycles, this function must be used both on the primary
711 * and the alternate descriptor prior to activating the DMA cycle.
712 *
713 * Notice that the DMA channel must also be configured. See DMA_CfgChannel().
714 *
715 * @note
716 * If using this function on a descriptor already activated and in use by
717 * the DMA controller, the behavior is undefined.
718 *
719 * @param[in] channel
720 * The DMA channel to configure for.
721 *
722 * @param[in] primary
723 * @li true - configure the primary descriptor
724 * @li false - configure an alternate descriptor
725 *
726 * @param[in] cfg
727 * The configuration to use.
728 ******************************************************************************/
DMA_CfgDescr(unsigned int channel,bool primary,DMA_CfgDescr_TypeDef * cfg)729 void DMA_CfgDescr(unsigned int channel,
730 bool primary,
731 DMA_CfgDescr_TypeDef *cfg)
732 {
733 DMA_DESCRIPTOR_TypeDef *descr;
734
735 EFM_ASSERT(channel < DMA_CHAN_COUNT);
736 EFM_ASSERT(cfg);
737
738 /* Find a descriptor to configure. */
739 if (primary) {
740 descr = (DMA_DESCRIPTOR_TypeDef *)DMA->CTRLBASE;
741 } else {
742 descr = (DMA_DESCRIPTOR_TypeDef *)DMA->ALTCTRLBASE;
743 }
744 descr += channel;
745
746 /* Prepare the descriptor. */
747 /* The source/destination end addresses set when started. */
748 descr->CTRL = (cfg->dstInc << _DMA_CTRL_DST_INC_SHIFT)
749 | (cfg->size << _DMA_CTRL_DST_SIZE_SHIFT)
750 | (cfg->srcInc << _DMA_CTRL_SRC_INC_SHIFT)
751 | (cfg->size << _DMA_CTRL_SRC_SIZE_SHIFT)
752 | ((uint32_t)(cfg->hprot) << _DMA_CTRL_SRC_PROT_CTRL_SHIFT)
753 | (cfg->arbRate << _DMA_CTRL_R_POWER_SHIFT)
754 | (0 << _DMA_CTRL_N_MINUS_1_SHIFT) /* Set when activated. */
755 | (0 << _DMA_CTRL_NEXT_USEBURST_SHIFT) /* Set when activated. */
756 | DMA_CTRL_CYCLE_CTRL_INVALID; /* Set when activated. */
757 }
758
759 #if defined(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK)
760 /***************************************************************************//**
761 * @brief Configure the DMA channel for Loop mode or 2D transfer.
762 *
763 * @details
764 * For 2D transfer, set cfg->enable to "false" and only configure nMinus1
765 * to the same width as the channel descriptor.
766 *
767 * @param[in] channel
768 * The DMA channel to configure for.
769 *
770 * @param[in] cfg
771 * The configuration to use.
772 ******************************************************************************/
DMA_CfgLoop(unsigned int channel,DMA_CfgLoop_TypeDef * cfg)773 void DMA_CfgLoop(unsigned int channel, DMA_CfgLoop_TypeDef *cfg)
774 {
775 EFM_ASSERT(channel <= 1);
776 EFM_ASSERT(cfg->nMinus1 <= 1023);
777
778 /* Configure the LOOP setting. */
779 switch ( channel ) {
780 case 0:
781 DMA->LOOP0 = (cfg->enable << _DMA_LOOP0_EN_SHIFT)
782 | (cfg->nMinus1 << _DMA_LOOP0_WIDTH_SHIFT);
783 break;
784 case 1:
785 DMA->LOOP1 = (cfg->enable << _DMA_LOOP1_EN_SHIFT)
786 | (cfg->nMinus1 << _DMA_LOOP1_WIDTH_SHIFT);
787 break;
788 }
789 }
790 #endif
791
792 #if defined(_DMA_RECT0_MASK)
793 /***************************************************************************//**
794 * @brief Configure the DMA channel 2D transfer properties.
795 *
796 * @param[in] channel
797 * The DMA channel to configure for.
798 *
799 * @param[in] cfg
800 * The configuration to use.
801 ******************************************************************************/
DMA_CfgRect(unsigned int channel,DMA_CfgRect_TypeDef * cfg)802 void DMA_CfgRect(unsigned int channel, DMA_CfgRect_TypeDef *cfg)
803 {
804 (void)channel; /* Unused parameter */
805
806 EFM_ASSERT(channel == 0);
807 EFM_ASSERT(cfg->dstStride <= 2047);
808 EFM_ASSERT(cfg->srcStride <= 2047);
809 EFM_ASSERT(cfg->height <= 1023);
810
811 /* Configure the rectangular/2D copy. */
812 DMA->RECT0 = (cfg->dstStride << _DMA_RECT0_DSTSTRIDE_SHIFT)
813 | (cfg->srcStride << _DMA_RECT0_SRCSTRIDE_SHIFT)
814 | (cfg->height << _DMA_RECT0_HEIGHT_SHIFT);
815 }
816 #endif
817
818 /***************************************************************************//**
819 * @brief
820 * Configure an alternate DMA descriptor for use with scatter-gather DMA
821 * cycles.
822 *
823 * @details
824 * In scatter-gather mode, the alternate descriptors are located in one
825 * contiguous memory area. Each of the alternate descriptors must be fully
826 * configured prior to starting the scatter-gather DMA cycle.
827 *
828 * The DMA cycle is not activated by this function. See
829 * DMA_ActivateScatterGather() to activate the DMA cycle. In some cases, the
830 * alternate configuration only has to be done once and all subsequent
831 * transfers may be activated with the activate function.
832 *
833 * Notice that the DMA channel must also be configured, see DMA_CfgChannel().
834 *
835 * @param[in] descr
836 * Points to the start of a memory area holding the alternate descriptors.
837 *
838 * @param[in] indx
839 * An alternate descriptor index number to configure (numbered from 0).
840 *
841 * @param[in] cfg
842 * The configuration to use.
843 ******************************************************************************/
DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef * descr,unsigned int indx,DMA_CfgDescrSGAlt_TypeDef * cfg)844 void DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef *descr,
845 unsigned int indx,
846 DMA_CfgDescrSGAlt_TypeDef *cfg)
847 {
848 uint32_t cycleCtrl;
849
850 EFM_ASSERT(descr);
851 EFM_ASSERT(cfg);
852
853 /* Point to a selected entry in the alternate descriptor table. */
854 descr += indx;
855
856 if (cfg->srcInc == dmaDataIncNone) {
857 descr->SRCEND = cfg->src;
858 } else {
859 descr->SRCEND = (void *)((uint32_t)(cfg->src)
860 + ((uint32_t)(cfg->nMinus1) << cfg->srcInc));
861 }
862
863 if (cfg->dstInc == dmaDataIncNone) {
864 descr->DSTEND = cfg->dst;
865 } else {
866 descr->DSTEND = (void *)((uint32_t)(cfg->dst)
867 + ((uint32_t)(cfg->nMinus1) << cfg->dstInc));
868 }
869
870 /* User-definable part not used. */
871 descr->USER = 0;
872
873 if (cfg->peripheral) {
874 cycleCtrl = (uint32_t)dmaCycleCtrlPerScatterGather + 1;
875 } else {
876 cycleCtrl = (uint32_t)dmaCycleCtrlMemScatterGather + 1;
877 }
878
879 descr->CTRL = (cfg->dstInc << _DMA_CTRL_DST_INC_SHIFT)
880 | (cfg->size << _DMA_CTRL_DST_SIZE_SHIFT)
881 | (cfg->srcInc << _DMA_CTRL_SRC_INC_SHIFT)
882 | (cfg->size << _DMA_CTRL_SRC_SIZE_SHIFT)
883 | ((uint32_t)(cfg->hprot) << _DMA_CTRL_SRC_PROT_CTRL_SHIFT)
884 | (cfg->arbRate << _DMA_CTRL_R_POWER_SHIFT)
885 | ((uint32_t)(cfg->nMinus1) << _DMA_CTRL_N_MINUS_1_SHIFT)
886 /* Never set next useburst bit since the descriptor used after the */
887 /* alternate descriptor is the primary descriptor which operates on */
888 /* memory. If the alternate descriptors need to have useBurst set, this */
889 /* is done when setting up the primary descriptor, i.e., when activating. */
890 | (0 << _DMA_CTRL_NEXT_USEBURST_SHIFT)
891 | (cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT);
892 }
893
894 /***************************************************************************//**
895 * @brief
896 * Enable or disable a DMA channel.
897 *
898 * @details
899 * Use this function to explicitly enable or disable a DMA channel. A DMA
900 * channel is automatically disabled when the DMA controller has finished a
901 * transaction.
902 *
903 * @param[in] channel
904 * The DMA channel to enable or disable.
905 *
906 * @param[in] enable
907 * If 'true', the channel will be enabled. If 'false', the channel will be
908 * disabled.
909 ******************************************************************************/
DMA_ChannelEnable(unsigned int channel,bool enable)910 void DMA_ChannelEnable(unsigned int channel, bool enable)
911 {
912 EFM_ASSERT(channel < DMA_CHAN_COUNT);
913
914 if (enable) {
915 DMA->CHENS = 1 << channel;
916 } else {
917 DMA->CHENC = 1 << channel;
918 }
919 }
920
921 /***************************************************************************//**
922 * @brief
923 * Check if the DMA channel is enabled.
924 *
925 * @details
926 * The DMA channel is disabled when the DMA controller has finished a DMA
927 * cycle.
928 *
929 * @param[in] channel
930 * The DMA channel to check.
931 *
932 * @return
933 * True if the channel is enabled, false if not.
934 ******************************************************************************/
DMA_ChannelEnabled(unsigned int channel)935 bool DMA_ChannelEnabled(unsigned int channel)
936 {
937 EFM_ASSERT(channel < DMA_CHAN_COUNT);
938
939 return (bool)((DMA->CHENS >> channel) & 1);
940 }
941
942 /***************************************************************************//**
943 * @brief
944 * Enable or disable a DMA channel request.
945 *
946 * @details
947 * Use this function to enable or disable a DMA channel request. This will
948 * prevent the DMA from proceeding after its current transaction if disabled.
949 *
950 * @param[in] channel
951 * The DMA channel to enable or disable the request on.
952 *
953 * @param[in] enable
954 * If 'true', the request will be enabled. If 'false', the request will be disabled.
955 ******************************************************************************/
DMA_ChannelRequestEnable(unsigned int channel,bool enable)956 void DMA_ChannelRequestEnable(unsigned int channel, bool enable)
957 {
958 EFM_ASSERT(channel < DMA_CHAN_COUNT);
959
960 if (enable) {
961 BUS_RegBitWrite(&DMA->CHREQMASKC, channel, 1);
962 } else {
963 BUS_RegBitWrite(&DMA->CHREQMASKS, channel, 1);
964 }
965 }
966
967 /***************************************************************************//**
968 * @brief
969 * Initialize the DMA controller.
970 *
971 * @details
972 * This function resets and prepares the DMA controller for use. Although
973 * it may be used several times, it is normally only used during system
974 * initialization. If reused during a normal operation, any ongoing DMA
975 * transfers will be aborted. When complete, the DMA controller is in
976 * an enabled state.
977 *
978 * @note
979 * Must be invoked before using the DMA controller.
980 *
981 * @param[in] init
982 * A pointer to a structure containing the DMA initialization information.
983 ******************************************************************************/
DMA_Init(DMA_Init_TypeDef * init)984 void DMA_Init(DMA_Init_TypeDef *init)
985 {
986 EFM_ASSERT(init);
987
988 /* Make sure that the control block is properly aligned. */
989 #if (DMA_CHAN_COUNT <= 4)
990 EFM_ASSERT(!((uint32_t)(init->controlBlock) & (128 - 1)));
991 #elif (DMA_CHAN_COUNT <= 8) || (DMA_CHAN_COUNT <= 12)
992 EFM_ASSERT(!((uint32_t)(init->controlBlock) & (256 - 1)));
993 #else
994 #error "Unsupported DMA channel count (em_dma.c)."
995 #endif
996
997 /* Make sure that the DMA clock is enabled prior to accessing the DMA module. */
998 CMU_ClockEnable(cmuClock_DMA, true);
999
1000 /* Make sure that the DMA controller is set to a known reset state. */
1001 DMA_Reset();
1002
1003 /* Clear/enable DMA interrupts. */
1004 NVIC_ClearPendingIRQ(DMA_IRQn);
1005 NVIC_EnableIRQ(DMA_IRQn);
1006
1007 /* Enable the bus error interrupt. */
1008 DMA->IEN = DMA_IEN_ERR;
1009
1010 /* Set the pointer to a control block. Notice that the pointer must have been */
1011 /* properly aligned according to requirements defined in the reference */
1012 /* manual. */
1013 DMA->CTRLBASE = (uint32_t)(init->controlBlock);
1014
1015 /* Configure and enable the DMA controller. */
1016 DMA->CONFIG = ((uint32_t)(init->hprot) << _DMA_CONFIG_CHPROT_SHIFT)
1017 | DMA_CONFIG_EN;
1018 }
1019
1020 /***************************************************************************//**
1021 * @brief
1022 * Refresh a descriptor used in a DMA ping-pong cycle.
1023 *
1024 * @details
1025 * During a ping-pong DMA cycle, the DMA controller automatically alternates
1026 * between the primary and alternate descriptors, when completing use of a
1027 * descriptor. While the other descriptor is in use by the DMA controller,
1028 * the software should refresh the completed descriptor. This is typically done from
1029 * the callback defined for the ping-pong cycle.
1030 *
1031 * @param[in] channel
1032 * The DMA channel to refresh the ping-pong descriptor for.
1033 *
1034 * @param[in] primary
1035 * @li true - refresh the primary descriptor
1036 * @li false - refresh an alternate descriptor
1037 *
1038 * @param[in] useBurst
1039 * The burst feature is only used on peripherals supporting DMA bursts.
1040 * Bursts must not be used if the total length (as given by nMinus1) is
1041 * less than the arbitration rate configured for the descriptor.
1042 * See the reference manual for more details on burst usage.
1043 *
1044 * @param[in] dst
1045 * An address to a start location to transfer data to. If NULL, leave setting in
1046 * descriptor as is.
1047 *
1048 * @param[in] src
1049 * An address to a start location to transfer data from. If NULL, leave setting in
1050 * descriptor as is.
1051 *
1052 * @param[in] nMinus1
1053 * A number of DMA transfer elements (minus 1) to transfer (<= 1023). The
1054 * size of the DMA transfer element (1, 2 or 4 bytes) is configured with
1055 * DMA_CfgDescr().
1056 *
1057 * @param[in] stop
1058 * Indicate that the DMA ping-pong cycle stops @b when done using
1059 * this descriptor.
1060 ******************************************************************************/
DMA_RefreshPingPong(unsigned int channel,bool primary,bool useBurst,void * dst,const void * src,unsigned int nMinus1,bool stop)1061 void DMA_RefreshPingPong(unsigned int channel,
1062 bool primary,
1063 bool useBurst,
1064 void *dst,
1065 const void *src,
1066 unsigned int nMinus1,
1067 bool stop)
1068 {
1069 DMA_CycleCtrl_TypeDef cycleCtrl;
1070 DMA_DESCRIPTOR_TypeDef *descr;
1071 uint32_t inc;
1072 uint32_t chBit;
1073 uint32_t tmp;
1074
1075 EFM_ASSERT(channel < DMA_CHAN_COUNT);
1076 EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT));
1077
1078 /* The ping-pong DMA cycle may be stopped by issuing a basic cycle type. */
1079 if (stop) {
1080 cycleCtrl = dmaCycleCtrlBasic;
1081 } else {
1082 cycleCtrl = dmaCycleCtrlPingPong;
1083 }
1084
1085 /* Find a descriptor to configure. */
1086 if (primary) {
1087 descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE)) + channel;
1088 } else {
1089 descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)) + channel;
1090 }
1091
1092 if (src) {
1093 inc = (descr->CTRL & _DMA_CTRL_SRC_INC_MASK) >> _DMA_CTRL_SRC_INC_SHIFT;
1094 if (inc == _DMA_CTRL_SRC_INC_NONE) {
1095 descr->SRCEND = (volatile void*)src;
1096 } else {
1097 descr->SRCEND = (void *)((uint32_t)src + (nMinus1 << inc));
1098 }
1099 }
1100
1101 if (dst) {
1102 inc = (descr->CTRL & _DMA_CTRL_DST_INC_MASK) >> _DMA_CTRL_DST_INC_SHIFT;
1103 if (inc == _DMA_CTRL_DST_INC_NONE) {
1104 descr->DSTEND = dst;
1105 } else {
1106 descr->DSTEND = (void *)((uint32_t)dst + (nMinus1 << inc));
1107 }
1108 }
1109
1110 chBit = 1 << channel;
1111 if (useBurst) {
1112 DMA->CHUSEBURSTS = chBit;
1113 } else {
1114 DMA->CHUSEBURSTC = chBit;
1115 }
1116
1117 /* Set cycle control. */
1118 tmp = descr->CTRL & ~(_DMA_CTRL_CYCLE_CTRL_MASK | _DMA_CTRL_N_MINUS_1_MASK);
1119 tmp |= nMinus1 << _DMA_CTRL_N_MINUS_1_SHIFT;
1120 tmp |= cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT;
1121 descr->CTRL = tmp;
1122 }
1123
1124 /***************************************************************************//**
1125 * @brief
1126 * Reset the DMA controller.
1127 *
1128 * @details
1129 * This functions will disable the DMA controller and set it to a reset
1130 * state.
1131 *
1132 * @note
1133 * Note that any ongoing transfers will be aborted.
1134 ******************************************************************************/
DMA_Reset(void)1135 void DMA_Reset(void)
1136 {
1137 int i;
1138
1139 /* Disable DMA interrupts */
1140 NVIC_DisableIRQ(DMA_IRQn);
1141
1142 /* Put the DMA controller into a known state, first disabling it. */
1143 DMA->CONFIG = _DMA_CONFIG_RESETVALUE;
1144 DMA->CHUSEBURSTC = _DMA_CHUSEBURSTC_MASK;
1145 DMA->CHREQMASKC = _DMA_CHREQMASKC_MASK;
1146 DMA->CHENC = _DMA_CHENC_MASK;
1147 DMA->CHALTC = _DMA_CHALTC_MASK;
1148 DMA->CHPRIC = _DMA_CHPRIC_MASK;
1149 DMA->ERRORC = DMA_ERRORC_ERRORC;
1150 DMA->IEN = _DMA_IEN_RESETVALUE;
1151 DMA->IFC = _DMA_IFC_MASK;
1152
1153 /* Clear channel control flags. */
1154 for (i = 0; i < DMA_CHAN_COUNT; i++) {
1155 DMA->CH[i].CTRL = _DMA_CH_CTRL_RESETVALUE;
1156 }
1157 }
1158
1159 /** @} (end addtogroup dma) */
1160 #endif /* defined( DMA_PRESENT ) */
1161