You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1899 lines
61 KiB
1899 lines
61 KiB
/**
|
|
******************************************************************************
|
|
* @file stm32h7xx_hal_mdma.c
|
|
* @author MCD Application Team
|
|
* @brief This file provides firmware functions to manage the following
|
|
* functionalities of the Master Direct Memory Access (MDMA) peripheral:
|
|
* + Initialization/de-initialization functions
|
|
* + I/O operation functions
|
|
* + Peripheral State and errors functions
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2017 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 #####
|
|
==============================================================================
|
|
[..]
|
|
(#) Enable and configure the peripheral to be connected to the MDMA Channel
|
|
(except for internal SRAM/FLASH memories: no initialization is
|
|
necessary) please refer to Reference manual for connection between peripherals
|
|
and MDMA requests.
|
|
|
|
(#)
|
|
For a given Channel use HAL_MDMA_Init function to program the required configuration through the following parameters:
|
|
transfer request , channel priority, data endianness, Source increment, destination increment ,
|
|
source data size, destination data size, data alignment, source Burst, destination Burst ,
|
|
buffer Transfer Length, Transfer Trigger Mode (buffer transfer, block transfer, repeated block transfer
|
|
or full transfer) source and destination block address offset, mask address and data.
|
|
|
|
If using the MDMA in linked list mode then use function HAL_MDMA_LinkedList_CreateNode to fill a transfer node.
|
|
Note that parameters given to the function HAL_MDMA_Init corresponds always to the node zero.
|
|
Use function HAL_MDMA_LinkedList_AddNode to connect the created node to the linked list at a given position.
|
|
User can make a linked list circular using function HAL_MDMA_LinkedList_EnableCircularMode , this function will automatically connect the
|
|
last node of the list to the first one in order to make the list circular.
|
|
In this case the linked list will loop on node 1 : first node connected after the initial transfer defined by the HAL_MDMA_Init
|
|
|
|
-@- The initial transfer itself (node 0 corresponding to the Init).
|
|
User can disable the circular mode using function HAL_MDMA_LinkedList_DisableCircularMode, this function will then remove
|
|
the connection between last node and first one.
|
|
|
|
Function HAL_MDMA_LinkedList_RemoveNode can be used to remove (disconnect) a node from the transfer linked list.
|
|
When a linked list is circular (last node connected to first one), if removing node1 (node where the linked list loops),
|
|
the linked list remains circular and node 2 becomes the first one.
|
|
Note that if the linked list is made circular the transfer will loop infinitely (or until aborted by the user).
|
|
|
|
[..]
|
|
(+) User can select the transfer trigger mode (parameter TransferTriggerMode) to define the amount of data to be
|
|
transfer upon a request :
|
|
(++) MDMA_BUFFER_TRANSFER : each request triggers a transfer of BufferTransferLength data
|
|
with BufferTransferLength defined within the HAL_MDMA_Init.
|
|
(++) MDMA_BLOCK_TRANSFER : each request triggers a transfer of a block
|
|
with block size defined within the function HAL_MDMA_Start/HAL_MDMA_Start_IT
|
|
or within the current linked list node parameters.
|
|
(++) MDMA_REPEAT_BLOCK_TRANSFER : each request triggers a transfer of a number of blocks
|
|
with block size and number of blocks defined within the function HAL_MDMA_Start/HAL_MDMA_Start_IT
|
|
or within the current linked list node parameters.
|
|
(++) MDMA_FULL_TRANSFER : each request triggers a full transfer
|
|
all blocks and all nodes(if a linked list has been created using HAL_MDMA_LinkedList_CreateNode \ HAL_MDMA_LinkedList_AddNode).
|
|
|
|
*** Polling mode IO operation ***
|
|
=================================
|
|
[..]
|
|
(+) Use HAL_MDMA_Start() to start MDMA transfer after the configuration of Source
|
|
address and destination address and the Length of data to be transferred.
|
|
(+) Use HAL_MDMA_PollForTransfer() to poll for the end of current transfer or a transfer level
|
|
In this case a fixed Timeout can be configured by User depending from his application.
|
|
(+) Use HAL_MDMA_Abort() function to abort the current transfer : blocking method this API returns
|
|
when the abort ends or timeout (should not be called from an interrupt service routine).
|
|
|
|
*** Interrupt mode IO operation ***
|
|
===================================
|
|
[..]
|
|
(+) Configure the MDMA interrupt priority using HAL_NVIC_SetPriority()
|
|
(+) Enable the MDMA IRQ handler using HAL_NVIC_EnableIRQ()
|
|
(+) Use HAL_MDMA_Start_IT() to start MDMA transfer after the configuration of
|
|
Source address and destination address and the Length of data to be transferred. In this
|
|
case the MDMA interrupt is configured.
|
|
(+) Use HAL_MDMA_IRQHandler() called under MDMA_IRQHandler() Interrupt subroutine
|
|
(+) At the end of data transfer HAL_MDMA_IRQHandler() function is executed and user can
|
|
add his own function by customization of function pointer XferCpltCallback and
|
|
XferErrorCallback (i.e a member of MDMA handle structure).
|
|
|
|
(+) Use HAL_MDMA_Abort_IT() function to abort the current transfer : non-blocking method. This API will finish the execution immediately
|
|
then the callback XferAbortCallback (if specified by the user) is asserted once the MDMA channel has effectively aborted.
|
|
(could be called from an interrupt service routine).
|
|
|
|
(+) Use functions HAL_MDMA_RegisterCallback and HAL_MDMA_UnRegisterCallback respectevely to register unregister user callbacks
|
|
from the following list :
|
|
(++) XferCpltCallback : transfer complete callback.
|
|
(++) XferBufferCpltCallback : buffer transfer complete callback.
|
|
(++) XferBlockCpltCallback : block transfer complete callback.
|
|
(++) XferRepeatBlockCpltCallback : repeated block transfer complete callback.
|
|
(++) XferErrorCallback : transfer error callback.
|
|
(++) XferAbortCallback : transfer abort complete callback.
|
|
|
|
[..]
|
|
(+) If the transfer Request corresponds to SW request (MDMA_REQUEST_SW) User can use function HAL_MDMA_GenerateSWRequest to
|
|
trigger requests manually. Function HAL_MDMA_GenerateSWRequest must be used with the following precautions:
|
|
(++) This function returns an error if used while the Transfer has ended or not started.
|
|
(++) If used while the current request has not been served yet (current request transfer on going)
|
|
this function returns an error and the new request is ignored.
|
|
|
|
Generally this function should be used in conjunctions with the MDMA callbacks:
|
|
(++) example 1:
|
|
(+++) Configure a transfer with request set to MDMA_REQUEST_SW and trigger mode set to MDMA_BUFFER_TRANSFER
|
|
(+++) Register a callback for buffer transfer complete (using callback ID set to HAL_MDMA_XFER_BUFFERCPLT_CB_ID)
|
|
(+++) After calling HAL_MDMA_Start_IT the MDMA will issue the transfer of a first BufferTransferLength data.
|
|
(+++) When the buffer transfer complete callback is asserted first buffer has been transferred and user can ask for a new buffer transfer
|
|
request using HAL_MDMA_GenerateSWRequest.
|
|
|
|
(++) example 2:
|
|
(+++) Configure a transfer with request set to MDMA_REQUEST_SW and trigger mode set to MDMA_BLOCK_TRANSFER
|
|
(+++) Register a callback for block transfer complete (using callback ID HAL_MDMA_XFER_BLOCKCPLT_CB_ID)
|
|
(+++) After calling HAL_MDMA_Start_IT the MDMA will issue the transfer of a first block of data.
|
|
(+++) When the block transfer complete callback is asserted the first block has been transferred and user can ask
|
|
for a new block transfer request using HAL_MDMA_GenerateSWRequest.
|
|
|
|
[..] Use HAL_MDMA_GetState() function to return the MDMA state and HAL_MDMA_GetError() in case of error detection.
|
|
|
|
*** MDMA HAL driver macros list ***
|
|
=============================================
|
|
[..]
|
|
Below the list of most used macros in MDMA HAL driver.
|
|
|
|
(+) __HAL_MDMA_ENABLE: Enable the specified MDMA Channel.
|
|
(+) __HAL_MDMA_DISABLE: Disable the specified MDMA Channel.
|
|
(+) __HAL_MDMA_GET_FLAG: Get the MDMA Channel pending flags.
|
|
(+) __HAL_MDMA_CLEAR_FLAG: Clear the MDMA Channel pending flags.
|
|
(+) __HAL_MDMA_ENABLE_IT: Enable the specified MDMA Channel interrupts.
|
|
(+) __HAL_MDMA_DISABLE_IT: Disable the specified MDMA Channel interrupts.
|
|
(+) __HAL_MDMA_GET_IT_SOURCE: Check whether the specified MDMA Channel interrupt has occurred or not.
|
|
|
|
[..]
|
|
(@) You can refer to the header file of the MDMA HAL driver for more useful macros.
|
|
|
|
[..]
|
|
|
|
@endverbatim
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "stm32h7xx_hal.h"
|
|
|
|
/** @addtogroup STM32H7xx_HAL_Driver
|
|
* @{
|
|
*/
|
|
|
|
/** @defgroup MDMA MDMA
|
|
* @brief MDMA HAL module driver
|
|
* @{
|
|
*/
|
|
|
|
#ifdef HAL_MDMA_MODULE_ENABLED
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/* Private constants ---------------------------------------------------------*/
|
|
/** @addtogroup MDMA_Private_Constants
|
|
* @{
|
|
*/
|
|
#define HAL_TIMEOUT_MDMA_ABORT 5U /* 5 ms */
|
|
#define HAL_MDMA_CHANNEL_SIZE 0x40U /* an MDMA instance channel size is 64 byte */
|
|
/**
|
|
* @}
|
|
*/
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/* Private variables ---------------------------------------------------------*/
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/** @addtogroup MDMA_Private_Functions_Prototypes
|
|
* @{
|
|
*/
|
|
static void MDMA_SetConfig(MDMA_HandleTypeDef *hmdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t BlockDataLength, uint32_t BlockCount);
|
|
static void MDMA_Init(MDMA_HandleTypeDef *hmdma);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @addtogroup MDMA_Exported_Functions MDMA Exported Functions
|
|
* @{
|
|
*/
|
|
|
|
/** @addtogroup MDMA_Exported_Functions_Group1
|
|
*
|
|
@verbatim
|
|
===============================================================================
|
|
##### Initialization and de-initialization functions #####
|
|
===============================================================================
|
|
[..]
|
|
This section provides functions allowing to :
|
|
Initialize and de-initialize the MDMA channel.
|
|
Register and Unregister MDMA callbacks
|
|
[..]
|
|
The HAL_MDMA_Init() function follows the MDMA channel configuration procedures as described in
|
|
reference manual.
|
|
The HAL_MDMA_DeInit function allows to deinitialize the MDMA channel.
|
|
HAL_MDMA_RegisterCallback and HAL_MDMA_UnRegisterCallback functions allows
|
|
respectevely to register/unregister an MDMA callback function.
|
|
|
|
@endverbatim
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Initializes the MDMA according to the specified
|
|
* parameters in the MDMA_InitTypeDef and create the associated handle.
|
|
* @param hmdma: Pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_Init(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
uint32_t tickstart = HAL_GetTick();
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_MDMA_STREAM_ALL_INSTANCE(hmdma->Instance));
|
|
assert_param(IS_MDMA_PRIORITY(hmdma->Init.Priority));
|
|
assert_param(IS_MDMA_ENDIANNESS_MODE(hmdma->Init.Endianness));
|
|
assert_param(IS_MDMA_REQUEST(hmdma->Init.Request));
|
|
assert_param(IS_MDMA_SOURCE_INC(hmdma->Init.SourceInc));
|
|
assert_param(IS_MDMA_DESTINATION_INC(hmdma->Init.DestinationInc));
|
|
assert_param(IS_MDMA_SOURCE_DATASIZE(hmdma->Init.SourceDataSize));
|
|
assert_param(IS_MDMA_DESTINATION_DATASIZE(hmdma->Init.DestDataSize));
|
|
assert_param(IS_MDMA_DATA_ALIGNMENT(hmdma->Init.DataAlignment));
|
|
assert_param(IS_MDMA_SOURCE_BURST(hmdma->Init.SourceBurst));
|
|
assert_param(IS_MDMA_DESTINATION_BURST(hmdma->Init.DestBurst));
|
|
assert_param(IS_MDMA_BUFFER_TRANSFER_LENGTH(hmdma->Init.BufferTransferLength));
|
|
assert_param(IS_MDMA_TRANSFER_TRIGGER_MODE(hmdma->Init.TransferTriggerMode));
|
|
assert_param(IS_MDMA_BLOCK_ADDR_OFFSET(hmdma->Init.SourceBlockAddressOffset));
|
|
assert_param(IS_MDMA_BLOCK_ADDR_OFFSET(hmdma->Init.DestBlockAddressOffset));
|
|
|
|
|
|
/* Allocate lock resource */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_BUSY;
|
|
|
|
/* Disable the MDMA channel */
|
|
__HAL_MDMA_DISABLE(hmdma);
|
|
|
|
/* Check if the MDMA channel is effectively disabled */
|
|
while((hmdma->Instance->CCR & MDMA_CCR_EN) != 0U)
|
|
{
|
|
/* Check for the Timeout */
|
|
if((HAL_GetTick() - tickstart ) > HAL_TIMEOUT_MDMA_ABORT)
|
|
{
|
|
/* Update error code */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_TIMEOUT;
|
|
|
|
/* Change the MDMA state */
|
|
hmdma->State = HAL_MDMA_STATE_ERROR;
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Initialize the MDMA channel registers */
|
|
MDMA_Init(hmdma);
|
|
|
|
/* Reset the MDMA first/last linkedlist node addresses and node counter */
|
|
hmdma->FirstLinkedListNodeAddress = 0;
|
|
hmdma->LastLinkedListNodeAddress = 0;
|
|
hmdma->LinkedListNodeCounter = 0;
|
|
|
|
/* Initialize the error code */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NONE;
|
|
|
|
/* Initialize the MDMA state */
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief DeInitializes the MDMA peripheral
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_DeInit(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Disable the selected MDMA Channelx */
|
|
__HAL_MDMA_DISABLE(hmdma);
|
|
|
|
/* Reset MDMA Channel control register */
|
|
hmdma->Instance->CCR = 0;
|
|
hmdma->Instance->CTCR = 0;
|
|
hmdma->Instance->CBNDTR = 0;
|
|
hmdma->Instance->CSAR = 0;
|
|
hmdma->Instance->CDAR = 0;
|
|
hmdma->Instance->CBRUR = 0;
|
|
hmdma->Instance->CLAR = 0;
|
|
hmdma->Instance->CTBR = 0;
|
|
hmdma->Instance->CMAR = 0;
|
|
hmdma->Instance->CMDR = 0;
|
|
|
|
/* Clear all flags */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma,(MDMA_FLAG_TE | MDMA_FLAG_CTC | MDMA_FLAG_BRT | MDMA_FLAG_BT | MDMA_FLAG_BFTC));
|
|
|
|
/* Reset the MDMA first/last linkedlist node addresses and node counter */
|
|
hmdma->FirstLinkedListNodeAddress = 0;
|
|
hmdma->LastLinkedListNodeAddress = 0;
|
|
hmdma->LinkedListNodeCounter = 0;
|
|
|
|
/* Initialize the error code */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NONE;
|
|
|
|
/* Initialize the MDMA state */
|
|
hmdma->State = HAL_MDMA_STATE_RESET;
|
|
|
|
/* Release Lock */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Config the Post request Mask address and Mask data
|
|
* @param hmdma : pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param MaskAddress: specifies the address to be updated (written) with MaskData after a request is served.
|
|
* @param MaskData: specifies the value to be written to MaskAddress after a request is served.
|
|
* MaskAddress and MaskData could be used to automatically clear a peripheral flag when the request is served.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_ConfigPostRequestMask(MDMA_HandleTypeDef *hmdma, uint32_t MaskAddress, uint32_t MaskData)
|
|
{
|
|
HAL_StatusTypeDef status = HAL_OK;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
/* if HW request set Post Request MaskAddress and MaskData, */
|
|
if((hmdma->Instance->CTCR & MDMA_CTCR_SWRM) == 0U)
|
|
{
|
|
/* Set the HW request clear Mask and Data */
|
|
hmdma->Instance->CMAR = MaskAddress;
|
|
hmdma->Instance->CMDR = MaskData;
|
|
|
|
/*
|
|
-If the request is done by SW : BWM could be set to 1 or 0.
|
|
-If the request is done by a peripheral :
|
|
If mask address not set (0) => BWM must be set to 0
|
|
If mask address set (different than 0) => BWM could be set to 1 or 0
|
|
*/
|
|
if(MaskAddress == 0U)
|
|
{
|
|
hmdma->Instance->CTCR &= ~MDMA_CTCR_BWM;
|
|
}
|
|
else
|
|
{
|
|
hmdma->Instance->CTCR |= MDMA_CTCR_BWM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Return error status */
|
|
status = HAL_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Return error status */
|
|
status = HAL_ERROR;
|
|
}
|
|
/* Release Lock */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief Register callbacks
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param CallbackID: User Callback identifier
|
|
* @param pCallback: pointer to callbacsk function.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_RegisterCallback(MDMA_HandleTypeDef *hmdma, HAL_MDMA_CallbackIDTypeDef CallbackID, void (* pCallback)(MDMA_HandleTypeDef *_hmdma))
|
|
{
|
|
HAL_StatusTypeDef status = HAL_OK;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
switch (CallbackID)
|
|
{
|
|
case HAL_MDMA_XFER_CPLT_CB_ID:
|
|
hmdma->XferCpltCallback = pCallback;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_BUFFERCPLT_CB_ID:
|
|
hmdma->XferBufferCpltCallback = pCallback;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_BLOCKCPLT_CB_ID:
|
|
hmdma->XferBlockCpltCallback = pCallback;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_REPBLOCKCPLT_CB_ID:
|
|
hmdma->XferRepeatBlockCpltCallback = pCallback;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_ERROR_CB_ID:
|
|
hmdma->XferErrorCallback = pCallback;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_ABORT_CB_ID:
|
|
hmdma->XferAbortCallback = pCallback;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Return error status */
|
|
status = HAL_ERROR;
|
|
}
|
|
|
|
/* Release Lock */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief UnRegister callbacks
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param CallbackID: User Callback identifier
|
|
* a HAL_MDMA_CallbackIDTypeDef ENUM as parameter.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_UnRegisterCallback(MDMA_HandleTypeDef *hmdma, HAL_MDMA_CallbackIDTypeDef CallbackID)
|
|
{
|
|
HAL_StatusTypeDef status = HAL_OK;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
switch (CallbackID)
|
|
{
|
|
case HAL_MDMA_XFER_CPLT_CB_ID:
|
|
hmdma->XferCpltCallback = NULL;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_BUFFERCPLT_CB_ID:
|
|
hmdma->XferBufferCpltCallback = NULL;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_BLOCKCPLT_CB_ID:
|
|
hmdma->XferBlockCpltCallback = NULL;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_REPBLOCKCPLT_CB_ID:
|
|
hmdma->XferRepeatBlockCpltCallback = NULL;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_ERROR_CB_ID:
|
|
hmdma->XferErrorCallback = NULL;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_ABORT_CB_ID:
|
|
hmdma->XferAbortCallback = NULL;
|
|
break;
|
|
|
|
case HAL_MDMA_XFER_ALL_CB_ID:
|
|
hmdma->XferCpltCallback = NULL;
|
|
hmdma->XferBufferCpltCallback = NULL;
|
|
hmdma->XferBlockCpltCallback = NULL;
|
|
hmdma->XferRepeatBlockCpltCallback = NULL;
|
|
hmdma->XferErrorCallback = NULL;
|
|
hmdma->XferAbortCallback = NULL;
|
|
break;
|
|
|
|
default:
|
|
status = HAL_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = HAL_ERROR;
|
|
}
|
|
|
|
/* Release Lock */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @addtogroup MDMA_Exported_Functions_Group2
|
|
*
|
|
@verbatim
|
|
===============================================================================
|
|
##### Linked list operation functions #####
|
|
===============================================================================
|
|
[..] This section provides functions allowing to:
|
|
(+) Create a linked list node
|
|
(+) Add a node to the MDMA linked list
|
|
(+) Remove a node from the MDMA linked list
|
|
(+) Enable/Disable linked list circular mode
|
|
@endverbatim
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Initializes an MDMA Link Node according to the specified
|
|
* parameters in the pMDMA_LinkedListNodeConfig .
|
|
* @param pNode: Pointer to a MDMA_LinkNodeTypeDef structure that contains Linked list node
|
|
* registers configurations.
|
|
* @param pNodeConfig: Pointer to a MDMA_LinkNodeConfTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Linked List Node.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_LinkedList_CreateNode(MDMA_LinkNodeTypeDef *pNode, MDMA_LinkNodeConfTypeDef *pNodeConfig)
|
|
{
|
|
uint32_t addressMask;
|
|
uint32_t blockoffset;
|
|
|
|
/* Check the MDMA peripheral state */
|
|
if((pNode == NULL) || (pNodeConfig == NULL))
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_MDMA_PRIORITY(pNodeConfig->Init.Priority));
|
|
assert_param(IS_MDMA_ENDIANNESS_MODE(pNodeConfig->Init.Endianness));
|
|
assert_param(IS_MDMA_REQUEST(pNodeConfig->Init.Request));
|
|
assert_param(IS_MDMA_SOURCE_INC(pNodeConfig->Init.SourceInc));
|
|
assert_param(IS_MDMA_DESTINATION_INC(pNodeConfig->Init.DestinationInc));
|
|
assert_param(IS_MDMA_SOURCE_DATASIZE(pNodeConfig->Init.SourceDataSize));
|
|
assert_param(IS_MDMA_DESTINATION_DATASIZE(pNodeConfig->Init.DestDataSize));
|
|
assert_param(IS_MDMA_DATA_ALIGNMENT(pNodeConfig->Init.DataAlignment));
|
|
assert_param(IS_MDMA_SOURCE_BURST(pNodeConfig->Init.SourceBurst));
|
|
assert_param(IS_MDMA_DESTINATION_BURST(pNodeConfig->Init.DestBurst));
|
|
assert_param(IS_MDMA_BUFFER_TRANSFER_LENGTH(pNodeConfig->Init.BufferTransferLength));
|
|
assert_param(IS_MDMA_TRANSFER_TRIGGER_MODE(pNodeConfig->Init.TransferTriggerMode));
|
|
assert_param(IS_MDMA_BLOCK_ADDR_OFFSET(pNodeConfig->Init.SourceBlockAddressOffset));
|
|
assert_param(IS_MDMA_BLOCK_ADDR_OFFSET(pNodeConfig->Init.DestBlockAddressOffset));
|
|
|
|
assert_param(IS_MDMA_TRANSFER_LENGTH(pNodeConfig->BlockDataLength));
|
|
assert_param(IS_MDMA_BLOCK_COUNT(pNodeConfig->BlockCount));
|
|
|
|
|
|
/* Configure next Link node Address Register to zero */
|
|
pNode->CLAR = 0;
|
|
|
|
/* Configure the Link Node registers*/
|
|
pNode->CTBR = 0;
|
|
pNode->CMAR = 0;
|
|
pNode->CMDR = 0;
|
|
pNode->Reserved = 0;
|
|
|
|
/* Write new CTCR Register value */
|
|
pNode->CTCR = pNodeConfig->Init.SourceInc | pNodeConfig->Init.DestinationInc | \
|
|
pNodeConfig->Init.SourceDataSize | pNodeConfig->Init.DestDataSize | \
|
|
pNodeConfig->Init.DataAlignment| pNodeConfig->Init.SourceBurst | \
|
|
pNodeConfig->Init.DestBurst | \
|
|
((pNodeConfig->Init.BufferTransferLength - 1U) << MDMA_CTCR_TLEN_Pos) | \
|
|
pNodeConfig->Init.TransferTriggerMode;
|
|
|
|
/* If SW request set the CTCR register to SW Request Mode*/
|
|
if(pNodeConfig->Init.Request == MDMA_REQUEST_SW)
|
|
{
|
|
pNode->CTCR |= MDMA_CTCR_SWRM;
|
|
}
|
|
|
|
/*
|
|
-If the request is done by SW : BWM could be set to 1 or 0.
|
|
-If the request is done by a peripheral :
|
|
If mask address not set (0) => BWM must be set to 0
|
|
If mask address set (different than 0) => BWM could be set to 1 or 0
|
|
*/
|
|
if((pNodeConfig->Init.Request == MDMA_REQUEST_SW) || (pNodeConfig->PostRequestMaskAddress != 0U))
|
|
{
|
|
pNode->CTCR |= MDMA_CTCR_BWM;
|
|
}
|
|
|
|
/* Set the new CBNDTR Register value */
|
|
pNode->CBNDTR = ((pNodeConfig->BlockCount - 1U) << MDMA_CBNDTR_BRC_Pos) & MDMA_CBNDTR_BRC;
|
|
|
|
/* if block source address offset is negative set the Block Repeat Source address Update Mode to decrement */
|
|
if(pNodeConfig->Init.SourceBlockAddressOffset < 0)
|
|
{
|
|
pNode->CBNDTR |= MDMA_CBNDTR_BRSUM;
|
|
/*write new CBRUR Register value : source repeat block offset */
|
|
blockoffset = (uint32_t)(- pNodeConfig->Init.SourceBlockAddressOffset);
|
|
pNode->CBRUR = blockoffset & 0x0000FFFFU;
|
|
}
|
|
else
|
|
{
|
|
/*write new CBRUR Register value : source repeat block offset */
|
|
pNode->CBRUR = (((uint32_t) pNodeConfig->Init.SourceBlockAddressOffset) & 0x0000FFFFU);
|
|
}
|
|
|
|
/* if block destination address offset is negative set the Block Repeat destination address Update Mode to decrement */
|
|
if(pNodeConfig->Init.DestBlockAddressOffset < 0)
|
|
{
|
|
pNode->CBNDTR |= MDMA_CBNDTR_BRDUM;
|
|
/*write new CBRUR Register value : destination repeat block offset */
|
|
blockoffset = (uint32_t)(- pNodeConfig->Init.DestBlockAddressOffset);
|
|
pNode->CBRUR |= ((blockoffset & 0x0000FFFFU) << MDMA_CBRUR_DUV_Pos);
|
|
}
|
|
else
|
|
{
|
|
/*write new CBRUR Register value : destination repeat block offset */
|
|
pNode->CBRUR |= ((((uint32_t)pNodeConfig->Init.DestBlockAddressOffset) & 0x0000FFFFU) << MDMA_CBRUR_DUV_Pos);
|
|
}
|
|
|
|
/* Configure MDMA Link Node data length */
|
|
pNode->CBNDTR |= pNodeConfig->BlockDataLength;
|
|
|
|
/* Configure MDMA Link Node destination address */
|
|
pNode->CDAR = pNodeConfig->DstAddress;
|
|
|
|
/* Configure MDMA Link Node Source address */
|
|
pNode->CSAR = pNodeConfig->SrcAddress;
|
|
|
|
/* if HW request set the HW request and the requet CleraMask and ClearData MaskData, */
|
|
if(pNodeConfig->Init.Request != MDMA_REQUEST_SW)
|
|
{
|
|
/* Set the HW request in CTBR register */
|
|
pNode->CTBR = pNodeConfig->Init.Request & MDMA_CTBR_TSEL;
|
|
/* Set the HW request clear Mask and Data */
|
|
pNode->CMAR = pNodeConfig->PostRequestMaskAddress;
|
|
pNode->CMDR = pNodeConfig->PostRequestMaskData;
|
|
}
|
|
|
|
addressMask = pNodeConfig->SrcAddress & 0xFF000000U;
|
|
if((addressMask == 0x20000000U) || (addressMask == 0x00000000U))
|
|
{
|
|
/*The AHBSbus is used as source (read operation) on channel x */
|
|
pNode->CTBR |= MDMA_CTBR_SBUS;
|
|
}
|
|
|
|
addressMask = pNodeConfig->DstAddress & 0xFF000000U;
|
|
if((addressMask == 0x20000000U) || (addressMask == 0x00000000U))
|
|
{
|
|
/*The AHB bus is used as destination (write operation) on channel x */
|
|
pNode->CTBR |= MDMA_CTBR_DBUS;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Connect a node to the linked list.
|
|
* @param hmdma : Pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param pNewNode : Pointer to a MDMA_LinkNodeTypeDef structure that contains Linked list node
|
|
* to be add to the list.
|
|
* @param pPrevNode : Pointer to the new node position in the linked list or zero to insert the new node
|
|
* at the end of the list
|
|
*
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_LinkedList_AddNode(MDMA_HandleTypeDef *hmdma, MDMA_LinkNodeTypeDef *pNewNode, MDMA_LinkNodeTypeDef *pPrevNode)
|
|
{
|
|
MDMA_LinkNodeTypeDef *pNode;
|
|
uint32_t counter = 0, nodeInserted = 0;
|
|
HAL_StatusTypeDef hal_status = HAL_OK;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if((hmdma == NULL) || (pNewNode == NULL))
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_BUSY;
|
|
|
|
/* Check if this is the first node (after the Inititlization node) */
|
|
if((uint32_t)hmdma->FirstLinkedListNodeAddress == 0U)
|
|
{
|
|
if(pPrevNode == NULL)
|
|
{
|
|
/* if this is the first node after the initialization
|
|
connect this node to the node 0 by updating
|
|
the MDMA channel CLAR register to this node address */
|
|
hmdma->Instance->CLAR = (uint32_t)pNewNode;
|
|
/* Set the MDMA handle First linked List node*/
|
|
hmdma->FirstLinkedListNodeAddress = pNewNode;
|
|
|
|
/*reset New node link */
|
|
pNewNode->CLAR = 0;
|
|
|
|
/* Update the Handle last node address */
|
|
hmdma->LastLinkedListNodeAddress = pNewNode;
|
|
|
|
hmdma->LinkedListNodeCounter = 1;
|
|
}
|
|
else
|
|
{
|
|
hal_status = HAL_ERROR;
|
|
}
|
|
}
|
|
else if(hmdma->FirstLinkedListNodeAddress != pNewNode)
|
|
{
|
|
/* Check if the node to insert already exists*/
|
|
pNode = hmdma->FirstLinkedListNodeAddress;
|
|
while((counter < hmdma->LinkedListNodeCounter) && (hal_status == HAL_OK))
|
|
{
|
|
if(pNode->CLAR == (uint32_t)pNewNode)
|
|
{
|
|
hal_status = HAL_ERROR; /* error this node already exist in the linked list and it is not first node */
|
|
}
|
|
pNode = (MDMA_LinkNodeTypeDef *)pNode->CLAR;
|
|
counter++;
|
|
}
|
|
|
|
if(hal_status == HAL_OK)
|
|
{
|
|
/* Check if the previous node is the last one in the current list or zero */
|
|
if((pPrevNode == hmdma->LastLinkedListNodeAddress) || (pPrevNode == NULL))
|
|
{
|
|
/* insert the new node at the end of the list */
|
|
pNewNode->CLAR = hmdma->LastLinkedListNodeAddress->CLAR;
|
|
hmdma->LastLinkedListNodeAddress->CLAR = (uint32_t)pNewNode;
|
|
/* Update the Handle last node address */
|
|
hmdma->LastLinkedListNodeAddress = pNewNode;
|
|
/* Increment the linked list node counter */
|
|
hmdma->LinkedListNodeCounter++;
|
|
}
|
|
else
|
|
{
|
|
/*insert the new node after the pPreviousNode node */
|
|
pNode = hmdma->FirstLinkedListNodeAddress;
|
|
counter = 0;
|
|
while((counter < hmdma->LinkedListNodeCounter) && (nodeInserted == 0U))
|
|
{
|
|
counter++;
|
|
if(pNode == pPrevNode)
|
|
{
|
|
/*Insert the new node after the previous one */
|
|
pNewNode->CLAR = pNode->CLAR;
|
|
pNode->CLAR = (uint32_t)pNewNode;
|
|
/* Increment the linked list node counter */
|
|
hmdma->LinkedListNodeCounter++;
|
|
nodeInserted = 1;
|
|
}
|
|
else
|
|
{
|
|
pNode = (MDMA_LinkNodeTypeDef *)pNode->CLAR;
|
|
}
|
|
}
|
|
|
|
if(nodeInserted == 0U)
|
|
{
|
|
hal_status = HAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hal_status = HAL_ERROR;
|
|
}
|
|
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
|
|
return hal_status;
|
|
}
|
|
else
|
|
{
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Return error status */
|
|
return HAL_BUSY;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Disconnect/Remove a node from the transfer linked list.
|
|
* @param hmdma : Pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param pNode : Pointer to a MDMA_LinkNodeTypeDef structure that contains Linked list node
|
|
* to be removed from the list.
|
|
*
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_LinkedList_RemoveNode(MDMA_HandleTypeDef *hmdma, MDMA_LinkNodeTypeDef *pNode)
|
|
{
|
|
MDMA_LinkNodeTypeDef *ptmpNode;
|
|
uint32_t counter = 0, nodeDeleted = 0;
|
|
HAL_StatusTypeDef hal_status = HAL_OK;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if((hmdma == NULL) || (pNode == NULL))
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_BUSY;
|
|
|
|
/* If first and last node are null (no nodes in the list) : return error*/
|
|
if(((uint32_t)hmdma->FirstLinkedListNodeAddress == 0U) || ((uint32_t)hmdma->LastLinkedListNodeAddress == 0U) || (hmdma->LinkedListNodeCounter == 0U))
|
|
{
|
|
hal_status = HAL_ERROR;
|
|
}
|
|
else if(hmdma->FirstLinkedListNodeAddress == pNode) /* Deleting first node */
|
|
{
|
|
/* Delete 1st node */
|
|
if(hmdma->LastLinkedListNodeAddress == pNode)
|
|
{
|
|
/*if the last node is at the same time the first one (1 single node after the init node 0)
|
|
then update the last node too */
|
|
|
|
hmdma->FirstLinkedListNodeAddress = 0;
|
|
hmdma->LastLinkedListNodeAddress = 0;
|
|
hmdma->LinkedListNodeCounter = 0;
|
|
|
|
hmdma->Instance->CLAR = 0;
|
|
}
|
|
else
|
|
{
|
|
if((uint32_t)hmdma->FirstLinkedListNodeAddress == hmdma->LastLinkedListNodeAddress->CLAR)
|
|
{
|
|
/* if last node is looping to first (circular list) one update the last node connection */
|
|
hmdma->LastLinkedListNodeAddress->CLAR = pNode->CLAR;
|
|
}
|
|
|
|
/* if deleting the first node after the initialization
|
|
connect the next node to the node 0 by updating
|
|
the MDMA channel CLAR register to this node address */
|
|
hmdma->Instance->CLAR = pNode->CLAR;
|
|
hmdma->FirstLinkedListNodeAddress = (MDMA_LinkNodeTypeDef *)hmdma->Instance->CLAR;
|
|
/* Update the Handle node counter */
|
|
hmdma->LinkedListNodeCounter--;
|
|
}
|
|
}
|
|
else /* Deleting any other node */
|
|
{
|
|
/*Deleted node is not the first one : find it */
|
|
ptmpNode = hmdma->FirstLinkedListNodeAddress;
|
|
while((counter < hmdma->LinkedListNodeCounter) && (nodeDeleted == 0U))
|
|
{
|
|
counter++;
|
|
if(ptmpNode->CLAR == ((uint32_t)pNode))
|
|
{
|
|
/* if deleting the last node */
|
|
if(pNode == hmdma->LastLinkedListNodeAddress)
|
|
{
|
|
/*Update the linked list last node address in the handle*/
|
|
hmdma->LastLinkedListNodeAddress = ptmpNode;
|
|
}
|
|
/* update the next node link after deleting pMDMA_LinkedListNode */
|
|
ptmpNode->CLAR = pNode->CLAR;
|
|
nodeDeleted = 1;
|
|
/* Update the Handle node counter */
|
|
hmdma->LinkedListNodeCounter--;
|
|
}
|
|
else
|
|
{
|
|
ptmpNode = (MDMA_LinkNodeTypeDef *)ptmpNode->CLAR;
|
|
}
|
|
}
|
|
|
|
if(nodeDeleted == 0U)
|
|
{
|
|
/* last node reashed without finding the node to delete : return error */
|
|
hal_status = HAL_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
|
|
return hal_status;
|
|
}
|
|
else
|
|
{
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Return error status */
|
|
return HAL_BUSY;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Make the linked list circular by connecting the last node to the first.
|
|
* @param hmdma : Pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_LinkedList_EnableCircularMode(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
HAL_StatusTypeDef hal_status = HAL_OK;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_BUSY;
|
|
|
|
/* If first and last node are null (no nodes in the list) : return error*/
|
|
if(((uint32_t)hmdma->FirstLinkedListNodeAddress == 0U) || ((uint32_t)hmdma->LastLinkedListNodeAddress == 0U) || (hmdma->LinkedListNodeCounter == 0U))
|
|
{
|
|
hal_status = HAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* to enable circular mode Last Node should be connected to first node */
|
|
hmdma->LastLinkedListNodeAddress->CLAR = (uint32_t)hmdma->FirstLinkedListNodeAddress;
|
|
}
|
|
|
|
}
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
|
|
return hal_status;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable the linked list circular mode by setting the last node connection to null
|
|
* @param hmdma : Pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_LinkedList_DisableCircularMode(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
HAL_StatusTypeDef hal_status = HAL_OK;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_BUSY;
|
|
|
|
/* If first and last node are null (no nodes in the list) : return error*/
|
|
if(((uint32_t)hmdma->FirstLinkedListNodeAddress == 0U) || ((uint32_t)hmdma->LastLinkedListNodeAddress == 0U) || (hmdma->LinkedListNodeCounter == 0U))
|
|
{
|
|
hal_status = HAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* to disable circular mode Last Node should be connected to NULL */
|
|
hmdma->LastLinkedListNodeAddress->CLAR = 0;
|
|
}
|
|
|
|
}
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
|
|
return hal_status;
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @addtogroup MDMA_Exported_Functions_Group3
|
|
*
|
|
@verbatim
|
|
===============================================================================
|
|
##### IO operation functions #####
|
|
===============================================================================
|
|
[..] This section provides functions allowing to:
|
|
(+) Configure the source, destination address and data length and Start MDMA transfer
|
|
(+) Configure the source, destination address and data length and
|
|
Start MDMA transfer with interrupt
|
|
(+) Abort MDMA transfer
|
|
(+) Poll for transfer complete
|
|
(+) Generate a SW request (when Request is set to MDMA_REQUEST_SW)
|
|
(+) Handle MDMA interrupt request
|
|
|
|
@endverbatim
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Starts the MDMA Transfer.
|
|
* @param hmdma : pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param SrcAddress : The source memory Buffer address
|
|
* @param DstAddress : The destination memory Buffer address
|
|
* @param BlockDataLength : The length of a block transfer in bytes
|
|
* @param BlockCount : The number of a blocks to be transfer
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_Start(MDMA_HandleTypeDef *hmdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t BlockDataLength, uint32_t BlockCount)
|
|
{
|
|
/* Check the parameters */
|
|
assert_param(IS_MDMA_TRANSFER_LENGTH(BlockDataLength));
|
|
assert_param(IS_MDMA_BLOCK_COUNT(BlockCount));
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_BUSY;
|
|
|
|
/* Initialize the error code */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NONE;
|
|
|
|
/* Disable the peripheral */
|
|
__HAL_MDMA_DISABLE(hmdma);
|
|
|
|
/* Configure the source, destination address and the data length */
|
|
MDMA_SetConfig(hmdma, SrcAddress, DstAddress, BlockDataLength, BlockCount);
|
|
|
|
/* Enable the Peripheral */
|
|
__HAL_MDMA_ENABLE(hmdma);
|
|
|
|
if(hmdma->Init.Request == MDMA_REQUEST_SW)
|
|
{
|
|
/* activate If SW request mode*/
|
|
hmdma->Instance->CCR |= MDMA_CCR_SWRQ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Return error status */
|
|
return HAL_BUSY;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Starts the MDMA Transfer with interrupts enabled.
|
|
* @param hmdma : pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param SrcAddress : The source memory Buffer address
|
|
* @param DstAddress : The destination memory Buffer address
|
|
* @param BlockDataLength : The length of a block transfer in bytes
|
|
* @param BlockCount : The number of a blocks to be transfer
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_Start_IT(MDMA_HandleTypeDef *hmdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t BlockDataLength, uint32_t BlockCount)
|
|
{
|
|
/* Check the parameters */
|
|
assert_param(IS_MDMA_TRANSFER_LENGTH(BlockDataLength));
|
|
assert_param(IS_MDMA_BLOCK_COUNT(BlockCount));
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hmdma);
|
|
|
|
if(HAL_MDMA_STATE_READY == hmdma->State)
|
|
{
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_BUSY;
|
|
|
|
/* Initialize the error code */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NONE;
|
|
|
|
/* Disable the peripheral */
|
|
__HAL_MDMA_DISABLE(hmdma);
|
|
|
|
/* Configure the source, destination address and the data length */
|
|
MDMA_SetConfig(hmdma, SrcAddress, DstAddress, BlockDataLength, BlockCount);
|
|
|
|
/* Enable Common interrupts i.e Transfer Error IT and Channel Transfer Complete IT*/
|
|
__HAL_MDMA_ENABLE_IT(hmdma, (MDMA_IT_TE | MDMA_IT_CTC));
|
|
|
|
if(hmdma->XferBlockCpltCallback != NULL)
|
|
{
|
|
/* if Block transfer complete Callback is set enable the corresponding IT*/
|
|
__HAL_MDMA_ENABLE_IT(hmdma, MDMA_IT_BT);
|
|
}
|
|
|
|
if(hmdma->XferRepeatBlockCpltCallback != NULL)
|
|
{
|
|
/* if Repeated Block transfer complete Callback is set enable the corresponding IT*/
|
|
__HAL_MDMA_ENABLE_IT(hmdma, MDMA_IT_BRT);
|
|
}
|
|
|
|
if(hmdma->XferBufferCpltCallback != NULL)
|
|
{
|
|
/* if buffer transfer complete Callback is set enable the corresponding IT*/
|
|
__HAL_MDMA_ENABLE_IT(hmdma, MDMA_IT_BFTC);
|
|
}
|
|
|
|
/* Enable the Peripheral */
|
|
__HAL_MDMA_ENABLE(hmdma);
|
|
|
|
if(hmdma->Init.Request == MDMA_REQUEST_SW)
|
|
{
|
|
/* activate If SW request mode*/
|
|
hmdma->Instance->CCR |= MDMA_CCR_SWRQ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Return error status */
|
|
return HAL_BUSY;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Aborts the MDMA Transfer.
|
|
* @param hmdma : pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
*
|
|
* @note After disabling a MDMA Channel, a check for wait until the MDMA Channel is
|
|
* effectively disabled is added. If a Channel is disabled
|
|
* while a data transfer is ongoing, the current data will be transferred
|
|
* and the Channel will be effectively disabled only after the transfer of
|
|
* this single data is finished.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_Abort(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
uint32_t tickstart = HAL_GetTick();
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if(HAL_MDMA_STATE_BUSY != hmdma->State)
|
|
{
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NO_XFER;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Disable all the transfer interrupts */
|
|
__HAL_MDMA_DISABLE_IT(hmdma, (MDMA_IT_TE | MDMA_IT_CTC | MDMA_IT_BT | MDMA_IT_BRT | MDMA_IT_BFTC));
|
|
|
|
/* Disable the channel */
|
|
__HAL_MDMA_DISABLE(hmdma);
|
|
|
|
/* Check if the MDMA Channel is effectively disabled */
|
|
while((hmdma->Instance->CCR & MDMA_CCR_EN) != 0U)
|
|
{
|
|
/* Check for the Timeout */
|
|
if( (HAL_GetTick() - tickstart ) > HAL_TIMEOUT_MDMA_ABORT)
|
|
{
|
|
/* Update error code */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Change the MDMA state */
|
|
hmdma->State = HAL_MDMA_STATE_ERROR;
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Clear all interrupt flags */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, (MDMA_FLAG_TE | MDMA_FLAG_CTC | MDMA_FLAG_BT | MDMA_FLAG_BRT | MDMA_FLAG_BFTC));
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Change the MDMA state*/
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Aborts the MDMA Transfer in Interrupt mode.
|
|
* @param hmdma : pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_Abort_IT(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if(HAL_MDMA_STATE_BUSY != hmdma->State)
|
|
{
|
|
/* No transfer ongoing */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NO_XFER;
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Set Abort State */
|
|
hmdma->State = HAL_MDMA_STATE_ABORT;
|
|
|
|
/* Disable the stream */
|
|
__HAL_MDMA_DISABLE(hmdma);
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Polling for transfer complete.
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param CompleteLevel: Specifies the MDMA level complete.
|
|
* @param Timeout: Timeout duration.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_PollForTransfer(MDMA_HandleTypeDef *hmdma, HAL_MDMA_LevelCompleteTypeDef CompleteLevel, uint32_t Timeout)
|
|
{
|
|
uint32_t levelFlag, errorFlag;
|
|
uint32_t tickstart;
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_MDMA_LEVEL_COMPLETE(CompleteLevel));
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if(HAL_MDMA_STATE_BUSY != hmdma->State)
|
|
{
|
|
/* No transfer ongoing */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NO_XFER;
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Get the level transfer complete flag */
|
|
levelFlag = ((CompleteLevel == HAL_MDMA_FULL_TRANSFER) ? MDMA_FLAG_CTC : \
|
|
(CompleteLevel == HAL_MDMA_BUFFER_TRANSFER)? MDMA_FLAG_BFTC : \
|
|
(CompleteLevel == HAL_MDMA_BLOCK_TRANSFER) ? MDMA_FLAG_BT : \
|
|
MDMA_FLAG_BRT);
|
|
|
|
|
|
/* Get timeout */
|
|
tickstart = HAL_GetTick();
|
|
|
|
while(__HAL_MDMA_GET_FLAG(hmdma, levelFlag) == 0U)
|
|
{
|
|
if((__HAL_MDMA_GET_FLAG(hmdma, MDMA_FLAG_TE) != 0U))
|
|
{
|
|
/* Get the transfer error source flag */
|
|
errorFlag = hmdma->Instance->CESR;
|
|
|
|
if((errorFlag & MDMA_CESR_TED) == 0U)
|
|
{
|
|
/* Update error code : Read Transfer error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_READ_XFER;
|
|
}
|
|
else
|
|
{
|
|
/* Update error code : Write Transfer error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_WRITE_XFER;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_TEMD) != 0U)
|
|
{
|
|
/* Update error code : Error Mask Data */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_MASK_DATA;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_TELD) != 0U)
|
|
{
|
|
/* Update error code : Error Linked list */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_LINKED_LIST;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_ASE) != 0U)
|
|
{
|
|
/* Update error code : Address/Size alignment error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_ALIGNMENT;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_BSE) != 0U)
|
|
{
|
|
/* Update error code : Block Size error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_BLOCK_SIZE;
|
|
}
|
|
|
|
(void) HAL_MDMA_Abort(hmdma); /* if error then abort the current transfer */
|
|
|
|
/*
|
|
Note that the Abort function will
|
|
- Clear all transfer flags
|
|
- Unlock
|
|
- Set the State
|
|
*/
|
|
|
|
return HAL_ERROR;
|
|
|
|
}
|
|
|
|
/* Check for the Timeout */
|
|
if(Timeout != HAL_MAX_DELAY)
|
|
{
|
|
if(((HAL_GetTick() - tickstart ) > Timeout) || (Timeout == 0U))
|
|
{
|
|
/* Update error code */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_TIMEOUT;
|
|
|
|
(void) HAL_MDMA_Abort(hmdma); /* if timeout then abort the current transfer */
|
|
|
|
/*
|
|
Note that the Abort function will
|
|
- Clear all transfer flags
|
|
- Unlock
|
|
- Set the State
|
|
*/
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Clear the transfer level flag */
|
|
if(CompleteLevel == HAL_MDMA_BUFFER_TRANSFER)
|
|
{
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, MDMA_FLAG_BFTC);
|
|
|
|
}
|
|
else if(CompleteLevel == HAL_MDMA_BLOCK_TRANSFER)
|
|
{
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, (MDMA_FLAG_BFTC | MDMA_FLAG_BT));
|
|
|
|
}
|
|
else if(CompleteLevel == HAL_MDMA_REPEAT_BLOCK_TRANSFER)
|
|
{
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, (MDMA_FLAG_BFTC | MDMA_FLAG_BT | MDMA_FLAG_BRT));
|
|
}
|
|
else if(CompleteLevel == HAL_MDMA_FULL_TRANSFER)
|
|
{
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, (MDMA_FLAG_BRT | MDMA_FLAG_BT | MDMA_FLAG_BFTC | MDMA_FLAG_CTC));
|
|
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
}
|
|
else
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Generate an MDMA SW request trigger to activate the request on the given Channel.
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Stream.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_MDMA_GenerateSWRequest(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
uint32_t request_mode;
|
|
|
|
/* Check the MDMA peripheral handle */
|
|
if(hmdma == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Get the softawre request mode */
|
|
request_mode = hmdma->Instance->CTCR & MDMA_CTCR_SWRM;
|
|
|
|
if((hmdma->Instance->CCR & MDMA_CCR_EN) == 0U)
|
|
{
|
|
/* if no Transfer on going (MDMA enable bit not set) return error */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_NO_XFER;
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
else if(((hmdma->Instance->CISR & MDMA_CISR_CRQA) != 0U) || (request_mode == 0U))
|
|
{
|
|
/* if an MDMA ongoing request has not yet end or if request mode is not SW request return error */
|
|
hmdma->ErrorCode = HAL_MDMA_ERROR_BUSY;
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Set the SW request bit to activate the request on the Channel */
|
|
hmdma->Instance->CCR |= MDMA_CCR_SWRQ;
|
|
|
|
return HAL_OK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Handles MDMA interrupt request.
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval None
|
|
*/
|
|
void HAL_MDMA_IRQHandler(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
__IO uint32_t count = 0;
|
|
uint32_t timeout = SystemCoreClock / 9600U;
|
|
|
|
uint32_t generalIntFlag, errorFlag;
|
|
|
|
/* General Interrupt Flag management ****************************************/
|
|
generalIntFlag = 1UL << ((((uint32_t)hmdma->Instance - (uint32_t)(MDMA_Channel0))/HAL_MDMA_CHANNEL_SIZE) & 0x1FU);
|
|
if((MDMA->GISR0 & generalIntFlag) == 0U)
|
|
{
|
|
return; /* the General interrupt flag for the current channel is down , nothing to do */
|
|
}
|
|
|
|
/* Transfer Error Interrupt management ***************************************/
|
|
if((__HAL_MDMA_GET_FLAG(hmdma, MDMA_FLAG_TE) != 0U))
|
|
{
|
|
if(__HAL_MDMA_GET_IT_SOURCE(hmdma, MDMA_IT_TE) != 0U)
|
|
{
|
|
/* Disable the transfer error interrupt */
|
|
__HAL_MDMA_DISABLE_IT(hmdma, MDMA_IT_TE);
|
|
|
|
/* Get the transfer error source flag */
|
|
errorFlag = hmdma->Instance->CESR;
|
|
|
|
if((errorFlag & MDMA_CESR_TED) == 0U)
|
|
{
|
|
/* Update error code : Read Transfer error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_READ_XFER;
|
|
}
|
|
else
|
|
{
|
|
/* Update error code : Write Transfer error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_WRITE_XFER;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_TEMD) != 0U)
|
|
{
|
|
/* Update error code : Error Mask Data */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_MASK_DATA;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_TELD) != 0U)
|
|
{
|
|
/* Update error code : Error Linked list */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_LINKED_LIST;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_ASE) != 0U)
|
|
{
|
|
/* Update error code : Address/Size alignment error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_ALIGNMENT;
|
|
}
|
|
|
|
if((errorFlag & MDMA_CESR_BSE) != 0U)
|
|
{
|
|
/* Update error code : Block Size error error */
|
|
hmdma->ErrorCode |= HAL_MDMA_ERROR_BLOCK_SIZE;
|
|
}
|
|
|
|
/* Clear the transfer error flags */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, MDMA_FLAG_TE);
|
|
}
|
|
}
|
|
|
|
/* Buffer Transfer Complete Interrupt management ******************************/
|
|
if((__HAL_MDMA_GET_FLAG(hmdma, MDMA_FLAG_BFTC) != 0U))
|
|
{
|
|
if(__HAL_MDMA_GET_IT_SOURCE(hmdma, MDMA_IT_BFTC) != 0U)
|
|
{
|
|
/* Clear the buffer transfer complete flag */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, MDMA_FLAG_BFTC);
|
|
|
|
if(hmdma->XferBufferCpltCallback != NULL)
|
|
{
|
|
/* Buffer transfer callback */
|
|
hmdma->XferBufferCpltCallback(hmdma);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Block Transfer Complete Interrupt management ******************************/
|
|
if((__HAL_MDMA_GET_FLAG(hmdma, MDMA_FLAG_BT) != 0U))
|
|
{
|
|
if(__HAL_MDMA_GET_IT_SOURCE(hmdma, MDMA_IT_BT) != 0U)
|
|
{
|
|
/* Clear the block transfer complete flag */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, MDMA_FLAG_BT);
|
|
|
|
if(hmdma->XferBlockCpltCallback != NULL)
|
|
{
|
|
/* Block transfer callback */
|
|
hmdma->XferBlockCpltCallback(hmdma);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Repeated Block Transfer Complete Interrupt management ******************************/
|
|
if((__HAL_MDMA_GET_FLAG(hmdma, MDMA_FLAG_BRT) != 0U))
|
|
{
|
|
if(__HAL_MDMA_GET_IT_SOURCE(hmdma, MDMA_IT_BRT) != 0U)
|
|
{
|
|
/* Clear the repeat block transfer complete flag */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, MDMA_FLAG_BRT);
|
|
|
|
if(hmdma->XferRepeatBlockCpltCallback != NULL)
|
|
{
|
|
/* Repeated Block transfer callback */
|
|
hmdma->XferRepeatBlockCpltCallback(hmdma);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Channel Transfer Complete Interrupt management ***********************************/
|
|
if((__HAL_MDMA_GET_FLAG(hmdma, MDMA_FLAG_CTC) != 0U))
|
|
{
|
|
if(__HAL_MDMA_GET_IT_SOURCE(hmdma, MDMA_IT_CTC) != 0U)
|
|
{
|
|
/* Disable all the transfer interrupts */
|
|
__HAL_MDMA_DISABLE_IT(hmdma, (MDMA_IT_TE | MDMA_IT_CTC | MDMA_IT_BT | MDMA_IT_BRT | MDMA_IT_BFTC));
|
|
|
|
if(HAL_MDMA_STATE_ABORT == hmdma->State)
|
|
{
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Change the DMA state */
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
|
|
if(hmdma->XferAbortCallback != NULL)
|
|
{
|
|
hmdma->XferAbortCallback(hmdma);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Clear the Channel Transfer Complete flag */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, MDMA_FLAG_CTC);
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
/* Change MDMA peripheral state */
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
|
|
if(hmdma->XferCpltCallback != NULL)
|
|
{
|
|
/* Channel Transfer Complete callback */
|
|
hmdma->XferCpltCallback(hmdma);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* manage error case */
|
|
if(hmdma->ErrorCode != HAL_MDMA_ERROR_NONE)
|
|
{
|
|
hmdma->State = HAL_MDMA_STATE_ABORT;
|
|
|
|
/* Disable the channel */
|
|
__HAL_MDMA_DISABLE(hmdma);
|
|
|
|
do
|
|
{
|
|
if (++count > timeout)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while((hmdma->Instance->CCR & MDMA_CCR_EN) != 0U);
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hmdma);
|
|
|
|
if((hmdma->Instance->CCR & MDMA_CCR_EN) != 0U)
|
|
{
|
|
/* Change the MDMA state to error if MDMA disable fails */
|
|
hmdma->State = HAL_MDMA_STATE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Change the MDMA state to Ready if MDMA disable success */
|
|
hmdma->State = HAL_MDMA_STATE_READY;
|
|
}
|
|
|
|
|
|
if (hmdma->XferErrorCallback != NULL)
|
|
{
|
|
/* Transfer error callback */
|
|
hmdma->XferErrorCallback(hmdma);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @addtogroup MDMA_Exported_Functions_Group4
|
|
*
|
|
@verbatim
|
|
===============================================================================
|
|
##### State and Errors functions #####
|
|
===============================================================================
|
|
[..]
|
|
This subsection provides functions allowing to
|
|
(+) Check the MDMA state
|
|
(+) Get error code
|
|
|
|
@endverbatim
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Returns the MDMA state.
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval HAL state
|
|
*/
|
|
HAL_MDMA_StateTypeDef HAL_MDMA_GetState(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
return hmdma->State;
|
|
}
|
|
|
|
/**
|
|
* @brief Return the MDMA error code
|
|
* @param hmdma : pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval MDMA Error Code
|
|
*/
|
|
uint32_t HAL_MDMA_GetError(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
return hmdma->ErrorCode;
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @addtogroup MDMA_Private_Functions
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Sets the MDMA Transfer parameter.
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @param SrcAddress: The source memory Buffer address
|
|
* @param DstAddress: The destination memory Buffer address
|
|
* @param BlockDataLength : The length of a block transfer in bytes
|
|
* @param BlockCount: The number of blocks to be transferred
|
|
* @retval HAL status
|
|
*/
|
|
static void MDMA_SetConfig(MDMA_HandleTypeDef *hmdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t BlockDataLength, uint32_t BlockCount)
|
|
{
|
|
uint32_t addressMask;
|
|
|
|
/* Configure the MDMA Channel data length */
|
|
MODIFY_REG(hmdma->Instance->CBNDTR ,MDMA_CBNDTR_BNDT, (BlockDataLength & MDMA_CBNDTR_BNDT));
|
|
|
|
/* Configure the MDMA block repeat count */
|
|
MODIFY_REG(hmdma->Instance->CBNDTR , MDMA_CBNDTR_BRC , ((BlockCount - 1U) << MDMA_CBNDTR_BRC_Pos) & MDMA_CBNDTR_BRC);
|
|
|
|
/* Clear all interrupt flags */
|
|
__HAL_MDMA_CLEAR_FLAG(hmdma, MDMA_FLAG_TE | MDMA_FLAG_CTC | MDMA_CISR_BRTIF | MDMA_CISR_BTIF | MDMA_CISR_TCIF);
|
|
|
|
/* Configure MDMA Channel destination address */
|
|
hmdma->Instance->CDAR = DstAddress;
|
|
|
|
/* Configure MDMA Channel Source address */
|
|
hmdma->Instance->CSAR = SrcAddress;
|
|
|
|
addressMask = SrcAddress & 0xFF000000U;
|
|
if((addressMask == 0x20000000U) || (addressMask == 0x00000000U))
|
|
{
|
|
/*The AHBSbus is used as source (read operation) on channel x */
|
|
hmdma->Instance->CTBR |= MDMA_CTBR_SBUS;
|
|
}
|
|
else
|
|
{
|
|
/*The AXI bus is used as source (read operation) on channel x */
|
|
hmdma->Instance->CTBR &= (~MDMA_CTBR_SBUS);
|
|
}
|
|
|
|
addressMask = DstAddress & 0xFF000000U;
|
|
if((addressMask == 0x20000000U) || (addressMask == 0x00000000U))
|
|
{
|
|
/*The AHB bus is used as destination (write operation) on channel x */
|
|
hmdma->Instance->CTBR |= MDMA_CTBR_DBUS;
|
|
}
|
|
else
|
|
{
|
|
/*The AXI bus is used as destination (write operation) on channel x */
|
|
hmdma->Instance->CTBR &= (~MDMA_CTBR_DBUS);
|
|
}
|
|
|
|
/* Set the linked list register to the first node of the list */
|
|
hmdma->Instance->CLAR = (uint32_t)hmdma->FirstLinkedListNodeAddress;
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes the MDMA handle according to the specified
|
|
* parameters in the MDMA_InitTypeDef
|
|
* @param hmdma: pointer to a MDMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified MDMA Channel.
|
|
* @retval None
|
|
*/
|
|
static void MDMA_Init(MDMA_HandleTypeDef *hmdma)
|
|
{
|
|
uint32_t blockoffset;
|
|
|
|
/* Prepare the MDMA Channel configuration */
|
|
hmdma->Instance->CCR = hmdma->Init.Priority | hmdma->Init.Endianness;
|
|
|
|
/* Write new CTCR Register value */
|
|
hmdma->Instance->CTCR = hmdma->Init.SourceInc | hmdma->Init.DestinationInc | \
|
|
hmdma->Init.SourceDataSize | hmdma->Init.DestDataSize | \
|
|
hmdma->Init.DataAlignment | hmdma->Init.SourceBurst | \
|
|
hmdma->Init.DestBurst | \
|
|
((hmdma->Init.BufferTransferLength - 1U) << MDMA_CTCR_TLEN_Pos) | \
|
|
hmdma->Init.TransferTriggerMode;
|
|
|
|
/* If SW request set the CTCR register to SW Request Mode */
|
|
if(hmdma->Init.Request == MDMA_REQUEST_SW)
|
|
{
|
|
/*
|
|
-If the request is done by SW : BWM could be set to 1 or 0.
|
|
-If the request is done by a peripheral :
|
|
If mask address not set (0) => BWM must be set to 0
|
|
If mask address set (different than 0) => BWM could be set to 1 or 0
|
|
*/
|
|
hmdma->Instance->CTCR |= (MDMA_CTCR_SWRM | MDMA_CTCR_BWM);
|
|
}
|
|
|
|
/* Reset CBNDTR Register */
|
|
hmdma->Instance->CBNDTR = 0;
|
|
|
|
/* if block source address offset is negative set the Block Repeat Source address Update Mode to decrement */
|
|
if(hmdma->Init.SourceBlockAddressOffset < 0)
|
|
{
|
|
hmdma->Instance->CBNDTR |= MDMA_CBNDTR_BRSUM;
|
|
/* Write new CBRUR Register value : source repeat block offset */
|
|
blockoffset = (uint32_t)(- hmdma->Init.SourceBlockAddressOffset);
|
|
hmdma->Instance->CBRUR = (blockoffset & 0x0000FFFFU);
|
|
}
|
|
else
|
|
{
|
|
/* Write new CBRUR Register value : source repeat block offset */
|
|
hmdma->Instance->CBRUR = (((uint32_t)hmdma->Init.SourceBlockAddressOffset) & 0x0000FFFFU);
|
|
}
|
|
|
|
/* If block destination address offset is negative set the Block Repeat destination address Update Mode to decrement */
|
|
if(hmdma->Init.DestBlockAddressOffset < 0)
|
|
{
|
|
hmdma->Instance->CBNDTR |= MDMA_CBNDTR_BRDUM;
|
|
/* Write new CBRUR Register value : destination repeat block offset */
|
|
blockoffset = (uint32_t)(- hmdma->Init.DestBlockAddressOffset);
|
|
hmdma->Instance->CBRUR |= ((blockoffset & 0x0000FFFFU) << MDMA_CBRUR_DUV_Pos);
|
|
}
|
|
else
|
|
{
|
|
/*write new CBRUR Register value : destination repeat block offset */
|
|
hmdma->Instance->CBRUR |= ((((uint32_t)hmdma->Init.DestBlockAddressOffset) & 0x0000FFFFU) << MDMA_CBRUR_DUV_Pos);
|
|
}
|
|
|
|
/* if HW request set the HW request and the requet CleraMask and ClearData MaskData, */
|
|
if(hmdma->Init.Request != MDMA_REQUEST_SW)
|
|
{
|
|
/* Set the HW request in CTRB register */
|
|
hmdma->Instance->CTBR = hmdma->Init.Request & MDMA_CTBR_TSEL;
|
|
}
|
|
else /* SW request : reset the CTBR register */
|
|
{
|
|
hmdma->Instance->CTBR = 0;
|
|
}
|
|
|
|
/* Write Link Address Register */
|
|
hmdma->Instance->CLAR = 0;
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#endif /* HAL_MDMA_MODULE_ENABLED */
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|