1 /** 2 * @file dma.h 3 * @brief Direct Memory Access (DMA) driver function prototypes and data types. 4 */ 5 6 /****************************************************************************** 7 * 8 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by 9 * Analog Devices, Inc.), 10 * Copyright (C) 2023-2024 Analog Devices, Inc. 11 * 12 * Licensed under the Apache License, Version 2.0 (the "License"); 13 * you may not use this file except in compliance with the License. 14 * You may obtain a copy of the License at 15 * 16 * http://www.apache.org/licenses/LICENSE-2.0 17 * 18 * Unless required by applicable law or agreed to in writing, software 19 * distributed under the License is distributed on an "AS IS" BASIS, 20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 * See the License for the specific language governing permissions and 22 * limitations under the License. 23 * 24 ******************************************************************************/ 25 26 #ifndef LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32680_DMA_H_ 27 #define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32680_DMA_H_ 28 29 /* **** Includes **** */ 30 #include <stdbool.h> 31 #include "mxc_device.h" 32 #include "dma_regs.h" 33 34 #ifdef __cplusplus 35 extern "C" { 36 #endif 37 38 /** 39 * @defgroup dma Direct Memory Access (DMA) 40 * @ingroup periphlibs 41 * @{ 42 */ 43 44 /* **** Definitions **** */ 45 46 /** 47 * @brief Enumeration for the DMA Channel's priority level. 48 * 49 */ 50 typedef enum { 51 MXC_DMA_PRIO_HIGH = MXC_V_DMA_CTRL_PRI_HIGH, ///< High Priority 52 MXC_DMA_PRIO_MEDHIGH = MXC_V_DMA_CTRL_PRI_MEDHIGH, ///< Medium High Priority 53 MXC_DMA_PRIO_MEDLOW = MXC_V_DMA_CTRL_PRI_MEDLOW, ///< Medium Low Priority 54 MXC_DMA_PRIO_LOW = MXC_V_DMA_CTRL_PRI_LOW, ///< Low Priority 55 } mxc_dma_priority_t; 56 57 /** @brief DMA request select */ 58 typedef enum { 59 MXC_DMA_REQUEST_MEMTOMEM = 60 MXC_S_DMA_CTRL_REQUEST_MEMTOMEM, ///< Memory to Memory DMA Request Selection 61 MXC_DMA_REQUEST_SPI1RX = MXC_S_DMA_CTRL_REQUEST_SPI1RX, ///< SPI1 Receive DMA Request Selection 62 MXC_DMA_REQUEST_SPI0RX = MXC_S_DMA_CTRL_REQUEST_SPI0RX, ///< SPI0 Receive DMA Request Selection 63 MXC_DMA_REQUEST_UART0RX = 64 MXC_S_DMA_CTRL_REQUEST_UART0RX, ///< UART0 Receive DMA Request Selection 65 MXC_DMA_REQUEST_UART1RX = 66 MXC_S_DMA_CTRL_REQUEST_UART1RX, ///< UART1 Receive DMA Request Selection 67 MXC_DMA_REQUEST_I2C0RX = MXC_S_DMA_CTRL_REQUEST_I2C0RX, ///< I2C0 Receive DMA Request Selection 68 MXC_DMA_REQUEST_I2C1RX = MXC_S_DMA_CTRL_REQUEST_I2C1RX, ///< I2C1 Receive DMA Request Selection 69 MXC_DMA_REQUEST_ADC = MXC_S_DMA_CTRL_REQUEST_ADC, ///< ADC Receive DMA Request Selection 70 MXC_DMA_REQUEST_I2C2RX = MXC_S_DMA_CTRL_REQUEST_I2C2RX, ///< I2C2 Receive DMA Request Selection 71 MXC_DMA_REQUEST_AESRX = MXC_S_DMA_CTRL_REQUEST_AESRX, ///< AES Receive DMA Request Selection 72 MXC_DMA_REQUEST_UART2RX = 73 MXC_S_DMA_CTRL_REQUEST_UART2RX, ///< UART2 Receive DMA Request Selection 74 MXC_DMA_REQUEST_UART3RX = 75 MXC_S_DMA_CTRL_REQUEST_UART3RX, ///< UART3 Receive DMA Request Selection 76 MXC_DMA_REQUEST_I2SRX = MXC_S_DMA_CTRL_REQUEST_I2SRX, ///< I2S Receive DMA Request Selection 77 MXC_DMA_REQUEST_SPI1TX = MXC_S_DMA_CTRL_REQUEST_SPI1TX, ///< SPI1 Transmit DMA Request Selection 78 MXC_DMA_REQUEST_SPI0TX = MXC_S_DMA_CTRL_REQUEST_SPI0TX, ///< SPI0 Transmit DMA Request Selection 79 MXC_DMA_REQUEST_UART0TX = 80 MXC_S_DMA_CTRL_REQUEST_UART0TX, ///< UART0 Transmit DMA Request Selection 81 MXC_DMA_REQUEST_UART1TX = 82 MXC_S_DMA_CTRL_REQUEST_UART1TX, ///< UART1 Transmit DMA Request Selection 83 MXC_DMA_REQUEST_I2C0TX = MXC_S_DMA_CTRL_REQUEST_I2C0TX, ///< I2C0 Transmit DMA Request Selection 84 MXC_DMA_REQUEST_I2C1TX = MXC_S_DMA_CTRL_REQUEST_I2C1TX, ///< I2C1 Transmit DMA Request Selection 85 MXC_DMA_REQUEST_I2C2TX = 86 MXC_S_DMA_CTRL_REQUEST_I2C2TX, ///< I2C2 Transmit DMA Request Selection */ 87 MXC_DMA_REQUEST_CRCTX = MXC_S_DMA_CTRL_REQUEST_CRCTX, ///< CRC Transmit DMA Request Selection */ 88 MXC_DMA_REQUEST_AESTX = MXC_S_DMA_CTRL_REQUEST_AESTX, ///< AES Transmit DMA Request Selection 89 MXC_DMA_REQUEST_UART2TX = 90 MXC_S_DMA_CTRL_REQUEST_UART2TX, ///< UART2 Transmit DMA Request Selection 91 MXC_DMA_REQUEST_UART3TX = 92 MXC_S_DMA_CTRL_REQUEST_UART3TX, ///< UART3 Transmit DMA Request Selection 93 MXC_DMA_REQUEST_I2STX = MXC_S_DMA_CTRL_REQUEST_I2STX, ///< I2S Transmit DMA Request Selection 94 } mxc_dma_reqsel_t; 95 96 /** @brief Enumeration for the DMA prescaler */ 97 typedef enum { 98 MXC_DMA_PRESCALE_DISABLE = MXC_S_DMA_CTRL_TO_CLKDIV_DIS, ///< Prescaler disabled 99 MXC_DMA_PRESCALE_DIV256 = MXC_S_DMA_CTRL_TO_CLKDIV_DIV256, ///< Divide by 256 100 MXC_DMA_PRESCALE_DIV64K = MXC_S_DMA_CTRL_TO_CLKDIV_DIV64K, ///< Divide by 65,536 101 MXC_DMA_PRESCALE_DIV16M = MXC_S_DMA_CTRL_TO_CLKDIV_DIV16M, ///< Divide by 16,777,216 102 } mxc_dma_prescale_t; 103 104 /** @brief Enumeration for the DMA timeout value */ 105 typedef enum { 106 MXC_DMA_TIMEOUT_4_CLK = MXC_S_DMA_CTRL_TO_PER_TO4, ///< DMA timeout of 4 clocks 107 MXC_DMA_TIMEOUT_8_CLK = MXC_S_DMA_CTRL_TO_PER_TO8, ///< DMA timeout of 8 clocks 108 MXC_DMA_TIMEOUT_16_CLK = MXC_S_DMA_CTRL_TO_PER_TO16, ///< DMA timeout of 16 clocks 109 MXC_DMA_TIMEOUT_32_CLK = MXC_S_DMA_CTRL_TO_PER_TO32, ///< DMA timeout of 32 clocks 110 MXC_DMA_TIMEOUT_64_CLK = MXC_S_DMA_CTRL_TO_PER_TO64, ///< DMA timeout of 64 clocks 111 MXC_DMA_TIMEOUT_128_CLK = MXC_S_DMA_CTRL_TO_PER_TO128, ///< DMA timeout of 128 clocks 112 MXC_DMA_TIMEOUT_256_CLK = MXC_S_DMA_CTRL_TO_PER_TO256, ///< DMA timeout of 256 clocks 113 MXC_DMA_TIMEOUT_512_CLK = MXC_S_DMA_CTRL_TO_PER_TO512, ///< DMA timeout of 512 clocks 114 } mxc_dma_timeout_t; 115 116 /** @brief DMA transfer data width */ 117 typedef enum { 118 /* Using the '_V_' define instead of the '_S_' since these same values will be used to 119 specify the DSTWD also. The API functions will shift the value the correct amount 120 prior to writing the cfg register. */ 121 MXC_DMA_WIDTH_BYTE = MXC_V_DMA_CTRL_SRCWD_BYTE, ///< DMA transfer in bytes 122 MXC_DMA_WIDTH_HALFWORD = MXC_V_DMA_CTRL_SRCWD_HALFWORD, ///< DMA transfer in 16-bit half-words 123 MXC_DMA_WIDTH_WORD = MXC_V_DMA_CTRL_SRCWD_WORD, ///< DMA transfer in 32-bit words 124 } mxc_dma_width_t; 125 126 /** 127 * @brief The basic configuration information to set up a DMA channel 128 * and prepare it for transfers. 129 * 130 */ 131 typedef struct { 132 int ch; ///< The channel to load the configuration data into 133 mxc_dma_reqsel_t reqsel; ///< The request select line to be used (mem2mem, peripheral) 134 mxc_dma_width_t srcwd; ///< The source width (could be dependent on FIFO width) 135 mxc_dma_width_t dstwd; ///< The destination width (could be dependent on FIFO width) 136 int srcinc_en; ///< Whether to increment the source address during the transfer 137 int dstinc_en; ///< Whether to increment the source address during the transfer 138 } mxc_dma_config_t; 139 140 /** 141 * @brief The information needed to complete a DMA transfer 142 * 143 */ 144 typedef struct { 145 int ch; ///< The channel to use for the transfer 146 void *source; ///< Pointer to the source address, if applicable 147 void *dest; ///< Pointer to the destination address, if applicable 148 int len; ///< Number of bytes to transfer 149 } mxc_dma_srcdst_t; 150 151 /** 152 * @brief The advanced configuration options, these are optional but could 153 * be needed in cases where multiple DMA channels are running concurrently 154 * or DMA is being used with low bandwidth peripherals. 155 * 156 */ 157 typedef struct { 158 int ch; ///< The channel to use for the transfer 159 mxc_dma_priority_t prio; ///< The DMA priority for the channel 160 unsigned int reqwait_en; ///< Delay the timeout timer start until after first transfer 161 mxc_dma_timeout_t tosel; ///< Number of prescaled clocks seen by the channel before a timeout 162 mxc_dma_prescale_t pssel; ///< Prescaler for the timeout timer 163 unsigned int burst_size; ///< Number of bytes moved in a single burst 164 } mxc_dma_adv_config_t; 165 166 /** 167 * @brief The callback called on completion of a DMA_MemCpy() transfer 168 * 169 * @param dest Pointer to the destination of the copy 170 */ 171 typedef void (*mxc_dma_complete_cb_t)(void *dest); 172 173 /** 174 * @brief The callback called on completion of a transfer, 175 * @note This callback is used with MXC_DMA_DoTransfer() 176 * to allow the user to chain an unlimited number of 177 * DMA Transfers. 178 * 179 * @param trans Struct of the completed transfer 180 * 181 * @return Returns the next transfer to be completed, or NULL 182 * if no more transfers will be done 183 */ 184 typedef mxc_dma_srcdst_t (*mxc_dma_trans_chain_t)(mxc_dma_srcdst_t dest); 185 186 /* **** Function Prototypes **** */ 187 /*************************/ 188 /* Low Level Functions */ 189 /*************************/ 190 /** 191 * @brief Initialize DMA resources 192 * @details This initialization is required before using the DMA driver functions. 193 * @note On default this function enables DMA peripheral clock. 194 * if you wish to manage clock and gpio related things in upper level instead of here. 195 * Define MSDK_NO_GPIO_CLK_INIT flag in project.mk file. 196 * By this flag this function will remove clock and gpio related codes from file. 197 * @return #E_NO_ERROR if successful 198 */ 199 int MXC_DMA_Init(void); 200 201 /** 202 * @brief De-Initialize DMA resources. 203 */ 204 void MXC_DMA_DeInit(void); 205 206 /** 207 * @brief Request DMA channel 208 * @details Returns a handle to the first free DMA channel, which can be used via API calls 209 * or direct access to channel registers using the MXC_DMA_GetCHRegs(int ch) function. 210 * @return Non-negative channel handle (inclusive of zero). 211 * @return #E_NONE_AVAIL All channels in use. 212 * @return #E_BAD_STATE DMA is not initialized, call MXC_DMA_Init() first. 213 * @return #E_BUSY DMA is currently busy (locked), try again later. 214 */ 215 int MXC_DMA_AcquireChannel(void); 216 217 /** 218 * @brief Release DMA channel 219 * @details Stops any DMA operation on the channel and returns it to the pool of free channels. 220 * 221 * @param ch DMA channel to release 222 * 223 * @return #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise 224 */ 225 int MXC_DMA_ReleaseChannel(int ch); 226 227 /** 228 * @brief Configure the DMA channel 229 * @details Configures the channel, which was previously requested by MXC_DMA_Getchannel() 230 * 231 * @param config Struct containing DMA configuration parameters 232 * @param srcdst Struct containing pointers and length of DMA operation 233 * 234 * @return #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise 235 */ 236 int MXC_DMA_ConfigChannel(mxc_dma_config_t config, mxc_dma_srcdst_t srcdst); 237 238 /** 239 * @brief Configure the DMA channel with more advanced parameters 240 * 241 * @param advConfig Struct containing advanced DMA parameters 242 * 243 * @return #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise 244 */ 245 int MXC_DMA_AdvConfigChannel(mxc_dma_adv_config_t advConfig); 246 247 /** 248 * @brief Set channel source, destination, and count for the transfer 249 * @param srcdst Struct containing the channel, source, destination, and count for the channel 250 * @note Unless the channel request select is #mxc_dma_srcdst_t = MXC_DMA_REQUEST_MEMTOMEM, 251 * either src_addr or dst_addr will be ignored by the DMA engine. 252 * In these cases, the address is a don't-care. See the User's 253 * Guide for more information. 254 * @return #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise 255 */ 256 int MXC_DMA_SetSrcDst(mxc_dma_srcdst_t srcdst); 257 258 /** 259 * @brief Get channel source, destination, and count for transfer 260 * 261 * @param srcdst Pointer to struct with the correct channel number 262 * 263 * @return See \ref MXC_Error_Codes for a list of return values 264 */ 265 int MXC_DMA_GetSrcDst(mxc_dma_srcdst_t *srcdst); 266 267 /** 268 * @brief Set channel reload source, destination, and count for the transfer 269 * @param srcdstReload Struct containing the channel, source, destination, and count for the channel 270 * @note Unless the channel request select is #mxc_dma_srcdst_t = MXC_DMA_REQUEST_MEMTOMEM, 271 * either src_addr or dst_addr will be ignored by the DMA engine. 272 * In these cases, the address is a don't-care. See the User's 273 * Guide for more information. 274 * @return #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise 275 */ 276 int MXC_DMA_SetSrcReload(mxc_dma_srcdst_t srcdstReload); 277 278 /** 279 * @brief Get channel reload source, destination, and count for transfer 280 * 281 * @param srcdstReload Pointer to struct with the correct channel number 282 * 283 * @return See \ref MXC_Error_Codes for a list of return values 284 */ 285 int MXC_DMA_GetSrcReload(mxc_dma_srcdst_t *srcdstReload); 286 287 /** 288 * @brief Set channel interrupt callback 289 * @param ch DMA channel 290 * @param callback Pointer to a function to call when the channel 291 * interrupt flag is set and interrupts are enabled or 292 * when DMA is shutdown by the driver. 293 * @details Configures the channel interrupt callback. The @p callback 294 * function is called for two conditions: 295 * -# When the channel's interrupt flag is set and DMA interrupts 296 * are enabled. 297 * -# If the driver calls the MXC_DMA_Shutdown() function. The 298 * callback function prototype is: 299 * @code 300 * void callback_fn(int ch, int reason); 301 * @endcode 302 * @p ch indicates the channel that generated the callback, @p 303 * reason is either #E_NO_ERROR for a DMA interrupt or #E_SHUTDOWN 304 * if the DMA is being shutdown. 305 * 306 * @return #E_BAD_PARAM if an unused or invalid channel handle, 307 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 308 */ 309 int MXC_DMA_SetCallback(int ch, void (*callback)(int, int)); 310 311 /** 312 * @brief Set channel interrupt 313 * @note Each channel has two interrupts (complete, and count to zero). 314 * To enable complete, pass true for chdis. To enable count to zero, 315 * pass true for ctz. 316 * @param ch DMA channel 317 * @param chdis Enable channel complete interrupt 318 * @param ctz Enable channel count to zero interrupt. 319 * @return #E_BAD_PARAM if an unused or invalid channel handle, #E_NO_ERROR otherwise 320 */ 321 int MXC_DMA_SetChannelInterruptEn(int ch, bool chdis, bool ctz); 322 323 /** 324 * @brief Enable channel interrupt 325 * @note Each channel has two interrupts (complete, and count to zero) 326 which must also be enabled with MXC_DMA_SetChannelInterruptEn() 327 * @param ch DMA channel to enable interrupts for. 328 * @param flags The flags to enable 329 * @return #E_BAD_PARAM if an unused or invalid channel handle, 330 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 331 */ 332 int MXC_DMA_ChannelEnableInt(int ch, int flags); 333 334 /** 335 * @brief Disable channel interrupt 336 * @param ch DMA channel to clear flags for. 337 * @param flags The flags to disable 338 * @return #E_BAD_PARAM if an unused or invalid channel handle, 339 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 340 */ 341 int MXC_DMA_ChannelDisableInt(int ch, int flags); 342 343 /** 344 * @brief Read channel interrupt flags 345 * @param ch DMA channel to get interrupt status from. 346 * @return #E_BAD_PARAM if an unused or invalid channel handle, 347 * flags otherwise, \ref MXC_Error_Codes 348 */ 349 int MXC_DMA_ChannelGetFlags(int ch); 350 351 /** 352 * @brief Clear channel interrupt flags 353 * @param ch DMA channel to clear the interrupt flag for. 354 * @param flags The flags to clear 355 * @return #E_BAD_PARAM if an unused or invalid channel handle, 356 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 357 */ 358 int MXC_DMA_ChannelClearFlags(int ch, int flags); 359 360 /** 361 * @brief Enable channel interrupt 362 * @note Each channel has two interrupts (complete, and count to zero) 363 which must also be enabled with MXC_DMA_SetChannelInterruptEn() 364 * @param ch DMA channel to enable interrupts for. 365 * @return #E_BAD_PARAM if an unused or invalid channel handle, 366 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 367 */ 368 int MXC_DMA_EnableInt(int ch); 369 370 /** 371 * @brief Disable channel interrupt 372 * @param ch DMA channel to disable interrupts for. 373 * @return #E_BAD_PARAM if an unused or invalid channel handle, 374 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 375 */ 376 int MXC_DMA_DisableInt(int ch); 377 378 /** 379 * @brief Start transfer 380 * @param ch DMA channel 381 * @details Start the DMA channel transfer, assumes that MXC_DMA_SetSrcDstCnt() has been called beforehand. 382 * @return #E_BAD_PARAM if an unused or invalid channel handle, 383 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 384 */ 385 int MXC_DMA_Start(int ch); 386 387 /** 388 * @brief Stop DMA transfer, irrespective of status (complete or in-progress) 389 * @param ch DMA channel 390 * @return #E_BAD_PARAM if an unused or invalid channel handle, 391 * #E_NO_ERROR otherwise, \ref MXC_Error_Codes 392 */ 393 int MXC_DMA_Stop(int ch); 394 395 /** 396 * @brief Get a pointer to the DMA channel registers 397 * @param ch DMA channel 398 * @note If direct access to DMA channel registers is required, this 399 * function can be used on a channel handle returned by MXC_DMA_AcquireChannel(). 400 * @return NULL if an unused or invalid channel handle, or a valid pointer otherwise 401 */ 402 mxc_dma_ch_regs_t *MXC_DMA_GetCHRegs(int ch); 403 404 /** 405 * @brief Interrupt handler function 406 * @details Call this function as the ISR for each DMA channel under driver control. 407 * Interrupt flags for channel ch will be automatically cleared before return. 408 */ 409 void MXC_DMA_Handler(void); 410 411 /*************************/ 412 /* High Level Functions */ 413 /*************************/ 414 415 /** 416 * @brief Performs a memcpy, using DMA, optionally asynchronous 417 * @note The user must have the DMA interrupt enabled and call 418 * MXC_DMA_Handler() from the ISR. 419 * 420 * @param dest pointer to destination memory 421 * @param src pointer to source memory 422 * @param len number of bytes to copy 423 * @param callback function to call when transfer is complete 424 * 425 * @return see \ref MXC_Error_Codes 426 */ 427 int MXC_DMA_MemCpy(void *dest, void *src, int len, mxc_dma_complete_cb_t callback); 428 429 /** 430 * @brief Performs a memcpy, using DMA, optionally asynchronous 431 * @note The user must have the DMA interrupt enabled and call 432 * MXC_DMA_Handler() from the ISR. 433 * 434 * @param config The channel config struct 435 * @param firstSrcDst The source, destination, and count for the first transfer 436 * @param callback function is called when transfer is complete 437 * 438 * @return see \ref MXC_Error_Codes 439 */ 440 int MXC_DMA_DoTransfer(mxc_dma_config_t config, mxc_dma_srcdst_t firstSrcDst, 441 mxc_dma_trans_chain_t callback); 442 /** 443 * For other functional uses of DMA (UART, SPI, etc) see the appropriate peripheral driver 444 */ 445 446 /**@} end of group dma */ 447 #ifdef __cplusplus 448 } 449 #endif 450 451 #endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32680_DMA_H_ 452