| /***************************************************************************//** |
| * @file em_dma.h |
| * @brief Direct Memory Access (DMA) API |
| * @version 5.6.0 |
| ******************************************************************************* |
| * # License |
| * <b>Copyright 2016 Silicon Laboratories, Inc. www.silabs.com</b> |
| ******************************************************************************* |
| * |
| * 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: Silicon Labs has no |
| * obligation to support this Software. Silicon Labs 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. |
| * |
| * Silicon Labs 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 "em_device.h" |
| #if defined(DMA_PRESENT) |
| |
| #include <stdio.h> |
| #include <stdbool.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /***************************************************************************//** |
| * @addtogroup emlib |
| * @{ |
| ******************************************************************************/ |
| |
| /***************************************************************************//** |
| * @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; |
| |
| /** Types 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 - DMA channel the callback function is invoked for. |
| * @li primary - Indicates if callback is invoked for completion of primary |
| * (true) or alternate (false) descriptor. Mainly useful for |
| * ping-pong DMA cycles, 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, referenced data must be |
| * valid at the point when the interrupt handler invokes 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 using callback feature). 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 is 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 will 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 to 0 for memory-to-memory DMA cycles. |
| */ |
| uint32_t select; |
| |
| /** |
| * @brief |
| * User definable callback handling configuration. |
| * @details |
| * Refer to structure definition for details. The callback |
| * is invoked when specified DMA cycle is complete (when dma_done |
| * signal asserted). Callback is invoked in interrupt context, |
| * and should be efficient and non-blocking. Set to NULL to not |
| * use the callback feature. |
| * @note |
| * 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, i.e., number of DMA transfers done before re-arbitration |
| * takes place. |
| */ |
| DMA_ArbiterConfig_TypeDef arbRate; |
| |
| /** |
| * HPROT signal state, 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(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK) |
| /** |
| * 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; |
| #endif |
| |
| #if defined(_DMA_RECT0_MASK) |
| /** |
| * 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, i.e., number of DMA transfers done before re-arbitration |
| * takes place. |
| */ |
| DMA_ArbiterConfig_TypeDef arbRate; |
| |
| /** Number of DMA transfers minus 1 to do. Must be <= 1023. */ |
| uint16_t nMinus1; |
| |
| /** |
| * HPROT signal state, 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 initialization 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 (i.e., when |
| * the DMA controller accesses the channel control block itself), |
| * privileged/non-privileged access. |
| */ |
| uint8_t hprot; |
| |
| /** |
| * Pointer to the control block in memory holding descriptors (channel |
| * control data structures). This memory must be properly aligned |
| * at a 256 bytes, i.e., the 8 least significant bits must be zero. |
| * |
| * 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. |
| * For instance, if only using 4 channels (0-3), both primary and alternate |
| * structures, then only 16*2*4 = 128 bytes must be provided. However, this |
| * implementation has 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, |
| const void *src, |
| unsigned int nMinus1); |
| void DMA_ActivateBasic(unsigned int channel, |
| bool primary, |
| bool useBurst, |
| void *dst, |
| const void *src, |
| unsigned int nMinus1); |
| void DMA_ActivatePingPong(unsigned int channel, |
| bool useBurst, |
| void *primDst, |
| const void *primSrc, |
| unsigned int primNMinus1, |
| void *altDst, |
| const 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(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK) |
| void DMA_CfgLoop(unsigned int channel, DMA_CfgLoop_TypeDef *cfg); |
| #endif |
| |
| #if defined(_DMA_RECT0_MASK) |
| void DMA_CfgRect(unsigned int channel, DMA_CfgRect_TypeDef *cfg); |
| #endif |
| |
| #if defined(_DMA_LOOP0_MASK) && defined(_DMA_LOOP1_MASK) |
| /***************************************************************************//** |
| * @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; |
| } |
| } |
| #endif |
| |
| #if defined(_DMA_RECT0_MASK) |
| /***************************************************************************//** |
| * @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); |
| void DMA_ChannelEnable(unsigned int channel, bool enable); |
| bool DMA_ChannelEnabled(unsigned int channel); |
| void DMA_ChannelRequestEnable(unsigned int channel, bool enable); |
| void DMA_Init(DMA_Init_TypeDef *init); |
| void DMA_IRQHandler(void); |
| void DMA_RefreshPingPong(unsigned int channel, |
| bool primary, |
| bool useBurst, |
| void *dst, |
| const void *src, |
| unsigned int nMinus1, |
| bool last); |
| void DMA_Reset(void); |
| |
| /***************************************************************************//** |
| * @brief |
| * Clear one or more pending DMA interrupts. |
| * |
| * @param[in] flags |
| * Pending DMA interrupt sources to clear. Use one or more valid |
| * interrupt flags for the DMA module (DMA_IFC_nnn). |
| ******************************************************************************/ |
| __STATIC_INLINE void DMA_IntClear(uint32_t flags) |
| { |
| DMA->IFC = flags; |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Disable one or more DMA interrupts. |
| * |
| * @param[in] flags |
| * DMA interrupt sources to disable. Use one or more valid |
| * interrupt flags for the DMA module (DMA_IEN_nnn). |
| ******************************************************************************/ |
| __STATIC_INLINE void DMA_IntDisable(uint32_t flags) |
| { |
| DMA->IEN &= ~flags; |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Enable one or more DMA interrupts. |
| * |
| * @note |
| * Depending on the use, a pending interrupt may already be set prior to |
| * enabling the interrupt. To ignore a pending interrupt, consider using |
| * DMA_IntClear() prior to enabling the interrupt. |
| * |
| * @param[in] flags |
| * DMA interrupt sources to enable. Use one or more valid |
| * interrupt flags for the DMA module (DMA_IEN_nnn). |
| ******************************************************************************/ |
| __STATIC_INLINE void DMA_IntEnable(uint32_t flags) |
| { |
| DMA->IEN |= flags; |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Get pending DMA interrupt flags. |
| * |
| * @note |
| * Event bits are not cleared by the use of this function. |
| * |
| * @return |
| * DMA interrupt sources pending. Returns one or more valid |
| * interrupt flags for the DMA module (DMA_IF_nnn). |
| ******************************************************************************/ |
| __STATIC_INLINE uint32_t DMA_IntGet(void) |
| { |
| return DMA->IF; |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Get enabled and pending DMA interrupt flags. |
| * Useful for handling more interrupt sources in the same interrupt handler. |
| * |
| * @note |
| * Interrupt flags are not cleared by the use of this function. |
| * |
| * @return |
| * Pending and enabled DMA interrupt sources |
| * Return value is the bitwise AND of |
| * - the enabled interrupt sources in DMA_IEN and |
| * - the pending interrupt flags DMA_IF. |
| ******************************************************************************/ |
| __STATIC_INLINE uint32_t DMA_IntGetEnabled(void) |
| { |
| uint32_t ien; |
| |
| ien = DMA->IEN; |
| return DMA->IF & ien; |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Set one or more pending DMA interrupts. |
| * |
| * @param[in] flags |
| * DMA interrupt sources to set to pending. Use one or more valid |
| * interrupt flags for the DMA module (DMA_IFS_nnn). |
| ******************************************************************************/ |
| __STATIC_INLINE void DMA_IntSet(uint32_t flags) |
| { |
| DMA->IFS = flags; |
| } |
| |
| /** @} (end addtogroup DMA) */ |
| /** @} (end addtogroup emlib) */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* defined( DMA_PRESENT ) */ |
| #endif /* EM_DMA_H */ |