1 /***************************************************************************//**
2 * @file
3 * @brief Direct Memory Access (DMA) 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 #ifndef EM_DMA_H
32 #define EM_DMA_H
33
34 #include "em_device.h"
35 #if defined(DMA_PRESENT)
36
37 #include <stdio.h>
38 #include <stdbool.h>
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43
44 /***************************************************************************//**
45 * @addtogroup dma
46 * @{
47 ******************************************************************************/
48
49 /*******************************************************************************
50 ******************************** ENUMS ************************************
51 ******************************************************************************/
52
53 /**
54 * Amount source/destination address should be incremented for each data
55 * transfer.
56 */
57 typedef enum {
58 dmaDataInc1 = _DMA_CTRL_SRC_INC_BYTE, /**< Increment address 1 byte. */
59 dmaDataInc2 = _DMA_CTRL_SRC_INC_HALFWORD, /**< Increment address 2 bytes. */
60 dmaDataInc4 = _DMA_CTRL_SRC_INC_WORD, /**< Increment address 4 bytes. */
61 dmaDataIncNone = _DMA_CTRL_SRC_INC_NONE /**< Do not increment address. */
62 } DMA_DataInc_TypeDef;
63
64 /** Data sizes (in number of bytes) to be read/written by DMA transfer. */
65 typedef enum {
66 dmaDataSize1 = _DMA_CTRL_SRC_SIZE_BYTE, /**< 1 byte DMA transfer size. */
67 dmaDataSize2 = _DMA_CTRL_SRC_SIZE_HALFWORD, /**< 2 byte DMA transfer size. */
68 dmaDataSize4 = _DMA_CTRL_SRC_SIZE_WORD /**< 4 byte DMA transfer size. */
69 } DMA_DataSize_TypeDef;
70
71 /** Types of DMA transfer. */
72 typedef enum {
73 /** Basic DMA cycle. */
74 dmaCycleCtrlBasic = _DMA_CTRL_CYCLE_CTRL_BASIC,
75 /** Auto-request DMA cycle. */
76 dmaCycleCtrlAuto = _DMA_CTRL_CYCLE_CTRL_AUTO,
77 /** Ping-pong DMA cycle. */
78 dmaCycleCtrlPingPong = _DMA_CTRL_CYCLE_CTRL_PINGPONG,
79 /** Memory scatter-gather DMA cycle. */
80 dmaCycleCtrlMemScatterGather = _DMA_CTRL_CYCLE_CTRL_MEM_SCATTER_GATHER,
81 /** Peripheral scatter-gather DMA cycle. */
82 dmaCycleCtrlPerScatterGather = _DMA_CTRL_CYCLE_CTRL_PER_SCATTER_GATHER
83 } DMA_CycleCtrl_TypeDef;
84
85 /** Number of transfers before controller does new arbitration. */
86 typedef enum {
87 dmaArbitrate1 = _DMA_CTRL_R_POWER_1, /**< Arbitrate after 1 DMA transfer. */
88 dmaArbitrate2 = _DMA_CTRL_R_POWER_2, /**< Arbitrate after 2 DMA transfers. */
89 dmaArbitrate4 = _DMA_CTRL_R_POWER_4, /**< Arbitrate after 4 DMA transfers. */
90 dmaArbitrate8 = _DMA_CTRL_R_POWER_8, /**< Arbitrate after 8 DMA transfers. */
91 dmaArbitrate16 = _DMA_CTRL_R_POWER_16, /**< Arbitrate after 16 DMA transfers. */
92 dmaArbitrate32 = _DMA_CTRL_R_POWER_32, /**< Arbitrate after 32 DMA transfers. */
93 dmaArbitrate64 = _DMA_CTRL_R_POWER_64, /**< Arbitrate after 64 DMA transfers. */
94 dmaArbitrate128 = _DMA_CTRL_R_POWER_128, /**< Arbitrate after 128 DMA transfers. */
95 dmaArbitrate256 = _DMA_CTRL_R_POWER_256, /**< Arbitrate after 256 DMA transfers. */
96 dmaArbitrate512 = _DMA_CTRL_R_POWER_512, /**< Arbitrate after 512 DMA transfers. */
97 dmaArbitrate1024 = _DMA_CTRL_R_POWER_1024 /**< Arbitrate after 1024 DMA transfers. */
98 } DMA_ArbiterConfig_TypeDef;
99
100 /*******************************************************************************
101 ******************************* STRUCTS ***********************************
102 ******************************************************************************/
103
104 /**
105 * @brief
106 * DMA interrupt callback function pointer.
107 * @details
108 * Parameters:
109 * @li channel - DMA channel the callback function is invoked for.
110 * @li primary - Indicates if callback is invoked for completion of primary
111 * (true) or alternate (false) descriptor. Mainly useful for
112 * ping-pong DMA cycles, to know which descriptor to refresh.
113 * @li user - User definable reference that may be used to pass information
114 * to be used by the callback handler. If used, referenced data must be
115 * valid at the point when the interrupt handler invokes callback.
116 * If callback changes any data in the provided user structure, remember
117 * that those changes are done in interrupt context and proper protection
118 * of data may be required.
119 */
120 typedef void (*DMA_FuncPtr_TypeDef)(unsigned int channel, bool primary, void *user);
121
122 /**
123 * @brief
124 * Callback structure that can be used to define DMA complete actions.
125 * @details
126 * A reference to this structure is only stored in the primary descriptor
127 * for a channel (if using callback feature). If callback is required
128 * for both primary and alternate descriptor completion, this must be
129 * handled by one common callback, using the provided 'primary' parameter
130 * with the callback function.
131 */
132 typedef struct {
133 /**
134 * Pointer to callback function to invoke when DMA transfer cycle is done.
135 * Notice that this function is invoked in interrupt context, and therefore
136 * should be short and non-blocking.
137 */
138 DMA_FuncPtr_TypeDef cbFunc;
139
140 /** User defined pointer to provide with callback function. */
141 void *userPtr;
142
143 /**
144 * For internal use only: Indicates if next callback applies to primary
145 * or alternate descriptor completion. Mainly useful for ping-pong DMA
146 * cycles. Set this value to 0 prior to configuring callback handling.
147 */
148 uint8_t primary;
149 } DMA_CB_TypeDef;
150
151 /** Configuration structure for a channel. */
152 typedef struct {
153 /**
154 * Select if channel priority is in the high or default priority group
155 * with respect to arbitration. Within a priority group, lower numbered
156 * channels have higher priority than higher numbered channels.
157 */
158 bool highPri;
159
160 /**
161 * Select if interrupt will be enabled for channel (triggering interrupt
162 * handler when dma_done signal is asserted). It should normally be
163 * enabled if using the callback feature for a channel, and disabled if
164 * not using the callback feature.
165 */
166 bool enableInt;
167
168 /**
169 * Channel control specifying the source of DMA signals. If accessing
170 * peripherals, use one of the DMAREQ_nnn defines available for the
171 * peripheral. Set to 0 for memory-to-memory DMA cycles.
172 */
173 uint32_t select;
174
175 /**
176 * @brief
177 * User definable callback handling configuration.
178 * @details
179 * Refer to structure definition for details. The callback
180 * is invoked when specified DMA cycle is complete (when dma_done
181 * signal asserted). Callback is invoked in interrupt context,
182 * and should be efficient and non-blocking. Set to NULL to not
183 * use the callback feature.
184 * @note
185 * Referenced structure is used by the interrupt handler, and must
186 * be available until no longer used. Thus, in most cases it should
187 * not be located on the stack.
188 */
189 DMA_CB_TypeDef *cb;
190 } DMA_CfgChannel_TypeDef;
191
192 /**
193 * Configuration structure for primary or alternate descriptor
194 * (not used for scatter-gather DMA cycles).
195 */
196 typedef struct {
197 /** Destination increment size for each DMA transfer. */
198 DMA_DataInc_TypeDef dstInc;
199
200 /** Source increment size for each DMA transfer. */
201 DMA_DataInc_TypeDef srcInc;
202
203 /** DMA transfer unit size. */
204 DMA_DataSize_TypeDef size;
205
206 /**
207 * Arbitration rate, i.e., number of DMA transfers done before re-arbitration
208 * takes place.
209 */
210 DMA_ArbiterConfig_TypeDef arbRate;
211
212 /**
213 * HPROT signal state, refer to reference manual, DMA chapter for
214 * further details. Normally set to 0 if protection is not an issue.
215 * The following bits are available:
216 * @li bit 0 - HPROT[1] control for source read accesses,
217 * privileged/non-privileged access.
218 * @li bit 3 - HPROT[1] control for destination write accesses,
219 * privileged/non-privileged access.
220 */
221 uint8_t hprot;
222 } DMA_CfgDescr_TypeDef;
223
224 #if defined(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK)
225 /**
226 * Configuration structure for loop mode.
227 */
228 typedef struct {
229 /** Enable repeated loop. */
230 bool enable;
231 /** Width of transfer, reload value for nMinus1. */
232 uint16_t nMinus1;
233 } DMA_CfgLoop_TypeDef;
234 #endif
235
236 #if defined(_DMA_RECT0_MASK)
237 /**
238 * Configuration structure for rectangular copy.
239 */
240 typedef struct {
241 /** DMA channel destination stride (width of destination image, distance between lines). */
242 uint16_t dstStride;
243 /** DMA channel source stride (width of source image, distance between lines). */
244 uint16_t srcStride;
245 /** 2D copy height. */
246 uint16_t height;
247 } DMA_CfgRect_TypeDef;
248 #endif
249
250 /** Configuration structure for alternate scatter-gather descriptor. */
251 typedef struct {
252 /** Pointer to location to transfer data from. */
253 void *src;
254
255 /** Pointer to location to transfer data to. */
256 void *dst;
257
258 /** Destination increment size for each DMA transfer. */
259 DMA_DataInc_TypeDef dstInc;
260
261 /** Source increment size for each DMA transfer. */
262 DMA_DataInc_TypeDef srcInc;
263
264 /** DMA transfer unit size. */
265 DMA_DataSize_TypeDef size;
266
267 /**
268 * Arbitration rate, i.e., number of DMA transfers done before re-arbitration
269 * takes place.
270 */
271 DMA_ArbiterConfig_TypeDef arbRate;
272
273 /** Number of DMA transfers minus 1 to do. Must be <= 1023. */
274 uint16_t nMinus1;
275
276 /**
277 * HPROT signal state, refer to reference manual, DMA chapter for
278 * further details. Normally set to 0 if protection is not an issue.
279 * The following bits are available:
280 * @li bit 0 - HPROT[1] control for source read accesses,
281 * privileged/non-privileged access.
282 * @li bit 3 - HPROT[1] control for destination write accesses,
283 * privileged/non-privileged access.
284 */
285 uint8_t hprot;
286
287 /** Specify if a memory or peripheral scatter-gather DMA cycle. Notice
288 * that this parameter should be the same for all alternate
289 * descriptors.
290 * @li true - this is a peripheral scatter-gather cycle.
291 * @li false - this is a memory scatter-gather cycle.
292 */
293 bool peripheral;
294 } DMA_CfgDescrSGAlt_TypeDef;
295
296 /** DMA initialization structure. */
297 typedef struct {
298 /**
299 * HPROT signal state when accessing the primary/alternate
300 * descriptors. Normally set to 0 if protection is not an issue.
301 * The following bits are available:
302 * @li bit 0 - HPROT[1] control for descriptor accesses (i.e., when
303 * the DMA controller accesses the channel control block itself),
304 * privileged/non-privileged access.
305 */
306 uint8_t hprot;
307
308 /**
309 * Pointer to the control block in memory holding descriptors (channel
310 * control data structures). This memory must be properly aligned
311 * at a 256 bytes, i.e., the 8 least significant bits must be zero.
312 *
313 * Refer to the reference manual, DMA chapter for more details.
314 *
315 * It is possible to provide a smaller memory block, only covering
316 * those channels actually used, if not all available channels are used.
317 * For instance, if only using 4 channels (0-3), both primary and alternate
318 * structures, then only 16*2*4 = 128 bytes must be provided. However, this
319 * implementation has no check if later exceeding such a limit
320 * by configuring for instance channel 4, in which case memory overwrite
321 * of some other data will occur.
322 */
323 DMA_DESCRIPTOR_TypeDef *controlBlock;
324 } DMA_Init_TypeDef;
325
326 /*******************************************************************************
327 ***************************** PROTOTYPES **********************************
328 ******************************************************************************/
329
330 void DMA_ActivateAuto(unsigned int channel,
331 bool primary,
332 void *dst,
333 const void *src,
334 unsigned int nMinus1);
335 void DMA_ActivateBasic(unsigned int channel,
336 bool primary,
337 bool useBurst,
338 void *dst,
339 const void *src,
340 unsigned int nMinus1);
341 void DMA_ActivatePingPong(unsigned int channel,
342 bool useBurst,
343 void *primDst,
344 const void *primSrc,
345 unsigned int primNMinus1,
346 void *altDst,
347 const void *altSrc,
348 unsigned int altNMinus1);
349 void DMA_ActivateScatterGather(unsigned int channel,
350 bool useBurst,
351 DMA_DESCRIPTOR_TypeDef *altDescr,
352 unsigned int count);
353 void DMA_CfgChannel(unsigned int channel, DMA_CfgChannel_TypeDef *cfg);
354 void DMA_CfgDescr(unsigned int channel,
355 bool primary,
356 DMA_CfgDescr_TypeDef *cfg);
357 #if defined(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK)
358 void DMA_CfgLoop(unsigned int channel, DMA_CfgLoop_TypeDef *cfg);
359 #endif
360
361 #if defined(_DMA_RECT0_MASK)
362 void DMA_CfgRect(unsigned int channel, DMA_CfgRect_TypeDef *cfg);
363 #endif
364
365 #if defined(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK)
366 /***************************************************************************//**
367 * @brief
368 * Clear Loop configuration for channel.
369 *
370 * @param[in] channel
371 * Channel to reset loop configuration for.
372 ******************************************************************************/
DMA_ResetLoop(unsigned int channel)373 __STATIC_INLINE void DMA_ResetLoop(unsigned int channel)
374 {
375 /* Clean loop copy operation */
376 switch (channel) {
377 case 0:
378 DMA->LOOP0 = _DMA_LOOP0_RESETVALUE;
379 break;
380 case 1:
381 DMA->LOOP1 = _DMA_LOOP1_RESETVALUE;
382 break;
383 default:
384 break;
385 }
386 }
387 #endif
388
389 #if defined(_DMA_RECT0_MASK)
390 /***************************************************************************//**
391 * @brief
392 * Clear Rect/2D DMA configuration for channel.
393 *
394 * @param[in] channel
395 * Channel to reset loop configuration for.
396 ******************************************************************************/
DMA_ResetRect(unsigned int channel)397 __STATIC_INLINE void DMA_ResetRect(unsigned int channel)
398 {
399 (void) channel;
400
401 /* Clear rect copy operation. */
402 DMA->RECT0 = _DMA_RECT0_RESETVALUE;
403 }
404 #endif
405 void DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef *descr,
406 unsigned int indx,
407 DMA_CfgDescrSGAlt_TypeDef *cfg);
408 void DMA_ChannelEnable(unsigned int channel, bool enable);
409 bool DMA_ChannelEnabled(unsigned int channel);
410 void DMA_ChannelRequestEnable(unsigned int channel, bool enable);
411 void DMA_Init(DMA_Init_TypeDef *init);
412 void DMA_IRQHandler(void);
413 void DMA_RefreshPingPong(unsigned int channel,
414 bool primary,
415 bool useBurst,
416 void *dst,
417 const void *src,
418 unsigned int nMinus1,
419 bool last);
420 void DMA_Reset(void);
421
422 /***************************************************************************//**
423 * @brief
424 * Clear one or more pending DMA interrupts.
425 *
426 * @param[in] flags
427 * Pending DMA interrupt sources to clear. Use one or more valid
428 * interrupt flags for the DMA module (DMA_IFC_nnn).
429 ******************************************************************************/
DMA_IntClear(uint32_t flags)430 __STATIC_INLINE void DMA_IntClear(uint32_t flags)
431 {
432 DMA->IFC = flags;
433 }
434
435 /***************************************************************************//**
436 * @brief
437 * Disable one or more DMA interrupts.
438 *
439 * @param[in] flags
440 * DMA interrupt sources to disable. Use one or more valid
441 * interrupt flags for the DMA module (DMA_IEN_nnn).
442 ******************************************************************************/
DMA_IntDisable(uint32_t flags)443 __STATIC_INLINE void DMA_IntDisable(uint32_t flags)
444 {
445 DMA->IEN &= ~flags;
446 }
447
448 /***************************************************************************//**
449 * @brief
450 * Enable one or more DMA interrupts.
451 *
452 * @note
453 * Depending on the use, a pending interrupt may already be set prior to
454 * enabling the interrupt. To ignore a pending interrupt, consider using
455 * DMA_IntClear() prior to enabling the interrupt.
456 *
457 * @param[in] flags
458 * DMA interrupt sources to enable. Use one or more valid
459 * interrupt flags for the DMA module (DMA_IEN_nnn).
460 ******************************************************************************/
DMA_IntEnable(uint32_t flags)461 __STATIC_INLINE void DMA_IntEnable(uint32_t flags)
462 {
463 DMA->IEN |= flags;
464 }
465
466 /***************************************************************************//**
467 * @brief
468 * Get pending DMA interrupt flags.
469 *
470 * @note
471 * Event bits are not cleared by the use of this function.
472 *
473 * @return
474 * DMA interrupt sources pending. Returns one or more valid
475 * interrupt flags for the DMA module (DMA_IF_nnn).
476 ******************************************************************************/
DMA_IntGet(void)477 __STATIC_INLINE uint32_t DMA_IntGet(void)
478 {
479 return DMA->IF;
480 }
481
482 /***************************************************************************//**
483 * @brief
484 * Get enabled and pending DMA interrupt flags.
485 * Useful for handling more interrupt sources in the same interrupt handler.
486 *
487 * @note
488 * Interrupt flags are not cleared by the use of this function.
489 *
490 * @return
491 * Pending and enabled DMA interrupt sources
492 * Return value is the bitwise AND of
493 * - the enabled interrupt sources in DMA_IEN and
494 * - the pending interrupt flags DMA_IF.
495 ******************************************************************************/
DMA_IntGetEnabled(void)496 __STATIC_INLINE uint32_t DMA_IntGetEnabled(void)
497 {
498 uint32_t ien;
499
500 ien = DMA->IEN;
501 return DMA->IF & ien;
502 }
503
504 /***************************************************************************//**
505 * @brief
506 * Set one or more pending DMA interrupts.
507 *
508 * @param[in] flags
509 * DMA interrupt sources to set to pending. Use one or more valid
510 * interrupt flags for the DMA module (DMA_IFS_nnn).
511 ******************************************************************************/
DMA_IntSet(uint32_t flags)512 __STATIC_INLINE void DMA_IntSet(uint32_t flags)
513 {
514 DMA->IFS = flags;
515 }
516
517 /** @} (end addtogroup dma) */
518
519 #ifdef __cplusplus
520 }
521 #endif
522
523 #endif /* defined( DMA_PRESENT ) */
524 #endif /* EM_DMA_H */
525