1 /***************************************************************************//**
2 * @file
3 * @brief Direct memory access (DMA) API
4 * @author Energy Micro AS
5 * @version 3.0.0
6 *******************************************************************************
7 * @section License
8 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9 *******************************************************************************
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 *
21 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22 * obligation to support this Software. Energy Micro AS is providing the
23 * Software "AS IS", with no express or implied warranties of any kind,
24 * including, but not limited to, any implied warranties of merchantability
25 * or fitness for any particular purpose or warranties against infringement
26 * of any proprietary rights of a third party.
27 *
28 * Energy Micro AS will not be liable for any consequential, incidental, or
29 * special damages, or any other relief, or for any claim by any third party,
30 * arising from your use of this Software.
31 *
32 ******************************************************************************/
33
34 #ifndef __EM_DMA_H
35 #define __EM_DMA_H
36
37 #include <stdio.h>
38 #include <stdbool.h>
39 #include "em_part.h"
40
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44
45 /***************************************************************************//**
46 * @addtogroup EM_Library
47 * @{
48 ******************************************************************************/
49
50 /***************************************************************************//**
51 * @addtogroup DMA
52 * @{
53 ******************************************************************************/
54
55 /*******************************************************************************
56 ******************************** ENUMS ************************************
57 ******************************************************************************/
58
59 /**
60 * Amount source/destination address should be incremented for each data
61 * transfer.
62 */
63 typedef enum
64 {
65 dmaDataInc1 = _DMA_CTRL_SRC_INC_BYTE, /**< Increment address 1 byte. */
66 dmaDataInc2 = _DMA_CTRL_SRC_INC_HALFWORD, /**< Increment address 2 bytes. */
67 dmaDataInc4 = _DMA_CTRL_SRC_INC_WORD, /**< Increment address 4 bytes. */
68 dmaDataIncNone = _DMA_CTRL_SRC_INC_NONE /**< Do not increment address. */
69 } DMA_DataInc_TypeDef;
70
71
72 /** Data sizes (in number of bytes) to be read/written by DMA transfer. */
73 typedef enum
74 {
75 dmaDataSize1 = _DMA_CTRL_SRC_SIZE_BYTE, /**< 1 byte DMA transfer size. */
76 dmaDataSize2 = _DMA_CTRL_SRC_SIZE_HALFWORD, /**< 2 byte DMA transfer size. */
77 dmaDataSize4 = _DMA_CTRL_SRC_SIZE_WORD /**< 4 byte DMA transfer size. */
78 } DMA_DataSize_TypeDef;
79
80
81 /** Type of DMA transfer. */
82 typedef enum
83 {
84 /** Basic DMA cycle. */
85 dmaCycleCtrlBasic = _DMA_CTRL_CYCLE_CTRL_BASIC,
86 /** Auto-request DMA cycle. */
87 dmaCycleCtrlAuto = _DMA_CTRL_CYCLE_CTRL_AUTO,
88 /** Ping-pong DMA cycle. */
89 dmaCycleCtrlPingPong = _DMA_CTRL_CYCLE_CTRL_PINGPONG,
90 /** Memory scatter-gather DMA cycle. */
91 dmaCycleCtrlMemScatterGather = _DMA_CTRL_CYCLE_CTRL_MEM_SCATTER_GATHER,
92 /** Peripheral scatter-gather DMA cycle. */
93 dmaCycleCtrlPerScatterGather = _DMA_CTRL_CYCLE_CTRL_PER_SCATTER_GATHER
94 } DMA_CycleCtrl_TypeDef;
95
96
97 /** Number of transfers before controller does new arbitration. */
98 typedef enum
99 {
100 dmaArbitrate1 = _DMA_CTRL_R_POWER_1, /**< Arbitrate after 1 DMA transfer. */
101 dmaArbitrate2 = _DMA_CTRL_R_POWER_2, /**< Arbitrate after 2 DMA transfers. */
102 dmaArbitrate4 = _DMA_CTRL_R_POWER_4, /**< Arbitrate after 4 DMA transfers. */
103 dmaArbitrate8 = _DMA_CTRL_R_POWER_8, /**< Arbitrate after 8 DMA transfers. */
104 dmaArbitrate16 = _DMA_CTRL_R_POWER_16, /**< Arbitrate after 16 DMA transfers. */
105 dmaArbitrate32 = _DMA_CTRL_R_POWER_32, /**< Arbitrate after 32 DMA transfers. */
106 dmaArbitrate64 = _DMA_CTRL_R_POWER_64, /**< Arbitrate after 64 DMA transfers. */
107 dmaArbitrate128 = _DMA_CTRL_R_POWER_128, /**< Arbitrate after 128 DMA transfers. */
108 dmaArbitrate256 = _DMA_CTRL_R_POWER_256, /**< Arbitrate after 256 DMA transfers. */
109 dmaArbitrate512 = _DMA_CTRL_R_POWER_512, /**< Arbitrate after 512 DMA transfers. */
110 dmaArbitrate1024 = _DMA_CTRL_R_POWER_1024 /**< Arbitrate after 1024 DMA transfers. */
111 } DMA_ArbiterConfig_TypeDef;
112
113
114 /*******************************************************************************
115 ******************************* STRUCTS ***********************************
116 ******************************************************************************/
117
118 /**
119 * @brief
120 * DMA interrupt callback function pointer.
121 * @details
122 * Parameters:
123 * @li channel - The DMA channel the callback function is invoked for.
124 * @li primary - Indicates if callback is invoked for completion of primary
125 * (true) or alternate (false) descriptor. This is mainly useful for
126 * ping-pong DMA cycles, in order to know which descriptor to refresh.
127 * @li user - User definable reference that may be used to pass information
128 * to be used by the callback handler. If used, the referenced data must be
129 * valid at the point when the interrupt handler invokes the callback.
130 * If callback changes any data in the provided user structure, remember
131 * that those changes are done in interrupt context, and proper protection
132 * of data may be required.
133 */
134 typedef void (*DMA_FuncPtr_TypeDef)(unsigned int channel, bool primary, void *user);
135
136
137 /**
138 * @brief
139 * Callback structure that can be used to define DMA complete actions.
140 * @details
141 * A reference to this structure is only stored in the primary descriptor
142 * for a channel (if callback feature is used). If callback is required
143 * for both primary and alternate descriptor completion, this must be
144 * handled by one common callback, using the provided 'primary' parameter
145 * with the callback function.
146 */
147 typedef struct
148 {
149 /**
150 * Pointer to callback function to invoke when DMA transfer cycle done.
151 * Notice that this function is invoked in interrupt context, and therefore
152 * should be short and non-blocking.
153 */
154 DMA_FuncPtr_TypeDef cbFunc;
155
156 /** User defined pointer to provide with callback function. */
157 void *userPtr;
158
159 /**
160 * For internal use only: Indicates if next callback applies to primary
161 * or alternate descriptor completion. Mainly useful for ping-pong DMA
162 * cycles. Set this value to 0 prior to configuring callback handling.
163 */
164 uint8_t primary;
165 } DMA_CB_TypeDef;
166
167
168 /** Configuration structure for a channel. */
169 typedef struct
170 {
171 /**
172 * Select if channel priority is in the high or default priority group
173 * with respect to arbitration. Within a priority group, lower numbered
174 * channels have higher priority than higher numbered channels.
175 */
176 bool highPri;
177
178 /**
179 * Select if interrupt shall be enabled for channel (triggering interrupt
180 * handler when dma_done signal is asserted). It should normally be
181 * enabled if using the callback feature for a channel, and disabled if
182 * not using the callback feature.
183 */
184 bool enableInt;
185
186 /**
187 * Channel control specifying the source of DMA signals. If accessing
188 * peripherals, use one of the DMAREQ_nnn defines available for the
189 * peripheral. Set it to 0 for memory-to-memory DMA cycles.
190 */
191 uint32_t select;
192
193 /**
194 * @brief
195 * User definable callback handling configuration.
196 * @details
197 * Please refer to structure definition for details. The callback
198 * is invoked when the specified DMA cycle is complete (when dma_done
199 * signal asserted). The callback is invoked in interrupt context,
200 * and should be efficient and non-blocking. Set to NULL to not
201 * use the callback feature.
202 * @note
203 * The referenced structure is used by the interrupt handler, and must
204 * be available until no longer used. Thus, in most cases it should
205 * not be located on the stack.
206 */
207 DMA_CB_TypeDef *cb;
208 } DMA_CfgChannel_TypeDef;
209
210
211 /**
212 * Configuration structure for primary or alternate descriptor
213 * (not used for scatter-gather DMA cycles).
214 */
215 typedef struct
216 {
217 /** Destination increment size for each DMA transfer */
218 DMA_DataInc_TypeDef dstInc;
219
220 /** Source increment size for each DMA transfer */
221 DMA_DataInc_TypeDef srcInc;
222
223 /** DMA transfer unit size. */
224 DMA_DataSize_TypeDef size;
225
226 /**
227 * Arbitration rate, ie number of DMA transfers done before rearbitration
228 * takes place.
229 */
230 DMA_ArbiterConfig_TypeDef arbRate;
231
232 /**
233 * HPROT signal state, please refer to reference manual, DMA chapter for
234 * further details. Normally set to 0 if protection is not an issue.
235 * The following bits are available:
236 * @li bit 0 - HPROT[1] control for source read accesses,
237 * privileged/non-privileged access
238 * @li bit 3 - HPROT[1] control for destination write accesses,
239 * privileged/non-privileged access
240 */
241 uint8_t hprot;
242 } DMA_CfgDescr_TypeDef;
243
244
245 #if defined(_EFM32_GIANT_FAMILY)
246 /**
247 * Configuration structure for loop mode
248 */
249 typedef struct
250 {
251 /** Enable repeated loop */
252 bool enable;
253 /** Width of transfer, reload value for nMinus1 */
254 uint16_t nMinus1;
255 } DMA_CfgLoop_TypeDef;
256
257
258 /**
259 * Configuration structure for rectangular copy
260 */
261 typedef struct
262 {
263 /** DMA channel destination stride (width of destination image, distance between lines) */
264 uint16_t dstStride;
265 /** DMA channel source stride (width of source image, distance between lines) */
266 uint16_t srcStride;
267 /** 2D copy height */
268 uint16_t height;
269 } DMA_CfgRect_TypeDef;
270 #endif
271
272
273 /** Configuration structure for alternate scatter-gather descriptor. */
274 typedef struct
275 {
276 /** Pointer to location to transfer data from. */
277 void *src;
278
279 /** Pointer to location to transfer data to. */
280 void *dst;
281
282 /** Destination increment size for each DMA transfer */
283 DMA_DataInc_TypeDef dstInc;
284
285 /** Source increment size for each DMA transfer */
286 DMA_DataInc_TypeDef srcInc;
287
288 /** DMA transfer unit size. */
289 DMA_DataSize_TypeDef size;
290
291 /**
292 * Arbitration rate, ie number of DMA transfers done before rearbitration
293 * takes place.
294 */
295 DMA_ArbiterConfig_TypeDef arbRate;
296
297 /** Number of DMA transfers minus 1 to do. Must be <= 1023. */
298 uint16_t nMinus1;
299
300 /**
301 * HPROT signal state, please refer to reference manual, DMA chapter for
302 * further details. Normally set to 0 if protection is not an issue.
303 * The following bits are available:
304 * @li bit 0 - HPROT[1] control for source read accesses,
305 * privileged/non-privileged access
306 * @li bit 3 - HPROT[1] control for destination write accesses,
307 * privileged/non-privileged access
308 */
309 uint8_t hprot;
310
311 /** Specify if a memory or peripheral scatter-gather DMA cycle. Notice
312 * that this parameter should be the same for all alternate
313 * descriptors.
314 * @li true - this is a peripheral scatter-gather cycle
315 * @li false - this is a memory scatter-gather cycle
316 */
317 bool peripheral;
318 } DMA_CfgDescrSGAlt_TypeDef;
319
320
321 /** DMA init structure */
322 typedef struct
323 {
324 /**
325 * HPROT signal state when accessing the primary/alternate
326 * descriptors. Normally set to 0 if protection is not an issue.
327 * The following bits are available:
328 * @li bit 0 - HPROT[1] control for descriptor accesses (ie when
329 * the DMA controller accesses the channel control block itself),
330 * privileged/non-privileged access
331 */
332 uint8_t hprot;
333
334 /**
335 * Pointer to the controlblock in memory holding descriptors (channel
336 * control data structures). This memory must be properly aligned
337 * according to requirements.
338 *
339 * Alignment requirements are
340 * a) 5 bits base requirement, bits [4:0]
341 * b) Add the number of bits needed to represent the wanted number
342 * of channels
343 * c) Align structure with this number of bits set to zero
344 *
345 * Examples: 4 channels, 5 + 2 (channels 0 to 3) = 7 bits
346 * 7 bit alignment, 64 byte address alignment
347 * 8 channels, 5 + 3 (channels 0 to 7) = 8 bits
348 * 8 bit alignment, 256 byte address alignment
349 * 12 channels, 5 + 4 (channels 0 to 11) = 9 bits
350 * 9 bit alignment, 512 byte address alignment
351 *
352 * Please refer to the reference manual, DMA chapter for more details.
353 *
354 * It is possible to provide a smaller memory block, only covering
355 * those channels actually used, if not all available channels are used.
356 * Ie, if only using 4 channels (0-3), both primary and alternate
357 * structures, then only 16*2*4 = 128 bytes must be provided. This
358 * implementation has however no check if later exceeding such a limit
359 * by configuring for instance channel 4, in which case memory overwrite
360 * of some other data will occur.
361 */
362 DMA_DESCRIPTOR_TypeDef *controlBlock;
363 } DMA_Init_TypeDef;
364
365
366 /*******************************************************************************
367 ***************************** PROTOTYPES **********************************
368 ******************************************************************************/
369
370 void DMA_ActivateAuto(unsigned int channel,
371 bool primary,
372 void *dst,
373 void *src,
374 unsigned int nMinus1);
375 void DMA_ActivateBasic(unsigned int channel,
376 bool primary,
377 bool useBurst,
378 void *dst,
379 void *src,
380 unsigned int nMinus1);
381 void DMA_ActivatePingPong(unsigned int channel,
382 bool useBurst,
383 void *primDst,
384 void *primSrc,
385 unsigned int primNMinus1,
386 void *altDst,
387 void *altSrc,
388 unsigned int altNMinus1);
389 void DMA_ActivateScatterGather(unsigned int channel,
390 bool useBurst,
391 DMA_DESCRIPTOR_TypeDef *altDescr,
392 unsigned int count);
393 void DMA_CfgChannel(unsigned int channel, DMA_CfgChannel_TypeDef *cfg);
394 void DMA_CfgDescr(unsigned int channel,
395 bool primary,
396 DMA_CfgDescr_TypeDef *cfg);
397 #if defined(_EFM32_GIANT_FAMILY)
398 void DMA_CfgLoop(unsigned int channel, DMA_CfgLoop_TypeDef *cfg);
399 void DMA_CfgRect(unsigned int channel, DMA_CfgRect_TypeDef *cfg);
400
401 /***************************************************************************//**
402 * @brief
403 * Clear Loop configuration for channel
404 *
405 * @param[in] channel
406 * Channel to reset loop configuration for
407 ******************************************************************************/
DMA_ResetLoop(unsigned int channel)408 __STATIC_INLINE void DMA_ResetLoop(unsigned int channel)
409 {
410 /* Clean loop copy operation */
411 switch(channel)
412 {
413 case 0:
414 DMA->LOOP0 = _DMA_LOOP0_RESETVALUE;
415 break;
416 case 1:
417 DMA->LOOP1 = _DMA_LOOP1_RESETVALUE;
418 break;
419 default:
420 break;
421 }
422 }
423
424
425 /***************************************************************************//**
426 * @brief
427 * Clear Rect/2D DMA configuration for channel
428 *
429 * @param[in] channel
430 * Channel to reset loop configuration for
431 ******************************************************************************/
DMA_ResetRect(unsigned int channel)432 __STATIC_INLINE void DMA_ResetRect(unsigned int channel)
433 {
434 (void) channel;
435
436 /* Clear rect copy operation */
437 DMA->RECT0 = _DMA_RECT0_RESETVALUE;
438 }
439 #endif
440 void DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef *descr,
441 unsigned int indx,
442 DMA_CfgDescrSGAlt_TypeDef *cfg);
443 bool DMA_ChannelEnabled(unsigned int channel);
444 void DMA_Init(DMA_Init_TypeDef *init);
445 void DMA_IRQHandler(void);
446 void DMA_RefreshPingPong(unsigned int channel,
447 bool primary,
448 bool useBurst,
449 void *dst,
450 void *src,
451 unsigned int nMinus1,
452 bool last);
453 void DMA_Reset(void);
454
455 /** @} (end addtogroup DMA) */
456 /** @} (end addtogroup EM_Library) */
457
458 #ifdef __cplusplus
459 }
460 #endif
461
462 #endif /* __EM_DMA_H */
463