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 */
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|