Files
BlindCane/Drivers/STM32H5xx_HAL_Driver/Src/stm32h5xx_hal_dma.c
SocChina2025 7f9bede0c7 Initial commit
2025-05-07 22:22:44 +08:00

1723 lines
56 KiB
C

/**
**********************************************************************************************************************
* @file stm32h5xx_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) 2023 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 DMA_Request_Selection
(+) BlkHWRequest : Specifies the Block hardware request mode for DMA channel
(++) can be a value of DMA_Block_Request
(+) Direction : Specifies the transfer direction for DMA channel
(++) can be a value of DMA_Transfer_Direction
(+) SrcInc : Specifies the source increment mode for the DMA channel
(++) can be a value of DMA_Source_Increment_Mode
(+) DestInc : Specifies the destination increment mode for the DMA channel
(++) can be a value of DMA_Destination_Increment_Mode
(+) SrcDataWidth : Specifies the source data width for the DMA channel
(++) can be a value of DMA_Source_Data_Width
(+) DestDataWidth : Specifies the destination data width for the DMA channel
(++) can be a value of DMA_Destination_Data_Width
(+) Priority : Specifies the priority for the DMA channel
(++) can be a value of 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 DMA_Transfer_Allocated_Port
(+) TransferEventMode : Specifies the transfer event mode for the DMA channel
(++) can be a value of DMA_Transfer_Event_Mode
(+) Mode : Specifies the transfer mode for the DMA channel
(++) can be one of the following modes :
(+++) DMA_NORMAL : Normal Mode
(+++) DMA_PFCTRL : Peripheral Flow Control (peripheral early termination) 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 can be called once after each system boot.
If called again, HAL_DMA_ConfigChannelAttributes() API has no effect.
Unlock is done either by a system boot or a by an RCC reset.
(+) 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 "stm32h5xx_hal.h"
/** @addtogroup STM32H5xx_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_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));
if (hdma->Init.Mode == DMA_PFCTRL)
{
assert_param(IS_DMA_PFREQ_INSTANCE(hdma->Instance));
}
/* 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);
/* Initialize the callbacks */
if (hdma->State == HAL_DMA_STATE_RESET)
{
/* Clean all callbacks */
hdma->XferCpltCallback = NULL;
hdma->XferHalfCpltCallback = NULL;
hdma->XferErrorCallback = NULL;
hdma->XferAbortCallback = NULL;
hdma->XferSuspendCallback = NULL;
}
/* 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 /* (__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 DMA Mode is DMA_NORMAL */
if (hdma->Mode != DMA_NORMAL)
{
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 DMA Mode is DMA_NORMAL */
if (hdma->Mode != DMA_NORMAL)
{
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)
{
const DMA_TypeDef *p_dma_instance = GET_DMA_INSTANCE(hdma);
uint32_t global_it_flag = 1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU);
uint32_t global_active_flag_ns = IS_DMA_GLOBAL_ACTIVE_FLAG_NS(p_dma_instance, global_it_flag);
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
uint32_t global_active_flag_s = IS_DMA_GLOBAL_ACTIVE_FLAG_S(p_dma_instance, global_it_flag);
#endif /* (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */
/* Global Interrupt Flag management *********************************************************************************/
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
if ((global_active_flag_s == 0U) && (global_active_flag_ns == 0U))
#else
if (global_active_flag_ns == 0U)
#endif /* (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */
{
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;
/* 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);
/* 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;
/* 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.
* @note The HAL_DMA_RegisterCallback() may be called before HAL_DMA_Init() in HAL_DMA_STATE_RESET
* to register callbacks for HAL_DMA_MSPINIT_CB_ID and HAL_DMA_MSPDEINIT_CB_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;
}
/* 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;
}
return status;
}
/**
* @brief Unregister callback according to specified ID.
* @note The HAL_DMA_UnRegisterCallback() may be called before HAL_DMA_Init() in HAL_DMA_STATE_RESET
* to un-register callbacks for HAL_DMA_MSPINIT_CB_ID and HAL_DMA_MSPDEINIT_CB_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;
}
/* 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;
}
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 /* (__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)
{
const 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 (DMA_SECCFGR_SEC0)
/* 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 /* DMA_SECCFGR_SEC0 */
/* return value */
*pChannelAttributes = attributes;
return HAL_OK;
}
#if defined (DMA_RCFGLOCKR_LOCK0)
#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 /* (__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)
{
const 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;
}
#endif /* DMA_RCFGLOCKR_LOCK0 */
/**
* @}
*/
/**
* @}
*/
/* 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) */
#if defined (DMA_CTR1_SSEC)
MODIFY_REG(hdma->Instance->CTR1, ~(DMA_CTR1_SSEC | DMA_CTR1_DSEC), tmpreg);
#else
WRITE_REG(hdma->Instance->CTR1, tmpreg);
#endif /* DMA_CTR1_SSEC */
/* 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 */
}
/* Set DMA channel operation mode */
tmpreg |= hdma->Init.Mode;
/* 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_PFREQ | 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 */
/**
* @}
*/
/**
* @}
*/