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