added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_dma.c@0:9b334a45a8ff, 2015-10-01 (annotated)
- Committer:
- bogdanm
- Date:
- Thu Oct 01 15:25:22 2015 +0300
- Revision:
- 0:9b334a45a8ff
- Child:
- 50:a417edff4437
Initial commit on mbed-dev
Replaces mbed-src (now inactive)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
bogdanm | 0:9b334a45a8ff | 1 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 2 | * @file em_dma.c |
bogdanm | 0:9b334a45a8ff | 3 | * @brief Direct memory access (DMA) module peripheral API |
bogdanm | 0:9b334a45a8ff | 4 | * @version 3.20.12 |
bogdanm | 0:9b334a45a8ff | 5 | ******************************************************************************* |
bogdanm | 0:9b334a45a8ff | 6 | * @section License |
bogdanm | 0:9b334a45a8ff | 7 | * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> |
bogdanm | 0:9b334a45a8ff | 8 | ******************************************************************************* |
bogdanm | 0:9b334a45a8ff | 9 | * |
bogdanm | 0:9b334a45a8ff | 10 | * Permission is granted to anyone to use this software for any purpose, |
bogdanm | 0:9b334a45a8ff | 11 | * including commercial applications, and to alter it and redistribute it |
bogdanm | 0:9b334a45a8ff | 12 | * freely, subject to the following restrictions: |
bogdanm | 0:9b334a45a8ff | 13 | * |
bogdanm | 0:9b334a45a8ff | 14 | * 1. The origin of this software must not be misrepresented; you must not |
bogdanm | 0:9b334a45a8ff | 15 | * claim that you wrote the original software. |
bogdanm | 0:9b334a45a8ff | 16 | * 2. Altered source versions must be plainly marked as such, and must not be |
bogdanm | 0:9b334a45a8ff | 17 | * misrepresented as being the original software. |
bogdanm | 0:9b334a45a8ff | 18 | * 3. This notice may not be removed or altered from any source distribution. |
bogdanm | 0:9b334a45a8ff | 19 | * |
bogdanm | 0:9b334a45a8ff | 20 | * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no |
bogdanm | 0:9b334a45a8ff | 21 | * obligation to support this Software. Silicon Labs is providing the |
bogdanm | 0:9b334a45a8ff | 22 | * Software "AS IS", with no express or implied warranties of any kind, |
bogdanm | 0:9b334a45a8ff | 23 | * including, but not limited to, any implied warranties of merchantability |
bogdanm | 0:9b334a45a8ff | 24 | * or fitness for any particular purpose or warranties against infringement |
bogdanm | 0:9b334a45a8ff | 25 | * of any proprietary rights of a third party. |
bogdanm | 0:9b334a45a8ff | 26 | * |
bogdanm | 0:9b334a45a8ff | 27 | * Silicon Labs will not be liable for any consequential, incidental, or |
bogdanm | 0:9b334a45a8ff | 28 | * special damages, or any other relief, or for any claim by any third party, |
bogdanm | 0:9b334a45a8ff | 29 | * arising from your use of this Software. |
bogdanm | 0:9b334a45a8ff | 30 | * |
bogdanm | 0:9b334a45a8ff | 31 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 32 | |
bogdanm | 0:9b334a45a8ff | 33 | |
bogdanm | 0:9b334a45a8ff | 34 | #include "em_dma.h" |
bogdanm | 0:9b334a45a8ff | 35 | #if defined( DMA_PRESENT ) |
bogdanm | 0:9b334a45a8ff | 36 | |
bogdanm | 0:9b334a45a8ff | 37 | #include "em_cmu.h" |
bogdanm | 0:9b334a45a8ff | 38 | #include "em_assert.h" |
bogdanm | 0:9b334a45a8ff | 39 | #include "em_bitband.h" |
bogdanm | 0:9b334a45a8ff | 40 | |
bogdanm | 0:9b334a45a8ff | 41 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 42 | * @addtogroup EM_Library |
bogdanm | 0:9b334a45a8ff | 43 | * @{ |
bogdanm | 0:9b334a45a8ff | 44 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 45 | |
bogdanm | 0:9b334a45a8ff | 46 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 47 | * @addtogroup DMA |
bogdanm | 0:9b334a45a8ff | 48 | * @brief Direct Memory Access (DMA) Peripheral API |
bogdanm | 0:9b334a45a8ff | 49 | * @details |
bogdanm | 0:9b334a45a8ff | 50 | * These DMA access functions provide basic support for the following |
bogdanm | 0:9b334a45a8ff | 51 | * types of DMA cycles: |
bogdanm | 0:9b334a45a8ff | 52 | * |
bogdanm | 0:9b334a45a8ff | 53 | * @li @b Basic, used for transferring data between memory and peripherals. |
bogdanm | 0:9b334a45a8ff | 54 | * @li @b Auto-request, used for transferring data between memory locations. |
bogdanm | 0:9b334a45a8ff | 55 | * @li @b Ping-pong, used for for continuous transfer of data between memory |
bogdanm | 0:9b334a45a8ff | 56 | * and peripherals, automatically toggling between primary and alternate |
bogdanm | 0:9b334a45a8ff | 57 | * descriptors. |
bogdanm | 0:9b334a45a8ff | 58 | * @li @b Memory @b scatter-gather, used for transferring a number of buffers |
bogdanm | 0:9b334a45a8ff | 59 | * between memory locations. |
bogdanm | 0:9b334a45a8ff | 60 | * @li @b Peripheral @b scatter-gather, used for transferring a number of |
bogdanm | 0:9b334a45a8ff | 61 | * buffers between memory and peripherals. |
bogdanm | 0:9b334a45a8ff | 62 | * |
bogdanm | 0:9b334a45a8ff | 63 | * A basic understanding of the DMA controller is assumed. Please refer to |
bogdanm | 0:9b334a45a8ff | 64 | * the EFM32 reference manual for further details. |
bogdanm | 0:9b334a45a8ff | 65 | * |
bogdanm | 0:9b334a45a8ff | 66 | * The term 'descriptor' is used as a synonym to the 'channel control data |
bogdanm | 0:9b334a45a8ff | 67 | * structure' term. |
bogdanm | 0:9b334a45a8ff | 68 | * |
bogdanm | 0:9b334a45a8ff | 69 | * In order to use the DMA controller, the initialization function must have |
bogdanm | 0:9b334a45a8ff | 70 | * been executed once (normally during system init): |
bogdanm | 0:9b334a45a8ff | 71 | * @verbatim |
bogdanm | 0:9b334a45a8ff | 72 | * DMA_Init(); |
bogdanm | 0:9b334a45a8ff | 73 | * @endverbatim |
bogdanm | 0:9b334a45a8ff | 74 | * |
bogdanm | 0:9b334a45a8ff | 75 | * Then, normally a user of a DMA channel configures the channel: |
bogdanm | 0:9b334a45a8ff | 76 | * @verbatim |
bogdanm | 0:9b334a45a8ff | 77 | * DMA_CfgChannel(); |
bogdanm | 0:9b334a45a8ff | 78 | * @endverbatim |
bogdanm | 0:9b334a45a8ff | 79 | * |
bogdanm | 0:9b334a45a8ff | 80 | * The channel configuration only has to be done once, if reusing the channel |
bogdanm | 0:9b334a45a8ff | 81 | * for the same purpose later. |
bogdanm | 0:9b334a45a8ff | 82 | * |
bogdanm | 0:9b334a45a8ff | 83 | * In order to set up a DMA cycle, the primary and/or alternate descriptor |
bogdanm | 0:9b334a45a8ff | 84 | * has to be set up as indicated below. |
bogdanm | 0:9b334a45a8ff | 85 | * |
bogdanm | 0:9b334a45a8ff | 86 | * For basic or auto-request cycles, use once on either primary or alternate |
bogdanm | 0:9b334a45a8ff | 87 | * descriptor: |
bogdanm | 0:9b334a45a8ff | 88 | * @verbatim |
bogdanm | 0:9b334a45a8ff | 89 | * DMA_CfgDescr(); |
bogdanm | 0:9b334a45a8ff | 90 | * @endverbatim |
bogdanm | 0:9b334a45a8ff | 91 | * |
bogdanm | 0:9b334a45a8ff | 92 | * For ping-pong cycles, configure both primary or alternate descriptors: |
bogdanm | 0:9b334a45a8ff | 93 | * @verbatim |
bogdanm | 0:9b334a45a8ff | 94 | * DMA_CfgDescr(); // Primary descriptor config |
bogdanm | 0:9b334a45a8ff | 95 | * DMA_CfgDescr(); // Alternate descriptor config |
bogdanm | 0:9b334a45a8ff | 96 | * @endverbatim |
bogdanm | 0:9b334a45a8ff | 97 | * |
bogdanm | 0:9b334a45a8ff | 98 | * For scatter-gather cycles, the alternate descriptor array must be programmed: |
bogdanm | 0:9b334a45a8ff | 99 | * @verbatim |
bogdanm | 0:9b334a45a8ff | 100 | * // 'n' is the number of scattered buffers |
bogdanm | 0:9b334a45a8ff | 101 | * // 'descr' points to the start of the alternate descriptor array |
bogdanm | 0:9b334a45a8ff | 102 | * |
bogdanm | 0:9b334a45a8ff | 103 | * // Fill in 'cfg' |
bogdanm | 0:9b334a45a8ff | 104 | * DMA_CfgDescrScatterGather(descr, 0, cfg); |
bogdanm | 0:9b334a45a8ff | 105 | * // Fill in 'cfg' |
bogdanm | 0:9b334a45a8ff | 106 | * DMA_CfgDescrScatterGather(descr, 1, cfg); |
bogdanm | 0:9b334a45a8ff | 107 | * : |
bogdanm | 0:9b334a45a8ff | 108 | * // Fill in 'cfg' |
bogdanm | 0:9b334a45a8ff | 109 | * DMA_CfgDescrScatterGather(descr, n - 1, cfg); |
bogdanm | 0:9b334a45a8ff | 110 | * @endverbatim |
bogdanm | 0:9b334a45a8ff | 111 | * |
bogdanm | 0:9b334a45a8ff | 112 | * In many cases, the descriptor configuration only has to be done once, if |
bogdanm | 0:9b334a45a8ff | 113 | * re-using the channel for the same type of DMA cycles later. |
bogdanm | 0:9b334a45a8ff | 114 | * |
bogdanm | 0:9b334a45a8ff | 115 | * In order to activate the DMA cycle, use the respective DMA_Activate...() |
bogdanm | 0:9b334a45a8ff | 116 | * function. |
bogdanm | 0:9b334a45a8ff | 117 | * |
bogdanm | 0:9b334a45a8ff | 118 | * For ping-pong DMA cycles, use DMA_RefreshPingPong() from the callback to |
bogdanm | 0:9b334a45a8ff | 119 | * prepare the completed descriptor for reuse. Notice that the refresh must |
bogdanm | 0:9b334a45a8ff | 120 | * be done prior to the other active descriptor completes, otherwise the |
bogdanm | 0:9b334a45a8ff | 121 | * ping-pong DMA cycle will halt. |
bogdanm | 0:9b334a45a8ff | 122 | * @{ |
bogdanm | 0:9b334a45a8ff | 123 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 124 | |
bogdanm | 0:9b334a45a8ff | 125 | /******************************************************************************* |
bogdanm | 0:9b334a45a8ff | 126 | ************************** LOCAL FUNCTIONS ******************************** |
bogdanm | 0:9b334a45a8ff | 127 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 128 | |
bogdanm | 0:9b334a45a8ff | 129 | /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ |
bogdanm | 0:9b334a45a8ff | 130 | |
bogdanm | 0:9b334a45a8ff | 131 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 132 | * @brief |
bogdanm | 0:9b334a45a8ff | 133 | * Prepare descriptor for DMA cycle. |
bogdanm | 0:9b334a45a8ff | 134 | * |
bogdanm | 0:9b334a45a8ff | 135 | * @details |
bogdanm | 0:9b334a45a8ff | 136 | * This function prepares the last pieces of configuration required to start a |
bogdanm | 0:9b334a45a8ff | 137 | * DMA cycle. Since the DMA controller itself modifies some parts of the |
bogdanm | 0:9b334a45a8ff | 138 | * descriptor during use, those parts need to be refreshed if reusing a |
bogdanm | 0:9b334a45a8ff | 139 | * descriptor configuration. |
bogdanm | 0:9b334a45a8ff | 140 | * |
bogdanm | 0:9b334a45a8ff | 141 | * @note |
bogdanm | 0:9b334a45a8ff | 142 | * If using this function on a descriptor already activated and in use by the |
bogdanm | 0:9b334a45a8ff | 143 | * DMA controller, the behaviour is undefined. |
bogdanm | 0:9b334a45a8ff | 144 | * |
bogdanm | 0:9b334a45a8ff | 145 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 146 | * DMA channel to prepare for DMA cycle. |
bogdanm | 0:9b334a45a8ff | 147 | * |
bogdanm | 0:9b334a45a8ff | 148 | * @param[in] cycleCtrl |
bogdanm | 0:9b334a45a8ff | 149 | * DMA cycle type to prepare for. |
bogdanm | 0:9b334a45a8ff | 150 | * |
bogdanm | 0:9b334a45a8ff | 151 | * @param[in] primary |
bogdanm | 0:9b334a45a8ff | 152 | * @li true - prepare primary descriptor |
bogdanm | 0:9b334a45a8ff | 153 | * @li false - prepare alternate descriptor |
bogdanm | 0:9b334a45a8ff | 154 | * |
bogdanm | 0:9b334a45a8ff | 155 | * @param[in] useBurst |
bogdanm | 0:9b334a45a8ff | 156 | * The burst feature is only used on peripherals supporting DMA bursts. |
bogdanm | 0:9b334a45a8ff | 157 | * Bursts must not be used if the total length (as given by nMinus1) is |
bogdanm | 0:9b334a45a8ff | 158 | * less than the arbitration rate configured for the descriptor. Please |
bogdanm | 0:9b334a45a8ff | 159 | * refer to the reference manual for further details on burst usage. |
bogdanm | 0:9b334a45a8ff | 160 | * |
bogdanm | 0:9b334a45a8ff | 161 | * @param[in] dst |
bogdanm | 0:9b334a45a8ff | 162 | * Address to start location to transfer data to. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 163 | * descriptor as is. |
bogdanm | 0:9b334a45a8ff | 164 | * |
bogdanm | 0:9b334a45a8ff | 165 | * @param[in] src |
bogdanm | 0:9b334a45a8ff | 166 | * Address to start location to transfer data from. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 167 | * descriptor as is. |
bogdanm | 0:9b334a45a8ff | 168 | * |
bogdanm | 0:9b334a45a8ff | 169 | * @param[in] nMinus1 |
bogdanm | 0:9b334a45a8ff | 170 | * Number of elements (minus 1) to transfer (<= 1023). |
bogdanm | 0:9b334a45a8ff | 171 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 172 | static void DMA_Prepare(unsigned int channel, |
bogdanm | 0:9b334a45a8ff | 173 | DMA_CycleCtrl_TypeDef cycleCtrl, |
bogdanm | 0:9b334a45a8ff | 174 | bool primary, |
bogdanm | 0:9b334a45a8ff | 175 | bool useBurst, |
bogdanm | 0:9b334a45a8ff | 176 | void *dst, |
bogdanm | 0:9b334a45a8ff | 177 | void *src, |
bogdanm | 0:9b334a45a8ff | 178 | unsigned int nMinus1) |
bogdanm | 0:9b334a45a8ff | 179 | { |
bogdanm | 0:9b334a45a8ff | 180 | DMA_DESCRIPTOR_TypeDef *descr; |
bogdanm | 0:9b334a45a8ff | 181 | DMA_DESCRIPTOR_TypeDef *primDescr; |
bogdanm | 0:9b334a45a8ff | 182 | DMA_CB_TypeDef *cb; |
bogdanm | 0:9b334a45a8ff | 183 | uint32_t inc; |
bogdanm | 0:9b334a45a8ff | 184 | uint32_t chBit; |
bogdanm | 0:9b334a45a8ff | 185 | uint32_t tmp; |
bogdanm | 0:9b334a45a8ff | 186 | |
bogdanm | 0:9b334a45a8ff | 187 | primDescr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE)) + channel; |
bogdanm | 0:9b334a45a8ff | 188 | |
bogdanm | 0:9b334a45a8ff | 189 | /* Find descriptor to configure */ |
bogdanm | 0:9b334a45a8ff | 190 | if (primary) |
bogdanm | 0:9b334a45a8ff | 191 | { |
bogdanm | 0:9b334a45a8ff | 192 | descr = primDescr; |
bogdanm | 0:9b334a45a8ff | 193 | } |
bogdanm | 0:9b334a45a8ff | 194 | else |
bogdanm | 0:9b334a45a8ff | 195 | { |
bogdanm | 0:9b334a45a8ff | 196 | descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)) + channel; |
bogdanm | 0:9b334a45a8ff | 197 | } |
bogdanm | 0:9b334a45a8ff | 198 | |
bogdanm | 0:9b334a45a8ff | 199 | /* If callback defined, update info on whether callback is issued */ |
bogdanm | 0:9b334a45a8ff | 200 | /* for primary or alternate descriptor. Mainly needed for ping-pong */ |
bogdanm | 0:9b334a45a8ff | 201 | /* cycles. */ |
bogdanm | 0:9b334a45a8ff | 202 | cb = (DMA_CB_TypeDef *)(primDescr->USER); |
bogdanm | 0:9b334a45a8ff | 203 | if (cb) |
bogdanm | 0:9b334a45a8ff | 204 | { |
bogdanm | 0:9b334a45a8ff | 205 | cb->primary = (uint8_t)primary; |
bogdanm | 0:9b334a45a8ff | 206 | } |
bogdanm | 0:9b334a45a8ff | 207 | |
bogdanm | 0:9b334a45a8ff | 208 | if (src) |
bogdanm | 0:9b334a45a8ff | 209 | { |
bogdanm | 0:9b334a45a8ff | 210 | inc = (descr->CTRL & _DMA_CTRL_SRC_INC_MASK) >> _DMA_CTRL_SRC_INC_SHIFT; |
bogdanm | 0:9b334a45a8ff | 211 | if (inc == _DMA_CTRL_SRC_INC_NONE) |
bogdanm | 0:9b334a45a8ff | 212 | { |
bogdanm | 0:9b334a45a8ff | 213 | descr->SRCEND = src; |
bogdanm | 0:9b334a45a8ff | 214 | } |
bogdanm | 0:9b334a45a8ff | 215 | else |
bogdanm | 0:9b334a45a8ff | 216 | { |
bogdanm | 0:9b334a45a8ff | 217 | descr->SRCEND = (void *)((uint32_t)src + (nMinus1 << inc)); |
bogdanm | 0:9b334a45a8ff | 218 | } |
bogdanm | 0:9b334a45a8ff | 219 | } |
bogdanm | 0:9b334a45a8ff | 220 | |
bogdanm | 0:9b334a45a8ff | 221 | if (dst) |
bogdanm | 0:9b334a45a8ff | 222 | { |
bogdanm | 0:9b334a45a8ff | 223 | inc = (descr->CTRL & _DMA_CTRL_DST_INC_MASK) >> _DMA_CTRL_DST_INC_SHIFT; |
bogdanm | 0:9b334a45a8ff | 224 | if (inc == _DMA_CTRL_DST_INC_NONE) |
bogdanm | 0:9b334a45a8ff | 225 | { |
bogdanm | 0:9b334a45a8ff | 226 | descr->DSTEND = dst; |
bogdanm | 0:9b334a45a8ff | 227 | } |
bogdanm | 0:9b334a45a8ff | 228 | else |
bogdanm | 0:9b334a45a8ff | 229 | { |
bogdanm | 0:9b334a45a8ff | 230 | descr->DSTEND = (void *)((uint32_t)dst + (nMinus1 << inc)); |
bogdanm | 0:9b334a45a8ff | 231 | } |
bogdanm | 0:9b334a45a8ff | 232 | } |
bogdanm | 0:9b334a45a8ff | 233 | |
bogdanm | 0:9b334a45a8ff | 234 | chBit = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 235 | if (useBurst) |
bogdanm | 0:9b334a45a8ff | 236 | { |
bogdanm | 0:9b334a45a8ff | 237 | DMA->CHUSEBURSTS = chBit; |
bogdanm | 0:9b334a45a8ff | 238 | } |
bogdanm | 0:9b334a45a8ff | 239 | else |
bogdanm | 0:9b334a45a8ff | 240 | { |
bogdanm | 0:9b334a45a8ff | 241 | DMA->CHUSEBURSTC = chBit; |
bogdanm | 0:9b334a45a8ff | 242 | } |
bogdanm | 0:9b334a45a8ff | 243 | |
bogdanm | 0:9b334a45a8ff | 244 | if (primary) |
bogdanm | 0:9b334a45a8ff | 245 | { |
bogdanm | 0:9b334a45a8ff | 246 | DMA->CHALTC = chBit; |
bogdanm | 0:9b334a45a8ff | 247 | } |
bogdanm | 0:9b334a45a8ff | 248 | else |
bogdanm | 0:9b334a45a8ff | 249 | { |
bogdanm | 0:9b334a45a8ff | 250 | DMA->CHALTS = chBit; |
bogdanm | 0:9b334a45a8ff | 251 | } |
bogdanm | 0:9b334a45a8ff | 252 | |
bogdanm | 0:9b334a45a8ff | 253 | /* Set cycle control */ |
bogdanm | 0:9b334a45a8ff | 254 | tmp = descr->CTRL & ~(_DMA_CTRL_CYCLE_CTRL_MASK | _DMA_CTRL_N_MINUS_1_MASK); |
bogdanm | 0:9b334a45a8ff | 255 | tmp |= nMinus1 << _DMA_CTRL_N_MINUS_1_SHIFT; |
bogdanm | 0:9b334a45a8ff | 256 | tmp |= (uint32_t)cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT; |
bogdanm | 0:9b334a45a8ff | 257 | descr->CTRL = tmp; |
bogdanm | 0:9b334a45a8ff | 258 | } |
bogdanm | 0:9b334a45a8ff | 259 | |
bogdanm | 0:9b334a45a8ff | 260 | /** @endcond */ |
bogdanm | 0:9b334a45a8ff | 261 | |
bogdanm | 0:9b334a45a8ff | 262 | /******************************************************************************* |
bogdanm | 0:9b334a45a8ff | 263 | ************************ INTERRUPT FUNCTIONS ****************************** |
bogdanm | 0:9b334a45a8ff | 264 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 265 | |
bogdanm | 0:9b334a45a8ff | 266 | #ifndef EXCLUDE_DEFAULT_DMA_IRQ_HANDLER |
bogdanm | 0:9b334a45a8ff | 267 | |
bogdanm | 0:9b334a45a8ff | 268 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 269 | * @brief |
bogdanm | 0:9b334a45a8ff | 270 | * Interrupt handler for DMA cycle completion handling. |
bogdanm | 0:9b334a45a8ff | 271 | * |
bogdanm | 0:9b334a45a8ff | 272 | * @details |
bogdanm | 0:9b334a45a8ff | 273 | * Clears any pending flags and calls registered callback (if any). |
bogdanm | 0:9b334a45a8ff | 274 | * |
bogdanm | 0:9b334a45a8ff | 275 | * If using the default interrupt vector table setup provided, this function |
bogdanm | 0:9b334a45a8ff | 276 | * is automatically placed in the IRQ table due to weak linking. If taking |
bogdanm | 0:9b334a45a8ff | 277 | * control over the interrupt vector table in some other way, this interrupt |
bogdanm | 0:9b334a45a8ff | 278 | * handler must be installed in order to be able to support callback actions. |
bogdanm | 0:9b334a45a8ff | 279 | * |
bogdanm | 0:9b334a45a8ff | 280 | * In order for the user to implement a custom IRQ handler or run without |
bogdanm | 0:9b334a45a8ff | 281 | * a DMA IRQ handler, the user can define EXCLUDE_DEFAULT_DMA_IRQ_HANDLER |
bogdanm | 0:9b334a45a8ff | 282 | * with a \#define statement or with the compiler option -D. |
bogdanm | 0:9b334a45a8ff | 283 | * |
bogdanm | 0:9b334a45a8ff | 284 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 285 | void DMA_IRQHandler(void) |
bogdanm | 0:9b334a45a8ff | 286 | { |
bogdanm | 0:9b334a45a8ff | 287 | int channel; |
bogdanm | 0:9b334a45a8ff | 288 | DMA_CB_TypeDef *cb; |
bogdanm | 0:9b334a45a8ff | 289 | uint32_t pending; |
bogdanm | 0:9b334a45a8ff | 290 | uint32_t pendingPrio; |
bogdanm | 0:9b334a45a8ff | 291 | uint32_t prio; |
bogdanm | 0:9b334a45a8ff | 292 | uint32_t primaryCpy; |
bogdanm | 0:9b334a45a8ff | 293 | int i; |
bogdanm | 0:9b334a45a8ff | 294 | |
bogdanm | 0:9b334a45a8ff | 295 | /* Get all pending and enabled interrupts */ |
bogdanm | 0:9b334a45a8ff | 296 | pending = DMA->IF; |
bogdanm | 0:9b334a45a8ff | 297 | pending &= DMA->IEN; |
bogdanm | 0:9b334a45a8ff | 298 | |
bogdanm | 0:9b334a45a8ff | 299 | /* Check for bus error */ |
bogdanm | 0:9b334a45a8ff | 300 | if (pending & DMA_IF_ERR) |
bogdanm | 0:9b334a45a8ff | 301 | { |
bogdanm | 0:9b334a45a8ff | 302 | /* Loop here to enable the debugger to see what has happened */ |
bogdanm | 0:9b334a45a8ff | 303 | while (1) |
bogdanm | 0:9b334a45a8ff | 304 | ; |
bogdanm | 0:9b334a45a8ff | 305 | } |
bogdanm | 0:9b334a45a8ff | 306 | |
bogdanm | 0:9b334a45a8ff | 307 | /* Process all pending channel interrupts. First process channels */ |
bogdanm | 0:9b334a45a8ff | 308 | /* defined with high priority, then those with default priority. */ |
bogdanm | 0:9b334a45a8ff | 309 | prio = DMA->CHPRIS; |
bogdanm | 0:9b334a45a8ff | 310 | pendingPrio = pending & prio; |
bogdanm | 0:9b334a45a8ff | 311 | for (i = 0; i < 2; i++) |
bogdanm | 0:9b334a45a8ff | 312 | { |
bogdanm | 0:9b334a45a8ff | 313 | channel = 0; |
bogdanm | 0:9b334a45a8ff | 314 | /* Process pending interrupts within high/default priority group */ |
bogdanm | 0:9b334a45a8ff | 315 | /* honouring priority within group. */ |
bogdanm | 0:9b334a45a8ff | 316 | while (pendingPrio) |
bogdanm | 0:9b334a45a8ff | 317 | { |
bogdanm | 0:9b334a45a8ff | 318 | if (pendingPrio & 1) |
bogdanm | 0:9b334a45a8ff | 319 | { |
bogdanm | 0:9b334a45a8ff | 320 | DMA_DESCRIPTOR_TypeDef *descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE); |
bogdanm | 0:9b334a45a8ff | 321 | uint32_t chmask = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 322 | |
bogdanm | 0:9b334a45a8ff | 323 | /* Clear pending interrupt prior to invoking callback, in case it */ |
bogdanm | 0:9b334a45a8ff | 324 | /* sets up another DMA cycle. */ |
bogdanm | 0:9b334a45a8ff | 325 | DMA->IFC = chmask; |
bogdanm | 0:9b334a45a8ff | 326 | |
bogdanm | 0:9b334a45a8ff | 327 | /* Normally, no point in enabling interrupt without callback, but */ |
bogdanm | 0:9b334a45a8ff | 328 | /* check if callback is defined anyway. Callback info is always */ |
bogdanm | 0:9b334a45a8ff | 329 | /* located in primary descriptor. */ |
bogdanm | 0:9b334a45a8ff | 330 | cb = (DMA_CB_TypeDef *)(descr[channel].USER); |
bogdanm | 0:9b334a45a8ff | 331 | if (cb) |
bogdanm | 0:9b334a45a8ff | 332 | { |
bogdanm | 0:9b334a45a8ff | 333 | /* Toggle next-descriptor indicator always prior to invoking */ |
bogdanm | 0:9b334a45a8ff | 334 | /* callback (in case callback reconfigurs something) */ |
bogdanm | 0:9b334a45a8ff | 335 | primaryCpy = cb->primary; |
bogdanm | 0:9b334a45a8ff | 336 | cb->primary ^= 1; |
bogdanm | 0:9b334a45a8ff | 337 | if (cb->cbFunc) |
bogdanm | 0:9b334a45a8ff | 338 | { |
bogdanm | 0:9b334a45a8ff | 339 | cb->cbFunc(channel, (bool)primaryCpy, cb->userPtr); |
bogdanm | 0:9b334a45a8ff | 340 | } |
bogdanm | 0:9b334a45a8ff | 341 | } |
bogdanm | 0:9b334a45a8ff | 342 | } |
bogdanm | 0:9b334a45a8ff | 343 | |
bogdanm | 0:9b334a45a8ff | 344 | pendingPrio >>= 1; |
bogdanm | 0:9b334a45a8ff | 345 | channel++; |
bogdanm | 0:9b334a45a8ff | 346 | } |
bogdanm | 0:9b334a45a8ff | 347 | |
bogdanm | 0:9b334a45a8ff | 348 | /* On second iteration, process default priority channels */ |
bogdanm | 0:9b334a45a8ff | 349 | pendingPrio = pending & ~prio; |
bogdanm | 0:9b334a45a8ff | 350 | } |
bogdanm | 0:9b334a45a8ff | 351 | } |
bogdanm | 0:9b334a45a8ff | 352 | |
bogdanm | 0:9b334a45a8ff | 353 | #endif /* EXCLUDE_DEFAULT_DMA_IRQ_HANDLER */ |
bogdanm | 0:9b334a45a8ff | 354 | |
bogdanm | 0:9b334a45a8ff | 355 | |
bogdanm | 0:9b334a45a8ff | 356 | /******************************************************************************* |
bogdanm | 0:9b334a45a8ff | 357 | ************************** GLOBAL FUNCTIONS ******************************* |
bogdanm | 0:9b334a45a8ff | 358 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 359 | |
bogdanm | 0:9b334a45a8ff | 360 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 361 | * @brief |
bogdanm | 0:9b334a45a8ff | 362 | * Activate DMA auto-request cycle (used for memory-memory transfers). |
bogdanm | 0:9b334a45a8ff | 363 | * |
bogdanm | 0:9b334a45a8ff | 364 | * @details |
bogdanm | 0:9b334a45a8ff | 365 | * Prior to activating the DMA cycle, the channel and descriptor to be used |
bogdanm | 0:9b334a45a8ff | 366 | * must have been properly configured. |
bogdanm | 0:9b334a45a8ff | 367 | * |
bogdanm | 0:9b334a45a8ff | 368 | * @note |
bogdanm | 0:9b334a45a8ff | 369 | * If using this function on a channel already activated and in use by the |
bogdanm | 0:9b334a45a8ff | 370 | * DMA controller, the behaviour is undefined. |
bogdanm | 0:9b334a45a8ff | 371 | * |
bogdanm | 0:9b334a45a8ff | 372 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 373 | * DMA channel to activate DMA cycle for. |
bogdanm | 0:9b334a45a8ff | 374 | * |
bogdanm | 0:9b334a45a8ff | 375 | * @param[in] primary |
bogdanm | 0:9b334a45a8ff | 376 | * @li true - activate using primary descriptor |
bogdanm | 0:9b334a45a8ff | 377 | * @li false - activate using alternate descriptor |
bogdanm | 0:9b334a45a8ff | 378 | * |
bogdanm | 0:9b334a45a8ff | 379 | * @param[in] dst |
bogdanm | 0:9b334a45a8ff | 380 | * Address to start location to transfer data to. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 381 | * descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 382 | * |
bogdanm | 0:9b334a45a8ff | 383 | * @param[in] src |
bogdanm | 0:9b334a45a8ff | 384 | * Address to start location to transfer data from. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 385 | * descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 386 | * |
bogdanm | 0:9b334a45a8ff | 387 | * @param[in] nMinus1 |
bogdanm | 0:9b334a45a8ff | 388 | * Number of DMA transfer elements (minus 1) to transfer (<= 1023). The |
bogdanm | 0:9b334a45a8ff | 389 | * size of the DMA transfer element (1, 2 or 4 bytes) is configured with |
bogdanm | 0:9b334a45a8ff | 390 | * DMA_CfgDescr(). |
bogdanm | 0:9b334a45a8ff | 391 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 392 | void DMA_ActivateAuto(unsigned int channel, |
bogdanm | 0:9b334a45a8ff | 393 | bool primary, |
bogdanm | 0:9b334a45a8ff | 394 | void *dst, |
bogdanm | 0:9b334a45a8ff | 395 | void *src, |
bogdanm | 0:9b334a45a8ff | 396 | unsigned int nMinus1) |
bogdanm | 0:9b334a45a8ff | 397 | { |
bogdanm | 0:9b334a45a8ff | 398 | uint32_t chBit; |
bogdanm | 0:9b334a45a8ff | 399 | |
bogdanm | 0:9b334a45a8ff | 400 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 401 | EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT)); |
bogdanm | 0:9b334a45a8ff | 402 | |
bogdanm | 0:9b334a45a8ff | 403 | DMA_Prepare(channel, |
bogdanm | 0:9b334a45a8ff | 404 | dmaCycleCtrlAuto, |
bogdanm | 0:9b334a45a8ff | 405 | primary, |
bogdanm | 0:9b334a45a8ff | 406 | false, |
bogdanm | 0:9b334a45a8ff | 407 | dst, |
bogdanm | 0:9b334a45a8ff | 408 | src, |
bogdanm | 0:9b334a45a8ff | 409 | nMinus1); |
bogdanm | 0:9b334a45a8ff | 410 | |
bogdanm | 0:9b334a45a8ff | 411 | chBit = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 412 | DMA->CHENS = chBit; /* Enable channel */ |
bogdanm | 0:9b334a45a8ff | 413 | DMA->CHSWREQ = chBit; /* Activate with SW request */ |
bogdanm | 0:9b334a45a8ff | 414 | } |
bogdanm | 0:9b334a45a8ff | 415 | |
bogdanm | 0:9b334a45a8ff | 416 | |
bogdanm | 0:9b334a45a8ff | 417 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 418 | * @brief |
bogdanm | 0:9b334a45a8ff | 419 | * Activate DMA basic cycle (used for memory-peripheral transfers). |
bogdanm | 0:9b334a45a8ff | 420 | * |
bogdanm | 0:9b334a45a8ff | 421 | * @details |
bogdanm | 0:9b334a45a8ff | 422 | * Prior to activating the DMA cycle, the channel and descriptor to be used |
bogdanm | 0:9b334a45a8ff | 423 | * must have been properly configured. |
bogdanm | 0:9b334a45a8ff | 424 | * |
bogdanm | 0:9b334a45a8ff | 425 | * @note |
bogdanm | 0:9b334a45a8ff | 426 | * If using this function on a channel already activated and in use by the |
bogdanm | 0:9b334a45a8ff | 427 | * DMA controller, the behaviour is undefined. |
bogdanm | 0:9b334a45a8ff | 428 | * |
bogdanm | 0:9b334a45a8ff | 429 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 430 | * DMA channel to activate DMA cycle for. |
bogdanm | 0:9b334a45a8ff | 431 | * |
bogdanm | 0:9b334a45a8ff | 432 | * @param[in] primary |
bogdanm | 0:9b334a45a8ff | 433 | * @li true - activate using primary descriptor |
bogdanm | 0:9b334a45a8ff | 434 | * @li false - activate using alternate descriptor |
bogdanm | 0:9b334a45a8ff | 435 | * |
bogdanm | 0:9b334a45a8ff | 436 | * @param[in] useBurst |
bogdanm | 0:9b334a45a8ff | 437 | * The burst feature is only used on peripherals supporting DMA bursts. |
bogdanm | 0:9b334a45a8ff | 438 | * Bursts must not be used if the total length (as given by nMinus1) is |
bogdanm | 0:9b334a45a8ff | 439 | * less than the arbitration rate configured for the descriptor. Please |
bogdanm | 0:9b334a45a8ff | 440 | * refer to the reference manual for further details on burst usage. |
bogdanm | 0:9b334a45a8ff | 441 | * |
bogdanm | 0:9b334a45a8ff | 442 | * @param[in] dst |
bogdanm | 0:9b334a45a8ff | 443 | * Address to start location to transfer data to. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 444 | * descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 445 | * |
bogdanm | 0:9b334a45a8ff | 446 | * @param[in] src |
bogdanm | 0:9b334a45a8ff | 447 | * Address to start location to transfer data from. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 448 | * descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 449 | * |
bogdanm | 0:9b334a45a8ff | 450 | * @param[in] nMinus1 |
bogdanm | 0:9b334a45a8ff | 451 | * Number of DMA transfer elements (minus 1) to transfer (<= 1023). The |
bogdanm | 0:9b334a45a8ff | 452 | * size of the DMA transfer element (1, 2 or 4 bytes) is configured with |
bogdanm | 0:9b334a45a8ff | 453 | * DMA_CfgDescr(). |
bogdanm | 0:9b334a45a8ff | 454 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 455 | void DMA_ActivateBasic(unsigned int channel, |
bogdanm | 0:9b334a45a8ff | 456 | bool primary, |
bogdanm | 0:9b334a45a8ff | 457 | bool useBurst, |
bogdanm | 0:9b334a45a8ff | 458 | void *dst, |
bogdanm | 0:9b334a45a8ff | 459 | void *src, |
bogdanm | 0:9b334a45a8ff | 460 | unsigned int nMinus1) |
bogdanm | 0:9b334a45a8ff | 461 | { |
bogdanm | 0:9b334a45a8ff | 462 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 463 | EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT)); |
bogdanm | 0:9b334a45a8ff | 464 | |
bogdanm | 0:9b334a45a8ff | 465 | DMA_Prepare(channel, |
bogdanm | 0:9b334a45a8ff | 466 | dmaCycleCtrlBasic, |
bogdanm | 0:9b334a45a8ff | 467 | primary, |
bogdanm | 0:9b334a45a8ff | 468 | useBurst, |
bogdanm | 0:9b334a45a8ff | 469 | dst, |
bogdanm | 0:9b334a45a8ff | 470 | src, |
bogdanm | 0:9b334a45a8ff | 471 | nMinus1); |
bogdanm | 0:9b334a45a8ff | 472 | |
bogdanm | 0:9b334a45a8ff | 473 | /* Enable channel, request signal is provided by peripheral device */ |
bogdanm | 0:9b334a45a8ff | 474 | DMA->CHENS = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 475 | } |
bogdanm | 0:9b334a45a8ff | 476 | |
bogdanm | 0:9b334a45a8ff | 477 | |
bogdanm | 0:9b334a45a8ff | 478 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 479 | * @brief |
bogdanm | 0:9b334a45a8ff | 480 | * Activate DMA ping-pong cycle (used for memory-peripheral transfers). |
bogdanm | 0:9b334a45a8ff | 481 | * |
bogdanm | 0:9b334a45a8ff | 482 | * @details |
bogdanm | 0:9b334a45a8ff | 483 | * Prior to activating the DMA cycle, the channel and both descriptors must |
bogdanm | 0:9b334a45a8ff | 484 | * have been properly configured. The primary descriptor is always the first |
bogdanm | 0:9b334a45a8ff | 485 | * descriptor to be used by the DMA controller. |
bogdanm | 0:9b334a45a8ff | 486 | * |
bogdanm | 0:9b334a45a8ff | 487 | * @note |
bogdanm | 0:9b334a45a8ff | 488 | * If using this function on a channel already activated and in use by the |
bogdanm | 0:9b334a45a8ff | 489 | * DMA controller, the behaviour is undefined. |
bogdanm | 0:9b334a45a8ff | 490 | * |
bogdanm | 0:9b334a45a8ff | 491 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 492 | * DMA channel to activate DMA cycle for. |
bogdanm | 0:9b334a45a8ff | 493 | * |
bogdanm | 0:9b334a45a8ff | 494 | * @param[in] useBurst |
bogdanm | 0:9b334a45a8ff | 495 | * The burst feature is only used on peripherals supporting DMA bursts. |
bogdanm | 0:9b334a45a8ff | 496 | * Bursts must not be used if the total length (as given by nMinus1) is |
bogdanm | 0:9b334a45a8ff | 497 | * less than the arbitration rate configured for the descriptors. Please |
bogdanm | 0:9b334a45a8ff | 498 | * refer to the reference manual for further details on burst usage. Notice |
bogdanm | 0:9b334a45a8ff | 499 | * that this setting is used for both the primary and alternate descriptors. |
bogdanm | 0:9b334a45a8ff | 500 | * |
bogdanm | 0:9b334a45a8ff | 501 | * @param[in] primDst |
bogdanm | 0:9b334a45a8ff | 502 | * Address to start location to transfer data to, for primary descriptor. |
bogdanm | 0:9b334a45a8ff | 503 | * If NULL, leave setting in descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 504 | * |
bogdanm | 0:9b334a45a8ff | 505 | * @param[in] primSrc |
bogdanm | 0:9b334a45a8ff | 506 | * Address to start location to transfer data from, for primary descriptor. |
bogdanm | 0:9b334a45a8ff | 507 | * If NULL, leave setting in descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 508 | * |
bogdanm | 0:9b334a45a8ff | 509 | * @param[in] primNMinus1 |
bogdanm | 0:9b334a45a8ff | 510 | * Number of DMA transfer elements (minus 1) to transfer (<= 1023), for |
bogdanm | 0:9b334a45a8ff | 511 | * primary descriptor. The size of the DMA transfer element (1, 2 or 4 bytes) |
bogdanm | 0:9b334a45a8ff | 512 | * is configured with DMA_CfgDescr(). |
bogdanm | 0:9b334a45a8ff | 513 | * |
bogdanm | 0:9b334a45a8ff | 514 | * @param[in] altDst |
bogdanm | 0:9b334a45a8ff | 515 | * Address to start location to transfer data to, for alternate descriptor. |
bogdanm | 0:9b334a45a8ff | 516 | * If NULL, leave setting in descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 517 | * |
bogdanm | 0:9b334a45a8ff | 518 | * @param[in] altSrc |
bogdanm | 0:9b334a45a8ff | 519 | * Address to start location to transfer data from, for alternate descriptor. |
bogdanm | 0:9b334a45a8ff | 520 | * If NULL, leave setting in descriptor as is from a previous activation. |
bogdanm | 0:9b334a45a8ff | 521 | * |
bogdanm | 0:9b334a45a8ff | 522 | * @param[in] altNMinus1 |
bogdanm | 0:9b334a45a8ff | 523 | * Number of DMA transfer elements (minus 1) to transfer (<= 1023), for |
bogdanm | 0:9b334a45a8ff | 524 | * alternate descriptor. The size of the DMA transfer element (1, 2 or 4 bytes) |
bogdanm | 0:9b334a45a8ff | 525 | * is configured with DMA_CfgDescr(). |
bogdanm | 0:9b334a45a8ff | 526 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 527 | void DMA_ActivatePingPong(unsigned int channel, |
bogdanm | 0:9b334a45a8ff | 528 | bool useBurst, |
bogdanm | 0:9b334a45a8ff | 529 | void *primDst, |
bogdanm | 0:9b334a45a8ff | 530 | void *primSrc, |
bogdanm | 0:9b334a45a8ff | 531 | unsigned int primNMinus1, |
bogdanm | 0:9b334a45a8ff | 532 | void *altDst, |
bogdanm | 0:9b334a45a8ff | 533 | void *altSrc, |
bogdanm | 0:9b334a45a8ff | 534 | unsigned int altNMinus1) |
bogdanm | 0:9b334a45a8ff | 535 | { |
bogdanm | 0:9b334a45a8ff | 536 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 537 | EFM_ASSERT(primNMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT)); |
bogdanm | 0:9b334a45a8ff | 538 | EFM_ASSERT(altNMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT)); |
bogdanm | 0:9b334a45a8ff | 539 | |
bogdanm | 0:9b334a45a8ff | 540 | /* Prepare alternate descriptor first */ |
bogdanm | 0:9b334a45a8ff | 541 | DMA_Prepare(channel, |
bogdanm | 0:9b334a45a8ff | 542 | dmaCycleCtrlPingPong, |
bogdanm | 0:9b334a45a8ff | 543 | false, |
bogdanm | 0:9b334a45a8ff | 544 | useBurst, |
bogdanm | 0:9b334a45a8ff | 545 | altDst, |
bogdanm | 0:9b334a45a8ff | 546 | altSrc, |
bogdanm | 0:9b334a45a8ff | 547 | altNMinus1); |
bogdanm | 0:9b334a45a8ff | 548 | |
bogdanm | 0:9b334a45a8ff | 549 | /* Prepare primary descriptor last in order to start cycle using it */ |
bogdanm | 0:9b334a45a8ff | 550 | DMA_Prepare(channel, |
bogdanm | 0:9b334a45a8ff | 551 | dmaCycleCtrlPingPong, |
bogdanm | 0:9b334a45a8ff | 552 | true, |
bogdanm | 0:9b334a45a8ff | 553 | useBurst, |
bogdanm | 0:9b334a45a8ff | 554 | primDst, |
bogdanm | 0:9b334a45a8ff | 555 | primSrc, |
bogdanm | 0:9b334a45a8ff | 556 | primNMinus1); |
bogdanm | 0:9b334a45a8ff | 557 | |
bogdanm | 0:9b334a45a8ff | 558 | /* Enable channel, request signal is provided by peripheral device */ |
bogdanm | 0:9b334a45a8ff | 559 | DMA->CHENS = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 560 | } |
bogdanm | 0:9b334a45a8ff | 561 | |
bogdanm | 0:9b334a45a8ff | 562 | |
bogdanm | 0:9b334a45a8ff | 563 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 564 | * @brief |
bogdanm | 0:9b334a45a8ff | 565 | * Activate DMA scatter-gather cycle (used for either memory-peripheral |
bogdanm | 0:9b334a45a8ff | 566 | * or memory-memory transfers). |
bogdanm | 0:9b334a45a8ff | 567 | * |
bogdanm | 0:9b334a45a8ff | 568 | * @details |
bogdanm | 0:9b334a45a8ff | 569 | * Prior to activating the DMA cycle, the array with alternate descriptors |
bogdanm | 0:9b334a45a8ff | 570 | * must have been properly configured. This function can be reused without |
bogdanm | 0:9b334a45a8ff | 571 | * reconfiguring the alternate descriptors, as long as @p count is the same. |
bogdanm | 0:9b334a45a8ff | 572 | * |
bogdanm | 0:9b334a45a8ff | 573 | * @note |
bogdanm | 0:9b334a45a8ff | 574 | * If using this function on a channel already activated and in use by the |
bogdanm | 0:9b334a45a8ff | 575 | * DMA controller, the behaviour is undefined. |
bogdanm | 0:9b334a45a8ff | 576 | * |
bogdanm | 0:9b334a45a8ff | 577 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 578 | * DMA channel to activate DMA cycle for. |
bogdanm | 0:9b334a45a8ff | 579 | * |
bogdanm | 0:9b334a45a8ff | 580 | * @param[in] useBurst |
bogdanm | 0:9b334a45a8ff | 581 | * The burst feature is only used on peripherals supporting DMA bursts |
bogdanm | 0:9b334a45a8ff | 582 | * (and thus this parameter is ignored for memory scatter-gather cycles). |
bogdanm | 0:9b334a45a8ff | 583 | * This parameter determines if bursts should be enabled during DMA transfers |
bogdanm | 0:9b334a45a8ff | 584 | * using the alternate descriptors. Bursts must not be used if the total |
bogdanm | 0:9b334a45a8ff | 585 | * length (as given by nMinus1 for the alternate descriptor) is |
bogdanm | 0:9b334a45a8ff | 586 | * less than the arbitration rate configured for the descriptor. Please |
bogdanm | 0:9b334a45a8ff | 587 | * refer to the reference manual for further details on burst usage. |
bogdanm | 0:9b334a45a8ff | 588 | * |
bogdanm | 0:9b334a45a8ff | 589 | * @param[in,out] altDescr |
bogdanm | 0:9b334a45a8ff | 590 | * Pointer to start of array with prepared alternate descriptors. The last |
bogdanm | 0:9b334a45a8ff | 591 | * descriptor will have its cycle control type reprogrammed to basic type. |
bogdanm | 0:9b334a45a8ff | 592 | * |
bogdanm | 0:9b334a45a8ff | 593 | * @param[in] count |
bogdanm | 0:9b334a45a8ff | 594 | * Number of alternate descriptors in @p altDescr array. Maximum number of |
bogdanm | 0:9b334a45a8ff | 595 | * alternate descriptors is 256. |
bogdanm | 0:9b334a45a8ff | 596 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 597 | void DMA_ActivateScatterGather(unsigned int channel, |
bogdanm | 0:9b334a45a8ff | 598 | bool useBurst, |
bogdanm | 0:9b334a45a8ff | 599 | DMA_DESCRIPTOR_TypeDef *altDescr, |
bogdanm | 0:9b334a45a8ff | 600 | unsigned int count) |
bogdanm | 0:9b334a45a8ff | 601 | { |
bogdanm | 0:9b334a45a8ff | 602 | DMA_DESCRIPTOR_TypeDef *descr; |
bogdanm | 0:9b334a45a8ff | 603 | DMA_CB_TypeDef *cb; |
bogdanm | 0:9b334a45a8ff | 604 | uint32_t cycleCtrl; |
bogdanm | 0:9b334a45a8ff | 605 | uint32_t chBit; |
bogdanm | 0:9b334a45a8ff | 606 | |
bogdanm | 0:9b334a45a8ff | 607 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 608 | EFM_ASSERT(altDescr); |
bogdanm | 0:9b334a45a8ff | 609 | EFM_ASSERT(count && (count <= 256)); |
bogdanm | 0:9b334a45a8ff | 610 | |
bogdanm | 0:9b334a45a8ff | 611 | /* We have to configure the primary descriptor properly in order to */ |
bogdanm | 0:9b334a45a8ff | 612 | /* transfer one complete alternate descriptor from the alternate */ |
bogdanm | 0:9b334a45a8ff | 613 | /* descriptor table into the actual alternate descriptor. */ |
bogdanm | 0:9b334a45a8ff | 614 | descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE) + channel; |
bogdanm | 0:9b334a45a8ff | 615 | |
bogdanm | 0:9b334a45a8ff | 616 | /* Set source end address to point to alternate descriptor array */ |
bogdanm | 0:9b334a45a8ff | 617 | descr->SRCEND = (uint32_t *)altDescr + (count * 4) - 1; |
bogdanm | 0:9b334a45a8ff | 618 | |
bogdanm | 0:9b334a45a8ff | 619 | /* The destination end address in the primary descriptor MUST point */ |
bogdanm | 0:9b334a45a8ff | 620 | /* to the corresponding alternate descriptor in scatter-gather mode. */ |
bogdanm | 0:9b334a45a8ff | 621 | descr->DSTEND = (uint32_t *)((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE) + |
bogdanm | 0:9b334a45a8ff | 622 | channel + 1) - 1; |
bogdanm | 0:9b334a45a8ff | 623 | |
bogdanm | 0:9b334a45a8ff | 624 | /* The user field of the descriptor is used for callback configuration, */ |
bogdanm | 0:9b334a45a8ff | 625 | /* and already configured when channel is configured. Do not modify it. */ |
bogdanm | 0:9b334a45a8ff | 626 | |
bogdanm | 0:9b334a45a8ff | 627 | /* Determine from alternate configuration whether this is a memory or */ |
bogdanm | 0:9b334a45a8ff | 628 | /* peripheral scatter-gather, by looking at the first alternate descriptor. */ |
bogdanm | 0:9b334a45a8ff | 629 | cycleCtrl = altDescr->CTRL & _DMA_CTRL_CYCLE_CTRL_MASK; |
bogdanm | 0:9b334a45a8ff | 630 | cycleCtrl &= ~(1 << _DMA_CTRL_CYCLE_CTRL_SHIFT); |
bogdanm | 0:9b334a45a8ff | 631 | |
bogdanm | 0:9b334a45a8ff | 632 | EFM_ASSERT((cycleCtrl == dmaCycleCtrlMemScatterGather) || |
bogdanm | 0:9b334a45a8ff | 633 | (cycleCtrl == dmaCycleCtrlPerScatterGather)); |
bogdanm | 0:9b334a45a8ff | 634 | |
bogdanm | 0:9b334a45a8ff | 635 | /* Set last alternate descriptor to basic or auto-request cycle type in */ |
bogdanm | 0:9b334a45a8ff | 636 | /* order to have dma_done signal asserted when complete. Otherwise interrupt */ |
bogdanm | 0:9b334a45a8ff | 637 | /* will not be triggered when done. */ |
bogdanm | 0:9b334a45a8ff | 638 | altDescr[count - 1].CTRL &= ~_DMA_CTRL_CYCLE_CTRL_MASK; |
bogdanm | 0:9b334a45a8ff | 639 | if (cycleCtrl == dmaCycleCtrlMemScatterGather) |
bogdanm | 0:9b334a45a8ff | 640 | { |
bogdanm | 0:9b334a45a8ff | 641 | altDescr[count - 1].CTRL |= (uint32_t)dmaCycleCtrlAuto << _DMA_CTRL_CYCLE_CTRL_SHIFT; |
bogdanm | 0:9b334a45a8ff | 642 | } |
bogdanm | 0:9b334a45a8ff | 643 | else |
bogdanm | 0:9b334a45a8ff | 644 | { |
bogdanm | 0:9b334a45a8ff | 645 | altDescr[count - 1].CTRL |= (uint32_t)dmaCycleCtrlBasic << _DMA_CTRL_CYCLE_CTRL_SHIFT; |
bogdanm | 0:9b334a45a8ff | 646 | } |
bogdanm | 0:9b334a45a8ff | 647 | |
bogdanm | 0:9b334a45a8ff | 648 | /* If callback defined, update info on whether callback is issued for */ |
bogdanm | 0:9b334a45a8ff | 649 | /* primary or alternate descriptor. Not really useful for scatter-gather, */ |
bogdanm | 0:9b334a45a8ff | 650 | /* but do for consistency. Always set to alternate, since that is the last */ |
bogdanm | 0:9b334a45a8ff | 651 | /* descriptor actually used. */ |
bogdanm | 0:9b334a45a8ff | 652 | cb = (DMA_CB_TypeDef *)(descr->USER); |
bogdanm | 0:9b334a45a8ff | 653 | if (cb) |
bogdanm | 0:9b334a45a8ff | 654 | { |
bogdanm | 0:9b334a45a8ff | 655 | cb->primary = false; |
bogdanm | 0:9b334a45a8ff | 656 | } |
bogdanm | 0:9b334a45a8ff | 657 | |
bogdanm | 0:9b334a45a8ff | 658 | /* Configure primary descriptor control word */ |
bogdanm | 0:9b334a45a8ff | 659 | descr->CTRL = |
bogdanm | 0:9b334a45a8ff | 660 | ((uint32_t)dmaDataInc4 << _DMA_CTRL_DST_INC_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 661 | ((uint32_t)dmaDataSize4 << _DMA_CTRL_DST_SIZE_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 662 | ((uint32_t)dmaDataInc4 << _DMA_CTRL_SRC_INC_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 663 | ((uint32_t)dmaDataSize4 << _DMA_CTRL_SRC_SIZE_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 664 | /* Use same protection scheme as for alternate descriptors */ |
bogdanm | 0:9b334a45a8ff | 665 | (altDescr->CTRL & _DMA_CTRL_SRC_PROT_CTRL_MASK) | |
bogdanm | 0:9b334a45a8ff | 666 | ((uint32_t)dmaArbitrate4 << _DMA_CTRL_R_POWER_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 667 | (((count * 4) - 1) << _DMA_CTRL_N_MINUS_1_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 668 | (((uint32_t)useBurst & 1) << _DMA_CTRL_NEXT_USEBURST_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 669 | cycleCtrl; |
bogdanm | 0:9b334a45a8ff | 670 | |
bogdanm | 0:9b334a45a8ff | 671 | chBit = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 672 | |
bogdanm | 0:9b334a45a8ff | 673 | /* Start with primary descriptor */ |
bogdanm | 0:9b334a45a8ff | 674 | DMA->CHALTC = chBit; |
bogdanm | 0:9b334a45a8ff | 675 | |
bogdanm | 0:9b334a45a8ff | 676 | /* Enable channel */ |
bogdanm | 0:9b334a45a8ff | 677 | DMA->CHENS = chBit; |
bogdanm | 0:9b334a45a8ff | 678 | |
bogdanm | 0:9b334a45a8ff | 679 | /* Send request if memory scatter-gather, otherwise request signal is */ |
bogdanm | 0:9b334a45a8ff | 680 | /* provided by peripheral. */ |
bogdanm | 0:9b334a45a8ff | 681 | if (cycleCtrl == dmaCycleCtrlMemScatterGather) |
bogdanm | 0:9b334a45a8ff | 682 | { |
bogdanm | 0:9b334a45a8ff | 683 | DMA->CHSWREQ = chBit; |
bogdanm | 0:9b334a45a8ff | 684 | } |
bogdanm | 0:9b334a45a8ff | 685 | } |
bogdanm | 0:9b334a45a8ff | 686 | |
bogdanm | 0:9b334a45a8ff | 687 | |
bogdanm | 0:9b334a45a8ff | 688 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 689 | * @brief |
bogdanm | 0:9b334a45a8ff | 690 | * Configure a DMA channel. |
bogdanm | 0:9b334a45a8ff | 691 | * |
bogdanm | 0:9b334a45a8ff | 692 | * @details |
bogdanm | 0:9b334a45a8ff | 693 | * Configure miscellaneous issues for a DMA channel. This function is typically |
bogdanm | 0:9b334a45a8ff | 694 | * used once to setup a channel for a certain type of use. |
bogdanm | 0:9b334a45a8ff | 695 | * |
bogdanm | 0:9b334a45a8ff | 696 | * @note |
bogdanm | 0:9b334a45a8ff | 697 | * If using this function on a channel already in use by the DMA controller, |
bogdanm | 0:9b334a45a8ff | 698 | * the behaviour is undefined. |
bogdanm | 0:9b334a45a8ff | 699 | * |
bogdanm | 0:9b334a45a8ff | 700 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 701 | * DMA channel to configure. |
bogdanm | 0:9b334a45a8ff | 702 | * |
bogdanm | 0:9b334a45a8ff | 703 | * @param[in] cfg |
bogdanm | 0:9b334a45a8ff | 704 | * Configuration to use. |
bogdanm | 0:9b334a45a8ff | 705 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 706 | void DMA_CfgChannel(unsigned int channel, DMA_CfgChannel_TypeDef *cfg) |
bogdanm | 0:9b334a45a8ff | 707 | { |
bogdanm | 0:9b334a45a8ff | 708 | DMA_DESCRIPTOR_TypeDef *descr; |
bogdanm | 0:9b334a45a8ff | 709 | |
bogdanm | 0:9b334a45a8ff | 710 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 711 | EFM_ASSERT(cfg); |
bogdanm | 0:9b334a45a8ff | 712 | |
bogdanm | 0:9b334a45a8ff | 713 | /* Always keep callback configuration reference in primary descriptor */ |
bogdanm | 0:9b334a45a8ff | 714 | descr = (DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE); |
bogdanm | 0:9b334a45a8ff | 715 | descr[channel].USER = (uint32_t)(cfg->cb); |
bogdanm | 0:9b334a45a8ff | 716 | |
bogdanm | 0:9b334a45a8ff | 717 | /* Set to specified priority for channel */ |
bogdanm | 0:9b334a45a8ff | 718 | if (cfg->highPri) |
bogdanm | 0:9b334a45a8ff | 719 | { |
bogdanm | 0:9b334a45a8ff | 720 | DMA->CHPRIS = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 721 | } |
bogdanm | 0:9b334a45a8ff | 722 | else |
bogdanm | 0:9b334a45a8ff | 723 | { |
bogdanm | 0:9b334a45a8ff | 724 | DMA->CHPRIC = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 725 | } |
bogdanm | 0:9b334a45a8ff | 726 | |
bogdanm | 0:9b334a45a8ff | 727 | /* Set DMA signal source select */ |
bogdanm | 0:9b334a45a8ff | 728 | DMA->CH[channel].CTRL = cfg->select; |
bogdanm | 0:9b334a45a8ff | 729 | |
bogdanm | 0:9b334a45a8ff | 730 | /* Enable/disable interrupt as specified */ |
bogdanm | 0:9b334a45a8ff | 731 | if (cfg->enableInt) |
bogdanm | 0:9b334a45a8ff | 732 | { |
bogdanm | 0:9b334a45a8ff | 733 | DMA->IFC = (1 << channel); |
bogdanm | 0:9b334a45a8ff | 734 | BITBAND_Peripheral(&(DMA->IEN), channel, 1); |
bogdanm | 0:9b334a45a8ff | 735 | } |
bogdanm | 0:9b334a45a8ff | 736 | else |
bogdanm | 0:9b334a45a8ff | 737 | { |
bogdanm | 0:9b334a45a8ff | 738 | BITBAND_Peripheral(&(DMA->IEN), channel, 0); |
bogdanm | 0:9b334a45a8ff | 739 | } |
bogdanm | 0:9b334a45a8ff | 740 | } |
bogdanm | 0:9b334a45a8ff | 741 | |
bogdanm | 0:9b334a45a8ff | 742 | |
bogdanm | 0:9b334a45a8ff | 743 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 744 | * @brief |
bogdanm | 0:9b334a45a8ff | 745 | * Configure DMA descriptor for auto-request, basic or ping-pong DMA cycles. |
bogdanm | 0:9b334a45a8ff | 746 | * |
bogdanm | 0:9b334a45a8ff | 747 | * @details |
bogdanm | 0:9b334a45a8ff | 748 | * This function is used for configuration of a descriptor for the following |
bogdanm | 0:9b334a45a8ff | 749 | * DMA cycle types: |
bogdanm | 0:9b334a45a8ff | 750 | * |
bogdanm | 0:9b334a45a8ff | 751 | * @li auto-request - used for memory/memory transfer |
bogdanm | 0:9b334a45a8ff | 752 | * @li basic - used for a peripheral/memory transfer |
bogdanm | 0:9b334a45a8ff | 753 | * @li ping-pong - used for a ping-pong based peripheral/memory transfer |
bogdanm | 0:9b334a45a8ff | 754 | * style providing time to refresh one descriptor while the other is |
bogdanm | 0:9b334a45a8ff | 755 | * in use. |
bogdanm | 0:9b334a45a8ff | 756 | * |
bogdanm | 0:9b334a45a8ff | 757 | * The DMA cycle is not activated, please see DMA_ActivateAuto(), |
bogdanm | 0:9b334a45a8ff | 758 | * DMA_ActivateBasic() or DMA_ActivatePingPong() to activate the DMA cycle. |
bogdanm | 0:9b334a45a8ff | 759 | * In many cases, the configuration only has to be done once, and all |
bogdanm | 0:9b334a45a8ff | 760 | * subsequent cycles may be activated with the activate function. |
bogdanm | 0:9b334a45a8ff | 761 | * |
bogdanm | 0:9b334a45a8ff | 762 | * For ping-pong DMA cycles, this function must be used both on the primary |
bogdanm | 0:9b334a45a8ff | 763 | * and the alternate descriptor prior to activating the DMA cycle. |
bogdanm | 0:9b334a45a8ff | 764 | * |
bogdanm | 0:9b334a45a8ff | 765 | * Notice that the DMA channel must also be configured, see DMA_CfgChannel(). |
bogdanm | 0:9b334a45a8ff | 766 | * |
bogdanm | 0:9b334a45a8ff | 767 | * @note |
bogdanm | 0:9b334a45a8ff | 768 | * If using this function on a descriptor already activated and in use by |
bogdanm | 0:9b334a45a8ff | 769 | * the DMA controller, the behaviour is undefined. |
bogdanm | 0:9b334a45a8ff | 770 | * |
bogdanm | 0:9b334a45a8ff | 771 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 772 | * DMA channel to configure for. |
bogdanm | 0:9b334a45a8ff | 773 | * |
bogdanm | 0:9b334a45a8ff | 774 | * @param[in] primary |
bogdanm | 0:9b334a45a8ff | 775 | * @li true - configure primary descriptor |
bogdanm | 0:9b334a45a8ff | 776 | * @li false - configure alternate descriptor |
bogdanm | 0:9b334a45a8ff | 777 | * |
bogdanm | 0:9b334a45a8ff | 778 | * @param[in] cfg |
bogdanm | 0:9b334a45a8ff | 779 | * Configuration to use. |
bogdanm | 0:9b334a45a8ff | 780 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 781 | void DMA_CfgDescr(unsigned int channel, |
bogdanm | 0:9b334a45a8ff | 782 | bool primary, |
bogdanm | 0:9b334a45a8ff | 783 | DMA_CfgDescr_TypeDef *cfg) |
bogdanm | 0:9b334a45a8ff | 784 | { |
bogdanm | 0:9b334a45a8ff | 785 | DMA_DESCRIPTOR_TypeDef *descr; |
bogdanm | 0:9b334a45a8ff | 786 | |
bogdanm | 0:9b334a45a8ff | 787 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 788 | EFM_ASSERT(cfg); |
bogdanm | 0:9b334a45a8ff | 789 | |
bogdanm | 0:9b334a45a8ff | 790 | /* Find descriptor to configure */ |
bogdanm | 0:9b334a45a8ff | 791 | if (primary) |
bogdanm | 0:9b334a45a8ff | 792 | { |
bogdanm | 0:9b334a45a8ff | 793 | descr = (DMA_DESCRIPTOR_TypeDef *)DMA->CTRLBASE; |
bogdanm | 0:9b334a45a8ff | 794 | } |
bogdanm | 0:9b334a45a8ff | 795 | else |
bogdanm | 0:9b334a45a8ff | 796 | { |
bogdanm | 0:9b334a45a8ff | 797 | descr = (DMA_DESCRIPTOR_TypeDef *)DMA->ALTCTRLBASE; |
bogdanm | 0:9b334a45a8ff | 798 | } |
bogdanm | 0:9b334a45a8ff | 799 | descr += channel; |
bogdanm | 0:9b334a45a8ff | 800 | |
bogdanm | 0:9b334a45a8ff | 801 | /* Prepare the descriptor */ |
bogdanm | 0:9b334a45a8ff | 802 | /* Source/destination end addresses set when started */ |
bogdanm | 0:9b334a45a8ff | 803 | descr->CTRL = |
bogdanm | 0:9b334a45a8ff | 804 | (cfg->dstInc << _DMA_CTRL_DST_INC_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 805 | (cfg->size << _DMA_CTRL_DST_SIZE_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 806 | (cfg->srcInc << _DMA_CTRL_SRC_INC_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 807 | (cfg->size << _DMA_CTRL_SRC_SIZE_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 808 | ((uint32_t)(cfg->hprot) << _DMA_CTRL_SRC_PROT_CTRL_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 809 | (cfg->arbRate << _DMA_CTRL_R_POWER_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 810 | (0 << _DMA_CTRL_N_MINUS_1_SHIFT) | /* Set when activated */ |
bogdanm | 0:9b334a45a8ff | 811 | (0 << _DMA_CTRL_NEXT_USEBURST_SHIFT) | /* Set when activated */ |
bogdanm | 0:9b334a45a8ff | 812 | DMA_CTRL_CYCLE_CTRL_INVALID; /* Set when activated */ |
bogdanm | 0:9b334a45a8ff | 813 | } |
bogdanm | 0:9b334a45a8ff | 814 | |
bogdanm | 0:9b334a45a8ff | 815 | |
bogdanm | 0:9b334a45a8ff | 816 | #if defined( _DMA_LOOP0_MASK ) && defined( _DMA_LOOP1_MASK ) |
bogdanm | 0:9b334a45a8ff | 817 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 818 | * @brief Configure DMA channel for Loop mode or 2D transfer. |
bogdanm | 0:9b334a45a8ff | 819 | * |
bogdanm | 0:9b334a45a8ff | 820 | * @details |
bogdanm | 0:9b334a45a8ff | 821 | * For 2D transfer, set cfg->enable to "false", and only configure nMinus1 |
bogdanm | 0:9b334a45a8ff | 822 | * to same width as channel descriptor. |
bogdanm | 0:9b334a45a8ff | 823 | * |
bogdanm | 0:9b334a45a8ff | 824 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 825 | * DMA channel to configure for. |
bogdanm | 0:9b334a45a8ff | 826 | * |
bogdanm | 0:9b334a45a8ff | 827 | * @param[in] cfg |
bogdanm | 0:9b334a45a8ff | 828 | * Configuration to use. |
bogdanm | 0:9b334a45a8ff | 829 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 830 | void DMA_CfgLoop(unsigned int channel, DMA_CfgLoop_TypeDef *cfg) |
bogdanm | 0:9b334a45a8ff | 831 | { |
bogdanm | 0:9b334a45a8ff | 832 | EFM_ASSERT(channel <= 1); |
bogdanm | 0:9b334a45a8ff | 833 | EFM_ASSERT(cfg->nMinus1 <= 1023); |
bogdanm | 0:9b334a45a8ff | 834 | |
bogdanm | 0:9b334a45a8ff | 835 | /* Configure LOOP setting */ |
bogdanm | 0:9b334a45a8ff | 836 | switch( channel ) |
bogdanm | 0:9b334a45a8ff | 837 | { |
bogdanm | 0:9b334a45a8ff | 838 | case 0: |
bogdanm | 0:9b334a45a8ff | 839 | DMA->LOOP0 = (cfg->enable << _DMA_LOOP0_EN_SHIFT| |
bogdanm | 0:9b334a45a8ff | 840 | cfg->nMinus1 << _DMA_LOOP0_WIDTH_SHIFT); |
bogdanm | 0:9b334a45a8ff | 841 | break; |
bogdanm | 0:9b334a45a8ff | 842 | case 1: |
bogdanm | 0:9b334a45a8ff | 843 | DMA->LOOP1 = (cfg->enable << _DMA_LOOP1_EN_SHIFT| |
bogdanm | 0:9b334a45a8ff | 844 | cfg->nMinus1 << _DMA_LOOP1_WIDTH_SHIFT); |
bogdanm | 0:9b334a45a8ff | 845 | break; |
bogdanm | 0:9b334a45a8ff | 846 | } |
bogdanm | 0:9b334a45a8ff | 847 | } |
bogdanm | 0:9b334a45a8ff | 848 | #endif |
bogdanm | 0:9b334a45a8ff | 849 | |
bogdanm | 0:9b334a45a8ff | 850 | |
bogdanm | 0:9b334a45a8ff | 851 | #if defined( _DMA_RECT0_MASK ) |
bogdanm | 0:9b334a45a8ff | 852 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 853 | * @brief Configure DMA channel 2D transfer properties. |
bogdanm | 0:9b334a45a8ff | 854 | * |
bogdanm | 0:9b334a45a8ff | 855 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 856 | * DMA channel to configure for. |
bogdanm | 0:9b334a45a8ff | 857 | * |
bogdanm | 0:9b334a45a8ff | 858 | * @param[in] cfg |
bogdanm | 0:9b334a45a8ff | 859 | * Configuration to use. |
bogdanm | 0:9b334a45a8ff | 860 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 861 | void DMA_CfgRect(unsigned int channel, DMA_CfgRect_TypeDef *cfg) |
bogdanm | 0:9b334a45a8ff | 862 | { |
bogdanm | 0:9b334a45a8ff | 863 | (void)channel; /* Unused parameter */ |
bogdanm | 0:9b334a45a8ff | 864 | |
bogdanm | 0:9b334a45a8ff | 865 | EFM_ASSERT(channel == 0); |
bogdanm | 0:9b334a45a8ff | 866 | EFM_ASSERT(cfg->dstStride <= 2047); |
bogdanm | 0:9b334a45a8ff | 867 | EFM_ASSERT(cfg->srcStride <= 2047); |
bogdanm | 0:9b334a45a8ff | 868 | EFM_ASSERT(cfg->height <= 1023); |
bogdanm | 0:9b334a45a8ff | 869 | |
bogdanm | 0:9b334a45a8ff | 870 | /* Configure rectangular/2D copy */ |
bogdanm | 0:9b334a45a8ff | 871 | DMA->RECT0 = (cfg->dstStride << _DMA_RECT0_DSTSTRIDE_SHIFT| |
bogdanm | 0:9b334a45a8ff | 872 | cfg->srcStride << _DMA_RECT0_SRCSTRIDE_SHIFT| |
bogdanm | 0:9b334a45a8ff | 873 | cfg->height << _DMA_RECT0_HEIGHT_SHIFT); |
bogdanm | 0:9b334a45a8ff | 874 | } |
bogdanm | 0:9b334a45a8ff | 875 | #endif |
bogdanm | 0:9b334a45a8ff | 876 | |
bogdanm | 0:9b334a45a8ff | 877 | |
bogdanm | 0:9b334a45a8ff | 878 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 879 | * @brief |
bogdanm | 0:9b334a45a8ff | 880 | * Configure an alternate DMA descriptor for use with scatter-gather DMA |
bogdanm | 0:9b334a45a8ff | 881 | * cycles. |
bogdanm | 0:9b334a45a8ff | 882 | * |
bogdanm | 0:9b334a45a8ff | 883 | * @details |
bogdanm | 0:9b334a45a8ff | 884 | * In scatter-gather mode, the alternate descriptors are located in one |
bogdanm | 0:9b334a45a8ff | 885 | * contiguous memory area. Each of the alternate descriptor must be fully |
bogdanm | 0:9b334a45a8ff | 886 | * configured prior to starting the scatter-gather DMA cycle. |
bogdanm | 0:9b334a45a8ff | 887 | * |
bogdanm | 0:9b334a45a8ff | 888 | * The DMA cycle is not activated by this function, please see |
bogdanm | 0:9b334a45a8ff | 889 | * DMA_ActivateScatterGather() to activate the DMA cycle. In some cases, the |
bogdanm | 0:9b334a45a8ff | 890 | * alternate configuration only has to be done once, and all subsequent |
bogdanm | 0:9b334a45a8ff | 891 | * transfers may be activated with the activate function. |
bogdanm | 0:9b334a45a8ff | 892 | * |
bogdanm | 0:9b334a45a8ff | 893 | * Notice that the DMA channel must also be configured, see DMA_CfgChannel(). |
bogdanm | 0:9b334a45a8ff | 894 | * |
bogdanm | 0:9b334a45a8ff | 895 | * @param[in] descr |
bogdanm | 0:9b334a45a8ff | 896 | * Points to start of memory area holding the alternate descriptors. |
bogdanm | 0:9b334a45a8ff | 897 | * |
bogdanm | 0:9b334a45a8ff | 898 | * @param[in] indx |
bogdanm | 0:9b334a45a8ff | 899 | * Alternate descriptor index number to configure (numbered from 0). |
bogdanm | 0:9b334a45a8ff | 900 | * |
bogdanm | 0:9b334a45a8ff | 901 | * @param[in] cfg |
bogdanm | 0:9b334a45a8ff | 902 | * Configuration to use. |
bogdanm | 0:9b334a45a8ff | 903 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 904 | void DMA_CfgDescrScatterGather(DMA_DESCRIPTOR_TypeDef *descr, |
bogdanm | 0:9b334a45a8ff | 905 | unsigned int indx, |
bogdanm | 0:9b334a45a8ff | 906 | DMA_CfgDescrSGAlt_TypeDef *cfg) |
bogdanm | 0:9b334a45a8ff | 907 | { |
bogdanm | 0:9b334a45a8ff | 908 | uint32_t cycleCtrl; |
bogdanm | 0:9b334a45a8ff | 909 | |
bogdanm | 0:9b334a45a8ff | 910 | EFM_ASSERT(descr); |
bogdanm | 0:9b334a45a8ff | 911 | EFM_ASSERT(cfg); |
bogdanm | 0:9b334a45a8ff | 912 | |
bogdanm | 0:9b334a45a8ff | 913 | /* Point to selected entry in alternate descriptor table */ |
bogdanm | 0:9b334a45a8ff | 914 | descr += indx; |
bogdanm | 0:9b334a45a8ff | 915 | |
bogdanm | 0:9b334a45a8ff | 916 | if (cfg->srcInc == dmaDataIncNone) |
bogdanm | 0:9b334a45a8ff | 917 | { |
bogdanm | 0:9b334a45a8ff | 918 | descr->SRCEND = cfg->src; |
bogdanm | 0:9b334a45a8ff | 919 | } |
bogdanm | 0:9b334a45a8ff | 920 | else |
bogdanm | 0:9b334a45a8ff | 921 | { |
bogdanm | 0:9b334a45a8ff | 922 | descr->SRCEND = (void *)((uint32_t)(cfg->src) + ((uint32_t)(cfg->nMinus1) << cfg->srcInc)); |
bogdanm | 0:9b334a45a8ff | 923 | } |
bogdanm | 0:9b334a45a8ff | 924 | |
bogdanm | 0:9b334a45a8ff | 925 | if (cfg->dstInc == dmaDataIncNone) |
bogdanm | 0:9b334a45a8ff | 926 | { |
bogdanm | 0:9b334a45a8ff | 927 | descr->DSTEND = cfg->dst; |
bogdanm | 0:9b334a45a8ff | 928 | } |
bogdanm | 0:9b334a45a8ff | 929 | else |
bogdanm | 0:9b334a45a8ff | 930 | { |
bogdanm | 0:9b334a45a8ff | 931 | descr->DSTEND = (void *)((uint32_t)(cfg->dst) + ((uint32_t)(cfg->nMinus1) << cfg->dstInc)); |
bogdanm | 0:9b334a45a8ff | 932 | } |
bogdanm | 0:9b334a45a8ff | 933 | |
bogdanm | 0:9b334a45a8ff | 934 | /* User definable part not used */ |
bogdanm | 0:9b334a45a8ff | 935 | descr->USER = 0; |
bogdanm | 0:9b334a45a8ff | 936 | |
bogdanm | 0:9b334a45a8ff | 937 | if (cfg->peripheral) |
bogdanm | 0:9b334a45a8ff | 938 | { |
bogdanm | 0:9b334a45a8ff | 939 | cycleCtrl = (uint32_t)dmaCycleCtrlPerScatterGather + 1; |
bogdanm | 0:9b334a45a8ff | 940 | } |
bogdanm | 0:9b334a45a8ff | 941 | else |
bogdanm | 0:9b334a45a8ff | 942 | { |
bogdanm | 0:9b334a45a8ff | 943 | cycleCtrl = (uint32_t)dmaCycleCtrlMemScatterGather + 1; |
bogdanm | 0:9b334a45a8ff | 944 | } |
bogdanm | 0:9b334a45a8ff | 945 | |
bogdanm | 0:9b334a45a8ff | 946 | descr->CTRL = |
bogdanm | 0:9b334a45a8ff | 947 | (cfg->dstInc << _DMA_CTRL_DST_INC_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 948 | (cfg->size << _DMA_CTRL_DST_SIZE_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 949 | (cfg->srcInc << _DMA_CTRL_SRC_INC_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 950 | (cfg->size << _DMA_CTRL_SRC_SIZE_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 951 | ((uint32_t)(cfg->hprot) << _DMA_CTRL_SRC_PROT_CTRL_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 952 | (cfg->arbRate << _DMA_CTRL_R_POWER_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 953 | ((uint32_t)(cfg->nMinus1) << _DMA_CTRL_N_MINUS_1_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 954 | /* Never set next useburst bit, since the descriptor used after the */ |
bogdanm | 0:9b334a45a8ff | 955 | /* alternate descriptor is the primary descriptor which operates on */ |
bogdanm | 0:9b334a45a8ff | 956 | /* memory. If the alternate descriptors need to have useBurst set, this */ |
bogdanm | 0:9b334a45a8ff | 957 | /* done when setting up the primary descriptor, ie when activating. */ |
bogdanm | 0:9b334a45a8ff | 958 | (0 << _DMA_CTRL_NEXT_USEBURST_SHIFT) | |
bogdanm | 0:9b334a45a8ff | 959 | (cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT); |
bogdanm | 0:9b334a45a8ff | 960 | } |
bogdanm | 0:9b334a45a8ff | 961 | |
bogdanm | 0:9b334a45a8ff | 962 | |
bogdanm | 0:9b334a45a8ff | 963 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 964 | * @brief |
bogdanm | 0:9b334a45a8ff | 965 | * Enable or disable a DMA channel. |
bogdanm | 0:9b334a45a8ff | 966 | * |
bogdanm | 0:9b334a45a8ff | 967 | * @details |
bogdanm | 0:9b334a45a8ff | 968 | * Use this function to explicitly enable or disable a DMA channel. A DMA |
bogdanm | 0:9b334a45a8ff | 969 | * channel is automatically disabled when the DMA controller has finished a |
bogdanm | 0:9b334a45a8ff | 970 | * transaction. |
bogdanm | 0:9b334a45a8ff | 971 | * |
bogdanm | 0:9b334a45a8ff | 972 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 973 | * DMA channel to enable or disable. |
bogdanm | 0:9b334a45a8ff | 974 | * |
bogdanm | 0:9b334a45a8ff | 975 | * @param[in] enable |
bogdanm | 0:9b334a45a8ff | 976 | * If 'true' the channel will be enabled. If 'false' the channel will be |
bogdanm | 0:9b334a45a8ff | 977 | * disabled. |
bogdanm | 0:9b334a45a8ff | 978 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 979 | void DMA_ChannelEnable(unsigned int channel, bool enable) |
bogdanm | 0:9b334a45a8ff | 980 | { |
bogdanm | 0:9b334a45a8ff | 981 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 982 | |
bogdanm | 0:9b334a45a8ff | 983 | if (enable) |
bogdanm | 0:9b334a45a8ff | 984 | { |
bogdanm | 0:9b334a45a8ff | 985 | DMA->CHENS = 1<<channel; |
bogdanm | 0:9b334a45a8ff | 986 | } |
bogdanm | 0:9b334a45a8ff | 987 | else |
bogdanm | 0:9b334a45a8ff | 988 | { |
bogdanm | 0:9b334a45a8ff | 989 | DMA->CHENC = 1<<channel; |
bogdanm | 0:9b334a45a8ff | 990 | } |
bogdanm | 0:9b334a45a8ff | 991 | } |
bogdanm | 0:9b334a45a8ff | 992 | |
bogdanm | 0:9b334a45a8ff | 993 | |
bogdanm | 0:9b334a45a8ff | 994 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 995 | * @brief |
bogdanm | 0:9b334a45a8ff | 996 | * Check if DMA channel is enabled. |
bogdanm | 0:9b334a45a8ff | 997 | * |
bogdanm | 0:9b334a45a8ff | 998 | * @details |
bogdanm | 0:9b334a45a8ff | 999 | * The DMA channel is disabled when the DMA controller has finished a DMA |
bogdanm | 0:9b334a45a8ff | 1000 | * cycle. |
bogdanm | 0:9b334a45a8ff | 1001 | * |
bogdanm | 0:9b334a45a8ff | 1002 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 1003 | * DMA channel to check. |
bogdanm | 0:9b334a45a8ff | 1004 | * |
bogdanm | 0:9b334a45a8ff | 1005 | * @return |
bogdanm | 0:9b334a45a8ff | 1006 | * true if channel is enabled, false if not. |
bogdanm | 0:9b334a45a8ff | 1007 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 1008 | bool DMA_ChannelEnabled(unsigned int channel) |
bogdanm | 0:9b334a45a8ff | 1009 | { |
bogdanm | 0:9b334a45a8ff | 1010 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 1011 | |
bogdanm | 0:9b334a45a8ff | 1012 | return (bool)((DMA->CHENS >> channel) & 1); |
bogdanm | 0:9b334a45a8ff | 1013 | } |
bogdanm | 0:9b334a45a8ff | 1014 | |
bogdanm | 0:9b334a45a8ff | 1015 | |
bogdanm | 0:9b334a45a8ff | 1016 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 1017 | * @brief |
bogdanm | 0:9b334a45a8ff | 1018 | * Initializes DMA controller. |
bogdanm | 0:9b334a45a8ff | 1019 | * |
bogdanm | 0:9b334a45a8ff | 1020 | * @details |
bogdanm | 0:9b334a45a8ff | 1021 | * This function will reset and prepare the DMA controller for use. Although |
bogdanm | 0:9b334a45a8ff | 1022 | * it may be used several times, it is normally only used during system |
bogdanm | 0:9b334a45a8ff | 1023 | * init. If reused during normal operation, notice that any ongoing DMA |
bogdanm | 0:9b334a45a8ff | 1024 | * transfers will be aborted. When completed, the DMA controller is in |
bogdanm | 0:9b334a45a8ff | 1025 | * an enabled state. |
bogdanm | 0:9b334a45a8ff | 1026 | * |
bogdanm | 0:9b334a45a8ff | 1027 | * @note |
bogdanm | 0:9b334a45a8ff | 1028 | * Must be invoked before using the DMA controller. |
bogdanm | 0:9b334a45a8ff | 1029 | * |
bogdanm | 0:9b334a45a8ff | 1030 | * @param[in] init |
bogdanm | 0:9b334a45a8ff | 1031 | * Pointer to a structure containing DMA init information. |
bogdanm | 0:9b334a45a8ff | 1032 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 1033 | void DMA_Init(DMA_Init_TypeDef *init) |
bogdanm | 0:9b334a45a8ff | 1034 | { |
bogdanm | 0:9b334a45a8ff | 1035 | EFM_ASSERT(init); |
bogdanm | 0:9b334a45a8ff | 1036 | |
bogdanm | 0:9b334a45a8ff | 1037 | /* Make sure control block is properly aligned */ |
bogdanm | 0:9b334a45a8ff | 1038 | #if (DMA_CHAN_COUNT <= 4) |
bogdanm | 0:9b334a45a8ff | 1039 | EFM_ASSERT(!((uint32_t)(init->controlBlock) & (128 - 1))); |
bogdanm | 0:9b334a45a8ff | 1040 | #elif (DMA_CHAN_COUNT <= 8) || (DMA_CHAN_COUNT <= 12) |
bogdanm | 0:9b334a45a8ff | 1041 | EFM_ASSERT(!((uint32_t)(init->controlBlock) & (256 - 1))); |
bogdanm | 0:9b334a45a8ff | 1042 | #else |
bogdanm | 0:9b334a45a8ff | 1043 | #error "Unsupported DMA channel count (em_dma.c)." |
bogdanm | 0:9b334a45a8ff | 1044 | #endif |
bogdanm | 0:9b334a45a8ff | 1045 | |
bogdanm | 0:9b334a45a8ff | 1046 | /* Make sure DMA clock is enabled prior to accessing DMA module */ |
bogdanm | 0:9b334a45a8ff | 1047 | CMU_ClockEnable(cmuClock_DMA, true); |
bogdanm | 0:9b334a45a8ff | 1048 | |
bogdanm | 0:9b334a45a8ff | 1049 | /* Make sure DMA controller is set to a known reset state */ |
bogdanm | 0:9b334a45a8ff | 1050 | DMA_Reset(); |
bogdanm | 0:9b334a45a8ff | 1051 | |
bogdanm | 0:9b334a45a8ff | 1052 | /* Clear/enable DMA interrupts */ |
bogdanm | 0:9b334a45a8ff | 1053 | NVIC_ClearPendingIRQ(DMA_IRQn); |
bogdanm | 0:9b334a45a8ff | 1054 | NVIC_EnableIRQ(DMA_IRQn); |
bogdanm | 0:9b334a45a8ff | 1055 | |
bogdanm | 0:9b334a45a8ff | 1056 | /* Enable bus error interrupt */ |
bogdanm | 0:9b334a45a8ff | 1057 | DMA->IEN = DMA_IEN_ERR; |
bogdanm | 0:9b334a45a8ff | 1058 | |
bogdanm | 0:9b334a45a8ff | 1059 | /* Set pointer to control block, notice that this ptr must have been */ |
bogdanm | 0:9b334a45a8ff | 1060 | /* properly aligned, according to requirements defined in the reference */ |
bogdanm | 0:9b334a45a8ff | 1061 | /* manual. */ |
bogdanm | 0:9b334a45a8ff | 1062 | DMA->CTRLBASE = (uint32_t)(init->controlBlock); |
bogdanm | 0:9b334a45a8ff | 1063 | |
bogdanm | 0:9b334a45a8ff | 1064 | /* Configure and enable the DMA controller */ |
bogdanm | 0:9b334a45a8ff | 1065 | DMA->CONFIG = ((uint32_t)(init->hprot) << _DMA_CONFIG_CHPROT_SHIFT) | DMA_CONFIG_EN; |
bogdanm | 0:9b334a45a8ff | 1066 | } |
bogdanm | 0:9b334a45a8ff | 1067 | |
bogdanm | 0:9b334a45a8ff | 1068 | |
bogdanm | 0:9b334a45a8ff | 1069 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 1070 | * @brief |
bogdanm | 0:9b334a45a8ff | 1071 | * Refresh a descriptor used in a DMA ping-pong cycle. |
bogdanm | 0:9b334a45a8ff | 1072 | * |
bogdanm | 0:9b334a45a8ff | 1073 | * @details |
bogdanm | 0:9b334a45a8ff | 1074 | * During a ping-pong DMA cycle, the DMA controller automatically alternates |
bogdanm | 0:9b334a45a8ff | 1075 | * between primary and alternate descriptors, when completing use of a |
bogdanm | 0:9b334a45a8ff | 1076 | * descriptor. While the other descriptor is in use by the DMA controller, |
bogdanm | 0:9b334a45a8ff | 1077 | * the SW should refresh the completed descriptor. This is typically done from |
bogdanm | 0:9b334a45a8ff | 1078 | * the callback defined for the ping-pong cycle. |
bogdanm | 0:9b334a45a8ff | 1079 | * |
bogdanm | 0:9b334a45a8ff | 1080 | * @param[in] channel |
bogdanm | 0:9b334a45a8ff | 1081 | * DMA channel to refresh ping-pong descriptor for. |
bogdanm | 0:9b334a45a8ff | 1082 | * |
bogdanm | 0:9b334a45a8ff | 1083 | * @param[in] primary |
bogdanm | 0:9b334a45a8ff | 1084 | * @li true - refresh primary descriptor |
bogdanm | 0:9b334a45a8ff | 1085 | * @li false - refresh alternate descriptor |
bogdanm | 0:9b334a45a8ff | 1086 | * |
bogdanm | 0:9b334a45a8ff | 1087 | * @param[in] useBurst |
bogdanm | 0:9b334a45a8ff | 1088 | * The burst feature is only used on peripherals supporting DMA bursts. |
bogdanm | 0:9b334a45a8ff | 1089 | * Bursts must not be used if the total length (as given by nMinus1) is |
bogdanm | 0:9b334a45a8ff | 1090 | * less than the arbitration rate configured for the descriptor. Please |
bogdanm | 0:9b334a45a8ff | 1091 | * refer to the reference manual for further details on burst usage. |
bogdanm | 0:9b334a45a8ff | 1092 | * |
bogdanm | 0:9b334a45a8ff | 1093 | * @param[in] dst |
bogdanm | 0:9b334a45a8ff | 1094 | * Address to start location to transfer data to. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 1095 | * descriptor as is. |
bogdanm | 0:9b334a45a8ff | 1096 | * |
bogdanm | 0:9b334a45a8ff | 1097 | * @param[in] src |
bogdanm | 0:9b334a45a8ff | 1098 | * Address to start location to transfer data from. If NULL, leave setting in |
bogdanm | 0:9b334a45a8ff | 1099 | * descriptor as is. |
bogdanm | 0:9b334a45a8ff | 1100 | * |
bogdanm | 0:9b334a45a8ff | 1101 | * @param[in] nMinus1 |
bogdanm | 0:9b334a45a8ff | 1102 | * Number of DMA transfer elements (minus 1) to transfer (<= 1023). The |
bogdanm | 0:9b334a45a8ff | 1103 | * size of the DMA transfer element (1, 2 or 4 bytes) is configured with |
bogdanm | 0:9b334a45a8ff | 1104 | * DMA_CfgDescr(). |
bogdanm | 0:9b334a45a8ff | 1105 | * |
bogdanm | 0:9b334a45a8ff | 1106 | * @param[in] stop |
bogdanm | 0:9b334a45a8ff | 1107 | * Indicate that the DMA ping-pong cycle shall stop @b after completing use |
bogdanm | 0:9b334a45a8ff | 1108 | * of this descriptor. |
bogdanm | 0:9b334a45a8ff | 1109 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 1110 | void DMA_RefreshPingPong(unsigned int channel, |
bogdanm | 0:9b334a45a8ff | 1111 | bool primary, |
bogdanm | 0:9b334a45a8ff | 1112 | bool useBurst, |
bogdanm | 0:9b334a45a8ff | 1113 | void *dst, |
bogdanm | 0:9b334a45a8ff | 1114 | void *src, |
bogdanm | 0:9b334a45a8ff | 1115 | unsigned int nMinus1, |
bogdanm | 0:9b334a45a8ff | 1116 | bool stop) |
bogdanm | 0:9b334a45a8ff | 1117 | { |
bogdanm | 0:9b334a45a8ff | 1118 | DMA_CycleCtrl_TypeDef cycleCtrl; |
bogdanm | 0:9b334a45a8ff | 1119 | DMA_DESCRIPTOR_TypeDef *descr; |
bogdanm | 0:9b334a45a8ff | 1120 | uint32_t inc; |
bogdanm | 0:9b334a45a8ff | 1121 | uint32_t chBit; |
bogdanm | 0:9b334a45a8ff | 1122 | uint32_t tmp; |
bogdanm | 0:9b334a45a8ff | 1123 | |
bogdanm | 0:9b334a45a8ff | 1124 | EFM_ASSERT(channel < DMA_CHAN_COUNT); |
bogdanm | 0:9b334a45a8ff | 1125 | EFM_ASSERT(nMinus1 <= (_DMA_CTRL_N_MINUS_1_MASK >> _DMA_CTRL_N_MINUS_1_SHIFT)); |
bogdanm | 0:9b334a45a8ff | 1126 | |
bogdanm | 0:9b334a45a8ff | 1127 | /* The ping-pong DMA cycle may be stopped by issuing a basic cycle type */ |
bogdanm | 0:9b334a45a8ff | 1128 | if (stop) |
bogdanm | 0:9b334a45a8ff | 1129 | { |
bogdanm | 0:9b334a45a8ff | 1130 | cycleCtrl = dmaCycleCtrlBasic; |
bogdanm | 0:9b334a45a8ff | 1131 | } |
bogdanm | 0:9b334a45a8ff | 1132 | else |
bogdanm | 0:9b334a45a8ff | 1133 | { |
bogdanm | 0:9b334a45a8ff | 1134 | cycleCtrl = dmaCycleCtrlPingPong; |
bogdanm | 0:9b334a45a8ff | 1135 | } |
bogdanm | 0:9b334a45a8ff | 1136 | |
bogdanm | 0:9b334a45a8ff | 1137 | /* Find descriptor to configure */ |
bogdanm | 0:9b334a45a8ff | 1138 | if (primary) |
bogdanm | 0:9b334a45a8ff | 1139 | { |
bogdanm | 0:9b334a45a8ff | 1140 | descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->CTRLBASE)) + channel; |
bogdanm | 0:9b334a45a8ff | 1141 | } |
bogdanm | 0:9b334a45a8ff | 1142 | else |
bogdanm | 0:9b334a45a8ff | 1143 | { |
bogdanm | 0:9b334a45a8ff | 1144 | descr = ((DMA_DESCRIPTOR_TypeDef *)(DMA->ALTCTRLBASE)) + channel; |
bogdanm | 0:9b334a45a8ff | 1145 | } |
bogdanm | 0:9b334a45a8ff | 1146 | |
bogdanm | 0:9b334a45a8ff | 1147 | if (src) |
bogdanm | 0:9b334a45a8ff | 1148 | { |
bogdanm | 0:9b334a45a8ff | 1149 | inc = (descr->CTRL & _DMA_CTRL_SRC_INC_MASK) >> _DMA_CTRL_SRC_INC_SHIFT; |
bogdanm | 0:9b334a45a8ff | 1150 | if (inc == _DMA_CTRL_SRC_INC_NONE) |
bogdanm | 0:9b334a45a8ff | 1151 | { |
bogdanm | 0:9b334a45a8ff | 1152 | descr->SRCEND = src; |
bogdanm | 0:9b334a45a8ff | 1153 | } |
bogdanm | 0:9b334a45a8ff | 1154 | else |
bogdanm | 0:9b334a45a8ff | 1155 | { |
bogdanm | 0:9b334a45a8ff | 1156 | descr->SRCEND = (void *)((uint32_t)src + (nMinus1 << inc)); |
bogdanm | 0:9b334a45a8ff | 1157 | } |
bogdanm | 0:9b334a45a8ff | 1158 | } |
bogdanm | 0:9b334a45a8ff | 1159 | |
bogdanm | 0:9b334a45a8ff | 1160 | if (dst) |
bogdanm | 0:9b334a45a8ff | 1161 | { |
bogdanm | 0:9b334a45a8ff | 1162 | inc = (descr->CTRL & _DMA_CTRL_DST_INC_MASK) >> _DMA_CTRL_DST_INC_SHIFT; |
bogdanm | 0:9b334a45a8ff | 1163 | if (inc == _DMA_CTRL_DST_INC_NONE) |
bogdanm | 0:9b334a45a8ff | 1164 | { |
bogdanm | 0:9b334a45a8ff | 1165 | descr->DSTEND = dst; |
bogdanm | 0:9b334a45a8ff | 1166 | } |
bogdanm | 0:9b334a45a8ff | 1167 | else |
bogdanm | 0:9b334a45a8ff | 1168 | { |
bogdanm | 0:9b334a45a8ff | 1169 | descr->DSTEND = (void *)((uint32_t)dst + (nMinus1 << inc)); |
bogdanm | 0:9b334a45a8ff | 1170 | } |
bogdanm | 0:9b334a45a8ff | 1171 | } |
bogdanm | 0:9b334a45a8ff | 1172 | |
bogdanm | 0:9b334a45a8ff | 1173 | chBit = 1 << channel; |
bogdanm | 0:9b334a45a8ff | 1174 | if (useBurst) |
bogdanm | 0:9b334a45a8ff | 1175 | { |
bogdanm | 0:9b334a45a8ff | 1176 | DMA->CHUSEBURSTS = chBit; |
bogdanm | 0:9b334a45a8ff | 1177 | } |
bogdanm | 0:9b334a45a8ff | 1178 | else |
bogdanm | 0:9b334a45a8ff | 1179 | { |
bogdanm | 0:9b334a45a8ff | 1180 | DMA->CHUSEBURSTC = chBit; |
bogdanm | 0:9b334a45a8ff | 1181 | } |
bogdanm | 0:9b334a45a8ff | 1182 | |
bogdanm | 0:9b334a45a8ff | 1183 | /* Set cycle control */ |
bogdanm | 0:9b334a45a8ff | 1184 | tmp = descr->CTRL & ~(_DMA_CTRL_CYCLE_CTRL_MASK | _DMA_CTRL_N_MINUS_1_MASK); |
bogdanm | 0:9b334a45a8ff | 1185 | tmp |= nMinus1 << _DMA_CTRL_N_MINUS_1_SHIFT; |
bogdanm | 0:9b334a45a8ff | 1186 | tmp |= cycleCtrl << _DMA_CTRL_CYCLE_CTRL_SHIFT; |
bogdanm | 0:9b334a45a8ff | 1187 | descr->CTRL = tmp; |
bogdanm | 0:9b334a45a8ff | 1188 | } |
bogdanm | 0:9b334a45a8ff | 1189 | |
bogdanm | 0:9b334a45a8ff | 1190 | |
bogdanm | 0:9b334a45a8ff | 1191 | /***************************************************************************//** |
bogdanm | 0:9b334a45a8ff | 1192 | * @brief |
bogdanm | 0:9b334a45a8ff | 1193 | * Reset the DMA controller. |
bogdanm | 0:9b334a45a8ff | 1194 | * |
bogdanm | 0:9b334a45a8ff | 1195 | * @details |
bogdanm | 0:9b334a45a8ff | 1196 | * This functions will disable the DMA controller and set it to a reset |
bogdanm | 0:9b334a45a8ff | 1197 | * state. |
bogdanm | 0:9b334a45a8ff | 1198 | * |
bogdanm | 0:9b334a45a8ff | 1199 | * @note |
bogdanm | 0:9b334a45a8ff | 1200 | * Notice that any ongoing transfers will be aborted. |
bogdanm | 0:9b334a45a8ff | 1201 | ******************************************************************************/ |
bogdanm | 0:9b334a45a8ff | 1202 | void DMA_Reset(void) |
bogdanm | 0:9b334a45a8ff | 1203 | { |
bogdanm | 0:9b334a45a8ff | 1204 | int i; |
bogdanm | 0:9b334a45a8ff | 1205 | |
bogdanm | 0:9b334a45a8ff | 1206 | /* Disable DMA interrupts */ |
bogdanm | 0:9b334a45a8ff | 1207 | NVIC_DisableIRQ(DMA_IRQn); |
bogdanm | 0:9b334a45a8ff | 1208 | |
bogdanm | 0:9b334a45a8ff | 1209 | /* Put the DMA controller into a known state, first disabling it. */ |
bogdanm | 0:9b334a45a8ff | 1210 | DMA->CONFIG = _DMA_CONFIG_RESETVALUE; |
bogdanm | 0:9b334a45a8ff | 1211 | DMA->CHUSEBURSTC = _DMA_CHUSEBURSTC_MASK; |
bogdanm | 0:9b334a45a8ff | 1212 | DMA->CHREQMASKC = _DMA_CHREQMASKC_MASK; |
bogdanm | 0:9b334a45a8ff | 1213 | DMA->CHENC = _DMA_CHENC_MASK; |
bogdanm | 0:9b334a45a8ff | 1214 | DMA->CHALTC = _DMA_CHALTC_MASK; |
bogdanm | 0:9b334a45a8ff | 1215 | DMA->CHPRIC = _DMA_CHPRIC_MASK; |
bogdanm | 0:9b334a45a8ff | 1216 | DMA->ERRORC = DMA_ERRORC_ERRORC; |
bogdanm | 0:9b334a45a8ff | 1217 | DMA->IEN = _DMA_IEN_RESETVALUE; |
bogdanm | 0:9b334a45a8ff | 1218 | DMA->IFC = _DMA_IFC_MASK; |
bogdanm | 0:9b334a45a8ff | 1219 | |
bogdanm | 0:9b334a45a8ff | 1220 | /* Clear channel control flags */ |
bogdanm | 0:9b334a45a8ff | 1221 | for (i = 0; i < DMA_CHAN_COUNT; i++) |
bogdanm | 0:9b334a45a8ff | 1222 | { |
bogdanm | 0:9b334a45a8ff | 1223 | DMA->CH[i].CTRL = _DMA_CH_CTRL_RESETVALUE; |
bogdanm | 0:9b334a45a8ff | 1224 | } |
bogdanm | 0:9b334a45a8ff | 1225 | } |
bogdanm | 0:9b334a45a8ff | 1226 | |
bogdanm | 0:9b334a45a8ff | 1227 | |
bogdanm | 0:9b334a45a8ff | 1228 | /** @} (end addtogroup DMA) */ |
bogdanm | 0:9b334a45a8ff | 1229 | /** @} (end addtogroup EM_Library) */ |
bogdanm | 0:9b334a45a8ff | 1230 | #endif /* defined( DMA_PRESENT ) */ |