/** ********************************************************************************************************************** * @file stm32u5xx_hal_dma.c * @author MCD Application Team * @brief This file provides firmware functions to manage the following functionalities of the Direct Memory Access * (DMA) peripheral: * + Initialization/De-Initialization Functions * + I/O Operation Functions * + State and Errors Functions * + DMA Attributes Functions * ********************************************************************************************************************** * @attention * * Copyright (c) 2021 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ********************************************************************************************************************** @verbatim ====================================================================================================================== ############### How to use this driver ############### ====================================================================================================================== [..] DMA transfer modes are divided to 2 major categories : (+) Normal transfers (legacy) (+) Linked-list transfers [..] Normal transfers mode is initialized via the standard module and linked-list mode is configured via the extended module. [..] Additionally to linked-list capability, all advanced DMA features are managed and configured via the extended module as extensions to normal mode. Advanced features are : (+) Repeated block feature. (+) Trigger feature. (+) Data handling feature. [..] DMA Legacy circular transfer, is replaced by circular linked-list configuration. *** Initialization and De-Initialization *** ============================================ [..] For a given channel, enable and configure the peripheral to be connected to the DMA Channel (except for internal SRAM/FLASH memories: no initialization is necessary) please refer to Reference manual for connection between peripherals and DMA requests. [..] For a given channel, use HAL_DMA_Init function to program the required configuration for normal transfer through the following parameters: (+) Request : Specifies the DMA channel request Request parameters : (++) can be a value of @ref DMA_Request_Selection (+) BlkHWRequest : Specifies the Block hardware request mode for DMA channel (++) can be a value of @ref DMA_Block_Request (+) Direction : Specifies the transfer direction for DMA channel (++) can be a value of @ref DMA_Transfer_Direction (+) SrcInc : Specifies the source increment mode for the DMA channel (++) can be a value of @ref DMA_Source_Increment_Mode (+) DestInc : Specifies the destination increment mode for the DMA channel (++) can be a value of @ref DMA_Destination_Increment_Mode (+) SrcDataWidth : Specifies the source data width for the DMA channel (++) can be a value of @ref DMA_Source_Data_Width (+) DestDataWidth : Specifies the destination data width for the DMA channel (++) can be a value of @ref DMA_Destination_Data_Width (+) Priority : Specifies the priority for the DMA channel (++) can be a value of @ref DMA_Priority_Level (+) SrcBurstLength : Specifies the source burst length (number of beats) for the DMA channel (++) can be a value of between 1 and 64 (+) DestBurstLength : Specifies the destination burst length (number of beats) for the DMA channel (++) can be a value of between 1 and 64 (+) TransferAllocatedPort : Specifies the source and destination allocated ports (++) can be a value of @ref DMA_Transfer_Allocated_Port (+) TransferEventMode : Specifies the transfer event mode for the DMA channel (++) can be a value of @ref DMA_Transfer_Event_Mode (+) Mode : Specifies the transfer mode for the DMA channel (++) can be a value of @ref DMA_Transfer_Mode *** Polling mode IO operation *** ================================= [..] (+) Use HAL_DMA_Start() to start a DMA normal transfer after the configuration of source address, destination address and the size of data to be transferred. (+) Use HAL_DMA_PollForTransfer() to poll for selected transfer level. In this case a fixed Timeout can be configured by User depending on his application. Transfer level can be : (++) HAL_DMA_HALF_TRANSFER (++) HAL_DMA_FULL_TRANSFER For circular transfer, this API returns an HAL_ERROR with HAL_DMA_ERROR_NOT_SUPPORTED error code. (+) Use HAL_DMA_Abort() function to abort any ongoing DMA transfer in blocking mode. This API returns HAL_ERROR when there is no ongoing transfer or timeout is reached when disabling the DMA channel. (This API should not be called from an interrupt service routine) *** Interrupt mode IO operation *** =================================== [..] (+) Configure the DMA interrupt priority using HAL_NVIC_SetPriority() (+) Enable the DMA IRQ handler using HAL_NVIC_EnableIRQ() (+) Use HAL_DMA_RegisterCallback() function to register user callbacks from the following list : (++) XferCpltCallback : transfer complete callback. (++) XferHalfCpltCallback : half transfer complete callback. (++) XferErrorCallback : transfer error callback. (++) XferAbortCallback : transfer abort complete callback. (++) XferSuspendCallback : transfer suspend complete callback. (+) Use HAL_DMA_Start_IT() to start the DMA transfer after the enable of DMA interrupts and the configuration of source address,destination address and the size of data to be transferred. (+) Use HAL_DMA_IRQHandler() called under DMA_IRQHandler() interrupt subroutine to handle any DMA interrupt. (+) Use HAL_DMA_Abort_IT() function to abort any on-going DMA transfer in non-blocking mode. This API will suspend immediately the DMA channel execution. When the transfer is effectively suspended, an interrupt is generated and HAL_DMA_IRQHandler() will reset the channel and execute the callback XferAbortCallback. (This API could be called from an interrupt service routine) *** State and errors *** ======================== [..] (+) Use HAL_DMA_GetState() function to get the DMA state. (+) Use HAL_DMA_GetError() function to get the DMA error code. *** Security and privilege attributes *** ========================================= [..] (+) Use HAL_DMA_ConfigChannelAttributes() function to configure DMA channel security and privilege attributes. (++) Security : at channel level, at source level and at destination level. (++) Privilege : at channel level. (+) Use HAL_DMA_GetConfigChannelAttributes() function to get the DMA channel attributes. (+) Use HAL_DMA_LockChannelAttributes() function to lock the DMA channel security and privilege attributes configuration. This API is called once after each system boot. When this API is called, HAL_DMA_ConfigChannelAttributes() API cannot be used anymore. (+) Use HAL_DMA_GetLockChannelAttributes() function to get the attributes lock status. *** DMA HAL driver macros list *** ================================== [..] Below the list of most used macros in DMA HAL driver. (+) __HAL_DMA_ENABLE : Enable the specified DMA Channel. (+) __HAL_DMA_DISABLE : Disable the specified DMA Channel. (+) __HAL_DMA_GET_FLAG : Get the DMA Channel pending flags. (+) __HAL_DMA_CLEAR_FLAG : Clear the DMA Channel pending flags. (+) __HAL_DMA_ENABLE_IT : Enable the specified DMA Channel interrupts. (+) __HAL_DMA_DISABLE_IT : Disable the specified DMA Channel interrupts. (+) __HAL_DMA_GET_IT_SOURCE : Check whether the specified DMA Channel interrupt has occurred or not. [..] (@) You can refer to the header file of the DMA HAL driver for more useful macros. @endverbatim ********************************************************************************************************************** */ /* Includes ----------------------------------------------------------------------------------------------------------*/ #include "stm32u5xx_hal.h" /** @addtogroup STM32U5xx_HAL_Driver * @{ */ /** @defgroup DMA DMA * @brief DMA HAL module driver * @{ */ #ifdef HAL_DMA_MODULE_ENABLED /* Private typedef ---------------------------------------------------------------------------------------------------*/ /* Private constants -------------------------------------------------------------------------------------------------*/ /* Private macro -----------------------------------------------------------------------------------------------------*/ /* Private variables -------------------------------------------------------------------------------------------------*/ /* Private function prototypes ---------------------------------------------------------------------------------------*/ static void DMA_SetConfig(DMA_HandleTypeDef const *const hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SrcDataSize); static void DMA_Init(DMA_HandleTypeDef const *const hdma); /* Exported functions ------------------------------------------------------------------------------------------------*/ /** @addtogroup DMA_Exported_Functions DMA Exported Functions * @{ */ /** @addtogroup DMA_Exported_Functions_Group1 * @verbatim ====================================================================================================================== ############### Initialization and de-initialization functions ############### ====================================================================================================================== [..] This section provides functions allowing to initialize and de-initialize the DMA channel in normal mode. [..] (+) The HAL_DMA_Init() function follows the DMA channel configuration procedures as described in reference manual. (+) The HAL_DMA_DeInit() function allows to de-initialize the DMA channel. @endverbatim * @{ */ /** * @brief Initialize the DMA channel in normal mode according to the specified parameters in the DMA_InitTypeDef and * create the associated handle. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *const hdma) { /* Get tick number */ uint32_t tickstart = HAL_GetTick(); /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance)); assert_param(IS_DMA_DIRECTION(hdma->Init.Direction)); if ((hdma->Init.Direction == DMA_MEMORY_TO_PERIPH) || (hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)) { assert_param(IS_DMA_REQUEST(hdma->Init.Request)); } assert_param(IS_DMA_BLOCK_HW_REQUEST(hdma->Init.BlkHWRequest)); assert_param(IS_DMA_SOURCE_INC(hdma->Init.SrcInc)); assert_param(IS_DMA_DESTINATION_INC(hdma->Init.DestInc)); assert_param(IS_DMA_SOURCE_DATA_WIDTH(hdma->Init.SrcDataWidth)); assert_param(IS_DMA_DESTINATION_DATA_WIDTH(hdma->Init.DestDataWidth)); assert_param(IS_DMA_PRIORITY(hdma->Init.Priority)); assert_param(IS_DMA_TCEM_EVENT_MODE(hdma->Init.TransferEventMode)); assert_param(IS_DMA_MODE(hdma->Init.Mode)); /* Check DMA channel instance */ if (IS_GPDMA_INSTANCE(hdma->Instance) != 0U) { assert_param(IS_DMA_BURST_LENGTH(hdma->Init.SrcBurstLength)); assert_param(IS_DMA_BURST_LENGTH(hdma->Init.DestBurstLength)); assert_param(IS_DMA_TRANSFER_ALLOCATED_PORT(hdma->Init.TransferAllocatedPort)); } /* Allocate lock resource */ __HAL_UNLOCK(hdma); /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_BUSY; /* Disable the DMA channel */ __HAL_DMA_DISABLE(hdma); /* Check if the DMA channel is effectively disabled */ while ((hdma->Instance->CCR & DMA_CCR_EN) != 0U) { /* Check for the Timeout */ if ((HAL_GetTick() - tickstart) > HAL_TIMEOUT_DMA_ABORT) { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_ERROR; return HAL_ERROR; } } /* Initialize the DMA channel registers */ DMA_Init(hdma); /* Update DMA channel operation mode */ hdma->Mode = hdma->Init.Mode; /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NONE; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; return HAL_OK; } /** * @brief DeInitialize the DMA channel when it is configured in normal mode. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_DeInit(DMA_HandleTypeDef *const hdma) { DMA_TypeDef *p_dma_instance; uint32_t tickstart = HAL_GetTick(); /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance)); /* Get DMA instance */ p_dma_instance = GET_DMA_INSTANCE(hdma); /* Disable the selected DMA Channel */ __HAL_DMA_DISABLE(hdma); /* Check if the DMA channel is effectively disabled */ while ((hdma->Instance->CCR & DMA_CCR_EN) != 0U) { /* Check for the Timeout */ if ((HAL_GetTick() - tickstart) > HAL_TIMEOUT_DMA_ABORT) { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_ERROR; return HAL_ERROR; } } /* Reset DMA Channel registers */ hdma->Instance->CLBAR = 0U; hdma->Instance->CCR = 0U; hdma->Instance->CTR1 = 0U; hdma->Instance->CTR2 = 0U; hdma->Instance->CBR1 = 0U; hdma->Instance->CSAR = 0U; hdma->Instance->CDAR = 0U; hdma->Instance->CLLR = 0U; /* Reset 2D Addressing registers */ if (IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance) != 0U) { hdma->Instance->CTR3 = 0U; hdma->Instance->CBR2 = 0U; } /* Clear privilege attribute */ CLEAR_BIT(p_dma_instance->PRIVCFGR, (1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU))); #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) /* Clear secure attribute */ CLEAR_BIT(p_dma_instance->SECCFGR, (1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU))); #endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ /* Clear all flags */ __HAL_DMA_CLEAR_FLAG(hdma, (DMA_FLAG_TC | DMA_FLAG_HT | DMA_FLAG_DTE | DMA_FLAG_ULE | DMA_FLAG_USE | DMA_FLAG_SUSP | DMA_FLAG_TO)); /* Clean all callbacks */ hdma->XferCpltCallback = NULL; hdma->XferHalfCpltCallback = NULL; hdma->XferErrorCallback = NULL; hdma->XferAbortCallback = NULL; hdma->XferSuspendCallback = NULL; /* Clean DMA queue */ hdma->LinkedListQueue = NULL; /* Clean DMA parent */ if (hdma->Parent != NULL) { hdma->Parent = NULL; } /* Update DMA channel operation mode */ hdma->Mode = DMA_NORMAL; /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NONE; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_RESET; /* Release Lock */ __HAL_UNLOCK(hdma); return HAL_OK; } /** * @} */ /** @addtogroup DMA_Exported_Functions_Group2 * @verbatim ====================================================================================================================== ############### IO operation functions ############### ====================================================================================================================== [..] This section provides functions allowing to : (+) Configure the source, destination address and data size and Start DMA transfer in normal mode (+) Abort DMA transfer (+) Poll for transfer complete (+) Handle DMA interrupt request (+) Register and Unregister DMA callbacks [..] (+) The HAL_DMA_Start() function allows to start the DMA channel transfer in normal mode (Blocking mode). (+) The HAL_DMA_Start_IT() function allows to start the DMA channel transfer in normal mode (Non-blocking mode). (+) The HAL_DMA_Abort() function allows to abort any on-going transfer (Blocking mode). (+) The HAL_DMA_Abort_IT() function allows to abort any on-going transfer (Non-blocking mode). (+) The HAL_DMA_PollForTransfer() function allows to poll on half transfer and transfer complete (Blocking mode). This API cannot be used for circular transfers. (+) The HAL_DMA_IRQHandler() function allows to handle any DMA channel interrupt (Non-blocking mode). (+) The HAL_DMA_RegisterCallback() and HAL_DMA_UnRegisterCallback() functions allow respectively to register and unregister user customized callbacks. User callbacks are called under HAL_DMA_IRQHandler(). @endverbatim * @{ */ /** * @brief Start the DMA channel transfer in normal mode (Blocking mode). * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for * the specified DMA Channel. * @param SrcAddress : The source data address. * @param DstAddress : The destination data address. * @param SrcDataSize : The length of data to be transferred from source to destination in bytes. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *const hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SrcDataSize) { /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_DMA_BLOCK_SIZE(SrcDataSize)); /* Process locked */ __HAL_LOCK(hdma); /* Check DMA channel state */ if (hdma->State == HAL_DMA_STATE_READY) { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_BUSY; /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NONE; /* Configure the source address, destination address, the data size and clear flags */ DMA_SetConfig(hdma, SrcAddress, DstAddress, SrcDataSize); /* Enable DMA channel */ __HAL_DMA_ENABLE(hdma); } else { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_BUSY; /* Process unlocked */ __HAL_UNLOCK(hdma); return HAL_ERROR; } return HAL_OK; } /** * @brief Starts the DMA channel transfer in normal mode with interrupts enabled (Non-blocking mode). * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @param SrcAddress : The source data address. * @param DstAddress : The destination data address. * @param SrcDataSize : The length of data to be transferred from source to destination in bytes. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *const hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SrcDataSize) { /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_DMA_BLOCK_SIZE(SrcDataSize)); /* Process locked */ __HAL_LOCK(hdma); /* Check DMA channel state */ if (hdma->State == HAL_DMA_STATE_READY) { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_BUSY; /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NONE; /* Configure the source address, destination address, the data size and clear flags */ DMA_SetConfig(hdma, SrcAddress, DstAddress, SrcDataSize); /* Enable common interrupts: Transfer Complete and Transfer Errors ITs */ __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_DTE | DMA_IT_ULE | DMA_IT_USE | DMA_IT_TO)); /* Check half transfer complete callback */ if (hdma->XferHalfCpltCallback != NULL) { /* If Half Transfer complete callback is set, enable the corresponding IT */ __HAL_DMA_ENABLE_IT(hdma, DMA_IT_HT); } /* Check Half suspend callback */ if (hdma->XferSuspendCallback != NULL) { /* If Transfer suspend callback is set, enable the corresponding IT */ __HAL_DMA_ENABLE_IT(hdma, DMA_IT_SUSP); } /* Enable DMA channel */ __HAL_DMA_ENABLE(hdma); } else { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_BUSY; /* Process unlocked */ __HAL_UNLOCK(hdma); return HAL_ERROR; } return HAL_OK; } /** * @brief Abort any on-going DMA channel transfer (Blocking mode). * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @note After suspending a DMA channel, a wait until the DMA channel is effectively stopped is added. If a channel * is suspended while a data transfer is on-going, the current data will be transferred and the channel will be * effectively suspended only after the transfer of any on-going data is finished. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *const hdma) { /* Get tick number */ uint32_t tickstart = HAL_GetTick(); /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check DMA channel state */ if (hdma->State != HAL_DMA_STATE_BUSY) { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER; /* Process Unlocked */ __HAL_UNLOCK(hdma); return HAL_ERROR; } else { /* Suspend the channel */ hdma->Instance->CCR |= DMA_CCR_SUSP; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_SUSPEND; /* Check if the DMA Channel is suspended */ while ((hdma->Instance->CSR & DMA_CSR_SUSPF) == 0U) { /* Check for the Timeout */ if ((HAL_GetTick() - tickstart) > HAL_TIMEOUT_DMA_ABORT) { /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_TIMEOUT; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_ERROR; /* Check DMA channel transfer mode */ if ((hdma->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { /* Update the linked-list queue state */ hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_READY; } /* Process Unlocked */ __HAL_UNLOCK(hdma); return HAL_ERROR; } } /* Reset the channel */ hdma->Instance->CCR |= DMA_CCR_RESET; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_ABORT; /* Clear all status flags */ __HAL_DMA_CLEAR_FLAG(hdma, (DMA_FLAG_TC | DMA_FLAG_HT | DMA_FLAG_DTE | DMA_FLAG_ULE | DMA_FLAG_USE | DMA_FLAG_SUSP | DMA_FLAG_TO)); /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; /* Check DMA channel transfer mode */ if ((hdma->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { /* Update the linked-list queue state */ hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_READY; /* Clear remaining data size to ensure loading linked-list from memory next start */ hdma->Instance->CBR1 = 0U; } /* Process Unlocked */ __HAL_UNLOCK(hdma); } return HAL_OK; } /** * @brief Abort any on-going DMA channel transfer in interrupt mode (Non-blocking mode). * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *const hdma) { /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check DMA channel state */ if (hdma->State != HAL_DMA_STATE_BUSY) { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER; return HAL_ERROR; } else { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_ABORT; /* Suspend the channel and activate suspend interrupt */ hdma->Instance->CCR |= (DMA_CCR_SUSP | DMA_CCR_SUSPIE); } return HAL_OK; } /** * @brief Polling for transfer status (Blocking mode). * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @param CompleteLevel : Specifies the DMA level complete. * @param Timeout : Timeout duration. * @retval HAL status */ HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *const hdma, HAL_DMA_LevelCompleteTypeDef CompleteLevel, uint32_t Timeout) { /* Get tick number */ uint32_t tickstart = HAL_GetTick(); uint32_t level_flag; uint32_t tmp_csr; /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_DMA_LEVEL_COMPLETE(CompleteLevel)); /* Check DMA channel state */ if (hdma->State != HAL_DMA_STATE_BUSY) { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER; /* Process Unlocked */ __HAL_UNLOCK(hdma); return HAL_ERROR; } /* Polling mode is not supported in circular mode */ if ((hdma->Mode & DMA_LINKEDLIST_CIRCULAR) == DMA_LINKEDLIST_CIRCULAR) { /* Update the DMA channel error code */ hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED; return HAL_ERROR; } /* Get the level transfer complete flag */ level_flag = ((CompleteLevel == HAL_DMA_FULL_TRANSFER) ? DMA_FLAG_IDLE : DMA_FLAG_HT); /* Get DMA channel status */ tmp_csr = hdma->Instance->CSR; while ((tmp_csr & level_flag) == 0U) { /* Check for the timeout */ if (Timeout != HAL_MAX_DELAY) { if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U)) { /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_TIMEOUT; /* If timeout, abort the current transfer. Note that the Abort function will - Clear all transfer flags. - Unlock. - Set the State. */ (void)HAL_DMA_Abort(hdma); return HAL_ERROR; } } /* Get a newer CSR register value */ tmp_csr = hdma->Instance->CSR; } /* Check trigger overrun flag */ if ((tmp_csr & DMA_FLAG_TO) != 0U) { /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_TO; /* Clear the error flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_TO); } /* Check error flags */ if ((tmp_csr & (DMA_FLAG_DTE | DMA_FLAG_ULE | DMA_FLAG_USE)) != 0U) { /* Check the data transfer error flag */ if ((tmp_csr & DMA_FLAG_DTE) != 0U) { /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_DTE; /* Clear the error flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_DTE); } /* Check the update link error flag */ if ((tmp_csr & DMA_FLAG_ULE) != 0U) { /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_ULE; /* Clear the error flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_ULE); } /* Check the user setting error flag */ if ((tmp_csr & DMA_FLAG_USE) != 0U) { /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_USE; /* Clear the error flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_USE); } /* Reset the channel */ hdma->Instance->CCR |= DMA_CCR_RESET; /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; /* Check DMA channel transfer mode */ if ((hdma->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { /* Update the linked-list queue state */ hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_READY; } /* Process Unlocked */ __HAL_UNLOCK(hdma); return HAL_ERROR; } /* Clear the transfer level flag */ if (CompleteLevel == HAL_DMA_HALF_TRANSFER) { /* Clear the Half Transfer flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_HT); } else if (CompleteLevel == HAL_DMA_FULL_TRANSFER) { /* Clear the transfer flags */ __HAL_DMA_CLEAR_FLAG(hdma, (DMA_FLAG_TC | DMA_FLAG_HT)); /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; /* Check DMA channel transfer mode */ if ((hdma->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { /* Update the linked-list queue state */ hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_READY; } /* Process unlocked */ __HAL_UNLOCK(hdma); } else { return HAL_ERROR; } return HAL_OK; } /** * @brief Handle DMA interrupt request (Non-blocking mode). * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval None. */ void HAL_DMA_IRQHandler(DMA_HandleTypeDef *const hdma) { DMA_TypeDef *p_dma_instance = GET_DMA_INSTANCE(hdma); uint32_t global_it_flag = 1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU); /* Global Interrupt Flag management *********************************************************************************/ if (IS_DMA_GLOBAL_ACTIVE_FLAG(p_dma_instance, global_it_flag) == 0U) { return; /* the global interrupt flag for the current channel is down , nothing to do */ } /* Data Transfer Error Interrupt management *************************************************************************/ if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_DTE) != 0U)) { /* Check if interrupt source is enabled */ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_DTE) != 0U) { /* Clear the transfer error flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_DTE); /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_DTE; } } /* Update Linked-list Error Interrupt management ********************************************************************/ if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_ULE) != 0U)) { /* Check if interrupt source is enabled */ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_ULE) != 0U) { /* Clear the update linked-list error flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_ULE); /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_ULE; } } /* User Setting Error Interrupt management **************************************************************************/ if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_USE) != 0U)) { /* Check if interrupt source is enabled */ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_USE) != 0U) { /* Clear the user setting error flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_USE); /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_USE; } } /* Trigger Overrun Interrupt management *****************************************************************************/ if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_TO) != 0U)) { /* Check if interrupt source is enabled */ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TO) != 0U) { /* Clear the trigger overrun flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_TO); /* Update the DMA channel error code */ hdma->ErrorCode |= HAL_DMA_ERROR_TO; } } /* Half Transfer Complete Interrupt management **********************************************************************/ if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_HT) != 0U)) { /* Check if interrupt source is enabled */ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_HT) != 0U) { /* Clear the half transfer flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_HT); /* Check half transfer complete callback */ if (hdma->XferHalfCpltCallback != NULL) { /* Half transfer callback */ hdma->XferHalfCpltCallback(hdma); } } } /* Suspend Transfer Interrupt management ****************************************************************************/ if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_SUSP) != 0U)) { /* Check if interrupt source is enabled */ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_SUSP) != 0U) { /* Clear the block transfer complete flag */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_SUSP); /* Check DMA channel state */ if (hdma->State == HAL_DMA_STATE_ABORT) { /* Disable the suspend transfer interrupt */ __HAL_DMA_DISABLE_IT(hdma, DMA_IT_SUSP); /* Reset the channel internal state and reset the FIFO */ hdma->Instance->CCR |= DMA_CCR_RESET; if ((hdma->Instance->CCR & DMA_CCR_EN) != 0U) { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_ERROR; } else { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; } /* Check DMA channel transfer mode */ if ((hdma->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { /* Update the linked-list queue state */ hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_READY; } /* Process Unlocked */ __HAL_UNLOCK(hdma); /* Check transfer abort callback */ if (hdma->XferAbortCallback != NULL) { /* Transfer abort callback */ hdma->XferAbortCallback(hdma); } return; } else { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_SUSPEND; /* Check transfer suspend callback */ if (hdma->XferSuspendCallback != NULL) { /* Transfer suspend callback */ hdma->XferSuspendCallback(hdma); } } } } /* Transfer Complete Interrupt management ***************************************************************************/ if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_TC) != 0U)) { /* Check if interrupt source is enabled */ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TC) != 0U) { /* Check DMA channel transfer mode */ if ((hdma->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { /* If linked-list transfer */ if (hdma->Instance->CLLR == 0U) { if (hdma->Instance->CBR1 == 0U) { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; /* Update the linked-list queue state */ hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_READY; } } } else { /* If normal transfer */ if (hdma->Instance->CBR1 == 0U) { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; } } /* Clear TC and HT transfer flags */ __HAL_DMA_CLEAR_FLAG(hdma, (DMA_FLAG_TC | DMA_FLAG_HT)); /* Process Unlocked */ __HAL_UNLOCK(hdma); /* Check transfer complete callback */ if (hdma->XferCpltCallback != NULL) { /* Channel Transfer Complete callback */ hdma->XferCpltCallback(hdma); } } } /* Manage error case ************************************************************************************************/ if (hdma->ErrorCode != HAL_DMA_ERROR_NONE) { /* Reset the channel internal state and reset the FIFO */ hdma->Instance->CCR |= DMA_CCR_RESET; if ((hdma->Instance->CCR & DMA_CCR_EN) != 0U) { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_ERROR; } else { /* Update the DMA channel state */ hdma->State = HAL_DMA_STATE_READY; } /* Check DMA channel transfer mode */ if ((hdma->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) { /* Update the linked-list queue state */ hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_READY; } /* Process Unlocked */ __HAL_UNLOCK(hdma); /* Check transfer error callback */ if (hdma->XferErrorCallback != NULL) { /* Transfer error callback */ hdma->XferErrorCallback(hdma); } } } /** * @brief Register callback according to specified ID. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @param CallbackID : User Callback identifier which could be a value of HAL_DMA_CallbackIDTypeDef enumeration. * @param pCallback : Pointer to private callback function. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_RegisterCallback(DMA_HandleTypeDef *const hdma, HAL_DMA_CallbackIDTypeDef CallbackID, void (*const pCallback)(DMA_HandleTypeDef *const _hdma)) { HAL_StatusTypeDef status = HAL_OK; /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Process locked */ __HAL_LOCK(hdma); /* Check DMA channel state */ if (hdma->State == HAL_DMA_STATE_READY) { /* Check callback ID */ switch (CallbackID) { case HAL_DMA_XFER_CPLT_CB_ID: { /* Register transfer complete callback */ hdma->XferCpltCallback = pCallback; break; } case HAL_DMA_XFER_HALFCPLT_CB_ID: { /* Register half transfer callback */ hdma->XferHalfCpltCallback = pCallback; break; } case HAL_DMA_XFER_ERROR_CB_ID: { /* Register transfer error callback */ hdma->XferErrorCallback = pCallback; break; } case HAL_DMA_XFER_ABORT_CB_ID: { /* Register abort callback */ hdma->XferAbortCallback = pCallback; break; } case HAL_DMA_XFER_SUSPEND_CB_ID: { /* Register suspend callback */ hdma->XferSuspendCallback = pCallback; break; } default: { /* Update error status */ status = HAL_ERROR; break; } } } else { /* Update error status */ status = HAL_ERROR; } /* Release Lock */ __HAL_UNLOCK(hdma); return status; } /** * @brief Unregister callback according to specified ID. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @param CallbackID : User Callback identifier which could be a value of HAL_DMA_CallbackIDTypeDef enum. * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_UnRegisterCallback(DMA_HandleTypeDef *const hdma, HAL_DMA_CallbackIDTypeDef CallbackID) { HAL_StatusTypeDef status = HAL_OK; /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Process locked */ __HAL_LOCK(hdma); /* Check DMA channel state */ if (hdma->State == HAL_DMA_STATE_READY) { /* Check callback ID */ switch (CallbackID) { case HAL_DMA_XFER_CPLT_CB_ID: { /* UnRegister transfer complete callback */ hdma->XferCpltCallback = NULL; break; } case HAL_DMA_XFER_HALFCPLT_CB_ID: { /* UnRegister half transfer callback */ hdma->XferHalfCpltCallback = NULL; break; } case HAL_DMA_XFER_ERROR_CB_ID: { /* UnRegister transfer error callback */ hdma->XferErrorCallback = NULL; break; } case HAL_DMA_XFER_ABORT_CB_ID: { /* UnRegister abort callback */ hdma->XferAbortCallback = NULL; break; } case HAL_DMA_XFER_SUSPEND_CB_ID: { /* UnRegister suspend callback */ hdma->XferSuspendCallback = NULL; break; } case HAL_DMA_XFER_ALL_CB_ID: { /* UnRegister all available callbacks */ hdma->XferCpltCallback = NULL; hdma->XferHalfCpltCallback = NULL; hdma->XferErrorCallback = NULL; hdma->XferAbortCallback = NULL; hdma->XferSuspendCallback = NULL; break; } default: { /* Update error status */ status = HAL_ERROR; break; } } } else { /* Update error status */ status = HAL_ERROR; } /* Release Lock */ __HAL_UNLOCK(hdma); return status; } /** * @} */ /** @addtogroup DMA_Exported_Functions_Group3 * @verbatim ====================================================================================================================== ############### State and Errors functions ############### ====================================================================================================================== [..] This section provides functions allowing to : (+) Check the DMA state (+) Get error code [..] (+) The HAL_DMA_GetState() function allows to get the DMA channel state. (+) The HAL_DMA_DeInit() function allows to get the DMA channel error code. @endverbatim * @{ */ /** * @brief Returns the DMA channel state. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval DMA state. */ HAL_DMA_StateTypeDef HAL_DMA_GetState(DMA_HandleTypeDef const *const hdma) { /* Return the DMA channel state */ return hdma->State; } /** * @brief Return the DMA channel error code. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval DMA Error Code. */ uint32_t HAL_DMA_GetError(DMA_HandleTypeDef const *const hdma) { /* Return the DMA channel error code */ return hdma->ErrorCode; } /** * @} */ /** @addtogroup DMA_Exported_Functions_Group4 * @verbatim ====================================================================================================================== ############### DMA Attributes functions ############### ====================================================================================================================== [..] This section provides functions allowing to : (+) Configure DMA channel secure and privilege attributes. (+) Get DMA channel secure and privilege attributes. (+) Lock DMA channel secure and privilege attributes configuration. (+) Check whether DMA channel secure and privilege attributes configuration is locked or not. [..] (+) The HAL_DMA_ConfigChannelAttributes() function allows to configure DMA channel security and privilege attributes. (+) The HAL_DMA_GetConfigChannelAttributes() function allows to get DMA channel security and privilege attributes configuration. (+) The HAL_DMA_LockChannelAttributes() function allows to lock the DMA channel security and privilege attributes. (+) The HAL_DMA_GetLockChannelAttributes() function allows to get the DMA channel security and privilege attributes lock status. @endverbatim * @{ */ /** * @brief Configure the DMA channel security and privilege attribute(s). * @note These attributes cannot be modified when the corresponding lock state is enabled. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for * the specified DMA Channel. * @param ChannelAttributes : Specifies the DMA channel secure/privilege attributes. * This parameter can be a one or a combination of @ref DMA_Channel_Attributes. * @retval HAL Status. */ HAL_StatusTypeDef HAL_DMA_ConfigChannelAttributes(DMA_HandleTypeDef *const hdma, uint32_t ChannelAttributes) { DMA_TypeDef *p_dma_instance; uint32_t channel_idx; /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Check the parameters */ assert_param(IS_DMA_ATTRIBUTES(ChannelAttributes)); /* Get DMA instance */ p_dma_instance = GET_DMA_INSTANCE(hdma); /* Get channel index */ channel_idx = 1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU); /* Check DMA channel privilege attribute management */ if ((ChannelAttributes & DMA_CHANNEL_ATTR_PRIV_MASK) == DMA_CHANNEL_ATTR_PRIV_MASK) { /* Configure DMA channel privilege attribute */ if ((ChannelAttributes & DMA_CHANNEL_PRIV) == DMA_CHANNEL_PRIV) { p_dma_instance->PRIVCFGR |= channel_idx; } else { p_dma_instance->PRIVCFGR &= (~channel_idx); } } #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) /* Check DMA channel security attribute management */ if ((ChannelAttributes & DMA_CHANNEL_ATTR_SEC_MASK) == DMA_CHANNEL_ATTR_SEC_MASK) { /* Configure DMA channel security attribute */ if ((ChannelAttributes & DMA_CHANNEL_SEC) == DMA_CHANNEL_SEC) { p_dma_instance->SECCFGR |= channel_idx; } else { p_dma_instance->SECCFGR &= (~channel_idx); } } /* Channel source security attribute management */ if ((ChannelAttributes & DMA_CHANNEL_ATTR_SEC_SRC_MASK) == DMA_CHANNEL_ATTR_SEC_SRC_MASK) { /* Configure DMA channel source security attribute */ if ((ChannelAttributes & DMA_CHANNEL_SRC_SEC) == DMA_CHANNEL_SRC_SEC) { hdma->Instance->CTR1 |= DMA_CTR1_SSEC; } else { hdma->Instance->CTR1 &= (~DMA_CTR1_SSEC); } } /* Channel destination security attribute management */ if ((ChannelAttributes & DMA_CHANNEL_ATTR_SEC_DEST_MASK) == DMA_CHANNEL_ATTR_SEC_DEST_MASK) { /* Configure DMA channel destination security attribute */ if ((ChannelAttributes & DMA_CHANNEL_DEST_SEC) == DMA_CHANNEL_DEST_SEC) { hdma->Instance->CTR1 |= DMA_CTR1_DSEC; } else { hdma->Instance->CTR1 &= (~DMA_CTR1_DSEC); } } #endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ return HAL_OK; } /** * @brief Get the DMA channel security and privilege attributes. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information * for the specified DMA Channel. * @param pChannelAttributes : Pointer to the returned attributes. * @retval HAL Status. */ HAL_StatusTypeDef HAL_DMA_GetConfigChannelAttributes(DMA_HandleTypeDef const *const hdma, uint32_t *const pChannelAttributes) { DMA_TypeDef *p_dma_instance; uint32_t attributes; uint32_t channel_idx; /* Check the DMA peripheral handle and channel attributes parameters */ if ((hdma == NULL) || (pChannelAttributes == NULL)) { return HAL_ERROR; } /* Get DMA instance */ p_dma_instance = GET_DMA_INSTANCE(hdma); /* Get channel index */ channel_idx = 1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU); /* Get DMA channel privilege attribute */ attributes = ((p_dma_instance->PRIVCFGR & channel_idx) == 0U) ? DMA_CHANNEL_NPRIV : DMA_CHANNEL_PRIV; #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) /* Get DMA channel security attribute */ attributes |= ((p_dma_instance->SECCFGR & channel_idx) == 0U) ? DMA_CHANNEL_NSEC : DMA_CHANNEL_SEC; /* Get DMA channel source security attribute */ attributes |= ((hdma->Instance->CTR1 & DMA_CTR1_SSEC) == 0U) ? DMA_CHANNEL_SRC_NSEC : DMA_CHANNEL_SRC_SEC; /* Get DMA channel destination security attribute */ attributes |= ((hdma->Instance->CTR1 & DMA_CTR1_DSEC) == 0U) ? DMA_CHANNEL_DEST_NSEC : DMA_CHANNEL_DEST_SEC; #endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ /* return value */ *pChannelAttributes = attributes; return HAL_OK; } #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) /** * @brief Lock the DMA channel security and privilege attribute(s). * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval HAL Status. */ HAL_StatusTypeDef HAL_DMA_LockChannelAttributes(DMA_HandleTypeDef const *const hdma) { DMA_TypeDef *p_dma_instance; uint32_t channel_idx; /* Check the DMA peripheral handle parameter */ if (hdma == NULL) { return HAL_ERROR; } /* Get DMA instance */ p_dma_instance = GET_DMA_INSTANCE(hdma); /* Get channel index */ channel_idx = 1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU); /* Lock the DMA channel privilege and security attributes */ p_dma_instance->RCFGLOCKR |= channel_idx; return HAL_OK; } #endif /* defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */ /** * @brief Get the security and privilege attribute lock state of a DMA channel. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @param pLockState : Pointer to lock state (returned value can be DMA_CHANNEL_ATTRIBUTE_UNLOCKED or * DMA_CHANNEL_ATTRIBUTE_LOCKED). * @retval HAL status. */ HAL_StatusTypeDef HAL_DMA_GetLockChannelAttributes(DMA_HandleTypeDef const *const hdma, uint32_t *const pLockState) { DMA_TypeDef *p_dma_instance; uint32_t channel_idx; /* Check the DMA peripheral handle and lock state parameters */ if ((hdma == NULL) || (pLockState == NULL)) { return HAL_ERROR; } /* Get DMA instance */ p_dma_instance = GET_DMA_INSTANCE(hdma); /* Get channel index */ channel_idx = 1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU); /* Get channel lock attribute state */ *pLockState = ((p_dma_instance->RCFGLOCKR & channel_idx) == 0U) ? DMA_CHANNEL_ATTRIBUTE_UNLOCKED : \ DMA_CHANNEL_ATTRIBUTE_LOCKED; return HAL_OK; } /** * @} */ /** * @} */ /* Private functions -------------------------------------------------------------------------------------------------*/ /** @defgroup DMA_Private_Functions DMA Private Functions * @brief DMA Private Functions * @{ */ /** * @brief Set the DMA channel normal transfer parameters. * @param hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @param SrcAddress : The source data address. * @param DstAddress : The destination data address. * @param SrcDataSize : The length of data to be transferred from source to destination in bytes. * @retval None. */ static void DMA_SetConfig(DMA_HandleTypeDef const *const hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SrcDataSize) { /* Configure the DMA channel data size */ MODIFY_REG(hdma->Instance->CBR1, DMA_CBR1_BNDT, (SrcDataSize & DMA_CBR1_BNDT)); /* Clear all interrupt flags */ __HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_TC | DMA_FLAG_HT | DMA_FLAG_DTE | DMA_FLAG_ULE | DMA_FLAG_USE | DMA_FLAG_SUSP | DMA_FLAG_TO); /* Configure DMA channel source address */ hdma->Instance->CSAR = SrcAddress; /* Configure DMA channel destination address */ hdma->Instance->CDAR = DstAddress; } /** * @brief Initialize the DMA channel in normal mode according to the specified parameters in the DMA_InitTypeDef. * @param hdma : pointer to a DMA_HandleTypeDef structure that contains the configuration information for the * specified DMA Channel. * @retval None. */ static void DMA_Init(DMA_HandleTypeDef const *const hdma) { uint32_t tmpreg; /* Prepare DMA Channel Control Register (CCR) value *****************************************************************/ tmpreg = hdma->Init.Priority; /* Write DMA Channel Control Register (CCR) */ MODIFY_REG(hdma->Instance->CCR, DMA_CCR_PRIO | DMA_CCR_LAP | DMA_CCR_LSM, tmpreg); /* Prepare DMA Channel Transfer Register (CTR1) value ***************************************************************/ tmpreg = hdma->Init.DestInc | hdma->Init.DestDataWidth | hdma->Init.SrcInc | hdma->Init.SrcDataWidth; /* Add parameters specific to GPDMA */ if (IS_GPDMA_INSTANCE(hdma->Instance) != 0U) { tmpreg |= (hdma->Init.TransferAllocatedPort | (((hdma->Init.DestBurstLength - 1U) << DMA_CTR1_DBL_1_Pos) & DMA_CTR1_DBL_1) | (((hdma->Init.SrcBurstLength - 1U) << DMA_CTR1_SBL_1_Pos) & DMA_CTR1_SBL_1)); } /* Write DMA Channel Transfer Register 1 (CTR1) */ MODIFY_REG(hdma->Instance->CTR1, ~(DMA_CTR1_SSEC | DMA_CTR1_DSEC), tmpreg); /* Prepare DMA Channel Transfer Register 2 (CTR2) value *************************************************************/ tmpreg = hdma->Init.BlkHWRequest | (hdma->Init.Request & DMA_CTR2_REQSEL) | hdma->Init.TransferEventMode; /* Memory to Peripheral Transfer */ if ((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH) { if (IS_GPDMA_INSTANCE(hdma->Instance) != 0U) { tmpreg |= DMA_CTR2_DREQ; } } /* Memory to Memory Transfer */ else if ((hdma->Init.Direction) == DMA_MEMORY_TO_MEMORY) { tmpreg |= DMA_CTR2_SWREQ; } else { /* Nothing to do */ } /* Write DMA Channel Transfer Register 2 (CTR2) */ MODIFY_REG(hdma->Instance->CTR2, (DMA_CTR2_TCEM | DMA_CTR2_TRIGPOL | DMA_CTR2_TRIGSEL | DMA_CTR2_TRIGM | DMA_CTR2_BREQ | DMA_CTR2_DREQ | DMA_CTR2_SWREQ | DMA_CTR2_REQSEL), tmpreg); /* Write DMA Channel Block Register 1 (CBR1) ************************************************************************/ WRITE_REG(hdma->Instance->CBR1, 0U); /* If 2D Addressing is supported by current channel */ if (IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance) != 0U) { /* Write DMA Channel Transfer Register 3 (CTR3) *******************************************************************/ WRITE_REG(hdma->Instance->CTR3, 0U); /* Write DMA Channel Block Register 2 (CBR2) **********************************************************************/ WRITE_REG(hdma->Instance->CBR2, 0U); } /* Write DMA Channel linked-list address register (CLLR) ************************************************************/ WRITE_REG(hdma->Instance->CLLR, 0U); } /** * @} */ #endif /* HAL_DMA_MODULE_ENABLED */ /** * @} */ /** * @} */