generated from Template/H563ZI-HAL-CMake-Template
	
		
			
				
	
	
		
			4763 lines
		
	
	
		
			170 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4763 lines
		
	
	
		
			170 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|   **********************************************************************************************************************
 | |
|   * @file    stm32h5xx_hal_dma_ex.c
 | |
|   * @author  MCD Application Team
 | |
|   * @brief   DMA Extension HAL module driver
 | |
|   *          This file provides firmware functions to manage the following functionalities of the DMA extension
 | |
|   *          peripheral:
 | |
|   *           + Linked-List Initialization and De-Initialization Functions
 | |
|   *           + Linked-List I/O Operation Functions
 | |
|   *           + Linked-List Management Functions
 | |
|   *           + Data Handling, Repeated Block and Trigger Configuration Functions
 | |
|   *           + Suspend and Resume Operation Functions
 | |
|   *           + FIFO Status Function
 | |
|   *
 | |
|   **********************************************************************************************************************
 | |
|   * @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 #####
 | |
|   ======================================================================================================================
 | |
|     [..]
 | |
|       Alternatively to the normal programming mode, a DMA channel can be programmed by a list of transfers, known as
 | |
|       linked-list (list of Node items). Each node is defined by its data structure.
 | |
|       Each node specifies a standalone DMA channel.
 | |
|       When enabled, the DMA channel fetch the first linked-list node from SRAM (known as head node). When executed, the
 | |
|       next linked list node will be fetched and executed. This operation is repeated until the end of the whole
 | |
|       linked-list queue. Optionally, the linked-list can be linear where the last linked-list queue node is not linked
 | |
|       to another queue node or circular where the last linked-list node is linked to any linked-list queue node.
 | |
| 
 | |
|           (+) Linear linked-list:
 | |
|               The DMA channel fetch and execute all DMA linked-list queue from first node (head node) to last node
 | |
|               (tail node) ones. When the last node is completed, the DMA channel remains in idle state and another
 | |
|               transfer can be lunched.
 | |
| 
 | |
|           (+) Circular linked-list:
 | |
|               The DMA channel fetch and execute all DMA linked-list queue from first node (head node) to last node (tail
 | |
|               node). When last node is executed, the DMA channel fetches the first circular node another time and repeat
 | |
|               the same sequence in an infinite loop (Circular transfer). To stop the DMA channel, an abort operation is
 | |
|               required. This linked-list mode replaces the legacy circular transfers.
 | |
| 
 | |
|     [..]
 | |
|       In order to reduce linked-list queue executing time and power consumption, the DMA channel supports executing the
 | |
|       dynamic linked-list format. In fact, the DMA supports the execution of 2 types of linked-list formats : static and
 | |
|       dynamic.
 | |
| 
 | |
|           (+) Static linked-list:
 | |
|               The static linked-list format refers to the full linked-list node where all DMA channel parameters are
 | |
|               fetched and executed independently of the redundancy of information.
 | |
| 
 | |
|           (+) Dynamic linked-list:
 | |
|               The dynamic linked-list format refer to the customized linked-list node where only DMA channel necessary
 | |
|               parameters are fetched and executed (Example: data size = 20 on previous node, and data size = 20 on the
 | |
|               current node => No need to update it).
 | |
| 
 | |
|       For linked-list transfers, the DMA channel can execute the linked-list queue node by node. This feature is named
 | |
|       link step mode. When activated, enabling the DMA channel first time allows to fetch the head node from memory
 | |
|       then it stops. Then, another DMA channel enable is needed to execute the node. After that, keeping enabling the
 | |
|       DMA channel is needed to execute each node until the end of linked-list queue. When the linked-list queue is
 | |
|       circular, enabling the DMA channel in an infinite loop is required to keep the DMA channel running. This feature
 | |
|       is useful for debug purpose or asynchronously executing queue nodes.
 | |
| 
 | |
|     [..]
 | |
|       Each DMA channel transfer (normal or linked-list), is highly configurable according to DMA channel instance
 | |
|       integrated in devices. These configuration can be :
 | |
| 
 | |
|           (+) Repeated block configuration :
 | |
|               If the feature is supported, the DMA channel can performs a repeated block transfers. Named also 2
 | |
|               dimension addressing transfers, this feature can transfer n iteration of programmed block transfer (Block
 | |
|               transfer is the legacy data size). Additional to the repeat count of a block, DMA channel addresses can
 | |
|               jump after at burst and block level. The jump length is a programmable parameter defined by DMA user.
 | |
|                (++) Jump at burst level :
 | |
|                     The DMA channel keep an empty area, between each 2 consecutive bursts transmitted.
 | |
|                (++) Jump at block level :
 | |
|                     The DMA channel keep an empty area, between each 2 consecutive blocks transmitted.
 | |
| 
 | |
|           (+) Trigger :
 | |
|               The DMA channel transfers can be conditioned by hardware signals edges (rising or falling) named hardware
 | |
|               triggers. Trigger condition can be applied at :
 | |
|                (++) Single/Burst level :
 | |
|                     Each single/burst data transmission is conditioned by a signal trigger hit.
 | |
|                (++) Block level :
 | |
|                     Each block data transmission is conditioned by a signal trigger hit.
 | |
|                (++) Repeated block level :
 | |
|                     Each repeated block data transmission is conditioned by a signal trigger hit.
 | |
|                (++) Node level :
 | |
|                     Each node execution is conditioned by a signal trigger hit.
 | |
|               The DMA channel can report a trigger overrun when detects more than 2 trigger signal edges before
 | |
|               executing the current transfer.
 | |
| 
 | |
|           (+) Data handling :
 | |
|               The data handling feature is a FIFO capability that can be :
 | |
|                 (++) Padding pattern :
 | |
|                      Padding selected pattern (zero padding or sign extension) when the source data width is smaller
 | |
|                      than the destination data width at single level.
 | |
|                 (++) Truncation :
 | |
|                      Truncate section from the source data single when the source data width is bigger than the
 | |
|                      destination data width.
 | |
|                 (++) Pack/Unpack :
 | |
|                      Pack a set of data when source data width is smaller than the destination data width.
 | |
|                      Unpack a set of data when source data width is bigger than the destination data width.
 | |
|                 (++) Exchange :
 | |
|                      Exchange data at byte and half-word on the destination and at byte level on the source.
 | |
| 
 | |
|     [..]
 | |
|       Each DMA channel transfer (normal or linked-list) when it is active, can be suspended and resumed at run time
 | |
|       application. When trying to suspend an ongoing transfer, the DMA channel isn't suspended instantly but complete
 | |
|       the current ongoing single/burst then it stops.
 | |
|       When the DMA channel is suspended, the current transfer can be resumed instantly.
 | |
| 
 | |
|     [..]
 | |
|       The DMA channel that supports FIFO, can report in real time the number of beats remains on destination (Output)
 | |
|       FIFO level.
 | |
| 
 | |
|     *** Linked-List Initialization and De-Initialization operation ***
 | |
|     ==================================================================
 | |
|     [..]
 | |
|       Differently from normal transfers, DMA channel initialization and de-initialization need less parameters as the
 | |
|       remaining transfer parameters are defined by linked-list nodes.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_Init() to initialize a DMA channel in linked-list mode according to programmed fields.
 | |
|               When called, the DMA channel will be ready to execute linked-list queues.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_DeInit() to de-initialize a DMA channel in linked-list mode.
 | |
|               When called, the DMA channel will be in reset. It is mandatory to reinitialize it for next transfer.
 | |
| 
 | |
|     *** Linked-List I/O Operation ***
 | |
|     =================================
 | |
|     [..]
 | |
|           (+) Use HAL_DMAEx_List_Start() to start a DMA transfer in linked-list mode after the configuration of
 | |
|               linked-list queue base address and offset in polling mode (Blocking mode).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_Start_IT() to start a DMA transfer in linked-list mode after the configuration of
 | |
|               linked-list queue base address and offset in interrupt mode (Non-blocking mode).
 | |
| 
 | |
|     *** Linked-List Management ***
 | |
|     ==============================
 | |
|     [..]
 | |
|       The linked-list management is a software processing independently of DMA channel hardware. It allows to reset,
 | |
|       build, create, insert, remove, replace, circularize, convert both nodes and queue in order to perform DMA
 | |
|       channel transfers in linked-list mode.
 | |
|       Linked-list APIs and types are adapted to reduce memory footprint.
 | |
| 
 | |
|     *** Linked-list nodes building ***
 | |
|     [..]
 | |
|       At node level, the operations that can be done are building a new linked-list node or get a linked-list node
 | |
|       information from a built node. The linked-list nodes have two forms according to 2 dimensions addressing
 | |
|       capability. The linear addressing nodes contains the information of all DMA channel features except the 2
 | |
|       dimension addressing features and the 2 dimensions addressing nodes contain the information of all available
 | |
|       features.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_BuildNode() to build the DMA linked-list node according to the specified parameters.
 | |
|               Build operation allow to convert the specified parameter in values known by the DMA channel and place them
 | |
|               in memory.
 | |
|               Placing DMA linked-list in SRAM must be done in accordance to product specification to ensure that the
 | |
|               link access port can access to the specified SRAM.
 | |
|               (++) The DMA linked-list node parameter address should be 32bit aligned and should not exceed the 64 KByte
 | |
|               addressable space.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_GetNodeConfig() to get the specified configuration parameter on building node.
 | |
|               This API can be used when need to change few parameter to build new node.
 | |
| 
 | |
|     *** Inserting nodes to linked-list queue ***
 | |
|     [..]
 | |
|       In order to build a sequence of DMA transaction with different configuration, we need to insert built node at
 | |
|       linked-list queue (node present an elementary DMA transaction) in linked-list queue on any position to have the
 | |
|       full flexibility of ordering nodes or extend the sequence of queue transactions.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_InsertNode() to insert new built node in any queue position of linked-list queue
 | |
|               according to selecting previous node. When calling this API with previous node parameter is NULL, the
 | |
|               inserted node will be placed at the head of the linked-list queue.
 | |
|               (++) This API must be used after HAL_DMAEx_List_BuildNode() otherwise an error will be returned.
 | |
|               (++) This API must be called for static queues format.
 | |
|               (++) This API shall be avoided when adding new node at the head or the tail of queue (overhead of
 | |
|                    footprint and performance : use HAL_DMAEx_List_InsertNode_Head() or HAL_DMAEx_List_InsertNode_Tail()
 | |
|                    instead).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_InsertNode_Head() to insert new built node at the head of linked-list queue. The head
 | |
|               node will not be overwritten but will be the second queue node.
 | |
|               (++) This API must be used after HAL_DMAEx_List_BuildNode() otherwise an error will be returned.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_InsertNode_Tail() to insert new built node at the tail of linked-list queue. The tail
 | |
|               node will not be overwritten but will be the penultimate queue node.
 | |
|               (++) This API must be used after HAL_DMAEx_List_BuildNode() otherwise an error will be returned.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|     *** Removing nodes from linked-list queue ***
 | |
|     [..]
 | |
|       There is some cases when removing a node from linked-list queue is needed (need to remove an elementary DMA
 | |
|       transaction). Removing node allows to unlink a node from DMA linked-list queue (NOT DELETED), so the removed node
 | |
|       can be reused for another queue or to be added to the same queue without need to rebuild it in next step.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_RemoveNode() to remove any yet built and inserted node from linked-list queue according
 | |
|               to selected node.
 | |
|               (++) This API must be called for static queues format.
 | |
|               (++) This API shall be avoided when removing the head or the tail of linked-list queue (overhead of
 | |
|                    footprint and performance : use HAL_DMAEx_List_RemoveNode_Head() or HAL_DMAEx_List_RemoveNode_Tail()
 | |
|                    instead).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_RemoveNode_Head() to remove the head node from linked-list queue.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_RemoveNode_Tail() to remove the tail node from linked-list queue.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|     *** Replacing nodes on linked-list queue ***
 | |
|     [..]
 | |
|       There is some cases when replacing a node from linked-list queue is needed (need to replace an elementary DMA
 | |
|       transfer, by another one that have not the same configuration). Replacing node allows to unlink the node to be
 | |
|       replaced from DMA linked-list queue (NOT DELETED) and link instead a new node. So the replaced node can be reused
 | |
|       for another queue or to be added to the same queue without need to rebuild it in next step and the new node cannot
 | |
|       be reused except when remove it or replaced in next step.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ReplaceNode() to replace any yet built and inserted node on linked-list queue according
 | |
|               to selected node.
 | |
|               (++) This API must be called for static queues format.
 | |
|               (++) This API shall be avoided when replacing the head or the tail linked-list queue (overhead of
 | |
|                    footprint and performance : use HAL_DMAEx_List_ReplaceNode_Head() or
 | |
|                    HAL_DMAEx_List_ReplaceNode_Tail() instead).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ReplaceNode_Head() to replace the head node of linked-list queue.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ReplaceNode_Tail() to replace the tail node from linked-list queue.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|     *** Reset linked-list queue ***
 | |
|     [..]
 | |
|       After finishing using a linked-list queue, it can be reset and cleared and it's content nodes will be
 | |
|       unlinked (NOT DELETED) and reused on another queue.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ResetQ() to reset a linked-list queue and unlink all it's content nodes.
 | |
|               (++) This API must be called for ready state queues.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|     *** Inserting linked-list queue ***
 | |
|     [..]
 | |
|       To ensure the flexibility of building linked-list queue by their targeted functionalities (Example: 3 nodes for
 | |
|       action 1 and 5 nodes for action 2), it is possible to build a queue for action 1 that contains action 1 nodes and
 | |
|       a queue for action 2 that contains action 2 nodes then concatenating the 2 queues. So, there are some cases where
 | |
|       the management of linked-list at queue granularity is needed.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_InsertQ() to insert source linked-list queue to a destination linked-list queue
 | |
|               according to selecting previous node.
 | |
|               (++) This API must be called for static queues format.
 | |
|               (++) This API shall be avoided when inserting source linked-list queue at the head or the tail of
 | |
|                    destination queue (overhead of footprint and performance : use HAL_DMAEx_List_InsertQ_Head() or
 | |
|                    HAL_DMAEx_List_InsertQ_Tail() instead).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_InsertQ_Head() to insert a source linked-list queue at the head of linked-list
 | |
|               destination queue.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_InsertQ_Tail() to insert a source linked-list queue at the tail of linked-list
 | |
|               destination queue.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|     *** Circularizing linked-list queue ***
 | |
|     [..]
 | |
|       In order to perform tasks in infinite loop with DMA channel, it is possible to circularize the linked-list queues.
 | |
|       Circularizing queue allows to link last linked-list queue node to any previous node of the same queue (This node
 | |
|       is named first circular queue). When the first circular node is the head node, all linked-list queue nodes will be
 | |
|       executed in infinite loop. When the first circular node is not the head nodes, all precedent nodes are executed
 | |
|       once and all remaining nodes are executed in an infinite loop.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_SetCircularModeConfig() to circularize the linked-list queue according to first
 | |
|               circular node selected.
 | |
|               (++) This API must be called for static queues format.
 | |
|               (++) This API shall be avoided when first circular node is the head linked-list queue node (overhead of
 | |
|                    footprint and performance : use HAL_DMAEx_List_SetCircularMode() instead).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_SetCircularMode() to circularize the linked-list queue with linking last queue node
 | |
|               with first queue node.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ClearCircularMode() to clear any linked-list queue circular configuration.
 | |
|               (++) This API must be called for static queues format.
 | |
| 
 | |
| 
 | |
|     *** Converting linked-list queue ***
 | |
|     [..]
 | |
|       To have the best DMA channel linked-list queue execution, it is recommended to convert yet build linked-list queue
 | |
|       to dynamic format (Static is the default format). When linked-list queue becomes dynamic, all queue nodes are
 | |
|       optimized and only changed parameters will be updated between nodes. So, the DMA will fetch only changes
 | |
|       parameters instead of the whole node.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ConvertQToDynamic() to convert a linked-list queue to dynamic format.
 | |
|               (++) This API must be called for ready state queues.
 | |
|               (++) This API must be called for static queues format.
 | |
|               (++) This API must be called as the last API before starting the DMA channel in linked-list mode.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ConvertQToStatic() to convert a linked-list queue to static format.
 | |
|               (++) This API must be called for ready state queues.
 | |
|               (++) This API must be called for dynamic queues format.
 | |
|               (++) This API must be called as the first API after the full execution of linked-list queue when the
 | |
|                    execution mode is linear (not circular) if it is dynamic and a linked-list queue management is
 | |
|                    needed.
 | |
|               (++) This API must be called as the first API after the aborting the execution of the current linked-list
 | |
|                    queue when the execution mode is linear (not circular) if it is dynamic and a linked-list queue
 | |
|                    management is needed.
 | |
| 
 | |
|     [..]
 | |
|       When converting a circular queue to dynamic format and when the first circular node is the last queue node, it is
 | |
|       recommended to duplicate the last circular node in order to ensure the full optimization when calling
 | |
|       HAL_DMAEx_List_ConvertQToDynamic() API. In this case, updated information are only addresses which allow to reduce
 | |
|       4 words of update for linear nodes per node execution and 6 words update for 2 dimensions addressing nodes per
 | |
|       node execution.
 | |
| 
 | |
| 
 | |
|     *** Linking linked-list queue to DMA channel ***
 | |
|     [..]
 | |
|       In order to have the possibility of the creation of an infinity queues (limited by available memory size), the
 | |
|       building of linked-list queue is fully independent from DMA channels. It is possible to build all needed queues if
 | |
|       their size is less then available memory at startup time, then linking each time when needed a linked-list queue
 | |
|       to an idle DMA channel.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_LinkQ() to link a ready linked-list queue to ready DMA channel.
 | |
|               (++) This API supports the two format of linked-list (Static and dynamic).
 | |
|               (++) This API must be called for ready state queues and DMA channels.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_List_ConvertQToStatic() to unlink a ready linked-list queue to ready DMA channel.
 | |
|               (++) This API supports the two format of linked-list (Static and dynamic).
 | |
|               (++) This API must be called for ready state queues and DMA channels.
 | |
| 
 | |
|     *** User sequence ***
 | |
|     [..]
 | |
|       To use cleanly the DMA linked-list library, ensure to apply the following call sequences :
 | |
| 
 | |
|           (+) Linear transfer :
 | |
|               Linked-list queue building
 | |
|               (++) HAL_DMAEx_List_BuildNode()
 | |
|               (++) HAL_DMAEx_List_InsertNode_Tail()
 | |
|                               .
 | |
|                               .
 | |
|                               .
 | |
|               (++) HAL_DMAEx_List_BuildNode()
 | |
|               (++) HAL_DMAEx_List_InsertNode_Tail()
 | |
|               (++) HAL_DMAEx_List_ConvertQToDynamic()
 | |
|               Linked-list queue execution
 | |
|               (++) HAL_DMAEx_List_Init()
 | |
|               (++) HAL_DMAEx_List_LinkQ()
 | |
|               (++) HAL_DMAEx_List_Start() / HAL_DMAEx_List_Start_IT()
 | |
|               (++) HAL_DMAEx_List_UnLinkQ()
 | |
|               (++) HAL_DMAEx_List_DeInit()
 | |
| 
 | |
|           (+) Circular transfer :
 | |
|               Linked-list queue building
 | |
|               (++) HAL_DMAEx_List_BuildNode()
 | |
|               (++) HAL_DMAEx_List_InsertNode_Tail()
 | |
|                               .
 | |
|                               .
 | |
|                               .
 | |
|               (++) HAL_DMAEx_List_BuildNode()
 | |
|               (++) HAL_DMAEx_List_InsertNode_Tail()
 | |
|               (++) HAL_DMAEx_List_SetCircularModeConfig() / HAL_DMAEx_List_SetCircularMode()
 | |
|               (++) HAL_DMAEx_List_ConvertQToDynamic()
 | |
|               Linked-list queue execution
 | |
|               (++) HAL_DMAEx_List_Init()
 | |
|               (++) HAL_DMAEx_List_LinkQ()
 | |
|               (++) HAL_DMAEx_List_Start() / HAL_DMAEx_List_Start_IT()
 | |
|               (++) HAL_DMA_Abort() / HAL_DMA_Abort_IT()
 | |
|               (++) HAL_DMAEx_List_UnLinkQ()
 | |
|               (++) HAL_DMAEx_List_DeInit()
 | |
| 
 | |
| 
 | |
|     *** Data Handling ***
 | |
|     =====================
 | |
|     [..]
 | |
|       In order to avoid some CPU data processing in several cases, the DMA channel provides some features related to
 | |
|       FIFO capabilities titled data handling.
 | |
|                 (++) Padding pattern
 | |
|                      Padding selected pattern (zero padding or sign extension) when the source data width is smaller
 | |
|                      than the destination data width at single level.
 | |
|                      Zero padding       (Source : 0xABAB ------> Destination : 0xABAB0000)
 | |
|                      Sign bit extension (Source : 0x0ABA ------> Destination : 0x00000ABA)
 | |
|                                         (Source : 0xFABA ------> Destination : 0xFFFFFABA)
 | |
|                 (++) Truncation :
 | |
|                      Truncate section from the source data single when the source data width is bigger than the
 | |
|                      destination data width.
 | |
|                      Left truncation  (Source : 0xABABCDCD ------> Destination : 0xCDCD)
 | |
|                      Right truncation (Source : 0xABABCDCD ------> Destination : 0xABAB)
 | |
|                 (++) Pack/Unpack :
 | |
|                      Pack a set of data when source data width is smaller than the destination data width.
 | |
|                      Unpack a set of data when source data width is bigger than the destination data width.
 | |
|                      Pack   (Source : 0xAB, 0xCD ------> Destination : 0xABCD)
 | |
|                      UnPack (Source : 0xABCD     ------> Destination : 0xAB, 0xCD)
 | |
|                 (++) Exchange :
 | |
|                      Exchange data at byte and half-word on the destination and at byte level on the source.
 | |
|                      Considering source and destination are both word type. Exchange operation can be as follows.
 | |
|                      In examples below, one exchange setting is enabled at a time.
 | |
|                      Source byte exchange only (Source : 0xAB12CD34 ------> Destination : 0xABCD1234)
 | |
|                      Destination byte exchange only (Source : 0xAB12CD34 ------> Destination : 0x12AB34CD)
 | |
|                      Destination half-word exchange only (Source : 0xAB12CD34 ------> Destination : 0xCD34AB12)
 | |
| 
 | |
|           (+) Use HAL_DMAEx_ConfigDataHandling() to configure data handling features. Previous elementary explained
 | |
|               can be combined according to application needs.
 | |
|               (++) This API is complementary of normal transfers.
 | |
|               (++) This API must not be called for linked-list transfers as data handling information are configured at
 | |
|                    node level.
 | |
| 
 | |
|     *** User sequence ***
 | |
|     [..]
 | |
|       To configure cleanly the DMA channel data handling, ensure to apply the following call sequence :
 | |
| 
 | |
|           (+) Linear transfer :
 | |
|               (++) HAL_DMA_Init()
 | |
|               (++) HAL_DMAEx_ConfigDataHandling()
 | |
|               (++) HAL_DMA_Start()
 | |
| 
 | |
|     *** Repeated Block ***
 | |
|     ======================
 | |
|     [..]
 | |
|       When available, this feature is used when the data size is higher then 65535 bytes (Maximum block size) or for
 | |
|       scattering / gathering data.
 | |
|                 (++) Gather data
 | |
|                      Source            Destination
 | |
|                      0xAA              0xAA
 | |
|                      0xBB              0xAA
 | |
|                      0xAA      ==>     0xAA
 | |
|                      0xCC
 | |
|                      0xAA
 | |
|                 (++) Scatter data
 | |
|                      Source            Destination
 | |
|                      0xAA              0xAA
 | |
|                      0xAA              0xBB
 | |
|                      0xAA      ==>     0xAA
 | |
|                                        0xBB
 | |
|                                        0xAA
 | |
| 
 | |
|           (+) Use HAL_DMAEx_ConfigRepeatBlock() to configure data repeated block feature. Jump addresses and
 | |
|               incrementing or decrementing on source and destination can be combined to have the need application
 | |
|               behavior.
 | |
|               (++) This API is complementary of normal transfers.
 | |
|               (++) This API must not be called for linked-list transfers as repeated block information are configured at
 | |
|                    node level.
 | |
|               (++) This API must be called only for DMA channel that supports repeated block feature.
 | |
| 
 | |
|     *** User sequence ***
 | |
|     [..]
 | |
|       To configure cleanly the DMA channel repeated block, ensure to apply the following call sequence :
 | |
| 
 | |
|           (+) Linear transfer :
 | |
|               (++) HAL_DMA_Init()
 | |
|               (++) HAL_DMAEx_ConfigRepeatBlock()
 | |
|               (++) HAL_DMA_Start()
 | |
| 
 | |
|     *** Trigger Configuration ***
 | |
|     =============================
 | |
|     [..]
 | |
|       When application needs that DMA transfers are conditioned by internal or external events, the trigger feature can
 | |
|       do that. Trigger signals are a set of device signal that are linked to DMA trigger inputs that allows to start the
 | |
|       DMA transfers.
 | |
|       To setup a trigger transfers, three DMA channel parameters are needed:
 | |
| 
 | |
|           (+) Trigger mode
 | |
|               This parameter specifies the trig level.
 | |
|                (++) Block level
 | |
|                (++) Repeated block level
 | |
|                (++) Node level
 | |
|                (++) Single / Burst level
 | |
| 
 | |
|           (+) Trigger polarity
 | |
|               This parameter specifies the DMA trigger sensitivity (Rising or falling).
 | |
| 
 | |
|           (+) Trigger selection
 | |
|               This parameter specifies the DMA trigger hardware signal.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_ConfigTrigger() to configure trigger feature.
 | |
|               (++) This API is complementary to normal transfers APIs.
 | |
|               (++) This API must not be called for linked-list transfers as trigger information are configured at
 | |
|                    node level.
 | |
| 
 | |
|     *** User sequence ***
 | |
|     [..]
 | |
|       To configure cleanly the DMA channel trigger, ensure to apply the following call sequence :
 | |
|           (+) Linear transfer :
 | |
|               (++) HAL_DMA_Init()
 | |
|               (++) HAL_DMAEx_ConfigTrigger()
 | |
|               (++) HAL_DMA_Start()
 | |
| 
 | |
|     *** Suspend and resume operation ***
 | |
|     ====================================
 | |
|     [..]
 | |
|       There are several cases when needs to suspend a DMA current transfer (Example: liberate bandwidth for more
 | |
|       priority DMA channel transfer). Suspending DMA channel (same as abort) is available in polling (blocking mode) and
 | |
|       interrupt (non-blocking mode) modes. When suspended, a DMA channel can be instantly resumed.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_Suspend() to suspend an ongoing DMA channel transfer in polling mode (Blocking mode).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_Suspend_IT() to suspend an ongoing DMA channel transfer in interrupt mode (Non-blocking
 | |
|               mode).
 | |
| 
 | |
|           (+) Use HAL_DMAEx_Resume() to resume a suspended DMA channel transfer execution.
 | |
| 
 | |
|     *** FIFO status ***
 | |
|     ===================
 | |
|     [..]
 | |
|       In several cases, the information of FIFO level is useful to inform at application level how to process remaining
 | |
|       data. When not empty, the DMA channel FIFO cannot be flashed only by reset.
 | |
| 
 | |
|           (+) Use HAL_DMAEx_GetFifoLevel() to get the DMA channel FIFO level (available beats in FIFO).
 | |
| 
 | |
|     @endverbatim
 | |
|   **********************************************************************************************************************
 | |
|   */
 | |
| 
 | |
| /* Includes ----------------------------------------------------------------------------------------------------------*/
 | |
| #include "stm32h5xx_hal.h"
 | |
| 
 | |
| /** @addtogroup STM32H5xx_HAL_Driver
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /** @defgroup DMAEx DMAEx
 | |
|   * @brief DMA Extended HAL module driver
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| #ifdef HAL_DMA_MODULE_ENABLED
 | |
| 
 | |
| /* Private types -----------------------------------------------------------------------------------------------------*/
 | |
| /* Private variables -------------------------------------------------------------------------------------------------*/
 | |
| /* Private Constants -------------------------------------------------------------------------------------------------*/
 | |
| /* Private macros ----------------------------------------------------------------------------------------------------*/
 | |
| /* Private function prototypes ---------------------------------------------------------------------------------------*/
 | |
| static void DMA_List_Init(DMA_HandleTypeDef const *const hdma);
 | |
| static void DMA_List_BuildNode(DMA_NodeConfTypeDef const *const pNodeConfig,
 | |
|                                DMA_NodeTypeDef *const pNode);
 | |
| static void DMA_List_GetNodeConfig(DMA_NodeConfTypeDef *const pNodeConfig,
 | |
|                                    DMA_NodeTypeDef const *const pNode);
 | |
| static uint32_t DMA_List_CheckNodesBaseAddresses(DMA_NodeTypeDef const *const pNode1,
 | |
|                                                  DMA_NodeTypeDef const *const pNode2,
 | |
|                                                  DMA_NodeTypeDef const *const pNode3);
 | |
| static uint32_t DMA_List_CheckNodesTypes(DMA_NodeTypeDef const *const pNode1,
 | |
|                                          DMA_NodeTypeDef const *const pNode2,
 | |
|                                          DMA_NodeTypeDef const *const pNode3);
 | |
| static void DMA_List_GetCLLRNodeInfo(DMA_NodeTypeDef const *const pNode,
 | |
|                                      uint32_t *const cllr_mask,
 | |
|                                      uint32_t *const cllr_offset);
 | |
| static uint32_t DMA_List_FindNode(DMA_QListTypeDef const *const pQList,
 | |
|                                   DMA_NodeTypeDef const *const pNode,
 | |
|                                   DMA_NodeInQInfoTypeDef *const NodeInfo);
 | |
| static void DMA_List_ResetQueueNodes(DMA_QListTypeDef const *const pQList,
 | |
|                                      DMA_NodeInQInfoTypeDef const *const NodeInfo);
 | |
| static void DMA_List_FillNode(DMA_NodeTypeDef const *const pSrcNode,
 | |
|                               DMA_NodeTypeDef *const pDestNode);
 | |
| static void DMA_List_ConvertNodeToDynamic(uint32_t ContextNodeAddr,
 | |
|                                           uint32_t CurrentNodeAddr,
 | |
|                                           uint32_t RegisterNumber);
 | |
| static void DMA_List_ConvertNodeToStatic(uint32_t ContextNodeAddr,
 | |
|                                          uint32_t CurrentNodeAddr,
 | |
|                                          uint32_t RegisterNumber);
 | |
| static void DMA_List_UpdateDynamicQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
 | |
|                                                  uint32_t LastNode_IsCircular);
 | |
| static void DMA_List_UpdateStaticQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
 | |
|                                                 uint32_t operation);
 | |
| static void DMA_List_FormatNode(DMA_NodeTypeDef *const pNode,
 | |
|                                 uint32_t RegisterIdx,
 | |
|                                 uint32_t RegisterNumber,
 | |
|                                 uint32_t Format);
 | |
| static void DMA_List_ClearUnusedFields(DMA_NodeTypeDef *const pNode,
 | |
|                                        uint32_t FirstUnusedField);
 | |
| static void DMA_List_CleanQueue(DMA_QListTypeDef *const pQList);
 | |
| 
 | |
| /* Exported functions ------------------------------------------------------------------------------------------------*/
 | |
| 
 | |
| /** @addtogroup DMAEx_Exported_Functions
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /** @addtogroup DMAEx_Exported_Functions_Group1
 | |
|   *
 | |
| @verbatim
 | |
|   ======================================================================================================================
 | |
|                  ##### Linked-List Initialization and De-Initialization Functions #####
 | |
|   ======================================================================================================================
 | |
|     [..]
 | |
|       This section provides functions allowing to initialize and de-initialize the DMA channel in linked-list mode.
 | |
|     [..]
 | |
|       (+) The HAL_DMAEx_List_Init() function follows the DMA channel linked-list mode configuration procedures as
 | |
|           described in reference manual.
 | |
|       (+) The HAL_DMAEx_List_DeInit() function allows to de-initialize the DMA channel in linked-list mode.
 | |
| 
 | |
| @endverbatim
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @brief  Initialize the DMA channel in linked-list mode according to the specified parameters in the
 | |
|   *         DMA_InitLinkedListTypeDef 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_DMAEx_List_Init(DMA_HandleTypeDef *const hdma)
 | |
| {
 | |
|   /* Get tick number */
 | |
|   uint32_t tickstart = HAL_GetTick();
 | |
| 
 | |
|   /* Check the DMA channel handle parameter */
 | |
|   if (hdma == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the parameters */
 | |
|   assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
 | |
|   assert_param(IS_DMA_PRIORITY(hdma->InitLinkedList.Priority));
 | |
|   assert_param(IS_DMA_LINK_STEP_MODE(hdma->InitLinkedList.LinkStepMode));
 | |
|   assert_param(IS_DMA_TCEM_LINKEDLIST_EVENT_MODE(hdma->InitLinkedList.TransferEventMode));
 | |
|   assert_param(IS_DMA_LINKEDLIST_MODE(hdma->InitLinkedList.LinkedListMode));
 | |
|   /* Check DMA channel instance */
 | |
|   if (IS_GPDMA_INSTANCE(hdma->Instance) != 0U)
 | |
|   {
 | |
|     assert_param(IS_DMA_LINK_ALLOCATED_PORT(hdma->InitLinkedList.LinkAllocatedPort));
 | |
|   }
 | |
| 
 | |
|   /* Allocate lock resource */
 | |
|   __HAL_UNLOCK(hdma);
 | |
| 
 | |
|   /* Change DMA peripheral 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 error code */
 | |
|       hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;
 | |
| 
 | |
|       /* Change the DMA state */
 | |
|       hdma->State = HAL_DMA_STATE_ERROR;
 | |
| 
 | |
|       return HAL_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Initialize the DMA channel registers */
 | |
|   DMA_List_Init(hdma);
 | |
| 
 | |
|   /* Update DMA channel operation mode */
 | |
|   hdma->Mode = hdma->InitLinkedList.LinkedListMode;
 | |
| 
 | |
|   /* 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 linked-list 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_DMAEx_List_DeInit(DMA_HandleTypeDef *const hdma)
 | |
| {
 | |
| 
 | |
|   /* Get DMA instance */
 | |
|   DMA_TypeDef *p_dma_instance;
 | |
| 
 | |
|   /* 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));
 | |
| 
 | |
| 
 | |
|   /* 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 error code */
 | |
|       hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;
 | |
| 
 | |
|       /* Change the DMA state */
 | |
|       hdma->State = HAL_DMA_STATE_ERROR;
 | |
| 
 | |
|       return HAL_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Reset DMA Channel registers */
 | |
|   hdma->Instance->CCR   = 0U;
 | |
|   hdma->Instance->CLBAR = 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;
 | |
| 
 | |
|   /* Check the linked-list queue */
 | |
|   if (hdma->LinkedListQueue != NULL)
 | |
|   {
 | |
|     /* Update the queue state and error code */
 | |
|     hdma->LinkedListQueue->State     = HAL_DMA_QUEUE_STATE_READY;
 | |
|     hdma->LinkedListQueue->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|     /* 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 DMAEx_Exported_Functions_Group2
 | |
|   *
 | |
| @verbatim
 | |
|   ======================================================================================================================
 | |
|                          ##### Linked-List IO Operation Functions #####
 | |
|   ======================================================================================================================
 | |
|     [..]
 | |
|       This section provides functions allowing to :
 | |
|       (+) Configure to start DMA transfer in linked-list mode.
 | |
| 
 | |
|     [..]
 | |
|       (+) The HAL_DMAEx_List_Start() function allows to start the DMA channel transfer in linked-list mode (Blocking
 | |
|           mode).
 | |
|       (+) The HAL_DMAEx_List_Start_IT() function allows to start the DMA channel transfer in linked-list mode
 | |
|           (Non-blocking mode).
 | |
|               (++) It is mandatory to register a linked-list queue to be executed by a DMA channel before starting
 | |
|                    transfer otherwise a HAL_ERROR will be returned.
 | |
| 
 | |
| @endverbatim
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @brief  Start the DMA channel transfer in linked-list mode (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_DMAEx_List_Start(DMA_HandleTypeDef *const hdma)
 | |
| {
 | |
|   HAL_DMA_StateTypeDef dma_state;
 | |
|   uint32_t ccr_value;
 | |
|   uint32_t cllr_mask;
 | |
| 
 | |
|   /* Check the DMA peripheral handle and the linked-list queue parameters */
 | |
|   if ((hdma == NULL) || (hdma->LinkedListQueue == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the DMA Mode is not DMA_NORMAL */
 | |
|   if (hdma->Mode == DMA_NORMAL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check DMA channel state */
 | |
|   dma_state = hdma->State;
 | |
|   ccr_value = hdma->Instance->CCR & DMA_CCR_LSM;
 | |
|   if ((dma_state == HAL_DMA_STATE_READY) || ((dma_state == HAL_DMA_STATE_BUSY) && (ccr_value != 0U)))
 | |
|   {
 | |
|     /* Check DMA channel state is ready */
 | |
|     if (hdma->State == HAL_DMA_STATE_READY)
 | |
|     {
 | |
|       /* Process locked */
 | |
|       __HAL_LOCK(hdma);
 | |
| 
 | |
|       /* Update the DMA channel and the queue states */
 | |
|       hdma->State                  = HAL_DMA_STATE_BUSY;
 | |
|       hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|       /* Update the DMA channel and the queue error codes */
 | |
|       hdma->ErrorCode                  = HAL_DMA_ERROR_NONE;
 | |
|       hdma->LinkedListQueue->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|       /* Get CLLR register mask and offset */
 | |
|       DMA_List_GetCLLRNodeInfo(hdma->LinkedListQueue->Head, &cllr_mask, NULL);
 | |
| 
 | |
|       /* Update DMA registers for linked-list transfer */
 | |
|       hdma->Instance->CLBAR = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLBAR_LBA);
 | |
|       hdma->Instance->CLLR  = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|     }
 | |
| 
 | |
|     /* 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 linked-list 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.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_Start_IT(DMA_HandleTypeDef *const hdma)
 | |
| {
 | |
|   HAL_DMA_StateTypeDef dma_state;
 | |
|   uint32_t ccr_value;
 | |
|   uint32_t cllr_mask;
 | |
| 
 | |
|   /* Check the DMA peripheral handle and the linked-list queue parameters */
 | |
|   if ((hdma == NULL) || (hdma->LinkedListQueue == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the DMA Mode is not DMA_NORMAL */
 | |
|   if (hdma->Mode == DMA_NORMAL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check DMA channel state */
 | |
|   dma_state = hdma->State;
 | |
|   ccr_value = hdma->Instance->CCR & DMA_CCR_LSM;
 | |
|   if ((dma_state == HAL_DMA_STATE_READY) || ((dma_state == HAL_DMA_STATE_BUSY) && (ccr_value != 0U)))
 | |
|   {
 | |
|     /* Check DMA channel state is ready */
 | |
|     if (hdma->State == HAL_DMA_STATE_READY)
 | |
|     {
 | |
|       /* Process locked */
 | |
|       __HAL_LOCK(hdma);
 | |
| 
 | |
|       /* Update the DMA channel and the queue states */
 | |
|       hdma->State                  = HAL_DMA_STATE_BUSY;
 | |
|       hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|       /* Update the DMA channel and the queue error codes */
 | |
|       hdma->ErrorCode                  = HAL_DMA_ERROR_NONE;
 | |
|       hdma->LinkedListQueue->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|       /* 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 suspend callback */
 | |
|       if (hdma->XferSuspendCallback != NULL)
 | |
|       {
 | |
|         /* If transfer suspend callback is set, enable the corresponding IT */
 | |
|         __HAL_DMA_ENABLE_IT(hdma, DMA_IT_SUSP);
 | |
|       }
 | |
| 
 | |
|       /* Get CLLR register mask and offset */
 | |
|       DMA_List_GetCLLRNodeInfo(hdma->LinkedListQueue->Head, &cllr_mask, NULL);
 | |
| 
 | |
|       /* Update DMA registers for linked-list transfer */
 | |
|       hdma->Instance->CLBAR = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLBAR_LBA);
 | |
|       hdma->Instance->CLLR  = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|     }
 | |
| 
 | |
|     /* Enable DMA channel */
 | |
|     __HAL_DMA_ENABLE(hdma);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Change the error code */
 | |
|     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
 | |
| 
 | |
|     /* Process unlocked */
 | |
|     __HAL_UNLOCK(hdma);
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| /** @addtogroup DMAEx_Exported_Functions_Group3
 | |
|   *
 | |
| @verbatim
 | |
|   ======================================================================================================================
 | |
|                          ##### Linked-List Management Functions #####
 | |
|   ======================================================================================================================
 | |
|     [..]
 | |
|       This section provides functions allowing to :
 | |
|       (+) Build linked-list node.
 | |
|       (+) Get linked-list node configuration.
 | |
|       (+) Insert node to linked-list queue in any queue position.
 | |
|       (+) Remove any node from linked-list queue.
 | |
|       (+) Replace any node from linked-list queue.
 | |
|       (+) Reset linked-list queue.
 | |
|       (+) Insert linked-list queue in any queue position.
 | |
|       (+) Set circular mode configuration to linked-list queue.
 | |
|       (+) Clear circular mode configuration from linked-list queue.
 | |
|       (+) Convert static linked-list queue to dynamic format.
 | |
|       (+) Convert dynamic linked-list queue to static format.
 | |
|       (+) Link linked-list queue to DMA channel.
 | |
|       (+) Unlink linked-list queue from DMA channel.
 | |
| 
 | |
|     [..]
 | |
|       (+) The HAL_DMAEx_List_BuildNode() function allows to build linked-list node.
 | |
|           Node type can be :
 | |
|               (++) 2 dimensions addressing node.
 | |
|               (++) Linear addressing node.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_GetNodeConfig() function allows to get the linked-list node configuration from built node.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_InsertNode() function allows to insert built linked-list node to static linked-list queue
 | |
|           according to selected position.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_InsertNode_Head() and HAL_DMAEx_List_InsertNode_Tail() functions allow to insert built
 | |
|           linked-list node to the head (respectively the tail) of static linked-list queue.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_RemoveNode() function allows to remove selected built linked-list node from static
 | |
|           linked-list queue.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_RemoveNode_Head() and HAL_DMAEx_List_RemoveNode_Tail() functions allow to remove the head
 | |
|           (respectively the tail) built linked-list node from static linked-list queue.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_ReplaceNode() function allows to replace selected built linked-list node from static
 | |
|           linked-list queue.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_ReplaceNode_Head() and HAL_DMAEx_List_ReplaceNode_Tail() functions allow to replace the
 | |
|           head (respectively the tail) built linked-list node of static linked-list queue.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_ResetQ() function allows to reset static linked-list queue and unlink all built linked-list
 | |
|           nodes.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_InsertQ() function allows to insert static linked-list source queue to static linked-list
 | |
|           destination queue according to selected position.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_InsertQ_Head() and HAL_DMAEx_List_InsertQ_Tail() functions allow to insert static
 | |
|           linked-list source queue to the head (respectively the tail) of static linked-list destination queue.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_SetCircularModeConfig() function allows to link the last static linked-list queue node to
 | |
|           the selected first circular node.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_SetCircularMode() function allows to link the last static linked-list queue node to the
 | |
|           first static linked-list queue node.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_ClearCircularMode() function allows to unlink the last static linked-list queue node from
 | |
|           any first circular node position.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_ConvertQToDynamic() function allows to convert the static linked-list queue to dynamic
 | |
|           format. (Optimized queue execution)
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_ConvertQToStatic() function allows to convert the dynamic linked-list queue to static
 | |
|           format. (Not optimized queue execution)
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_LinkQ() function allows to link the (Dynamic / Static) linked-list queue to DMA channel to
 | |
|           be executed.
 | |
| 
 | |
|       (+) The HAL_DMAEx_List_UnLinkQ() function allows to unlink the (Dynamic / Static) linked-list queue from DMA
 | |
|           channel when execution is completed.
 | |
| 
 | |
| @endverbatim
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @brief  Build a DMA channel node according to the specified parameters in the DMA_NodeConfTypeDef.
 | |
|   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
 | |
|   *                       specified DMA linked-list Node.
 | |
|   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
 | |
|   *                       configurations.
 | |
|   * @note   The DMA linked-list node parameter address should be 32bit aligned and should not exceed the 64 KByte
 | |
|   *         addressable space.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_BuildNode(DMA_NodeConfTypeDef const *const pNodeConfig,
 | |
|                                            DMA_NodeTypeDef *const pNode)
 | |
| {
 | |
|   /* Check the node configuration and physical node parameters */
 | |
|   if ((pNodeConfig == NULL) || (pNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check node type parameter */
 | |
|   assert_param(IS_DMA_NODE_TYPE(pNodeConfig->NodeType));
 | |
| 
 | |
|   /* Check DMA channel basic transfer parameters */
 | |
|   assert_param(IS_DMA_SOURCE_INC(pNodeConfig->Init.SrcInc));
 | |
|   assert_param(IS_DMA_DESTINATION_INC(pNodeConfig->Init.DestInc));
 | |
|   assert_param(IS_DMA_SOURCE_DATA_WIDTH(pNodeConfig->Init.SrcDataWidth));
 | |
|   assert_param(IS_DMA_DESTINATION_DATA_WIDTH(pNodeConfig->Init.DestDataWidth));
 | |
|   assert_param(IS_DMA_DATA_ALIGNMENT(pNodeConfig->DataHandlingConfig.DataAlignment));
 | |
|   assert_param(IS_DMA_REQUEST(pNodeConfig->Init.Request));
 | |
|   assert_param(IS_DMA_DIRECTION(pNodeConfig->Init.Direction));
 | |
|   assert_param(IS_DMA_TCEM_EVENT_MODE(pNodeConfig->Init.TransferEventMode));
 | |
|   assert_param(IS_DMA_BLOCK_HW_REQUEST(pNodeConfig->Init.BlkHWRequest));
 | |
|   assert_param(IS_DMA_MODE(pNodeConfig->Init.Mode));
 | |
| 
 | |
|   /* Check DMA channel parameters */
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_GPDMA) == DMA_CHANNEL_TYPE_GPDMA)
 | |
|   {
 | |
|     assert_param(IS_DMA_BURST_LENGTH(pNodeConfig->Init.SrcBurstLength));
 | |
|     assert_param(IS_DMA_BURST_LENGTH(pNodeConfig->Init.DestBurstLength));
 | |
|     assert_param(IS_DMA_DATA_EXCHANGE(pNodeConfig->DataHandlingConfig.DataExchange));
 | |
|     assert_param(IS_DMA_TRANSFER_ALLOCATED_PORT(pNodeConfig->Init.TransferAllocatedPort));
 | |
|   }
 | |
| 
 | |
|   /* Check DMA channel trigger parameters */
 | |
|   assert_param(IS_DMA_TRIGGER_POLARITY(pNodeConfig->TriggerConfig.TriggerPolarity));
 | |
|   if (pNodeConfig->TriggerConfig.TriggerPolarity != DMA_TRIG_POLARITY_MASKED)
 | |
|   {
 | |
|     assert_param(IS_DMA_TRIGGER_MODE(pNodeConfig->TriggerConfig.TriggerMode));
 | |
|     assert_param(IS_DMA_TRIGGER_SELECTION(pNodeConfig->TriggerConfig.TriggerSelection));
 | |
|   }
 | |
| 
 | |
|   /* Check DMA channel repeated block parameters */
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
 | |
|   {
 | |
|     assert_param(IS_DMA_REPEAT_COUNT(pNodeConfig->RepeatBlockConfig.RepeatCount));
 | |
|     assert_param(IS_DMA_BURST_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.SrcAddrOffset));
 | |
|     assert_param(IS_DMA_BURST_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.DestAddrOffset));
 | |
|     assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset));
 | |
|     assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset));
 | |
|   }
 | |
| 
 | |
|   /* Check DMA channel security and privilege attributes parameters */
 | |
| #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
 | |
|   assert_param(IS_DMA_ATTRIBUTES(pNodeConfig->SrcSecure));
 | |
|   assert_param(IS_DMA_ATTRIBUTES(pNodeConfig->DestSecure));
 | |
| #endif /* (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */
 | |
| 
 | |
|   /* Build the DMA channel node */
 | |
|   DMA_List_BuildNode(pNodeConfig, pNode);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Get a DMA channel node configuration.
 | |
|   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
 | |
|   *                       specified DMA linked-list Node.
 | |
|   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
 | |
|   *                       configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_GetNodeConfig(DMA_NodeConfTypeDef *const pNodeConfig,
 | |
|                                                DMA_NodeTypeDef const *const pNode)
 | |
| {
 | |
|   /* Check the node configuration and physical node parameters */
 | |
|   if ((pNodeConfig == NULL) || (pNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Get the DMA channel node configuration */
 | |
|   DMA_List_GetNodeConfig(pNodeConfig, pNode);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Insert new node in any queue position of linked-list queue according to selecting previous node.
 | |
|   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pPrevNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list previous node registers
 | |
|   *                     configurations.
 | |
|   * @param  pNewNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
 | |
|   *                     configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_InsertNode(DMA_QListTypeDef *const pQList,
 | |
|                                             DMA_NodeTypeDef *const pPrevNode,
 | |
|                                             DMA_NodeTypeDef *const pNewNode)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue and the new node parameters */
 | |
|   if ((pQList == NULL) || (pNewNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pPrevNode, pNewNode) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pQList->Head, pPrevNode, pNewNode) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Empty queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Add only new node to queue */
 | |
|     if (pPrevNode == NULL)
 | |
|     {
 | |
|       pQList->Head       = pNewNode;
 | |
|       pQList->NodeNumber = 1U;
 | |
|     }
 | |
|     /* Add previous node then new node to queue */
 | |
|     else
 | |
|     {
 | |
|       pQList->Head                          = pPrevNode;
 | |
|       pPrevNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
|       pQList->NodeNumber                    = 2U;
 | |
|     }
 | |
|   }
 | |
|   /* Not empty queue */
 | |
|   else
 | |
|   {
 | |
|     /* Add new node at the head of queue */
 | |
|     if (pPrevNode == NULL)
 | |
|     {
 | |
|       pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|       pQList->Head                         = pNewNode;
 | |
|     }
 | |
|     /* Add new node according to selected position */
 | |
|     else
 | |
|     {
 | |
|       /* Find node and get its position in selected queue */
 | |
|       node_info.cllr_offset = cllr_offset;
 | |
|       if (DMA_List_FindNode(pQList, pPrevNode, &node_info) == 0U)
 | |
|       {
 | |
|         /* Selected node is the last queue node */
 | |
|         if (node_info.currentnode_pos == pQList->NodeNumber)
 | |
|         {
 | |
|           /* Check if queue is circular */
 | |
|           if (pQList->FirstCircularNode != NULL)
 | |
|           {
 | |
|             pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
 | |
|           }
 | |
| 
 | |
|           pPrevNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
|         }
 | |
|         /* Selected node is not the last queue node */
 | |
|         else
 | |
|         {
 | |
|           pNewNode->LinkRegisters[cllr_offset] = pPrevNode->LinkRegisters[cllr_offset];
 | |
|           pPrevNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
|         }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         /* Update the queue error code */
 | |
|         pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
 | |
| 
 | |
|         return HAL_ERROR;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     /* Increment queue node number */
 | |
|     pQList->NodeNumber++;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Insert new node at the head of linked-list queue.
 | |
|   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pNewNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
 | |
|   *                     configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_InsertNode_Head(DMA_QListTypeDef *const pQList,
 | |
|                                                  DMA_NodeTypeDef *const pNewNode)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
| 
 | |
|   /* Check the queue and the new node parameters */
 | |
|   if ((pQList == NULL) || (pNewNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pNewNode, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pQList->Head, pNewNode, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Empty queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     pQList->Head = pNewNode;
 | |
|   }
 | |
|   /* Not empty queue */
 | |
|   else
 | |
|   {
 | |
|     /* Get CLLR register mask and offset */
 | |
|     DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|     pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|     pQList->Head                         = pNewNode;
 | |
|   }
 | |
| 
 | |
|   /* Increment queue node number */
 | |
|   pQList->NodeNumber++;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Insert new node at the tail of linked-list queue.
 | |
|   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pNewNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
 | |
|   *                     configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_InsertNode_Tail(DMA_QListTypeDef *const pQList,
 | |
|                                                  DMA_NodeTypeDef *const pNewNode)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue and the new node parameters */
 | |
|   if ((pQList == NULL) || (pNewNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pNewNode, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pQList->Head, pNewNode, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Empty queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     pQList->Head = pNewNode;
 | |
|   }
 | |
|   /* Not empty queue */
 | |
|   else
 | |
|   {
 | |
|     /* Get CLLR register mask and offset */
 | |
|     DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|     /* Find node and get its position in selected queue */
 | |
|     node_info.cllr_offset = cllr_offset;
 | |
|     (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|     /* Check if queue is circular */
 | |
|     if (pQList->FirstCircularNode != NULL)
 | |
|     {
 | |
|       pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
 | |
|     }
 | |
| 
 | |
|     ((DMA_NodeTypeDef *)node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
 | |
|       ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
|   }
 | |
| 
 | |
|   /* Increment queue node number */
 | |
|   pQList->NodeNumber++;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Remove node from any linked-list queue position.
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list previous node registers
 | |
|   *                  configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_RemoveNode(DMA_QListTypeDef *const pQList,
 | |
|                                             DMA_NodeTypeDef *const pNode)
 | |
| {
 | |
|   uint32_t previousnode_addr;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue and the node parameters */
 | |
|   if ((pQList == NULL) || (pNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pNode, NULL, &cllr_offset);
 | |
| 
 | |
|   /* Find node and get its position in selected queue */
 | |
|   node_info.cllr_offset = cllr_offset;
 | |
|   if (DMA_List_FindNode(pQList, pNode, &node_info) == 0U)
 | |
|   {
 | |
|     /* Removed node is the head node */
 | |
|     if (node_info.currentnode_pos == 1U)
 | |
|     {
 | |
|       /* Check if first circular node queue is the first node */
 | |
|       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)node_info.currentnode_addr))
 | |
|       {
 | |
|         /* Find last queue node */
 | |
|         (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|         /* Clear last node link */
 | |
|         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|         /* Clear first circular node */
 | |
|         pQList->FirstCircularNode = NULL;
 | |
|       }
 | |
| 
 | |
|       /* Update the queue head node */
 | |
|       pQList->Head = (DMA_NodeTypeDef *)(((uint32_t)pQList->Head & DMA_CLBAR_LBA) +
 | |
|                                          (pNode->LinkRegisters[cllr_offset] & DMA_CLLR_LA));
 | |
|       /* Unlink node to be removed */
 | |
|       pNode->LinkRegisters[cllr_offset] = 0U;
 | |
|     }
 | |
|     /* Removed node is the last node */
 | |
|     else if (node_info.currentnode_pos == pQList->NodeNumber)
 | |
|     {
 | |
|       /* Clear CLLR for previous node */
 | |
|       ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|       /* Clear CLLR for last node */
 | |
|       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|       /* Clear first circular node */
 | |
|       pQList->FirstCircularNode = NULL;
 | |
|     }
 | |
|     /* Removed node is in the middle */
 | |
|     else
 | |
|     {
 | |
|       /* Store previous node address to be updated later */
 | |
|       previousnode_addr = node_info.previousnode_addr;
 | |
| 
 | |
|       /* Check if first circular node queue is the current node */
 | |
|       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)node_info.currentnode_addr))
 | |
|       {
 | |
|         /* Find last queue node */
 | |
|         (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|         /* Clear last node link */
 | |
|         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|         /* Clear first circular node */
 | |
|         pQList->FirstCircularNode = NULL;
 | |
|       }
 | |
| 
 | |
|       /* Link previous node */
 | |
|       ((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[cllr_offset] = pNode->LinkRegisters[cllr_offset];
 | |
| 
 | |
|       /* Unlink node to be removed */
 | |
|       pNode->LinkRegisters[cllr_offset] = 0U;
 | |
|     }
 | |
| 
 | |
|     /* Decrement node number */
 | |
|     pQList->NodeNumber--;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check if queue is empty */
 | |
|   if (pQList->NodeNumber == 0U)
 | |
|   {
 | |
|     /* Clean empty queue parameter */
 | |
|     DMA_List_CleanQueue(pQList);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|     /* Update the queue state */
 | |
|     pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
|   }
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Remove the head node from linked-list queue.
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_RemoveNode_Head(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   uint32_t cllr_offset;
 | |
|   uint32_t current_addr;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue parameter */
 | |
|   if (pQList == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
 | |
| 
 | |
|   /* Queue contains only one node */
 | |
|   if (pQList->NodeNumber == 1U)
 | |
|   {
 | |
|     pQList->Head->LinkRegisters[cllr_offset] = 0U;
 | |
|     pQList->FirstCircularNode = 0U;
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
|   }
 | |
|   /* Queue contains more then one node */
 | |
|   else
 | |
|   {
 | |
|     /* Check if first circular node queue is the first node */
 | |
|     if (pQList->FirstCircularNode == pQList->Head)
 | |
|     {
 | |
|       /* Find last queue node */
 | |
|       node_info.cllr_offset = cllr_offset;
 | |
|       (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|       /* Clear last node link */
 | |
|       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|       /* Clear first circular node */
 | |
|       pQList->FirstCircularNode = NULL;
 | |
|     }
 | |
| 
 | |
|     current_addr = pQList->Head->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
 | |
|     pQList->Head->LinkRegisters[cllr_offset] = 0U;
 | |
|     pQList->Head = ((DMA_NodeTypeDef *)(current_addr + ((uint32_t)pQList->Head & DMA_CLBAR_LBA)));
 | |
|   }
 | |
| 
 | |
|   /* Decrement node number */
 | |
|   pQList->NodeNumber--;
 | |
| 
 | |
|   /* Check if queue is empty */
 | |
|   if (pQList->NodeNumber == 0U)
 | |
|   {
 | |
|     /* Clean empty queue parameter */
 | |
|     DMA_List_CleanQueue(pQList);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|     /* Update the queue state */
 | |
|     pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
|   }
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Remove the tail node from linked-list queue.
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_RemoveNode_Tail(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue parameter */
 | |
|   if (pQList == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
 | |
| 
 | |
|   /* Queue contains only one node */
 | |
|   if (pQList->NodeNumber == 1U)
 | |
|   {
 | |
|     pQList->Head->LinkRegisters[cllr_offset] = 0U;
 | |
|     pQList->FirstCircularNode = 0U;
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
|   }
 | |
|   /* Queue contains more then one node */
 | |
|   else
 | |
|   {
 | |
|     /* Find node and get its position in selected queue */
 | |
|     node_info.cllr_offset = cllr_offset;
 | |
|     (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|     /* Clear CLLR for previous node */
 | |
|     ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|     /* Clear CLLR for last node */
 | |
|     ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|     /* Clear first circular node */
 | |
|     pQList->FirstCircularNode = NULL;
 | |
|   }
 | |
| 
 | |
|   /* Decrement node number */
 | |
|   pQList->NodeNumber--;
 | |
| 
 | |
|   /* Check if queue is empty */
 | |
|   if (pQList->NodeNumber == 0U)
 | |
|   {
 | |
|     /* Clean empty queue parameter */
 | |
|     DMA_List_CleanQueue(pQList);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|     /* Update the queue state */
 | |
|     pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
|   }
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Replace node in linked-list queue.
 | |
|   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pOldNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list old node registers
 | |
|   *                    configurations.
 | |
|   * @param  pNewNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
 | |
|   *                    configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_ReplaceNode(DMA_QListTypeDef *const pQList,
 | |
|                                              DMA_NodeTypeDef *const pOldNode,
 | |
|                                              DMA_NodeTypeDef *const pNewNode)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue and the nodes parameters */
 | |
|   if ((pQList == NULL) || (pOldNode == NULL) || (pNewNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pOldNode, pNewNode) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pQList->Head, pOldNode, pNewNode) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Find node and get its position in selected queue */
 | |
|   node_info.cllr_offset = cllr_offset;
 | |
|   if (DMA_List_FindNode(pQList, pOldNode, &node_info) == 0U)
 | |
|   {
 | |
|     /* Replaced node is the head node */
 | |
|     if (node_info.currentnode_pos == 1U)
 | |
|     {
 | |
|       pNewNode->LinkRegisters[cllr_offset] =
 | |
|         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset];
 | |
|       pQList->Head = pNewNode;
 | |
|       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|       /* Check if first circular node queue is the first node */
 | |
|       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)node_info.currentnode_addr))
 | |
|       {
 | |
|         /* Find last queue node */
 | |
|         (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|         /* Clear last node link */
 | |
|         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|           ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|         /* Set new node as first circular node */
 | |
|         pQList->FirstCircularNode = pNewNode;
 | |
|       }
 | |
|     }
 | |
|     /* Replaced node is the last */
 | |
|     else if (node_info.currentnode_pos == pQList->NodeNumber)
 | |
|     {
 | |
|       ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] =
 | |
|         ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
|       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|       /* Check if first circular node queue is the last node */
 | |
|       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)(node_info.currentnode_addr)))
 | |
|       {
 | |
|         /* Link first circular node to new node */
 | |
|         pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|         /* Set new node as first circular node */
 | |
|         pQList->FirstCircularNode = pNewNode;
 | |
|       }
 | |
|       /* Check if first circular node queue is not the last node */
 | |
|       else if (pQList->FirstCircularNode != NULL)
 | |
|       {
 | |
|         /* Link first circular node to new node */
 | |
|         pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         /* Prevent MISRA-C2012-Rule-15.7 */
 | |
|       }
 | |
|     }
 | |
|     /* Replaced node is in the middle */
 | |
|     else
 | |
|     {
 | |
|       ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] =
 | |
|         ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
|       pNewNode->LinkRegisters[cllr_offset] =
 | |
|         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset];
 | |
|       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|       /* Check if first circular node queue is the current node */
 | |
|       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)(node_info.currentnode_addr)))
 | |
|       {
 | |
|         /* Find last node and get its position in selected queue */
 | |
|         (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|         /* Link last queue node to new node */
 | |
|         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|           ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|         /* Set new node as first circular node */
 | |
|         pQList->FirstCircularNode = pNewNode;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Replace the head node of linked-list queue.
 | |
|   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pNewNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
 | |
|   *                    configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_ReplaceNode_Head(DMA_QListTypeDef *const pQList,
 | |
|                                                   DMA_NodeTypeDef *const pNewNode)
 | |
| {
 | |
|   uint32_t cllr_offset;
 | |
|   uint32_t cllr_mask;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue and the new node parameters */
 | |
|   if ((pQList == NULL) || (pNewNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pNewNode, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pQList->Head, pNewNode, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Check if first circular node queue is the first node */
 | |
|   if (pQList->FirstCircularNode == pQList->Head)
 | |
|   {
 | |
|     /* Find last queue node */
 | |
|     node_info.cllr_offset = cllr_offset;
 | |
|     (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|     /* Clear last node link */
 | |
|     ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|       ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|     /* Set new node as first circular node */
 | |
|     pQList->FirstCircularNode = pNewNode;
 | |
|   }
 | |
| 
 | |
|   /* Replace head node */
 | |
|   pNewNode->LinkRegisters[cllr_offset] = pQList->Head->LinkRegisters[cllr_offset];
 | |
|   pQList->Head->LinkRegisters[cllr_offset] = 0U;
 | |
|   pQList->Head = pNewNode;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Replace the tail node of linked-list queue.
 | |
|   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pNewNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
 | |
|   *                    configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_ReplaceNode_Tail(DMA_QListTypeDef *const pQList,
 | |
|                                                   DMA_NodeTypeDef *const pNewNode)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue and the new node parameters */
 | |
|   if ((pQList == NULL) || (pNewNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Find last node and get its position in selected queue */
 | |
|   node_info.cllr_offset = cllr_offset;
 | |
|   (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|   /* Link previous node to new node */
 | |
|   ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] =
 | |
|     ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|   /* Clear CLLR for current node */
 | |
|   ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|   /* Check if first circular node queue is the last node */
 | |
|   if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)(node_info.currentnode_addr)))
 | |
|   {
 | |
|     /* Link first circular node to new node */
 | |
|     pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|     /* Set new node as first circular node */
 | |
|     pQList->FirstCircularNode = pNewNode;
 | |
|   }
 | |
|   /* Check if first circular node queue is not the last node */
 | |
|   else if (pQList->FirstCircularNode != NULL)
 | |
|   {
 | |
|     /* Link first circular node to new node */
 | |
|     pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Prevent MISRA-C2012-Rule-15.7 */
 | |
|   }
 | |
| 
 | |
|   /* Check if queue contains one node */
 | |
|   if (pQList->NodeNumber == 1U)
 | |
|   {
 | |
|     pQList->Head = pNewNode;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Reset the linked-list queue and unlink queue nodes.
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_ResetQ(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue parameter */
 | |
|   if (pQList == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue state */
 | |
|   if (pQList->State == HAL_DMA_QUEUE_STATE_BUSY)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_BUSY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head != NULL)
 | |
|   {
 | |
|     /* Get CLLR register mask and offset */
 | |
|     DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
 | |
| 
 | |
|     /* Reset selected queue nodes */
 | |
|     node_info.cllr_offset = cllr_offset;
 | |
|     DMA_List_ResetQueueNodes(pQList, &node_info);
 | |
|   }
 | |
| 
 | |
|   /* Reset head node address */
 | |
|   pQList->Head = NULL;
 | |
| 
 | |
|   /* Reset node number */
 | |
|   pQList->NodeNumber = 0U;
 | |
| 
 | |
|   /* Reset first circular node */
 | |
|   pQList->FirstCircularNode = NULL;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_RESET;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Insert a source linked-list queue to a destination linked-list queue according to selecting previous node.
 | |
|   * @param  pSrcQList  : Pointer to a DMA_QListTypeDef structure that contains source queue information.
 | |
|   * @param  pPrevNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list previous node registers
 | |
|   *                      configurations.
 | |
|   * @param  pDestQList : Pointer to a DMA_QListTypeDef structure that contains destination queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_InsertQ(DMA_QListTypeDef *const pSrcQList,
 | |
|                                          DMA_NodeTypeDef const *const pPrevNode,
 | |
|                                          DMA_QListTypeDef *const pDestQList)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef src_q_node_info;
 | |
|   DMA_NodeInQInfoTypeDef dest_q_node_info;
 | |
| 
 | |
|   /* Check the source and destination queues and the previous node parameters */
 | |
|   if ((pSrcQList == NULL) || (pDestQList == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the source queue */
 | |
|   if (pSrcQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the source queue type */
 | |
|   if (pSrcQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the destination queue type */
 | |
|   if (pDestQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the source queue circularity */
 | |
|   if (pSrcQList->FirstCircularNode != NULL)
 | |
|   {
 | |
|     /* Update the source queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pSrcQList->Head, pPrevNode, pDestQList->Head) != 0U)
 | |
|   {
 | |
|     /* Update the source queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     /* Update the destination queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pSrcQList->Head, pPrevNode, pDestQList->Head) != 0U)
 | |
|   {
 | |
|     /* Update the source queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     /* Update the destination queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the source queue state */
 | |
|   pSrcQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the source queue error code */
 | |
|   pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the destination queue state */
 | |
|   pDestQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the destination queue error code */
 | |
|   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pSrcQList->Head, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Empty destination queue */
 | |
|   if (pDestQList->Head == NULL)
 | |
|   {
 | |
|     pDestQList->Head       = pSrcQList->Head;
 | |
|     pDestQList->NodeNumber = pSrcQList->NodeNumber;
 | |
|   }
 | |
|   /* Not empty destination queue */
 | |
|   else
 | |
|   {
 | |
|     /* Previous node is empty */
 | |
|     if (pPrevNode == NULL)
 | |
|     {
 | |
|       /* Find node and get its position in selected queue */
 | |
|       src_q_node_info.cllr_offset = cllr_offset;
 | |
|       (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
 | |
| 
 | |
|       /* Check if first circular node queue is the first node */
 | |
|       if (pDestQList->FirstCircularNode == pDestQList->Head)
 | |
|       {
 | |
|         /* Find node and get its position in selected queue */
 | |
|         dest_q_node_info.cllr_offset = cllr_offset;
 | |
|         (void)DMA_List_FindNode(pDestQList, NULL, &dest_q_node_info);
 | |
| 
 | |
|         /* Link destination queue tail node to new first circular node */
 | |
|         ((DMA_NodeTypeDef *)dest_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
 | |
|           ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|         /* Set the head node of source queue as the first circular node */
 | |
|         pDestQList->FirstCircularNode = pSrcQList->Head;
 | |
|       }
 | |
| 
 | |
|       /* Link the last node of source queue to the fist node of destination queue */
 | |
|       ((DMA_NodeTypeDef *)(src_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|         ((uint32_t)pDestQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|       pDestQList->Head        = pSrcQList->Head;
 | |
|       pDestQList->NodeNumber += pSrcQList->NodeNumber;
 | |
|     }
 | |
|     /* Previous node is not empty */
 | |
|     else
 | |
|     {
 | |
|       /* Find node and get its position in selected queue */
 | |
|       dest_q_node_info.cllr_offset = cllr_offset;
 | |
|       if (DMA_List_FindNode(pDestQList, pPrevNode, &dest_q_node_info) == 0U)
 | |
|       {
 | |
|         /* Selected node is the last destination queue node */
 | |
|         if (dest_q_node_info.currentnode_pos == pDestQList->NodeNumber)
 | |
|         {
 | |
|           /* Link the first node of source queue to the last node of destination queue */
 | |
|           ((DMA_NodeTypeDef *)(dest_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|             ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|           pDestQList->NodeNumber += pSrcQList->NodeNumber;
 | |
| 
 | |
|           /* Check if first circular node queue is not empty */
 | |
|           if (pDestQList->FirstCircularNode != NULL)
 | |
|           {
 | |
|             /* Find node and get its position in selected queue */
 | |
|             src_q_node_info.cllr_offset = cllr_offset;
 | |
|             (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
 | |
| 
 | |
|             /* Find first circular node */
 | |
|             (void)DMA_List_FindNode(pDestQList, pDestQList->FirstCircularNode, &dest_q_node_info);
 | |
| 
 | |
|             /* Link last source queue node to first destination queue */
 | |
|             ((DMA_NodeTypeDef *)src_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
 | |
|               (dest_q_node_info.currentnode_addr & DMA_CLLR_LA) | cllr_mask;
 | |
|           }
 | |
|         }
 | |
|         /* Selected node is not the last destination queue node */
 | |
|         else
 | |
|         {
 | |
|           /* Link the first node of source queue to the previous node of destination queue */
 | |
|           ((DMA_NodeTypeDef *)(dest_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|             ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|           /* Find node and get its position in selected queue */
 | |
|           src_q_node_info.cllr_offset = cllr_offset;
 | |
|           (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
 | |
| 
 | |
|           /* Link the last node of source queue to the next node of destination queue */
 | |
|           ((DMA_NodeTypeDef *)(src_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|             (dest_q_node_info.nextnode_addr & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|           /* Update queues counter */
 | |
|           pDestQList->NodeNumber += pSrcQList->NodeNumber;
 | |
|         }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         /* Update the destination queue error code */
 | |
|         pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
 | |
| 
 | |
|         return HAL_ERROR;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Clean the source queue variable as it is obsolete */
 | |
|   DMA_List_CleanQueue(pSrcQList);
 | |
| 
 | |
|   /* Update the destination queue error code */
 | |
|   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the destination queue state */
 | |
|   pDestQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(src_q_node_info);
 | |
|   UNUSED(dest_q_node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Insert a source linked-list queue at the head of destination queue.
 | |
|   * @param  pSrcQList  : Pointer to a DMA_QListTypeDef structure that contains source queue information.
 | |
|   * @param  pDestQList : Pointer to a DMA_QListTypeDef structure that contains destination queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_InsertQ_Head(DMA_QListTypeDef *const pSrcQList,
 | |
|                                               DMA_QListTypeDef *const pDestQList)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef src_q_node_info;
 | |
|   DMA_NodeInQInfoTypeDef dest_q_node_info;
 | |
| 
 | |
|   /* Check the source and destination queues and the previous node parameters */
 | |
|   if ((pSrcQList == NULL) || (pDestQList == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the source queue */
 | |
|   if (pSrcQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the source queue type */
 | |
|   if (pSrcQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the destination queue type */
 | |
|   if (pDestQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the source queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     /* Update the destination queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the source queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     /* Update the destination queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the source queue state */
 | |
|   pSrcQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the source queue error code */
 | |
|   pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the destination queue state */
 | |
|   pDestQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the destination queue error code */
 | |
|   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pSrcQList->Head, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Empty destination queue */
 | |
|   if (pDestQList->Head == NULL)
 | |
|   {
 | |
|     pDestQList->Head       = pSrcQList->Head;
 | |
|     pDestQList->NodeNumber = pSrcQList->NodeNumber;
 | |
|   }
 | |
|   /* Not empty destination queue */
 | |
|   else
 | |
|   {
 | |
|     /* Find node and get its position in selected queue */
 | |
|     src_q_node_info.cllr_offset = cllr_offset;
 | |
|     (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
 | |
| 
 | |
|     /* Check if first circular node queue is the first node */
 | |
|     if (pDestQList->FirstCircularNode == pDestQList->Head)
 | |
|     {
 | |
|       /* Find node and get its position in selected queue */
 | |
|       dest_q_node_info.cllr_offset = cllr_offset;
 | |
|       (void)DMA_List_FindNode(pDestQList, NULL, &dest_q_node_info);
 | |
| 
 | |
|       /* Link destination queue tail node to new first circular node */
 | |
|       ((DMA_NodeTypeDef *)dest_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
 | |
|         ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|       /* Set the head node of source queue as the first circular node */
 | |
|       pDestQList->FirstCircularNode = pSrcQList->Head;
 | |
|     }
 | |
| 
 | |
|     /* Link the last node of source queue to the fist node of destination queue */
 | |
|     ((DMA_NodeTypeDef *)(src_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|       ((uint32_t)pDestQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|     pDestQList->Head        = pSrcQList->Head;
 | |
|     pDestQList->NodeNumber += pSrcQList->NodeNumber;
 | |
|   }
 | |
| 
 | |
|   /* Clean the source queue variable as it is obsolete */
 | |
|   DMA_List_CleanQueue(pSrcQList);
 | |
| 
 | |
|   /* Update the destination queue error code */
 | |
|   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the destination queue state */
 | |
|   pDestQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(src_q_node_info);
 | |
|   UNUSED(dest_q_node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Insert a source linked-list queue at the tail of destination queue.
 | |
|   * @param  pSrcQList  : Pointer to a DMA_QListTypeDef structure that contains source queue information.
 | |
|   * @param  pDestQList : Pointer to a DMA_QListTypeDef structure that contains destination queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_InsertQ_Tail(DMA_QListTypeDef *const pSrcQList,
 | |
|                                               DMA_QListTypeDef *const pDestQList)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef src_q_node_info;
 | |
|   DMA_NodeInQInfoTypeDef dest_q_node_info;
 | |
| 
 | |
|   /* Check the source and destination queues and the previous node parameters */
 | |
|   if ((pSrcQList == NULL) || (pDestQList == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the source queue */
 | |
|   if (pSrcQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the source queue type */
 | |
|   if (pSrcQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the destination queue type */
 | |
|   if (pDestQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes base addresses */
 | |
|   if (DMA_List_CheckNodesBaseAddresses(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the source queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     /* Update the destination queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check nodes types compatibility */
 | |
|   if (DMA_List_CheckNodesTypes(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
 | |
|   {
 | |
|     /* Update the source queue error code */
 | |
|     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     /* Update the destination queue error code */
 | |
|     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the source queue state */
 | |
|   pSrcQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the source queue error code */
 | |
|   pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the destination queue state */
 | |
|   pDestQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the destination queue error code */
 | |
|   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pSrcQList->Head, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Empty destination queue */
 | |
|   if (pDestQList->Head == NULL)
 | |
|   {
 | |
|     pDestQList->Head       = pSrcQList->Head;
 | |
|     pDestQList->NodeNumber = pSrcQList->NodeNumber;
 | |
|   }
 | |
|   /* Not empty destination queue */
 | |
|   else
 | |
|   {
 | |
|     /* Find node and get its position in selected queue */
 | |
|     dest_q_node_info.cllr_offset = cllr_offset;
 | |
|     (void)DMA_List_FindNode(pDestQList, NULL, &dest_q_node_info);
 | |
| 
 | |
|     /* Update source queue last node CLLR to link it with destination first node */
 | |
|     ((DMA_NodeTypeDef *)(dest_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|       ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|     pDestQList->NodeNumber += pSrcQList->NodeNumber;
 | |
| 
 | |
|     /* Check if first circular node queue is not empty */
 | |
|     if (pDestQList->FirstCircularNode != NULL)
 | |
|     {
 | |
|       /* Find node and get its position in selected queue */
 | |
|       src_q_node_info.cllr_offset = cllr_offset;
 | |
|       (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
 | |
| 
 | |
|       /* Find first circular node */
 | |
|       (void)DMA_List_FindNode(pDestQList, pDestQList->FirstCircularNode, &dest_q_node_info);
 | |
| 
 | |
|       /* Link last source queue node to first destination queue */
 | |
|       ((DMA_NodeTypeDef *)src_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
 | |
|         (dest_q_node_info.currentnode_addr & DMA_CLLR_LA) | cllr_mask;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Clean the source queue variable as it is obsolete */
 | |
|   DMA_List_CleanQueue(pSrcQList);
 | |
| 
 | |
|   /* Update the destination queue error code */
 | |
|   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the destination queue state */
 | |
|   pDestQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(src_q_node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Set circular mode configuration for linked-list queue.
 | |
|   * @param  pQList             : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pFirstCircularNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list first circular node
 | |
|   *                              registers configurations.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_SetCircularModeConfig(DMA_QListTypeDef *const pQList,
 | |
|                                                        DMA_NodeTypeDef *const pFirstCircularNode)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue and the first circular node parameters */
 | |
|   if ((pQList == NULL) || (pFirstCircularNode == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue circular mode */
 | |
|   if (pQList->FirstCircularNode != NULL)
 | |
|   {
 | |
|     if (pQList->FirstCircularNode == pFirstCircularNode)
 | |
|     {
 | |
|       return HAL_OK;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Update the queue error code */
 | |
|       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|       return HAL_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pFirstCircularNode, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Find the first circular node and get its position in selected queue */
 | |
|   node_info.cllr_offset = cllr_offset;
 | |
|   if (DMA_List_FindNode(pQList, pFirstCircularNode, &node_info) == 0U)
 | |
|   {
 | |
|     /* Find the last queue node and get its position in selected queue */
 | |
|     (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|     /* Set circular mode */
 | |
|     ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|       ((uint32_t)pFirstCircularNode & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|     /* Update first circular node in queue */
 | |
|     pQList->FirstCircularNode = pFirstCircularNode;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Set circular mode for linked-list queue.
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_SetCircularMode(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue parameter */
 | |
|   if (pQList == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue circular mode */
 | |
|   if (pQList->FirstCircularNode != NULL)
 | |
|   {
 | |
|     if (pQList->FirstCircularNode == pQList->Head)
 | |
|     {
 | |
|       return HAL_OK;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Update the queue error code */
 | |
|       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|       return HAL_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pQList->Head, &cllr_mask, &cllr_offset);
 | |
| 
 | |
|   /* Find the last queue node and get its position in selected queue */
 | |
|   node_info.cllr_offset = cllr_offset;
 | |
|   (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|   /* Set circular mode */
 | |
|   ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
 | |
|     ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
| 
 | |
|   /* Update linked-list circular state */
 | |
|   pQList->FirstCircularNode = pQList->Head;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Clear circular mode for linked-list queue.
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_ClearCircularMode(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   uint32_t cllr_offset;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue parameter */
 | |
|   if (pQList == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue circular mode */
 | |
|   if (pQList->FirstCircularNode == NULL)
 | |
|   {
 | |
|     return HAL_OK;
 | |
|   }
 | |
| 
 | |
|   /* Check queue type */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
 | |
| 
 | |
|   /* Find the last queue node and get its position in selected queue */
 | |
|   node_info.cllr_offset = cllr_offset;
 | |
|   (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
| 
 | |
|   /* Clear circular mode */
 | |
|   ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|   /* Update linked-list circular configuration */
 | |
|   pQList->FirstCircularNode = NULL;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   /* Prevent MISRA-C2012-Rule-2.2_b */
 | |
|   UNUSED(node_info);
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Convert a linked-list queue to dynamic (Optimized DMA queue execution).
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_ConvertQToDynamic(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   uint32_t cllr_offset;
 | |
|   uint32_t currentnode_addr;
 | |
|   DMA_NodeTypeDef context_node;
 | |
|   DMA_NodeInQInfoTypeDef node_info;
 | |
| 
 | |
|   /* Check the queue parameter */
 | |
|   if (pQList == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check if queue is dynamic */
 | |
|   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
 | |
|   {
 | |
|     return HAL_OK;
 | |
|   }
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
 | |
| 
 | |
|   /* Check queue circularity */
 | |
|   if (pQList->FirstCircularNode != 0U)
 | |
|   {
 | |
|     /* Find the last queue node and get its position in selected queue */
 | |
|     node_info.cllr_offset = cllr_offset;
 | |
|     (void)DMA_List_FindNode(pQList, NULL, &node_info);
 | |
|   }
 | |
| 
 | |
|   /* Set current node address */
 | |
|   currentnode_addr = (uint32_t)pQList->Head;
 | |
| 
 | |
|   /* Store register value */
 | |
|   DMA_List_FillNode(pQList->Head, &context_node);
 | |
| 
 | |
|   /* Convert all nodes to dyncamic (Bypass head node) */
 | |
|   for (uint32_t node_count = 1U; node_count < pQList->NodeNumber; node_count++)
 | |
|   {
 | |
|     /* Update node address */
 | |
|     MODIFY_REG(currentnode_addr, DMA_CLLR_LA, (context_node.LinkRegisters[cllr_offset] & DMA_CLLR_LA));
 | |
| 
 | |
|     /* Bypass the first circular node when first circular node isn't the last queue node */
 | |
|     if (((uint32_t)pQList->FirstCircularNode != 0U)                         &&
 | |
|         ((uint32_t)pQList->FirstCircularNode != node_info.currentnode_addr) &&
 | |
|         ((uint32_t)pQList->FirstCircularNode == currentnode_addr))
 | |
|     {
 | |
|       /* Copy first circular node to context node */
 | |
|       DMA_List_FillNode(pQList->FirstCircularNode, &context_node);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Convert current node to dynamic */
 | |
|       DMA_List_ConvertNodeToDynamic((uint32_t)&context_node, currentnode_addr, (cllr_offset + 1U));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Check if first circular node is the last node queue */
 | |
|   if (((uint32_t)pQList->FirstCircularNode != 0U) &&
 | |
|       ((uint32_t)pQList->FirstCircularNode != node_info.currentnode_addr))
 | |
|   {
 | |
|     /* Update all queue nodes CLLR */
 | |
|     DMA_List_UpdateDynamicQueueNodesCLLR(pQList, LASTNODE_ISNOT_CIRCULAR);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update all queue nodes CLLR */
 | |
|     DMA_List_UpdateDynamicQueueNodesCLLR(pQList, LASTNODE_IS_CIRCULAR);
 | |
|   }
 | |
| 
 | |
|   /* Set queue type */
 | |
|   pQList->Type = QUEUE_TYPE_DYNAMIC;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Convert a linked-list queue to static (Not optimized DMA queue execution).
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_ConvertQToStatic(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   uint32_t cllr_offset;
 | |
|   uint32_t currentnode_addr;
 | |
|   DMA_NodeTypeDef context_node;
 | |
| 
 | |
|   /* Check the queue parameter */
 | |
|   if (pQList == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the queue */
 | |
|   if (pQList->Head == NULL)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check if queue is static */
 | |
|   if (pQList->Type == QUEUE_TYPE_STATIC)
 | |
|   {
 | |
|     return HAL_OK;
 | |
|   }
 | |
| 
 | |
|   /* Set current node address */
 | |
|   currentnode_addr = (uint32_t)pQList->Head;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Get CLLR register mask and offset */
 | |
|   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
 | |
| 
 | |
|   /* Set all CLLR queue nodes to their default positions */
 | |
|   DMA_List_UpdateStaticQueueNodesCLLR(pQList, UPDATE_CLLR_POSITION);
 | |
| 
 | |
|   /* Convert all nodes to static (Bypass head node) */
 | |
|   for (uint32_t node_count = 1U; node_count < pQList->NodeNumber; node_count++)
 | |
|   {
 | |
|     /* Update context node register values */
 | |
|     DMA_List_FillNode((DMA_NodeTypeDef *)currentnode_addr, &context_node);
 | |
| 
 | |
|     /* Update node address */
 | |
|     MODIFY_REG(currentnode_addr, DMA_CLLR_LA, (context_node.LinkRegisters[cllr_offset] & DMA_CLLR_LA));
 | |
| 
 | |
|     /* Convert current node to static */
 | |
|     DMA_List_ConvertNodeToStatic((uint32_t)&context_node, currentnode_addr, (cllr_offset + 1U));
 | |
|   }
 | |
| 
 | |
|   /* Set all CLLR queue nodes to their default values */
 | |
|   DMA_List_UpdateStaticQueueNodesCLLR(pQList, UPDATE_CLLR_VALUE);
 | |
| 
 | |
|   /* Set queue type */
 | |
|   pQList->Type = QUEUE_TYPE_STATIC;
 | |
| 
 | |
|   /* Update the queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Update the queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_READY;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Link linked-list queue to a DMA channel.
 | |
|   * @param  hdma   : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
 | |
|   *                  specified DMA Channel.
 | |
|   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_LinkQ(DMA_HandleTypeDef *const hdma,
 | |
|                                        DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   HAL_DMA_StateTypeDef state;
 | |
| 
 | |
|   /* Check the DMA channel handle and the queue parameters */
 | |
|   if ((hdma == NULL) || (pQList == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the DMA Mode is not DMA_NORMAL */
 | |
|   if (hdma->Mode == DMA_NORMAL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Get DMA state */
 | |
|   state = hdma->State;
 | |
| 
 | |
|   /* Check DMA channel state */
 | |
|   if ((hdma->State == HAL_DMA_STATE_BUSY) || (state == HAL_DMA_STATE_SUSPEND))
 | |
|   {
 | |
|     /* Update the DMA channel error code */
 | |
|     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
 | |
| 
 | |
|     /* Process unlocked */
 | |
|     __HAL_UNLOCK(hdma);
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check queue state */
 | |
|   if (pQList->State == HAL_DMA_QUEUE_STATE_BUSY)
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_BUSY;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check linearity compatibility */
 | |
|   if ((IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance) == 0U) &&
 | |
|       ((pQList->Head->NodeInfo & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR))
 | |
|   {
 | |
|     /* Update the queue error code */
 | |
|     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_UNSUPPORTED;
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check circularity compatibility */
 | |
|   if (hdma->Mode == DMA_LINKEDLIST_CIRCULAR)
 | |
|   {
 | |
|     /* Check first circular node */
 | |
|     if (pQList->FirstCircularNode == NULL)
 | |
|     {
 | |
|       /* Update the queue error code */
 | |
|       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|       return HAL_ERROR;
 | |
|     }
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Check first circular node */
 | |
|     if (pQList->FirstCircularNode != NULL)
 | |
|     {
 | |
|       /* Update the queue error code */
 | |
|       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
 | |
| 
 | |
|       return HAL_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Register queue to DMA handle */
 | |
|   hdma->LinkedListQueue = pQList;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Unlink linked-list queue from a DMA channel.
 | |
|   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
 | |
|   *                specified DMA Channel.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_List_UnLinkQ(DMA_HandleTypeDef *const hdma)
 | |
| {
 | |
|   HAL_DMA_StateTypeDef state;
 | |
| 
 | |
|   /* Check the DMA channel parameter */
 | |
|   if (hdma == NULL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the DMA Mode is not DMA_NORMAL */
 | |
|   if (hdma->Mode == DMA_NORMAL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Get DMA state */
 | |
|   state = hdma->State;
 | |
| 
 | |
|   /* Check DMA channel state */
 | |
|   if ((hdma->State == HAL_DMA_STATE_BUSY) || (state == HAL_DMA_STATE_SUSPEND))
 | |
|   {
 | |
|     /* Update the DMA channel error code */
 | |
|     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
 | |
| 
 | |
|     /* Process unlocked */
 | |
|     __HAL_UNLOCK(hdma);
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Clear queue information from DMA channel handle */
 | |
|   hdma->LinkedListQueue = NULL;
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| /** @addtogroup DMAEx_Exported_Functions_Group4
 | |
|   *
 | |
| @verbatim
 | |
|   ======================================================================================================================
 | |
|              ##### Data handling, repeated block and trigger configuration functions #####
 | |
|   ======================================================================================================================
 | |
|     [..]
 | |
|       This section provides functions allowing to :
 | |
|       (+) Configure DMA channel data handling.
 | |
|       (+) Configure DMA channel repeated block.
 | |
|       (+) Configure DMA channel trigger.
 | |
| 
 | |
|     [..]
 | |
|       (+) The HAL_DMAEx_ConfigDataHandling() function allows to configure DMA channel data handling.
 | |
|               (++) GPDMA data handling : byte-based reordering, packing/unpacking, padding/truncation, sign extension
 | |
|                                          and left/right alignment.
 | |
| 
 | |
|       (+) The HAL_DMAEx_ConfigTrigger() function allows to configure DMA channel HW triggers.
 | |
| 
 | |
|       (+) The HAL_DMAEx_ConfigRepeatBlock() function allows to configure DMA channel repeated block.
 | |
|               (++) This feature is available only for channel that supports 2 dimensions addressing capability.
 | |
| 
 | |
| @endverbatim
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @brief  Configure the DMA channel data handling according to the specified parameters in the
 | |
|   *         DMA_DataHandlingConfTypeDef.
 | |
|   * @param  hdma                : Pointer to a DMA_HandleTypeDef structure that contains the configuration information
 | |
|   *                               for the specified DMA Channel.
 | |
|   * @param  pConfigDataHandling : Pointer to a DMA_DataHandlingConfTypeDef structure that contains the data handling
 | |
|   *                               configuration.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_ConfigDataHandling(DMA_HandleTypeDef *const hdma,
 | |
|                                                DMA_DataHandlingConfTypeDef const *const pConfigDataHandling)
 | |
| {
 | |
|   /* Check the DMA peripheral handle and data handling parameters */
 | |
|   if ((hdma == NULL) || (pConfigDataHandling == 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_DATA_ALIGNMENT(pConfigDataHandling->DataAlignment));
 | |
|   assert_param(IS_DMA_DATA_EXCHANGE(pConfigDataHandling->DataExchange));
 | |
| 
 | |
|   /* Check DMA channel state */
 | |
|   if (hdma->State == HAL_DMA_STATE_READY)
 | |
|   {
 | |
|     MODIFY_REG(hdma->Instance->CTR1, (DMA_CTR1_DHX | DMA_CTR1_DBX | DMA_CTR1_SBX | DMA_CTR1_PAM),
 | |
|                (pConfigDataHandling->DataAlignment | pConfigDataHandling->DataExchange));
 | |
|   }
 | |
|   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  Configure the DMA channel trigger according to the specified parameters in the DMA_TriggerConfTypeDef.
 | |
|   * @param  hdma           : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for
 | |
|   *                          the specified DMA Channel.
 | |
|   * @param  pConfigTrigger : Pointer to a DMA_TriggerConfTypeDef structure that contains the trigger configuration.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_ConfigTrigger(DMA_HandleTypeDef *const hdma,
 | |
|                                           DMA_TriggerConfTypeDef const *const pConfigTrigger)
 | |
| {
 | |
|   /* Check the DMA peripheral handle and trigger parameters */
 | |
|   if ((hdma == NULL) || (pConfigTrigger == 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_ALL_INSTANCE(hdma->Instance));
 | |
|   assert_param(IS_DMA_TRIGGER_POLARITY(pConfigTrigger->TriggerPolarity));
 | |
|   assert_param(IS_DMA_TRIGGER_MODE(pConfigTrigger->TriggerMode));
 | |
|   assert_param(IS_DMA_TRIGGER_SELECTION(pConfigTrigger->TriggerSelection));
 | |
| 
 | |
|   /* Check DMA channel state */
 | |
|   if (hdma->State == HAL_DMA_STATE_READY)
 | |
|   {
 | |
|     MODIFY_REG(hdma->Instance->CTR2, (DMA_CTR2_TRIGPOL | DMA_CTR2_TRIGSEL | DMA_CTR2_TRIGM),
 | |
|                (pConfigTrigger->TriggerPolarity | pConfigTrigger->TriggerMode |
 | |
|                 (pConfigTrigger->TriggerSelection << DMA_CTR2_TRIGSEL_Pos)));
 | |
|   }
 | |
|   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  Configure the DMA channel repeated block according to the specified parameters in the
 | |
|   *         DMA_RepeatBlockConfTypeDef.
 | |
|   * @param  hdma               : Pointer to a DMA_HandleTypeDef structure that contains the configuration information
 | |
|   *                              for the specified DMA Channel.
 | |
|   * @param  pConfigRepeatBlock : Pointer to a DMA_RepeatBlockConfTypeDef structure that contains the repeated block
 | |
|   *                              configuration.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_ConfigRepeatBlock(DMA_HandleTypeDef *const hdma,
 | |
|                                               DMA_RepeatBlockConfTypeDef const *const pConfigRepeatBlock)
 | |
| {
 | |
|   uint32_t tmpreg1;
 | |
|   uint32_t tmpreg2;
 | |
| 
 | |
|   /* Check the DMA peripheral handle and repeated block parameters */
 | |
|   if ((hdma == NULL) || (pConfigRepeatBlock == NULL))
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check the DMA Mode is DMA_NORMAL */
 | |
|   if (hdma->Mode != DMA_NORMAL)
 | |
|   {
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   /* Check parameters */
 | |
|   assert_param(IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance));
 | |
|   assert_param(IS_DMA_REPEAT_COUNT(pConfigRepeatBlock->RepeatCount));
 | |
|   assert_param(IS_DMA_BURST_ADDR_OFFSET(pConfigRepeatBlock->SrcAddrOffset));
 | |
|   assert_param(IS_DMA_BURST_ADDR_OFFSET(pConfigRepeatBlock->DestAddrOffset));
 | |
|   assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pConfigRepeatBlock->BlkSrcAddrOffset));
 | |
|   assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pConfigRepeatBlock->BlkDestAddrOffset));
 | |
| 
 | |
|   /* Check DMA channel state */
 | |
|   if (hdma->State == HAL_DMA_STATE_READY)
 | |
|   {
 | |
|     /* Store repeat block count */
 | |
|     tmpreg1 = ((pConfigRepeatBlock->RepeatCount - 1U) << DMA_CBR1_BRC_Pos);
 | |
| 
 | |
|     /* Check the sign of single/burst destination address offset value */
 | |
|     if (pConfigRepeatBlock->DestAddrOffset < 0)
 | |
|     {
 | |
|       /* Store single/burst destination address offset configuration (signed case) */
 | |
|       tmpreg1 |= DMA_CBR1_DDEC;
 | |
|       tmpreg2 = (uint32_t)(- pConfigRepeatBlock->DestAddrOffset);
 | |
|       tmpreg2 = tmpreg2 << DMA_CTR3_DAO_Pos;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Store single/burst destination address offset configuration (unsigned case) */
 | |
|       tmpreg2 = ((uint32_t)pConfigRepeatBlock->DestAddrOffset << DMA_CTR3_DAO_Pos);
 | |
|     }
 | |
| 
 | |
|     /* Check the sign of single/burst source address offset value */
 | |
|     if (pConfigRepeatBlock->SrcAddrOffset < 0)
 | |
|     {
 | |
|       /* Store single/burst source address offset configuration (signed case) */
 | |
|       tmpreg1 |= DMA_CBR1_SDEC;
 | |
|       tmpreg2 |= (uint32_t)(- pConfigRepeatBlock->SrcAddrOffset);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Store single/burst source address offset configuration (unsigned case) */
 | |
|       tmpreg2 |= (uint32_t)pConfigRepeatBlock->SrcAddrOffset;
 | |
|     }
 | |
| 
 | |
|     /* Write DMA Channel Transfer Register 3 (CTR3) */
 | |
|     WRITE_REG(hdma->Instance->CTR3, tmpreg2);
 | |
| 
 | |
|     /* Check the sign of block destination address offset value */
 | |
|     if (pConfigRepeatBlock->BlkDestAddrOffset < 0)
 | |
|     {
 | |
|       /* Store block destination address offset configuration (signed case) */
 | |
|       tmpreg1 |= DMA_CBR1_BRDDEC;
 | |
|       tmpreg2 = (uint32_t)(- pConfigRepeatBlock->BlkDestAddrOffset);
 | |
|       tmpreg2 = tmpreg2 << DMA_CBR2_BRDAO_Pos;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Store block destination address offset configuration (unsigned case) */
 | |
|       tmpreg2 = ((uint32_t)pConfigRepeatBlock->BlkDestAddrOffset << DMA_CBR2_BRDAO_Pos);
 | |
|     }
 | |
| 
 | |
|     /* Check the sign of block source address offset value */
 | |
|     if (pConfigRepeatBlock->BlkSrcAddrOffset < 0)
 | |
|     {
 | |
|       /* Store block source address offset configuration (signed case) */
 | |
|       tmpreg1 |= DMA_CBR1_BRSDEC;
 | |
|       tmpreg2 |= (uint32_t)(- pConfigRepeatBlock->BlkSrcAddrOffset);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Store block source address offset configuration (unsigned case) */
 | |
|       tmpreg2 |= (uint32_t)pConfigRepeatBlock->BlkSrcAddrOffset;
 | |
|     }
 | |
| 
 | |
|     /* Write DMA Channel block register 2 (CBR2) */
 | |
|     WRITE_REG(hdma->Instance->CBR2, tmpreg2);
 | |
| 
 | |
|     /* Write DMA Channel block register 1 (CBR1) */
 | |
|     WRITE_REG(hdma->Instance->CBR1, tmpreg1);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update the DMA channel error code */
 | |
|     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
 | |
| 
 | |
|     /* Process unlocked */
 | |
|     __HAL_UNLOCK(hdma);
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| /** @addtogroup DMAEx_Exported_Functions_Group5
 | |
|   *
 | |
| @verbatim
 | |
|   ======================================================================================================================
 | |
|                          ##### Suspend and resume operation functions #####
 | |
|   ======================================================================================================================
 | |
|     [..]
 | |
|       This section provides functions allowing to :
 | |
|       (+) Suspend any ongoing DMA channel transfer.
 | |
|       (+) Resume any suspended DMA channel transfer.
 | |
| 
 | |
|     [..]
 | |
|       (+) The HAL_DMAEx_Suspend() function allows to suspend any ongoing DMA channel transfer in polling mode (Blocking
 | |
|           mode).
 | |
| 
 | |
|       (+) The HAL_DMAEx_Suspend_IT() function allows to suspend any ongoing DMA channel transfer in interrupt mode
 | |
|          (Non-blocking mode).
 | |
| 
 | |
|       (+) The HAL_DMAEx_Resume() function allows to resume any suspended DMA channel transfer.
 | |
| 
 | |
| @endverbatim
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @brief  Suspend any ongoing DMA channel transfer in polling mode (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 check for wait until the DMA channel is effectively suspended is added. If
 | |
|   *         a channel is suspended while a data transfer is ongoing, the current data will be transferred and the
 | |
|   *         channel will be effectively suspended only after the transfer of this single/burst data is finished.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_Suspend(DMA_HandleTypeDef *const hdma)
 | |
| {
 | |
|   /* Get tick number */
 | |
|   uint32_t tickstart = HAL_GetTick();
 | |
| 
 | |
|   /* Check the DMA peripheral handle */
 | |
|   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;
 | |
| 
 | |
|     /* 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;
 | |
| 
 | |
|         /* Process Unlocked */
 | |
|         __HAL_UNLOCK(hdma);
 | |
| 
 | |
|         return HAL_ERROR;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     /* Update the DMA channel state */
 | |
|     hdma->State = HAL_DMA_STATE_SUSPEND;
 | |
|   }
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Suspend any ongoing DMA channel transfer in polling 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_DMAEx_Suspend_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;
 | |
| 
 | |
|     /* Process unlocked */
 | |
|     __HAL_UNLOCK(hdma);
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Suspend the DMA channel and activate suspend interrupt */
 | |
|     hdma->Instance->CCR |= (DMA_CCR_SUSP | DMA_CCR_SUSPIE);
 | |
|   }
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Resume any suspended DMA channel transfer.
 | |
|   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
 | |
|   *                specified DMA Channel.
 | |
|   * @retval HAL status.
 | |
|   */
 | |
| HAL_StatusTypeDef HAL_DMAEx_Resume(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_SUSPEND)
 | |
|   {
 | |
|     /* Update the DMA channel error code */
 | |
|     hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
 | |
| 
 | |
|     /* Process unlocked */
 | |
|     __HAL_UNLOCK(hdma);
 | |
| 
 | |
|     return HAL_ERROR;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Resume the DMA channel */
 | |
|     hdma->Instance->CCR &= (~DMA_CCR_SUSP);
 | |
| 
 | |
|     /* Clear the suspend flag */
 | |
|     hdma->Instance->CFCR |= DMA_CFCR_SUSPF;
 | |
| 
 | |
|     /* Update the DMA channel state */
 | |
|     hdma->State = HAL_DMA_STATE_BUSY;
 | |
|   }
 | |
| 
 | |
|   return HAL_OK;
 | |
| }
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| /** @addtogroup DMAEx_Exported_Functions_Group6
 | |
|   *
 | |
| @verbatim
 | |
|   ======================================================================================================================
 | |
|                                ##### Fifo status function #####
 | |
|   ======================================================================================================================
 | |
|     [..]
 | |
|       This section provides function allowing to get DMA channel FIFO level.
 | |
| 
 | |
|     [..]
 | |
|       (+) The HAL_DMAEx_GetFifoLevel() function allows to return the number of available write beats in the FIFO, in
 | |
|           units of the programmed destination data.
 | |
|               (++) This API is available only for DMA channels that supports FIFO.
 | |
| 
 | |
| @endverbatim
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @brief  Get and returns the DMA channel FIFO level.
 | |
|   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
 | |
|   *                specified DMA Channel.
 | |
|   * @retval Returns the number of available beats in FIFO.
 | |
|   */
 | |
| uint32_t HAL_DMAEx_GetFifoLevel(DMA_HandleTypeDef const *const hdma)
 | |
| {
 | |
|   return ((hdma->Instance->CSR & DMA_CSR_FIFOL) >> DMA_CSR_FIFOL_Pos);
 | |
| }
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| /* Private functions -------------------------------------------------------------------------------------------------*/
 | |
| /** @defgroup DMAEx_Private_Functions DMAEx Private Functions
 | |
|   * @brief    DMAEx Private Functions
 | |
|   * @{
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @brief  Initialize the DMA handle 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_List_Init(DMA_HandleTypeDef const *const hdma)
 | |
| {
 | |
|   uint32_t tmpreg;
 | |
| 
 | |
|   /* Prepare DMA Channel Control Register (CCR) value */
 | |
|   tmpreg = hdma->InitLinkedList.Priority | hdma->InitLinkedList.LinkStepMode;
 | |
| 
 | |
|   /* Check DMA channel instance */
 | |
|   if (IS_GPDMA_INSTANCE(hdma->Instance) != 0U)
 | |
|   {
 | |
|     tmpreg |= hdma->InitLinkedList.LinkAllocatedPort;
 | |
|   }
 | |
| 
 | |
|   /* Write DMA Channel Control Register (CCR) */
 | |
|   MODIFY_REG(hdma->Instance->CCR, DMA_CCR_PRIO | DMA_CCR_LAP | DMA_CCR_LSM, tmpreg);
 | |
| 
 | |
|   /* Write DMA Channel Control Register (CTR1) */
 | |
|   WRITE_REG(hdma->Instance->CTR1, 0U);
 | |
| 
 | |
|   /* Write DMA Channel Control Register (CTR2) */
 | |
|   WRITE_REG(hdma->Instance->CTR2, hdma->InitLinkedList.TransferEventMode);
 | |
| 
 | |
|   /* Write DMA Channel Control Register (CBR1) */
 | |
|   WRITE_REG(hdma->Instance->CBR1, 0U);
 | |
| 
 | |
|   /* Write DMA Channel Control Register (CSAR) */
 | |
|   WRITE_REG(hdma->Instance->CSAR, 0U);
 | |
| 
 | |
|   /* Write DMA Channel Control Register (CDAR) */
 | |
|   WRITE_REG(hdma->Instance->CDAR, 0U);
 | |
| 
 | |
|   /* If 2D Addressing is supported by current channel */
 | |
|   if (IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance) != 0U)
 | |
|   {
 | |
|     /* Write DMA Channel Control Register (CTR3) */
 | |
|     WRITE_REG(hdma->Instance->CTR3, 0U);
 | |
| 
 | |
|     /* Write DMA Channel Control Register (CBR2) */
 | |
|     WRITE_REG(hdma->Instance->CBR2, 0U);
 | |
|   }
 | |
| 
 | |
|   /* Write DMA Channel linked-list address register (CLLR) */
 | |
|   WRITE_REG(hdma->Instance->CLLR, 0U);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Build a DMA channel node according to the specified parameters in the DMA_NodeConfTypeDef.
 | |
|   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
 | |
|   *                       specified DMA linked-list Node.
 | |
|   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
 | |
|   *                       configurations.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_BuildNode(DMA_NodeConfTypeDef const *const pNodeConfig,
 | |
|                                DMA_NodeTypeDef *const pNode)
 | |
| {
 | |
|   int32_t blockoffset;
 | |
| 
 | |
|   /* Update CTR1 register value ***************************************************************************************/
 | |
|   /* Prepare DMA channel transfer register (CTR1) value */
 | |
|   pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] = pNodeConfig->Init.DestInc                     |
 | |
|                                                    pNodeConfig->Init.DestDataWidth               |
 | |
|                                                    pNodeConfig->DataHandlingConfig.DataAlignment |
 | |
|                                                    pNodeConfig->Init.SrcInc                      |
 | |
|                                                    pNodeConfig->Init.SrcDataWidth;
 | |
| 
 | |
| #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
 | |
|   /* set source channel security attribute */
 | |
|   if (pNodeConfig->SrcSecure == DMA_CHANNEL_SRC_SEC)
 | |
|   {
 | |
|     pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] |= DMA_CTR1_SSEC;
 | |
|   }
 | |
| 
 | |
|   /* set destination channel security attribute */
 | |
|   if (pNodeConfig->DestSecure == DMA_CHANNEL_DEST_SEC)
 | |
|   {
 | |
|     pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] |= DMA_CTR1_DSEC;
 | |
|   }
 | |
| #endif /* (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */
 | |
| 
 | |
|   /* Add parameters related to DMA configuration */
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_GPDMA) == DMA_CHANNEL_TYPE_GPDMA)
 | |
|   {
 | |
|     /* Prepare DMA channel transfer register (CTR1) value */
 | |
|     pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] |=
 | |
|       (pNodeConfig->Init.TransferAllocatedPort | pNodeConfig->DataHandlingConfig.DataExchange |
 | |
|        (((pNodeConfig->Init.DestBurstLength - 1U) << DMA_CTR1_DBL_1_Pos) & DMA_CTR1_DBL_1)    |
 | |
|        (((pNodeConfig->Init.SrcBurstLength - 1U) << DMA_CTR1_SBL_1_Pos) & DMA_CTR1_SBL_1));
 | |
|   }
 | |
|   /*********************************************************************************** CTR1 register value is updated */
 | |
| 
 | |
| 
 | |
|   /* Update CTR2 register value ***************************************************************************************/
 | |
|   /* Prepare DMA channel transfer register 2 (CTR2) value */
 | |
|   pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] = pNodeConfig->Init.TransferEventMode |
 | |
|                                                    (pNodeConfig->Init.Request & (DMA_CTR2_REQSEL | DMA_CTR2_SWREQ));
 | |
| 
 | |
|   /* Check for memory to peripheral transfer */
 | |
|   if ((pNodeConfig->Init.Direction) == DMA_MEMORY_TO_PERIPH)
 | |
|   {
 | |
|     /* Check for GPDMA */
 | |
|     if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_GPDMA) == DMA_CHANNEL_TYPE_GPDMA)
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |= DMA_CTR2_DREQ;
 | |
|     }
 | |
|   }
 | |
|   /* Memory to memory transfer */
 | |
|   else if ((pNodeConfig->Init.Direction) == DMA_MEMORY_TO_MEMORY)
 | |
|   {
 | |
|     pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |= DMA_CTR2_SWREQ;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Prevent MISRA-C2012-Rule-15.7 */
 | |
|   }
 | |
| 
 | |
|   /* Configure HW Peripheral flow control selection */
 | |
|   pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |= pNodeConfig->Init.Mode;
 | |
| 
 | |
|   /* Check if trigger feature is active */
 | |
|   if (pNodeConfig->TriggerConfig.TriggerPolarity != DMA_TRIG_POLARITY_MASKED)
 | |
|   {
 | |
|     /* Prepare DMA channel transfer register 2 (CTR2) value */
 | |
|     pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |=
 | |
|       pNodeConfig->TriggerConfig.TriggerMode | pNodeConfig->TriggerConfig.TriggerPolarity |
 | |
|       ((pNodeConfig->TriggerConfig.TriggerSelection << DMA_CTR2_TRIGSEL_Pos) & DMA_CTR2_TRIGSEL);
 | |
|   }
 | |
|   /*********************************************************************************** CTR2 register value is updated */
 | |
| 
 | |
| 
 | |
|   /* Update CBR1 register value ***************************************************************************************/
 | |
|   /* Prepare DMA channel block register 1 (CBR1) value */
 | |
|   pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] = (pNodeConfig->DataSize & DMA_CBR1_BNDT);
 | |
| 
 | |
|   /* If 2D addressing is supported by the selected DMA channel */
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
 | |
|   {
 | |
|     /* Set the new CBR1 Register value */
 | |
|     pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |=
 | |
|       (((pNodeConfig->RepeatBlockConfig.RepeatCount - 1U) << DMA_CBR1_BRC_Pos) & DMA_CBR1_BRC);
 | |
| 
 | |
|     /* If the source address offset is negative, set SDEC bit */
 | |
|     if (pNodeConfig->RepeatBlockConfig.SrcAddrOffset < 0)
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_SDEC;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_SDEC);
 | |
|     }
 | |
| 
 | |
|     /* If the destination address offset is negative, set DDEC bit */
 | |
|     if (pNodeConfig->RepeatBlockConfig.DestAddrOffset < 0)
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_DDEC;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_DDEC);
 | |
|     }
 | |
| 
 | |
|     /* If the repeated block source address offset is negative, set BRSEC bit */
 | |
|     if (pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset < 0)
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_BRSDEC;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_BRSDEC);
 | |
|     }
 | |
| 
 | |
|     /* if the repeated block destination address offset is negative, set BRDEC bit */
 | |
|     if (pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset < 0)
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_BRDDEC;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_BRDDEC);
 | |
|     }
 | |
|   }
 | |
|   /*********************************************************************************** CBR1 register value is updated */
 | |
| 
 | |
| 
 | |
|   /* Update CSAR register value ***************************************************************************************/
 | |
|   pNode->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET] = pNodeConfig->SrcAddress;
 | |
|   /*********************************************************************************** CSAR register value is updated */
 | |
| 
 | |
| 
 | |
|   /* Update CDAR register value ***************************************************************************************/
 | |
|   pNode->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] = pNodeConfig->DstAddress;
 | |
|   /*********************************************************************************** CDAR register value is updated */
 | |
| 
 | |
|   /* Check if the selected channel is 2D addressing */
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
 | |
|   {
 | |
|     /* Update CTR3 register value *************************************************************************************/
 | |
|     /* Write new CTR3 Register value : source address offset */
 | |
|     if (pNodeConfig->RepeatBlockConfig.SrcAddrOffset < 0)
 | |
|     {
 | |
|       blockoffset = (- pNodeConfig->RepeatBlockConfig.SrcAddrOffset);
 | |
|       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] = ((uint32_t)blockoffset & DMA_CTR3_SAO);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] =
 | |
|         ((uint32_t)pNodeConfig->RepeatBlockConfig.SrcAddrOffset & DMA_CTR3_SAO);
 | |
|     }
 | |
| 
 | |
|     /* Write new CTR3 Register value : destination address offset */
 | |
|     if (pNodeConfig->RepeatBlockConfig.DestAddrOffset < 0)
 | |
|     {
 | |
|       blockoffset = (- pNodeConfig->RepeatBlockConfig.DestAddrOffset);
 | |
|       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] |= (((uint32_t)blockoffset << DMA_CTR3_DAO_Pos) & DMA_CTR3_DAO);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] |=
 | |
|         (((uint32_t)pNodeConfig->RepeatBlockConfig.DestAddrOffset << DMA_CTR3_DAO_Pos) & DMA_CTR3_DAO);
 | |
|     }
 | |
|     /********************************************************************************* CTR3 register value is updated */
 | |
| 
 | |
| 
 | |
|     /* Update CBR2 register value *************************************************************************************/
 | |
|     /* Write new CBR2 Register value : repeated block source address offset */
 | |
|     if (pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset < 0)
 | |
|     {
 | |
|       blockoffset = (- pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset);
 | |
|       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] = ((uint32_t)blockoffset & DMA_CBR2_BRSAO);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] =
 | |
|         ((uint32_t)pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset & DMA_CBR2_BRSAO);
 | |
|     }
 | |
| 
 | |
|     /* Write new CBR2 Register value : repeated block destination address offset */
 | |
|     if (pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset < 0)
 | |
|     {
 | |
|       blockoffset = (- pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset);
 | |
|       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] |=
 | |
|         (((uint32_t)blockoffset & DMA_CBR2_BRSAO) << DMA_CBR2_BRDAO_Pos);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] |=
 | |
|         (((uint32_t)pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset << DMA_CBR2_BRDAO_Pos) & DMA_CBR2_BRDAO);
 | |
|     }
 | |
|     /********************************************************************************* CBR2 register value is updated */
 | |
| 
 | |
|     /* Update CLLR register value *************************************************************************************/
 | |
|     /* Reset CLLR Register value : channel linked-list address register offset */
 | |
|     pNode->LinkRegisters[NODE_CLLR_2D_DEFAULT_OFFSET] = 0U;
 | |
|     /********************************************************************************* CLLR register value is cleared */
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Update CLLR register value *************************************************************************************/
 | |
|     /* Reset CLLR Register value : channel linked-list address register offset */
 | |
|     pNode->LinkRegisters[NODE_CLLR_LINEAR_DEFAULT_OFFSET] = 0U;
 | |
|     /********************************************************************************* CLLR register value is cleared */
 | |
|   }
 | |
| 
 | |
|   /* Update node information value ************************************************************************************/
 | |
|   /* Set node information */
 | |
|   pNode->NodeInfo = pNodeConfig->NodeType;
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
 | |
|   {
 | |
|     pNode->NodeInfo |= (NODE_CLLR_2D_DEFAULT_OFFSET << NODE_CLLR_IDX_POS);
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     pNode->NodeInfo |= (NODE_CLLR_LINEAR_DEFAULT_OFFSET << NODE_CLLR_IDX_POS);
 | |
|   }
 | |
|   /******************************************************************************** Node information value is updated */
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Get a DMA channel node configuration.
 | |
|   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
 | |
|   *                       specified DMA linked-list Node.
 | |
|   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
 | |
|   *                       configurations.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_GetNodeConfig(DMA_NodeConfTypeDef *const pNodeConfig,
 | |
|                                    DMA_NodeTypeDef const *const pNode)
 | |
| {
 | |
|   uint16_t offset;
 | |
| 
 | |
|   /* Get node information *********************************************************************************************/
 | |
|   pNodeConfig->NodeType = (pNode->NodeInfo & NODE_TYPE_MASK);
 | |
|   /*************************************************************************************** Node type value is updated */
 | |
| 
 | |
| 
 | |
|   /* Get CTR1 fields values *******************************************************************************************/
 | |
|   pNodeConfig->Init.SrcInc                      = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_SINC;
 | |
|   pNodeConfig->Init.DestInc                     = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_DINC;
 | |
|   pNodeConfig->Init.SrcDataWidth                = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_SDW_LOG2;
 | |
|   pNodeConfig->Init.DestDataWidth               = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_DDW_LOG2;
 | |
|   pNodeConfig->Init.SrcBurstLength              = ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] &
 | |
|                                                     DMA_CTR1_SBL_1) >> DMA_CTR1_SBL_1_Pos) + 1U;
 | |
|   pNodeConfig->Init.DestBurstLength             = ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] &
 | |
|                                                     DMA_CTR1_DBL_1) >> DMA_CTR1_DBL_1_Pos) + 1U;
 | |
|   pNodeConfig->Init.TransferAllocatedPort       = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   &
 | |
|                                                   (DMA_CTR1_SAP | DMA_CTR1_DAP);
 | |
|   pNodeConfig->DataHandlingConfig.DataExchange  = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   &
 | |
|                                                   (DMA_CTR1_SBX | DMA_CTR1_DBX | DMA_CTR1_DHX);
 | |
|   pNodeConfig->DataHandlingConfig.DataAlignment = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_PAM;
 | |
| #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
 | |
|   if ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] & DMA_CTR1_SSEC) != 0U)
 | |
|   {
 | |
|     pNodeConfig->SrcSecure = DMA_CHANNEL_SRC_SEC;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     pNodeConfig->SrcSecure = DMA_CHANNEL_SRC_NSEC;
 | |
|   }
 | |
| 
 | |
|   if ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] & DMA_CTR1_DSEC) != 0U)
 | |
|   {
 | |
|     pNodeConfig->DestSecure = DMA_CHANNEL_DEST_SEC;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     pNodeConfig->DestSecure = DMA_CHANNEL_DEST_NSEC;
 | |
|   }
 | |
| #endif /* (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) */
 | |
|   /*********************************************************************************** CTR1 fields values are updated */
 | |
| 
 | |
| 
 | |
|   /* Get CTR2 fields values *******************************************************************************************/
 | |
|   if ((pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_SWREQ) != 0U)
 | |
|   {
 | |
|     pNodeConfig->Init.Request   = DMA_REQUEST_SW;
 | |
|     pNodeConfig->Init.Direction = DMA_MEMORY_TO_MEMORY;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     pNodeConfig->Init.Request   = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_REQSEL;
 | |
| 
 | |
|     if ((pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_DREQ) != 0U)
 | |
|     {
 | |
|       pNodeConfig->Init.Direction = DMA_MEMORY_TO_PERIPH;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       pNodeConfig->Init.Direction = DMA_PERIPH_TO_MEMORY;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   pNodeConfig->Init.BlkHWRequest              = (pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_BREQ);
 | |
|   pNodeConfig->TriggerConfig.TriggerMode      = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET]  & DMA_CTR2_TRIGM;
 | |
|   pNodeConfig->TriggerConfig.TriggerPolarity  = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET]  & DMA_CTR2_TRIGPOL;
 | |
|   pNodeConfig->TriggerConfig.TriggerSelection = (pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] &
 | |
|                                                  DMA_CTR2_TRIGSEL) >> DMA_CTR2_TRIGSEL_Pos;
 | |
|   pNodeConfig->Init.TransferEventMode         = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET]  & DMA_CTR2_TCEM;
 | |
|   /*********************************************************************************** CTR2 fields values are updated */
 | |
| 
 | |
| 
 | |
|   /* Get CBR1 fields **************************************************************************************************/
 | |
|   pNodeConfig->DataSize = pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BNDT;
 | |
| 
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
 | |
|   {
 | |
|     pNodeConfig->RepeatBlockConfig.RepeatCount =
 | |
|       ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BRC) >> DMA_CBR1_BRC_Pos) + 1U;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     pNodeConfig->RepeatBlockConfig.RepeatCount = 1U;
 | |
|   }
 | |
|   /*********************************************************************************** CBR1 fields values are updated */
 | |
| 
 | |
| 
 | |
|   /* Get CSAR field ***************************************************************************************************/
 | |
|   pNodeConfig->SrcAddress = pNode->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET];
 | |
|   /************************************************************************************** CSAR field value is updated */
 | |
| 
 | |
| 
 | |
|   /* Get CDAR field ***************************************************************************************************/
 | |
|   pNodeConfig->DstAddress = pNode->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET];
 | |
|   /************************************************************************************** CDAR field value is updated */
 | |
| 
 | |
|   /* Check if the selected channel is 2D addressing */
 | |
|   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
 | |
|   {
 | |
|     /* Get CTR3 field *************************************************************************************************/
 | |
|     offset = (uint16_t)(pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] & DMA_CTR3_SAO);
 | |
|     pNodeConfig->RepeatBlockConfig.SrcAddrOffset  = (int32_t)offset;
 | |
| 
 | |
|     offset = (uint16_t)((pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] & DMA_CTR3_DAO) >> DMA_CTR3_DAO_Pos);
 | |
|     pNodeConfig->RepeatBlockConfig.DestAddrOffset = (int32_t)offset;
 | |
| 
 | |
|     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_SDEC) != 0U)
 | |
|     {
 | |
|       pNodeConfig->RepeatBlockConfig.SrcAddrOffset *= (-1);
 | |
|     }
 | |
| 
 | |
|     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_DDEC) != 0U)
 | |
|     {
 | |
|       pNodeConfig->RepeatBlockConfig.DestAddrOffset *= (-1);
 | |
|     }
 | |
|     /************************************************************************************ CTR3 field value is updated */
 | |
| 
 | |
| 
 | |
|     /* Get CBR2 fields ************************************************************************************************/
 | |
|     offset = (uint16_t)(pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] & DMA_CBR2_BRSAO);
 | |
|     pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset = (int32_t)offset;
 | |
| 
 | |
|     offset = (uint16_t)((pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] & DMA_CBR2_BRDAO) >> DMA_CBR2_BRDAO_Pos);
 | |
|     pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset = (int32_t)offset;
 | |
| 
 | |
|     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BRSDEC) != 0U)
 | |
|     {
 | |
|       pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset *= (-1);
 | |
|     }
 | |
| 
 | |
|     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BRDDEC) != 0U)
 | |
|     {
 | |
|       pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset *= (-1);
 | |
|     }
 | |
|     /************************************************************************************ CBR2 field value is updated */
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Get CTR3 field *************************************************************************************************/
 | |
|     pNodeConfig->RepeatBlockConfig.SrcAddrOffset     = 0;
 | |
|     pNodeConfig->RepeatBlockConfig.DestAddrOffset    = 0;
 | |
|     /************************************************************************************ CTR3 field value is updated */
 | |
| 
 | |
| 
 | |
|     /* Get CBR2 fields ************************************************************************************************/
 | |
|     pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset  = 0;
 | |
|     pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset = 0;
 | |
|     /************************************************************************************ CBR2 field value is updated */
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Check nodes base addresses compatibility.
 | |
|   * @param  pNode1 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 1 registers configurations.
 | |
|   * @param  pNode2 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 2 registers configurations.
 | |
|   * @param  pNode3 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 3 registers configurations.
 | |
|   * @retval Return 0 when nodes addresses are compatible, 1 otherwise.
 | |
|   */
 | |
| static uint32_t DMA_List_CheckNodesBaseAddresses(DMA_NodeTypeDef const *const pNode1,
 | |
|                                                  DMA_NodeTypeDef const *const pNode2,
 | |
|                                                  DMA_NodeTypeDef const *const pNode3)
 | |
| {
 | |
|   uint32_t temp = (((uint32_t)pNode1 | (uint32_t)pNode2 | (uint32_t)pNode3) & DMA_CLBAR_LBA);
 | |
|   uint32_t ref  = 0U;
 | |
| 
 | |
|   /* Check node 1 address */
 | |
|   if ((uint32_t)pNode1 != 0U)
 | |
|   {
 | |
|     ref = (uint32_t)pNode1;
 | |
|   }
 | |
|   /* Check node 2 address */
 | |
|   else if ((uint32_t)pNode2 != 0U)
 | |
|   {
 | |
|     ref = (uint32_t)pNode2;
 | |
|   }
 | |
|   /* Check node 3 address */
 | |
|   else if ((uint32_t)pNode3 != 0U)
 | |
|   {
 | |
|     ref = (uint32_t)pNode3;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Prevent MISRA-C2012-Rule-15.7 */
 | |
|   }
 | |
| 
 | |
|   /* Check addresses compatibility */
 | |
|   if (temp != ((uint32_t)ref & DMA_CLBAR_LBA))
 | |
|   {
 | |
|     return 1U;
 | |
|   }
 | |
| 
 | |
|   return 0U;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Check nodes types compatibility.
 | |
|   * @param  pNode1 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 1 registers configurations.
 | |
|   * @param  pNode2 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 2 registers configurations.
 | |
|   * @param  pNode3 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 3 registers configurations.
 | |
|   * @retval Return 0 when nodes types are compatible, otherwise nodes types are not compatible.
 | |
|   */
 | |
| static uint32_t DMA_List_CheckNodesTypes(DMA_NodeTypeDef const *const pNode1,
 | |
|                                          DMA_NodeTypeDef const *const pNode2,
 | |
|                                          DMA_NodeTypeDef const *const pNode3)
 | |
| {
 | |
|   uint32_t ref = 0U;
 | |
| 
 | |
|   /* Check node 1 parameter */
 | |
|   if (pNode1 != NULL)
 | |
|   {
 | |
|     ref = pNode1->NodeInfo & NODE_TYPE_MASK;
 | |
|   }
 | |
|   /* Check node 2 parameter */
 | |
|   else if (pNode2 != NULL)
 | |
|   {
 | |
|     ref = pNode2->NodeInfo & NODE_TYPE_MASK;
 | |
|   }
 | |
|   /* Check node 3 parameter */
 | |
|   else if (pNode3 != NULL)
 | |
|   {
 | |
|     ref = pNode3->NodeInfo & NODE_TYPE_MASK;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Prevent MISRA-C2012-Rule-15.7 */
 | |
|   }
 | |
| 
 | |
|   /* Check node 2 parameter */
 | |
|   if (pNode2 != NULL)
 | |
|   {
 | |
|     /* Check node type compatibility */
 | |
|     if (ref != (pNode2->NodeInfo & NODE_TYPE_MASK))
 | |
|     {
 | |
|       return 2U;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Check node 3 parameter */
 | |
|   if (pNode3 != NULL)
 | |
|   {
 | |
|     /* Check node type compatibility */
 | |
|     if (ref != (pNode3->NodeInfo & NODE_TYPE_MASK))
 | |
|     {
 | |
|       return 3U;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return 0U;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Check nodes types compatibility.
 | |
|   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
 | |
|   *                       configurations.
 | |
|   * @param  cllr_mask   : Pointer to CLLR register mask value.
 | |
|   * @param  cllr_offset : Pointer to CLLR register offset value.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_GetCLLRNodeInfo(DMA_NodeTypeDef const *const pNode,
 | |
|                                      uint32_t *const cllr_mask,
 | |
|                                      uint32_t *const cllr_offset)
 | |
| {
 | |
|   /* Check node type */
 | |
|   if ((pNode->NodeInfo & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
 | |
|   {
 | |
|     /* Update CLLR register mask value */
 | |
|     if (cllr_mask != NULL)
 | |
|     {
 | |
|       *cllr_mask = DMA_CLLR_UT1 | DMA_CLLR_UT2 | DMA_CLLR_UB1 | DMA_CLLR_USA | DMA_CLLR_UDA | DMA_CLLR_UT3 |
 | |
|                    DMA_CLLR_UB2 | DMA_CLLR_ULL;
 | |
|     }
 | |
| 
 | |
|     /* Update CLLR register offset */
 | |
|     if (cllr_offset != NULL)
 | |
|     {
 | |
|       *cllr_offset = NODE_CLLR_2D_DEFAULT_OFFSET;
 | |
|     }
 | |
|   }
 | |
|   /* Update CLLR and register number for linear addressing node */
 | |
|   else
 | |
|   {
 | |
|     /* Update CLLR register mask value */
 | |
|     if (cllr_mask != NULL)
 | |
|     {
 | |
|       *cllr_mask = DMA_CLLR_UT1 | DMA_CLLR_UT2 | DMA_CLLR_UB1 | DMA_CLLR_USA | DMA_CLLR_UDA | DMA_CLLR_ULL;
 | |
|     }
 | |
| 
 | |
|     /* Update CLLR register offset */
 | |
|     if (cllr_offset != NULL)
 | |
|     {
 | |
|       *cllr_offset = NODE_CLLR_LINEAR_DEFAULT_OFFSET;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Find node in queue.
 | |
|   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  pNode    : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers configurations.
 | |
|   * @param  NodeInfo : Pointer to a DMA_NodeInQInfoTypeDef structure that contains node linked to queue information.
 | |
|   * @retval Return 0 when node is found in selected queue, otherwise node is not found.
 | |
|   */
 | |
| static uint32_t DMA_List_FindNode(DMA_QListTypeDef const *const pQList,
 | |
|                                   DMA_NodeTypeDef const *const pNode,
 | |
|                                   DMA_NodeInQInfoTypeDef *const NodeInfo)
 | |
| {
 | |
|   uint32_t node_idx = 0U;
 | |
|   uint32_t currentnode_address  = 0U;
 | |
|   uint32_t previousnode_address  = 0U;
 | |
|   uint32_t cllr_offset = NodeInfo->cllr_offset;
 | |
| 
 | |
|   /* Find last node in queue */
 | |
|   if (pNode ==  NULL)
 | |
|   {
 | |
|     /* Check that previous node is linked to the selected queue */
 | |
|     while (node_idx < pQList->NodeNumber)
 | |
|     {
 | |
|       /* Get head node address */
 | |
|       if (node_idx == 0U)
 | |
|       {
 | |
|         currentnode_address = (uint32_t)pQList->Head & DMA_CLLR_LA;
 | |
|       }
 | |
|       /* Calculate nodes addresses */
 | |
|       else
 | |
|       {
 | |
|         previousnode_address = currentnode_address;
 | |
|         currentnode_address =
 | |
|           ((DMA_NodeTypeDef *)(currentnode_address +
 | |
|                                ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
 | |
|       }
 | |
| 
 | |
|       /* Increment node index */
 | |
|       node_idx++;
 | |
|     }
 | |
|   }
 | |
|   /* Find selected node node in queue */
 | |
|   else
 | |
|   {
 | |
|     /* Check that previous node is linked to the selected queue */
 | |
|     while ((node_idx < pQList->NodeNumber) && (currentnode_address != ((uint32_t)pNode & DMA_CLLR_LA)))
 | |
|     {
 | |
|       /* Get head node address */
 | |
|       if (node_idx == 0U)
 | |
|       {
 | |
|         currentnode_address = (uint32_t)pQList->Head & DMA_CLLR_LA;
 | |
|       }
 | |
|       /* Calculate nodes addresses */
 | |
|       else
 | |
|       {
 | |
|         previousnode_address = currentnode_address;
 | |
|         currentnode_address =
 | |
|           ((DMA_NodeTypeDef *)(currentnode_address +
 | |
|                                ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
 | |
|       }
 | |
| 
 | |
|       /* Increment node index */
 | |
|       node_idx++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Check stored address */
 | |
|   if (pNode != NULL)
 | |
|   {
 | |
|     if (currentnode_address != ((uint32_t)pNode & DMA_CLLR_LA))
 | |
|     {
 | |
|       return 1U;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* Update current node position */
 | |
|   NodeInfo->currentnode_pos = node_idx;
 | |
| 
 | |
|   /* Update previous node address */
 | |
|   NodeInfo->previousnode_addr = previousnode_address | ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
 | |
| 
 | |
|   /* Update current node address */
 | |
|   NodeInfo->currentnode_addr = currentnode_address | ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
 | |
| 
 | |
|   /* Update next node address */
 | |
|   if (((DMA_NodeTypeDef *)NodeInfo->currentnode_addr)->LinkRegisters[cllr_offset] != 0U)
 | |
|   {
 | |
|     NodeInfo->nextnode_addr = (((DMA_NodeTypeDef *)NodeInfo->currentnode_addr)->LinkRegisters[cllr_offset] &
 | |
|                                DMA_CLLR_LA) | ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
 | |
|   }
 | |
| 
 | |
|   return 0U;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Reset queue nodes.
 | |
|   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  NodeInfo : Pointer to a DMA_NodeInQInfoTypeDef structure that contains node linked to queue information.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_ResetQueueNodes(DMA_QListTypeDef const *const pQList,
 | |
|                                      DMA_NodeInQInfoTypeDef const *const NodeInfo)
 | |
| {
 | |
|   uint32_t node_idx = 0U;
 | |
|   uint32_t currentnode_address  = 0U;
 | |
|   uint32_t previousnode_address;
 | |
|   uint32_t cllr_offset = NodeInfo->cllr_offset;
 | |
| 
 | |
|   /* Check that previous node is linked to the selected queue */
 | |
|   while (node_idx < pQList->NodeNumber)
 | |
|   {
 | |
|     /* Get head node address */
 | |
|     if (node_idx == 0U)
 | |
|     {
 | |
|       previousnode_address = (uint32_t)pQList->Head & DMA_CLLR_LA;
 | |
|       currentnode_address  = (pQList->Head->LinkRegisters[cllr_offset] & DMA_CLLR_LA);
 | |
|     }
 | |
|     /* Calculate nodes addresses */
 | |
|     else
 | |
|     {
 | |
|       previousnode_address = currentnode_address;
 | |
|       currentnode_address =
 | |
|         ((DMA_NodeTypeDef *)(currentnode_address +
 | |
|                              ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
 | |
|     }
 | |
| 
 | |
|     /* Reset node */
 | |
|     ((DMA_NodeTypeDef *)(previousnode_address +
 | |
|                          ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] = 0U;
 | |
| 
 | |
|     /* Increment node index */
 | |
|     node_idx++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Fill source node registers values by destination nodes registers values.
 | |
|   * @param  pSrcNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list source node registers
 | |
|   *                     configurations.
 | |
|   * @param  pDestNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list destination node registers
 | |
|   *                     configurations.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_FillNode(DMA_NodeTypeDef const *const pSrcNode,
 | |
|                               DMA_NodeTypeDef *const pDestNode)
 | |
| {
 | |
|   /* Repeat for all register nodes */
 | |
|   for (uint32_t reg_idx = 0U; reg_idx < NODE_MAXIMUM_SIZE; reg_idx++)
 | |
|   {
 | |
|     pDestNode->LinkRegisters[reg_idx] = pSrcNode->LinkRegisters[reg_idx];
 | |
|   }
 | |
| 
 | |
|   /* Fill node information */
 | |
|   pDestNode->NodeInfo = pSrcNode->NodeInfo;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Convert node to dynamic.
 | |
|   * @param  ContextNodeAddr : The context node address.
 | |
|   * @param  CurrentNodeAddr : The current node address to be converted.
 | |
|   * @param  RegisterNumber  : The register number to be converted.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_ConvertNodeToDynamic(uint32_t ContextNodeAddr,
 | |
|                                           uint32_t CurrentNodeAddr,
 | |
|                                           uint32_t RegisterNumber)
 | |
| {
 | |
|   uint32_t currentnode_reg_counter = 0U;
 | |
|   uint32_t contextnode_reg_counter = 0U;
 | |
|   uint32_t cllr_idx = RegisterNumber - 1U;
 | |
|   DMA_NodeTypeDef *context_node = (DMA_NodeTypeDef *)ContextNodeAddr;
 | |
|   DMA_NodeTypeDef *current_node = (DMA_NodeTypeDef *)CurrentNodeAddr;
 | |
|   uint32_t update_link[NODE_MAXIMUM_SIZE] = {DMA_CLLR_UT1, DMA_CLLR_UT2, DMA_CLLR_UB1, DMA_CLLR_USA,
 | |
|                                              DMA_CLLR_UDA, DMA_CLLR_UT3, DMA_CLLR_UB2, DMA_CLLR_ULL
 | |
|                                             };
 | |
| 
 | |
|   /* Update ULL position according to register number */
 | |
|   update_link[cllr_idx] = update_link[NODE_MAXIMUM_SIZE - 1U];
 | |
| 
 | |
|   /* Repeat for all node registers */
 | |
|   while (contextnode_reg_counter != RegisterNumber)
 | |
|   {
 | |
|     /* Check if register values are equal (exception for CSAR, CDAR and CLLR registers) */
 | |
|     if ((context_node->LinkRegisters[contextnode_reg_counter]  ==
 | |
|          current_node->LinkRegisters[currentnode_reg_counter]) &&
 | |
|         (contextnode_reg_counter != NODE_CSAR_DEFAULT_OFFSET)  &&
 | |
|         (contextnode_reg_counter != NODE_CDAR_DEFAULT_OFFSET)  &&
 | |
|         (contextnode_reg_counter != (RegisterNumber - 1U)))
 | |
|     {
 | |
|       /* Format the node according to unused registers */
 | |
|       DMA_List_FormatNode(current_node, currentnode_reg_counter, RegisterNumber, NODE_DYNAMIC_FORMAT);
 | |
| 
 | |
|       /* Update CLLR index */
 | |
|       cllr_idx --;
 | |
| 
 | |
|       /* Update CLLR fields */
 | |
|       current_node->LinkRegisters[cllr_idx] &= ~update_link[contextnode_reg_counter];
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Update context node register fields with new values */
 | |
|       context_node->LinkRegisters[contextnode_reg_counter] = current_node->LinkRegisters[currentnode_reg_counter];
 | |
| 
 | |
|       /* Update CLLR fields */
 | |
|       current_node->LinkRegisters[cllr_idx] |= update_link[contextnode_reg_counter];
 | |
| 
 | |
|       /* Increment current node number register counter */
 | |
|       currentnode_reg_counter++;
 | |
|     }
 | |
| 
 | |
|     /* Increment context node number register counter */
 | |
|     contextnode_reg_counter++;
 | |
|   }
 | |
| 
 | |
|   /* Update node information */
 | |
|   MODIFY_REG(current_node->NodeInfo, NODE_CLLR_IDX, ((currentnode_reg_counter - 1U) << NODE_CLLR_IDX_POS));
 | |
| 
 | |
|   /* Clear unused node fields */
 | |
|   DMA_List_ClearUnusedFields(current_node, currentnode_reg_counter);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Convert node to static.
 | |
|   * @param  ContextNodeAddr : The context node address.
 | |
|   * @param  CurrentNodeAddr : The current node address to be converted.
 | |
|   * @param  RegisterNumber  : The register number to be converted.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_ConvertNodeToStatic(uint32_t ContextNodeAddr,
 | |
|                                          uint32_t CurrentNodeAddr,
 | |
|                                          uint32_t RegisterNumber)
 | |
| {
 | |
|   uint32_t contextnode_reg_counter = 0U;
 | |
|   uint32_t cllr_idx;
 | |
|   uint32_t cllr_mask;
 | |
|   const DMA_NodeTypeDef *context_node = (DMA_NodeTypeDef *)ContextNodeAddr;
 | |
|   DMA_NodeTypeDef *current_node = (DMA_NodeTypeDef *)CurrentNodeAddr;
 | |
|   uint32_t update_link[NODE_MAXIMUM_SIZE] = {DMA_CLLR_UT1, DMA_CLLR_UT2, DMA_CLLR_UB1, DMA_CLLR_USA,
 | |
|                                              DMA_CLLR_UDA, DMA_CLLR_UT3, DMA_CLLR_UB2, DMA_CLLR_ULL
 | |
|                                             };
 | |
| 
 | |
|   /* Update ULL position according to register number */
 | |
|   update_link[RegisterNumber - 1U] = update_link[NODE_MAXIMUM_SIZE - 1U];
 | |
| 
 | |
|   /* Get context node CLLR information */
 | |
|   cllr_idx  = (context_node->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
 | |
|   cllr_mask = context_node->LinkRegisters[cllr_idx];
 | |
| 
 | |
|   /* Repeat for all node registers */
 | |
|   while (contextnode_reg_counter != RegisterNumber)
 | |
|   {
 | |
|     /* Check if node field is dynamic */
 | |
|     if ((cllr_mask & update_link[contextnode_reg_counter]) == 0U)
 | |
|     {
 | |
|       /* Format the node according to unused registers */
 | |
|       DMA_List_FormatNode(current_node, contextnode_reg_counter, RegisterNumber, NODE_STATIC_FORMAT);
 | |
| 
 | |
|       /* Update node field */
 | |
|       current_node->LinkRegisters[contextnode_reg_counter] = context_node->LinkRegisters[contextnode_reg_counter];
 | |
|     }
 | |
| 
 | |
|     /* Increment context node number register counter */
 | |
|     contextnode_reg_counter++;
 | |
|   }
 | |
| 
 | |
|   /* Update node information */
 | |
|   MODIFY_REG(current_node->NodeInfo, NODE_CLLR_IDX, ((RegisterNumber - 1U) << NODE_CLLR_IDX_POS));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Format the node according to unused registers.
 | |
|   * @param  pNode           : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
 | |
|   *                           configurations.
 | |
|   * @param  RegisterIdx     : The first register index to be formatted.
 | |
|   * @param  RegisterNumber  : The number of node registers.
 | |
|   * @param  Format          : The format type.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_FormatNode(DMA_NodeTypeDef *const pNode,
 | |
|                                 uint32_t RegisterIdx,
 | |
|                                 uint32_t RegisterNumber,
 | |
|                                 uint32_t Format)
 | |
| {
 | |
|   if (Format == NODE_DYNAMIC_FORMAT)
 | |
|   {
 | |
|     /* Repeat for all registers to be formatted */
 | |
|     for (uint32_t reg_idx = RegisterIdx; reg_idx < (RegisterNumber - 1U); reg_idx++)
 | |
|     {
 | |
|       pNode->LinkRegisters[reg_idx] = pNode->LinkRegisters[reg_idx + 1U];
 | |
|     }
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Repeat for all registers to be formatted */
 | |
|     for (uint32_t reg_idx = (RegisterNumber - 2U); reg_idx > RegisterIdx; reg_idx--)
 | |
|     {
 | |
|       pNode->LinkRegisters[reg_idx] = pNode->LinkRegisters[reg_idx - 1U];
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Clear unused register fields.
 | |
|   * @param  pNode            : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
 | |
|   *                            configurations.
 | |
|   * @param  FirstUnusedField : The first unused field to be cleared.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_ClearUnusedFields(DMA_NodeTypeDef *const pNode,
 | |
|                                        uint32_t FirstUnusedField)
 | |
| {
 | |
|   /* Repeat for all unused fields */
 | |
|   for (uint32_t reg_idx = FirstUnusedField; reg_idx < NODE_MAXIMUM_SIZE; reg_idx++)
 | |
|   {
 | |
|     pNode->LinkRegisters[reg_idx] = 0U;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Update CLLR for all dynamic queue nodes.
 | |
|   * @param  pQList :              Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  LastNode_IsCircular : The first circular node is the last queue node or not.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_UpdateDynamicQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
 | |
|                                                  uint32_t LastNode_IsCircular)
 | |
| {
 | |
|   uint32_t previous_cllr_offset;
 | |
|   uint32_t current_cllr_offset = 0U;
 | |
|   uint32_t previousnode_addr;
 | |
|   uint32_t currentnode_addr = (uint32_t)pQList->Head;
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t node_idx = 0U;
 | |
| 
 | |
|   /*  Repeat for all register nodes */
 | |
|   while (node_idx < pQList->NodeNumber)
 | |
|   {
 | |
|     /* Get head node address */
 | |
|     if (node_idx == 0U)
 | |
|     {
 | |
|       /* Get current node information */
 | |
|       current_cllr_offset = (((DMA_NodeTypeDef *)currentnode_addr)->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
 | |
|     }
 | |
|     /* Calculate nodes addresses */
 | |
|     else
 | |
|     {
 | |
|       /* Get previous node information */
 | |
|       previousnode_addr = currentnode_addr;
 | |
|       previous_cllr_offset = current_cllr_offset;
 | |
| 
 | |
|       /* Get current node information */
 | |
|       currentnode_addr = (((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[previous_cllr_offset] & DMA_CLLR_LA) +
 | |
|                          ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
 | |
|       current_cllr_offset = (((DMA_NodeTypeDef *)currentnode_addr)->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
 | |
| 
 | |
|       /* Calculate CLLR register value to be updated */
 | |
|       cllr_mask = (((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] & ~DMA_CLLR_LA) |
 | |
|                   (((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[previous_cllr_offset] & DMA_CLLR_LA);
 | |
| 
 | |
|       /* Set new CLLR value to previous node */
 | |
|       ((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[previous_cllr_offset] = cllr_mask;
 | |
|     }
 | |
| 
 | |
|     /* Increment node index */
 | |
|     node_idx++;
 | |
|   }
 | |
| 
 | |
|   /* Check queue circularity */
 | |
|   if (pQList->FirstCircularNode != 0U)
 | |
|   {
 | |
|     /* First circular queue is not last queue node */
 | |
|     if (LastNode_IsCircular == 0U)
 | |
|     {
 | |
|       /* Get CLLR node information */
 | |
|       DMA_List_GetCLLRNodeInfo(((DMA_NodeTypeDef *)currentnode_addr), &cllr_mask, NULL);
 | |
| 
 | |
|       /* Update CLLR register for last circular node */
 | |
|       ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] =
 | |
|         ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
 | |
|     }
 | |
|     /* First circular queue is last queue node */
 | |
|     else
 | |
|     {
 | |
|       /* Disable CLLR updating */
 | |
|       ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] &= ~DMA_CLLR_ULL;
 | |
|     }
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     /* Clear CLLR register for last node */
 | |
|     ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] = 0U;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Update CLLR for all static queue nodes.
 | |
|   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @param  operation : The operation type.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_UpdateStaticQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
 | |
|                                                 uint32_t operation)
 | |
| {
 | |
|   uint32_t currentnode_addr = (uint32_t)pQList->Head;
 | |
|   uint32_t current_cllr_offset = ((uint32_t)pQList->Head->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
 | |
|   uint32_t cllr_default_offset;
 | |
|   uint32_t cllr_default_mask;
 | |
|   uint32_t cllr_mask;
 | |
|   uint32_t node_idx = 0U;
 | |
| 
 | |
|   /* Get CLLR node information */
 | |
|   DMA_List_GetCLLRNodeInfo(pQList->Head, &cllr_default_mask, &cllr_default_offset);
 | |
| 
 | |
|   /*  Repeat for all register nodes (Bypass last queue node) */
 | |
|   while (node_idx < pQList->NodeNumber)
 | |
|   {
 | |
|     if (operation == UPDATE_CLLR_POSITION)
 | |
|     {
 | |
|       /* Get CLLR value */
 | |
|       cllr_mask = ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset];
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* Calculate CLLR value */
 | |
|       cllr_mask = (((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] & DMA_CLLR_LA) |
 | |
|                   cllr_default_mask;
 | |
|     }
 | |
| 
 | |
|     /* Set new CLLR value to default position */
 | |
|     if ((node_idx == (pQList->NodeNumber - 1U)) && (pQList->FirstCircularNode == NULL))
 | |
|     {
 | |
|       ((DMA_NodeTypeDef *)(currentnode_addr))->LinkRegisters[cllr_default_offset] = 0U;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       ((DMA_NodeTypeDef *)(currentnode_addr))->LinkRegisters[cllr_default_offset] = cllr_mask;
 | |
|     }
 | |
| 
 | |
|     /* Update current node address with next node address */
 | |
|     currentnode_addr = (currentnode_addr & DMA_CLBAR_LBA) | (cllr_mask & DMA_CLLR_LA);
 | |
| 
 | |
|     /* Update current CLLR offset with next CLLR offset */
 | |
|     current_cllr_offset = (((DMA_NodeTypeDef *)currentnode_addr)->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
 | |
| 
 | |
|     /* Increment node index */
 | |
|     node_idx++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   * @brief  Clean linked-list queue variable.
 | |
|   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
 | |
|   * @retval None.
 | |
|   */
 | |
| static void DMA_List_CleanQueue(DMA_QListTypeDef *const pQList)
 | |
| {
 | |
|   /* Clear head node */
 | |
|   pQList->Head = NULL;
 | |
| 
 | |
|   /* Clear first circular queue node */
 | |
|   pQList->FirstCircularNode = NULL;
 | |
| 
 | |
|   /* Reset node number */
 | |
|   pQList->NodeNumber = 0U;
 | |
| 
 | |
|   /* Reset queue state */
 | |
|   pQList->State = HAL_DMA_QUEUE_STATE_RESET;
 | |
| 
 | |
|   /* Reset queue error code */
 | |
|   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
 | |
| 
 | |
|   /* Reset queue type */
 | |
|   pQList->Type = QUEUE_TYPE_STATIC;
 | |
| }
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| #endif /* HAL_DMA_MODULE_ENABLED */
 | |
| /**
 | |
|   * @}
 | |
|   */
 | |
| 
 | |
| /**
 | |
|   * @}
 | |
|   */
 | 
