/***************************************************************************//** * @file * @brief Direct memory access (DMA) API * @author Energy Micro AS * @version 3.0.0 ******************************************************************************* * @section License * (C) Copyright 2012 Energy Micro AS, http://www.energymicro.com ******************************************************************************* * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no * obligation to support this Software. Energy Micro AS is providing the * Software "AS IS", with no express or implied warranties of any kind, * including, but not limited to, any implied warranties of merchantability * or fitness for any particular purpose or warranties against infringement * of any proprietary rights of a third party. * * Energy Micro AS will not be liable for any consequential, incidental, or * special damages, or any other relief, or for any claim by any third party, * arising from your use of this Software. * ******************************************************************************/ #ifndef __EM_DMA_H #define __EM_DMA_H #include #include #include "em_part.h" #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * @addtogroup EM_Library * @{ ******************************************************************************/ /***************************************************************************//** * @addtogroup DMA * @{ ******************************************************************************/ /******************************************************************************* ******************************** ENUMS ************************************ ******************************************************************************/ /** * Amount source/destination address should be incremented for each data * transfer. */ typedef enum { dmaDataInc1 = _DMA_CTRL_SRC_INC_BYTE, /**< Increment address 1 byte. */ dmaDataInc2 = _DMA_CTRL_SRC_INC_HALFWORD, /**< Increment address 2 bytes. */ dmaDataInc4 = _DMA_CTRL_SRC_INC_WORD, /**< Increment address 4 bytes. */ dmaDataIncNone = _DMA_CTRL_SRC_INC_NONE /**< Do not increment address. */ } DMA_DataInc_TypeDef; /** Data sizes (in number of bytes) to be read/written by DMA transfer. */ typedef enum { dmaDataSize1 = _DMA_CTRL_SRC_SIZE_BYTE, /**< 1 byte DMA transfer size. */ dmaDataSize2 = _DMA_CTRL_SRC_SIZE_HALFWORD, /**< 2 byte DMA transfer size. */ dmaDataSize4 = _DMA_CTRL_SRC_SIZE_WORD /**< 4 byte DMA transfer size. */ } DMA_DataSize_TypeDef; /** Type of DMA transfer. */ typedef enum { /** Basic DMA cycle. */ dmaCycleCtrlBasic = _DMA_CTRL_CYCLE_CTRL_BASIC, /** Auto-request DMA cycle. */ dmaCycleCtrlAuto = _DMA_CTRL_CYCLE_CTRL_AUTO, /** Ping-pong DMA cycle. */ dmaCycleCtrlPingPong = _DMA_CTRL_CYCLE_CTRL_PINGPONG, /** Memory scatter-gather DMA cycle. */ dmaCycleCtrlMemScatterGather = _DMA_CTRL_CYCLE_CTRL_MEM_SCATTER_GATHER, /** Peripheral scatter-gather DMA cycle. */ dmaCycleCtrlPerScatterGather = _DMA_CTRL_CYCLE_CTRL_PER_SCATTER_GATHER } DMA_CycleCtrl_TypeDef; /** Number of transfers before controller does new arbitration. */ typedef enum { dmaArbitrate1 = _DMA_CTRL_R_POWER_1, /**< Arbitrate after 1 DMA transfer. */ dmaArbitrate2 = _DMA_CTRL_R_POWER_2, /**< Arbitrate after 2 DMA transfers. */ dmaArbitrate4 = _DMA_CTRL_R_POWER_4, /**< Arbitrate after 4 DMA transfers. */ dmaArbitrate8 = _DMA_CTRL_R_POWER_8, /**< Arbitrate after 8 DMA transfers. */ dmaArbitrate16 = _DMA_CTRL_R_POWER_16, /**< Arbitrate after 16 DMA transfers. */ dmaArbitrate32 = _DMA_CTRL_R_POWER_32, /**< Arbitrate after 32 DMA transfers. */ dmaArbitrate64 = _DMA_CTRL_R_POWER_64, /**< Arbitrate after 64 DMA transfers. */ dmaArbitrate128 = _DMA_CTRL_R_POWER_128, /**< Arbitrate after 128 DMA transfers. */ dmaArbitrate256 = _DMA_CTRL_R_POWER_256, /**< Arbitrate after 256 DMA transfers. */ dmaArbitrate512 = _DMA_CTRL_R_POWER_512, /**< Arbitrate after 512 DMA transfers. */ dmaArbitrate1024 = _DMA_CTRL_R_POWER_1024 /**< Arbitrate after 1024 DMA transfers. */ } DMA_ArbiterConfig_TypeDef; /******************************************************************************* ******************************* STRUCTS *********************************** ******************************************************************************/ /** * @brief * DMA interrupt callback function pointer. * @details * Parameters: * @li channel - The DMA channel the callback function is invoked for. * @li primary - Indicates if callback is invoked for completion of primary * (true) or alternate (false) descriptor. This is mainly useful for * ping-pong DMA cycles, in order to know which descriptor to refresh. * @li user - User definable reference that may be used to pass information * to be used by the callback handler. If used, the referenced data must be * valid at the point when the interrupt handler invokes the callback. * If callback changes any data in the provided user structure, remember * that those changes are done in interrupt context, and proper protection * of data may be required. */ typedef void (*DMA_FuncPtr_TypeDef)(unsigned int channel, bool primary, void *user); /** * @brief * Callback structure that can be used to define DMA complete actions. * @details * A reference to this structure is only stored in the primary descriptor * for a channel (if callback feature is used). If callback is required * for both primary and alternate descriptor completion, this must be * handled by one common callback, using the provided 'primary' parameter * with the callback function. */ typedef struct { /** * Pointer to callback function to invoke when DMA transfer cycle done. * Notice that this function is invoked in interrupt context, and therefore * should be short and non-blocking. */ DMA_FuncPtr_TypeDef cbFunc; /** User defined pointer to provide with callback function. */ void *userPtr; /** * For internal use only: Indicates if next callback applies to primary * or alternate descriptor completion. Mainly useful for ping-pong DMA * cycles. Set this value to 0 prior to configuring callback handling. */ uint8_t primary; } DMA_CB_TypeDef; /** Configuration structure for a channel. */ typedef struct { /** * Select if channel priority is in the high or default priority group * with respect to arbitration. Within a priority group, lower numbered * channels have higher priority than higher numbered channels. */ bool highPri; /** * Select if interrupt shall be enabled for channel (triggering interrupt * handler when dma_done signal is asserted). It should normally be * enabled if using the callback feature for a channel, and disabled if * not using the callback feature. */ bool enableInt; /** * Channel control specifying the source of DMA signals. If accessing * peripherals, use one of the DMAREQ_nnn defines available for the * peripheral. Set it to 0 for memory-to-memory DMA cycles. */ uint32_t select; /** * @brief * User definable callback handling configuration. * @details * Please refer to structure definition for details. The callback * is invoked when the specified DMA cycle is complete (when dma_done * signal asserted). The callback is invoked in interrupt context, * and should be efficient and non-blocking. Set to NULL to not * use the callback feature. * @note * The referenced structure is used by the interrupt handler, and must * be available until no longer used. Thus, in most cases it should * not be located on the stack. */ DMA_CB_TypeDef *cb; } DMA_CfgChannel_TypeDef; /** * Configuration structure for primary or alternate descriptor * (not used for scatter-gather DMA cycles). */ typedef struct { /** Destination increment size for each DMA transfer */ DMA_DataInc_TypeDef dstInc; /** Source increment size for each DMA transfer */ DMA_DataInc_TypeDef srcInc; /** DMA transfer unit size. */ DMA_DataSize_TypeDef size; /** * Arbitration rate, ie number of DMA transfers done before rearbitration * takes place. */ DMA_ArbiterConfig_TypeDef arbRate; /** * HPROT signal state, please refer to reference manual, DMA chapter for * further details. Normally set to 0 if protection is not an issue. * The following bits are available: * @li bit 0 - HPROT[1] control for source read accesses, * privileged/non-privileged access * @li bit 3 - HPROT[1] control for destination write accesses, * privileged/non-privileged access */ uint8_t hprot; } DMA_CfgDescr_TypeDef; #if defined(_EFM32_GIANT_FAMILY) /** * Configuration structure for loop mode */ typedef struct { /** Enable repeated loop */ bool enable; /** Width of transfer, reload value for nMinus1 */ uint16_t nMinus1; } DMA_CfgLoop_TypeDef; /** * Configuration structure for rectangular copy */ typedef struct { /** DMA channel destination stride (width of destination image, distance between lines) */ uint16_t dstStride; /** DMA channel source stride (width of source image, distance between lines) */ uint16_t srcStride; /** 2D copy height */ uint16_t height; } DMA_CfgRect_TypeDef; #endif /** Configuration structure for alternate scatter-gather descriptor. */ typedef struct { /** Pointer to location to transfer data from. */ void *src; /** Pointer to location to transfer data to. */ void *dst; /** Destination increment size for each DMA transfer */ DMA_DataInc_TypeDef dstInc; /** Source increment size for each DMA transfer */ DMA_DataInc_TypeDef srcInc; /** DMA transfer unit size. */ DMA_DataSize_TypeDef size; /** * Arbitration rate, ie number of DMA transfers done before rearbitration * takes place. */ DMA_ArbiterConfig_TypeDef arbRate; /** Number of DMA transfers minus 1 to do. Must be <= 1023. */ uint16_t nMinus1; /** * HPROT signal state, please refer to reference manual, DMA chapter for * further details. Normally set to 0 if protection is not an issue. * The following bits are available: * @li bit 0 - HPROT[1] control for source read accesses, * privileged/non-privileged access * @li bit 3 - HPROT[1] control for destination write accesses, * privileged/non-privileged access */ uint8_t hprot; /** Specify if a memory or peripheral scatter-gather DMA cycle. Notice * that this parameter should be the same for all alternate * descriptors. * @li true - this is a peripheral scatter-gather cycle * @li false - this is a memory scatter-gather cycle */ bool peripheral; } DMA_CfgDescrSGAlt_TypeDef; /** DMA init structure */ typedef struct { /** * HPROT signal state when accessing the primary/alternate * descriptors. Normally set to 0 if protection is not an issue. * The following bits are available: * @li bit 0 - HPROT[1] control for descriptor accesses (ie when * the DMA controller accesses the channel control block itself), * privileged/non-privileged access */ uint8_t hprot; /** * Pointer to the controlblock in memory holding descriptors (channel * control data structures). This memory must be properly aligned * according to requirements. * * Alignment requirements are * a) 5 bits base requirement, bits [4:0] * b) Add the number of bits needed to represent the wanted number * of channels * c) Align structure with this number of bits set to zero * * Examples: 4 channels, 5 + 2 (channels 0 to 3) = 7 bits * 7 bit alignment, 64 byte address alignment * 8 channels, 5 + 3 (channels 0 to 7) = 8 bits * 8 bit alignment, 256 byte address alignment * 12 channels, 5 + 4 (channels 0 to 11) = 9 bits * 9 bit alignment, 512 byte address alignment * * Please refer to the reference manual, DMA chapter for more details. * * It is possible to provide a smaller memory block, only covering * those channels actually used, if not all available channels are used. * Ie, if only using 4 channels (0-3), both primary and alternate * structures, then only 16*2*4 = 128 bytes must be provided. This * implementation has however no check if later exceeding such a limit * by configuring for instance channel 4, in which case memory overwrite * of some other data will occur. */ DMA_DESCRIPTOR_TypeDef *controlBlock; } DMA_Init_TypeDef; /******************************************************************************* ***************************** PROTOTYPES ********************************** ******************************************************************************/ void DMA_ActivateAuto(unsigned int channel, bool primary, void *dst, void *src, unsigned int nMinus1); void DMA_ActivateBasic(unsigned int channel, bool primary, bool useBurst, void *dst, void *src, unsigned int nMinus1); void DMA_ActivatePingPong(unsigned int channel, bool useBurst, void *primDst, void *primSrc, unsigned int primNMinus1, void *altDst, void *altSrc, unsigned int altNMinus1); void DMA_ActivateScatterGather(unsigned int channel, bool useBurst, DMA_DESCRIPTOR_TypeDef *altDescr, unsigned int count); void DMA_CfgChannel(unsigned int channel, DMA_CfgChannel_TypeDef *cfg); void DMA_CfgDescr(unsigned int channel, bool primary, DMA_CfgDescr_TypeDef *cfg); #if defined(_EFM32_GIANT_FAMILY) void DMA_CfgLoop(unsigned int channel, DMA_CfgLoop_TypeDef *cfg); void DMA_CfgRect(unsigned int channel, DMA_CfgRect_TypeDef *cfg); /***************************************************************************//** * @brief * Clear Loop configuration for channel * * @param[in] channel * Channel to reset loop configuration for ******************************************************************************/ __STATIC_INLINE void DMA_ResetLoop(unsigned int channel) { /* Clean loop copy operation */ switch(channel) { case 0: DMA->LOOP0 = _DMA_LOOP0_RESETVALUE; break; case 1: DMA->LOOP1 = _DMA_LOOP1_RESETVALUE; break; default: break; } } /***************************************************************************//** * @brief * Clear Rect/2D DMA configuration for channel * * @param[in] channel * Channel to reset loop configuration for ******************************************************************************/ __STATIC_INLINE void DMA_ResetRect(unsigned int channel) { (void) channel; /* Clear rect copy operation */ DMA->RECT0 = _DMA_RECT0_RESETVALUE; } #endif void DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef *descr, unsigned int indx, DMA_CfgDescrSGAlt_TypeDef *cfg); bool DMA_ChannelEnabled(unsigned int channel); void DMA_Init(DMA_Init_TypeDef *init); void DMA_IRQHandler(void); void DMA_RefreshPingPong(unsigned int channel, bool primary, bool useBurst, void *dst, void *src, unsigned int nMinus1, bool last); void DMA_Reset(void); /** @} (end addtogroup DMA) */ /** @} (end addtogroup EM_Library) */ #ifdef __cplusplus } #endif #endif /* __EM_DMA_H */