| /** |
| ****************************************************************************** |
| * @file stm32l5xx_hal_dma_ex.c |
| * @author MCD Application Team |
| * @brief DMA Extension HAL module driver |
| * This file provides firmware functions to manage the following |
| * functionalities of the DMA Extension peripheral: |
| * + Extended features functions |
| * |
| ****************************************************************************** |
| * @attention |
| * |
| * Copyright (c) 2019 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 ##### |
| ============================================================================== |
| [..] |
| The DMA Extension HAL driver can be used as follows: |
| |
| (+) Configure the DMA_MUX Synchronization Block using HAL_DMAEx_ConfigMuxSync function. |
| (+) Configure the DMA_MUX Request Generator Block using HAL_DMAEx_ConfigMuxRequestGenerator function. |
| Functions HAL_DMAEx_EnableMuxRequestGenerator and HAL_DMAEx_DisableMuxRequestGenerator can then be used |
| to respectively enable/disable the request generator. |
| |
| (+) To handle the DMAMUX Interrupts, the function HAL_DMAEx_MUX_IRQHandler should be called from |
| the DMAMUX IRQ handler i.e DMAMUX1_OVR_IRQHandler. |
| As only one interrupt line is available for all DMAMUX channels and request generators , HAL_DMAEx_MUX_IRQHandler should be |
| called with, as parameter, the appropriate DMA handle as many as used DMAs in the user project |
| (exception done if a given DMA is not using the DMAMUX SYNC block neither a request generator) |
| |
| -@- In Memory-to-Memory transfer mode, Multi (Double) Buffer mode is not allowed. |
| -@- When Multi (Double) Buffer mode is enabled, the transfer is circular by default. |
| -@- In Multi (Double) buffer mode, it is possible to update the base address for |
| the AHB memory port on the fly (DMA_CM0ARx or DMA_CM1ARx) when the channel is enabled. |
| |
| |
| @endverbatim |
| ****************************************************************************** |
| */ |
| |
| /* Includes ------------------------------------------------------------------*/ |
| #include "stm32l5xx_hal.h" |
| |
| /** @addtogroup STM32L5xx_HAL_Driver |
| * @{ |
| */ |
| |
| /** @defgroup DMAEx DMAEx |
| * @brief DMA Extended HAL module driver |
| * @{ |
| */ |
| |
| #ifdef HAL_DMA_MODULE_ENABLED |
| |
| /* Private typedef -----------------------------------------------------------*/ |
| /* Private define ------------------------------------------------------------*/ |
| /* Private macro -------------------------------------------------------------*/ |
| /* Private variables ---------------------------------------------------------*/ |
| /* Private Constants ---------------------------------------------------------*/ |
| /* Private function prototypes -----------------------------------------------*/ |
| /** @addtogroup DMAEx_Private_Functions |
| * @{ |
| */ |
| |
| static void DMA_MultiBufferSetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength); |
| |
| /** |
| * @} |
| */ |
| |
| |
| /* Private functions ---------------------------------------------------------*/ |
| |
| |
| /** @defgroup DMAEx_Exported_Functions DMAEx Exported Functions |
| * @{ |
| */ |
| |
| /** @defgroup DMAEx_Exported_Functions_Group1 DMAEx Extended features functions |
| * @brief Extended features functions |
| * |
| @verbatim |
| =============================================================================== |
| ##### Extended features functions ##### |
| =============================================================================== |
| [..] This section provides functions allowing to: |
| |
| (+) Configure the DMAMUX Synchronization Block using HAL_DMAEx_ConfigMuxSync function. |
| (+) Configure the DMAMUX Request Generator Block using HAL_DMAEx_ConfigMuxRequestGenerator function. |
| Functions HAL_DMAEx_EnableMuxRequestGenerator and HAL_DMAEx_DisableMuxRequestGenerator can then be used |
| to respectively enable/disable the request generator. |
| |
| @endverbatim |
| * @{ |
| */ |
| |
| /** |
| * @brief Starts the multi_buffer DMA Transfer. |
| * @note The multi_buffer transfer operates in circular transfer only. |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA channel. |
| * @param SrcAddress: The source memory Buffer address |
| * @param DstAddress: The destination memory Buffer address |
| * @param SecondMemAddress: The second memory Buffer address in case of multi buffer Transfer |
| * @param DataLength: The length of data to be transferred from source to destination |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| |
| /* Check the parameters */ |
| assert_param(IS_DMA_BUFFER_SIZE(DataLength)); |
| |
| /* Memory-to-memory transfer not supported in double buffering mode */ |
| if (hdma->Init.Direction == DMA_MEMORY_TO_MEMORY) |
| { |
| hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED; |
| status = HAL_ERROR; |
| } |
| else |
| { |
| /* Process Locked */ |
| __HAL_LOCK(hdma); |
| |
| if(hdma->State == HAL_DMA_STATE_READY) |
| { |
| /* Change DMA peripheral state */ |
| hdma->State = HAL_DMA_STATE_BUSY; |
| |
| /* Initialize the error code */ |
| hdma->ErrorCode = HAL_DMA_ERROR_NONE; |
| |
| /* Enable the double buffer mode */ |
| hdma->Instance->CCR |= (uint32_t) (DMA_CCR_DBM | DMA_CCR_CIRC); |
| |
| /* Configure DMA channel destination address */ |
| hdma->Instance->CM1AR = SecondMemAddress; |
| |
| /* Configure the source, destination address and the data length */ |
| DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength); |
| |
| /* Clear all flags */ |
| hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << (hdma->ChannelIndex & 0x1CU)); |
| |
| /* Clear the DMAMUX synchro overrun flag */ |
| hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask; |
| |
| if(hdma->DMAmuxRequestGen != 0U) |
| { |
| /* Clear the DMAMUX request generator overrun flag */ |
| hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask; |
| } |
| |
| /* Enable the peripheral */ |
| __HAL_DMA_ENABLE(hdma); |
| } |
| else |
| { |
| /* Process Unlocked */ |
| __HAL_UNLOCK(hdma); |
| status = HAL_BUSY; |
| } |
| } |
| return status; |
| } |
| |
| /** |
| * @brief Starts the multi_buffer DMA Transfer with interrupt enabled. |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA Channel. |
| * @param SrcAddress: The source memory Buffer address |
| * @param DstAddress: The destination memory Buffer address |
| * @param SecondMemAddress: The second memory Buffer address in case of multi buffer Transfer |
| * @param DataLength: The length of data to be transferred from source to destination |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength) |
| { |
| HAL_StatusTypeDef status = HAL_OK; |
| |
| /* Check the parameters */ |
| assert_param(IS_DMA_BUFFER_SIZE(DataLength)); |
| |
| /* Memory-to-memory transfer not supported in double buffering mode */ |
| /* double buffering mode not supported for BDMA (D3 DMA) */ |
| if(hdma->Init.Direction == DMA_MEMORY_TO_MEMORY) |
| { |
| hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED; |
| return HAL_ERROR; |
| } |
| |
| /* Process locked */ |
| __HAL_LOCK(hdma); |
| |
| if(hdma->State == HAL_DMA_STATE_READY) |
| { |
| /* Change DMA peripheral state */ |
| hdma->State = HAL_DMA_STATE_BUSY; |
| |
| /* Initialize the error code */ |
| hdma->ErrorCode = HAL_DMA_ERROR_NONE; |
| |
| /* Disable the peripheral */ |
| __HAL_DMA_DISABLE(hdma); |
| |
| /* Enable the double buffer mode */ |
| /* Circular mode has to be Enable when double buffer mode is used */ |
| hdma->Instance->CCR |= (uint32_t) (DMA_CCR_DBM | DMA_CCR_CIRC); |
| |
| /* Configure DMA channel destination address */ |
| hdma->Instance->CM1AR = SecondMemAddress; |
| |
| /* Configure the source, destination address and the data length */ |
| DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength); |
| |
| /* Clear all flags */ |
| hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << (hdma->ChannelIndex & 0x1CU)); |
| |
| /* Clear the DMAMUX synchro overrun flag */ |
| hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask; |
| |
| if(hdma->DMAmuxRequestGen != 0U) |
| { |
| /* Clear the DMAMUX request generator overrun flag */ |
| hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask; |
| } |
| |
| /* Enable common interrupts */ |
| if(NULL != hdma->XferHalfCpltCallback ) |
| { |
| /* Enable the Half transfer complete interrupt as well */ |
| __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE)); |
| } |
| else |
| { |
| __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT); |
| __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_TE)); |
| } |
| |
| /* Check if DMAMUX Synchronization is enabled*/ |
| if((hdma->DMAmuxChannel->CCR & DMAMUX_CxCR_SE) != 0U) |
| { |
| /* Enable DMAMUX sync overrun IT*/ |
| hdma->DMAmuxChannel->CCR |= DMAMUX_CxCR_SOIE; |
| } |
| |
| if(hdma->DMAmuxRequestGen != 0U) |
| { |
| /* if using DMAMUX request generator, enable the DMAMUX request generator overrun IT*/ |
| /* enable the request gen overrun IT*/ |
| hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_OIE; |
| } |
| |
| /* Enable the peripheral */ |
| __HAL_DMA_ENABLE(hdma); |
| } |
| else |
| { |
| /* Process Unlocked */ |
| __HAL_UNLOCK(hdma); |
| |
| /* Remain BUSY */ |
| status = HAL_BUSY; |
| } |
| return status; |
| } |
| |
| /** |
| * @brief Change the memory0 or memory1 address on the fly. |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA Channel. |
| * @param Address: The new address |
| * @param memory: the memory to be changed, This parameter can be one of |
| * the following values: |
| * MEMORY0 / |
| * MEMORY1 |
| * @note The MEMORY0 address can be changed only when the current transfer use |
| * MEMORY1 and the MEMORY1 address can be changed only when the current |
| * transfer use MEMORY0. |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_DMAEx_ChangeMemory(DMA_HandleTypeDef *hdma, uint32_t Address, HAL_DMA_MemoryTypeDef memory) |
| { |
| if(memory == MEMORY0) |
| { |
| /* change the memory0 address */ |
| hdma->Instance->CM0AR = Address; |
| } |
| else |
| { |
| /* change the memory1 address */ |
| hdma->Instance->CM1AR = Address; |
| } |
| |
| return HAL_OK; |
| } |
| |
| /** |
| * @brief Configure the DMAMUX synchronization parameters for a given DMA channel (instance). |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA channel. |
| * @param pSyncConfig : pointer to HAL_DMA_MuxSyncConfigTypeDef : contains the DMAMUX synchronization parameters |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_DMAEx_ConfigMuxSync(DMA_HandleTypeDef *hdma, HAL_DMA_MuxSyncConfigTypeDef *pSyncConfig) |
| { |
| /* Check the parameters */ |
| assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance)); |
| |
| assert_param(IS_DMAMUX_SYNC_SIGNAL_ID(pSyncConfig->SyncSignalID)); |
| |
| assert_param(IS_DMAMUX_SYNC_POLARITY(pSyncConfig-> SyncPolarity)); |
| assert_param(IS_DMAMUX_SYNC_STATE(pSyncConfig->SyncEnable)); |
| assert_param(IS_DMAMUX_SYNC_EVENT(pSyncConfig->EventEnable)); |
| assert_param(IS_DMAMUX_SYNC_REQUEST_NUMBER(pSyncConfig->RequestNumber)); |
| |
| /*Check if the DMA state is ready */ |
| if(hdma->State == HAL_DMA_STATE_READY) |
| { |
| /* Process Locked */ |
| __HAL_LOCK(hdma); |
| |
| /* Set the new synchronization parameters (and keep the request ID filled during the Init)*/ |
| MODIFY_REG( hdma->DMAmuxChannel->CCR, \ |
| (~DMAMUX_CxCR_DMAREQ_ID) , \ |
| ((pSyncConfig->SyncSignalID) << DMAMUX_CxCR_SYNC_ID_Pos) | ((pSyncConfig->RequestNumber - 1U) << DMAMUX_CxCR_NBREQ_Pos) | \ |
| pSyncConfig->SyncPolarity | ((uint32_t)pSyncConfig->SyncEnable << DMAMUX_CxCR_SE_Pos) | \ |
| ((uint32_t)pSyncConfig->EventEnable << DMAMUX_CxCR_EGE_Pos)); |
| |
| /* Process UnLocked */ |
| __HAL_UNLOCK(hdma); |
| |
| return HAL_OK; |
| } |
| else |
| { |
| /*DMA State not Ready*/ |
| return HAL_ERROR; |
| } |
| } |
| |
| /** |
| * @brief Configure the DMAMUX request generator block used by the given DMA channel (instance). |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA channel. |
| * @param pRequestGeneratorConfig : pointer to HAL_DMA_MuxRequestGeneratorConfigTypeDef : |
| * contains the request generator parameters. |
| * |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_DMAEx_ConfigMuxRequestGenerator (DMA_HandleTypeDef *hdma, HAL_DMA_MuxRequestGeneratorConfigTypeDef *pRequestGeneratorConfig) |
| { |
| /* Check the parameters */ |
| assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance)); |
| |
| assert_param(IS_DMAMUX_REQUEST_GEN_SIGNAL_ID(pRequestGeneratorConfig->SignalID)); |
| |
| assert_param(IS_DMAMUX_REQUEST_GEN_POLARITY(pRequestGeneratorConfig->Polarity)); |
| assert_param(IS_DMAMUX_REQUEST_GEN_REQUEST_NUMBER(pRequestGeneratorConfig->RequestNumber)); |
| |
| /* check if the DMA state is ready |
| and DMA is using a DMAMUX request generator block |
| */ |
| if((hdma->State == HAL_DMA_STATE_READY) && (hdma->DMAmuxRequestGen != 0U)) |
| { |
| /* Process Locked */ |
| __HAL_LOCK(hdma); |
| |
| /* Set the request generator new parameters */ |
| hdma->DMAmuxRequestGen->RGCR = pRequestGeneratorConfig->SignalID | \ |
| ((pRequestGeneratorConfig->RequestNumber - 1U) << DMAMUX_RGxCR_GNBREQ_Pos)| \ |
| pRequestGeneratorConfig->Polarity; |
| /* Process UnLocked */ |
| __HAL_UNLOCK(hdma); |
| |
| return HAL_OK; |
| } |
| else |
| { |
| return HAL_ERROR; |
| } |
| } |
| |
| /** |
| * @brief Enable the DMAMUX request generator block used by the given DMA channel (instance). |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA channel. |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_DMAEx_EnableMuxRequestGenerator (DMA_HandleTypeDef *hdma) |
| { |
| /* Check the parameters */ |
| assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance)); |
| |
| /* check if the DMA state is ready |
| and DMA is using a DMAMUX request generator block |
| */ |
| if((hdma->State != HAL_DMA_STATE_RESET) && (hdma->DMAmuxRequestGen != 0)) |
| { |
| |
| /* Enable the request generator*/ |
| hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_GE; |
| |
| return HAL_OK; |
| } |
| else |
| { |
| return HAL_ERROR; |
| } |
| } |
| |
| /** |
| * @brief Disable the DMAMUX request generator block used by the given DMA channel (instance). |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA channel. |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_DMAEx_DisableMuxRequestGenerator (DMA_HandleTypeDef *hdma) |
| { |
| /* Check the parameters */ |
| assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance)); |
| |
| /* check if the DMA state is ready |
| and DMA is using a DMAMUX request generator block |
| */ |
| if((hdma->State != HAL_DMA_STATE_RESET) && (hdma->DMAmuxRequestGen != 0)) |
| { |
| |
| /* Disable the request generator*/ |
| hdma->DMAmuxRequestGen->RGCR &= ~DMAMUX_RGxCR_GE; |
| |
| return HAL_OK; |
| } |
| else |
| { |
| return HAL_ERROR; |
| } |
| } |
| |
| /** |
| * @brief Handles DMAMUX interrupt request. |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA channel. |
| * @retval None |
| */ |
| void HAL_DMAEx_MUX_IRQHandler(DMA_HandleTypeDef *hdma) |
| { |
| /* Check for DMAMUX Synchronization overrun */ |
| if((hdma->DMAmuxChannelStatus->CSR & hdma->DMAmuxChannelStatusMask) != 0U) |
| { |
| /* Disable the synchro overrun interrupt */ |
| hdma->DMAmuxChannel->CCR &= ~DMAMUX_CxCR_SOIE; |
| |
| /* Clear the DMAMUX synchro overrun flag */ |
| hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask; |
| |
| /* Update error code */ |
| hdma->ErrorCode |= HAL_DMA_ERROR_SYNC; |
| |
| if(hdma->XferErrorCallback != NULL) |
| { |
| /* Transfer error callback */ |
| hdma->XferErrorCallback(hdma); |
| } |
| } |
| |
| if(hdma->DMAmuxRequestGen != 0) |
| { |
| /* if using a DMAMUX request generator block Check for DMAMUX request generator overrun */ |
| if((hdma->DMAmuxRequestGenStatus->RGSR & hdma->DMAmuxRequestGenStatusMask) != 0U) |
| { |
| /* Disable the request gen overrun interrupt */ |
| hdma->DMAmuxRequestGen->RGCR &= ~DMAMUX_RGxCR_OIE; |
| |
| /* Clear the DMAMUX request generator overrun flag */ |
| hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask; |
| |
| /* Update error code */ |
| hdma->ErrorCode |= HAL_DMA_ERROR_REQGEN; |
| |
| if(hdma->XferErrorCallback != NULL) |
| { |
| /* Transfer error callback */ |
| hdma->XferErrorCallback(hdma); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @} |
| */ |
| |
| /** |
| * @} |
| */ |
| |
| /** @addtogroup DMAEx_Private_Functions |
| * @{ |
| */ |
| |
| /** |
| * @brief Set the DMA Transfer parameter. |
| * @param hdma pointer to a DMA_HandleTypeDef structure that contains |
| * the configuration information for the specified DMA channel. |
| * @param SrcAddress: The source memory Buffer address |
| * @param DstAddress: The destination memory Buffer address |
| * @param DataLength: The length of data to be transferred from source to destination |
| * @retval HAL status |
| */ |
| static void DMA_MultiBufferSetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) |
| { |
| /* Configure DMA channel data length */ |
| hdma->Instance->CNDTR = DataLength; |
| |
| /* Memory to Peripheral */ |
| if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH) |
| { |
| /* Configure DMA channel destination address */ |
| hdma->Instance->CPAR = DstAddress; |
| |
| /* Configure DMA channel source address */ |
| hdma->Instance->CM0AR = SrcAddress; |
| } |
| /* Peripheral to Memory */ |
| else |
| { |
| /* Configure DMA channel source address */ |
| hdma->Instance->CPAR = SrcAddress; |
| |
| /* Configure DMA channel destination address */ |
| hdma->Instance->CM0AR = DstAddress; |
| } |
| } |
| |
| /** |
| * @} |
| */ |
| |
| #endif /* HAL_DMA_MODULE_ENABLED */ |
| |
| /** |
| * @} |
| */ |
| |
| /** |
| * @} |
| */ |
| |
| |