1 /**
2   **********************************************************************************************************************
3   * @file    stm32n6xx_hal_dma_ex.c
4   * @author  MCD Application Team
5   * @brief   DMA Extension HAL module driver
6   *          This file provides firmware functions to manage the following functionalities of the DMA extension
7   *          peripheral:
8   *           + Linked-List Initialization and De-Initialization Functions
9   *           + Linked-List I/O Operation Functions
10   *           + Linked-List Management Functions
11   *           + Data Handling, Repeated Block and Trigger Configuration Functions
12   *           + Suspend and Resume Operation Functions
13   *           + FIFO Status Function
14   *
15   **********************************************************************************************************************
16   * @attention
17   *
18   * Copyright (c) 2023 STMicroelectronics.
19   * All rights reserved.
20   *
21   * This software is licensed under terms that can be found in the LICENSE file
22   * in the root directory of this software component.
23   * If no LICENSE file comes with this software, it is provided AS-IS.
24   *
25   **********************************************************************************************************************
26   @verbatim
27   ======================================================================================================================
28                                  ##### How to use this driver #####
29   ======================================================================================================================
30     [..]
31       Alternatively to the normal programming mode, a DMA channel can be programmed by a list of transfers, known as
32       linked-list (list of Node items). Each node is defined by its data structure.
33       Each node specifies a standalone DMA channel.
34       When enabled, the DMA channel fetch the first linked-list node from SRAM (known as head node). When executed, the
35       next linked list node will be fetched and executed. This operation is repeated until the end of the whole
36       linked-list queue. Optionally, the linked-list can be linear where the last linked-list queue node is not linked
37       to another queue node or circular where the last linked-list node is linked to any linked-list queue node.
38 
39           (+) Linear linked-list:
40               The DMA channel fetch and execute all DMA linked-list queue from first node (head node) to last node
41               (tail node) ones. When the last node is completed, the DMA channel remains in idle state and another
42               transfer can be lunched.
43 
44           (+) Circular linked-list:
45               The DMA channel fetch and execute all DMA linked-list queue from first node (head node) to last node (tail
46               node). When last node is executed, the DMA channel fetches the first circular node another time and repeat
47               the same sequence in an infinite loop (Circular transfer). To stop the DMA channel, an abort operation is
48               required. This linked-list mode replaces the legacy circular transfers.
49 
50     [..]
51       In order to reduce linked-list queue executing time and power consumption, the DMA channel supports executing the
52       dynamic linked-list format. In fact, the DMA supports the execution of 2 types of linked-list formats : static and
53       dynamic.
54 
55           (+) Static linked-list:
56               The static linked-list format refers to the full linked-list node where all DMA channel parameters are
57               fetched and executed independently of the redundancy of information.
58 
59           (+) Dynamic linked-list:
60               The dynamic linked-list format refer to the customized linked-list node where only DMA channel necessary
61               parameters are fetched and executed (Example: data size = 20 on previous node, and data size = 20 on the
62               current node => No need to update it).
63 
64       For linked-list transfers, the DMA channel can execute the linked-list queue node by node. This feature is named
65       link step mode. When activated, enabling the DMA channel first time allows to fetch the head node from memory
66       then it stops. Then, another DMA channel enable is needed to execute the node. After that, keeping enabling the
67       DMA channel is needed to execute each node until the end of linked-list queue. When the linked-list queue is
68       circular, enabling the DMA channel in an infinite loop is required to keep the DMA channel running. This feature
69       is useful for debug purpose or asynchronously executing queue nodes.
70 
71     [..]
72       Each DMA channel transfer (normal or linked-list), is highly configurable according to DMA channel instance
73       integrated in devices. These configuration can be :
74 
75           (+) Repeated block configuration :
76               If the feature is supported, the DMA channel can performs a repeated block transfers. Named also 2
77               dimension addressing transfers, this feature can transfer n iteration of programmed block transfer (Block
78               transfer is the legacy data size). Additional to the repeat count of a block, DMA channel addresses can
79               jump after at burst and block level. The jump length is a programmable parameter defined by DMA user.
80                (++) Jump at burst level :
81                     The DMA channel keep an empty area, between each 2 consecutive bursts transmitted.
82                (++) Jump at block level :
83                     The DMA channel keep an empty area, between each 2 consecutive blocks transmitted.
84 
85           (+) Trigger :
86               The DMA channel transfers can be conditioned by hardware signals edges (rising or falling) named hardware
87               triggers. Trigger condition can be applied at :
88                (++) Single/Burst level :
89                     Each single/burst data transmission is conditioned by a signal trigger hit.
90                (++) Block level :
91                     Each block data transmission is conditioned by a signal trigger hit.
92                (++) Repeated block level :
93                     Each repeated block data transmission is conditioned by a signal trigger hit.
94                (++) Node level :
95                     Each node execution is conditioned by a signal trigger hit.
96               The DMA channel can report a trigger overrun when detects more than 2 trigger signal edges before
97               executing the current transfer.
98 
99           (+) Data handling :
100               The data handling feature is a FIFO capability that can be :
101                 (++) Padding pattern :
102                      Padding selected pattern (zero padding or sign extension) when the source data width is smaller
103                      than the destination data width at single level.
104                 (++) Truncation :
105                      Truncate section from the source data single when the source data width is bigger than the
106                      destination data width.
107                 (++) Pack/Unpack :
108                      Pack a set of data when source data width is smaller than the destination data width.
109                      Unpack a set of data when source data width is bigger than the destination data width.
110                 (++) Exchange :
111                      Exchange data at byte, half-word and word on the destination and at byte level on the source.
112 
113     [..]
114       Each DMA channel transfer (normal or linked-list) when it is active, can be suspended and resumed at run time
115       application. When trying to suspend an ongoing transfer, the DMA channel isn't suspended instantly but complete
116       the current ongoing single/burst then it stops.
117       When the DMA channel is suspended, the current transfer can be resumed instantly.
118 
119     [..]
120       The DMA channel that supports FIFO, can report in real time the number of beats remains on destination (Output)
121       FIFO level.
122 
123     *** Linked-List Initialization and De-Initialization operation ***
124     ==================================================================
125     [..]
126       Differently from normal transfers, DMA channel initialization and de-initialization need less parameters as the
127       remaining transfer parameters are defined by linked-list nodes.
128 
129           (+) Use HAL_DMAEx_List_Init() to initialize a DMA channel in linked-list mode according to programmed fields.
130               When called, the DMA channel will be ready to execute linked-list queues.
131 
132           (+) Use HAL_DMAEx_List_DeInit() to de-initialize a DMA channel in linked-list mode.
133               When called, the DMA channel will be in reset. It is mandatory to reinitialize it for next transfer.
134 
135     *** Linked-List I/O Operation ***
136     =================================
137     [..]
138           (+) Use HAL_DMAEx_List_Start() to start a DMA transfer in linked-list mode after the configuration of
139               linked-list queue base address and offset in polling mode (Blocking mode).
140 
141           (+) Use HAL_DMAEx_List_Start_IT() to start a DMA transfer in linked-list mode after the configuration of
142               linked-list queue base address and offset in interrupt mode (Non-blocking mode).
143 
144     *** Linked-List Management ***
145     ==============================
146     [..]
147       The linked-list management is a software processing independently of DMA channel hardware. It allows to reset,
148       build, create, insert, remove, replace, circularize, convert both nodes and queue in order to perform DMA
149       channel transfers in linked-list mode.
150       Linked-list APIs and types are adapted to reduce memory footprint.
151 
152     *** Linked-list nodes building ***
153     [..]
154       At node level, the operations that can be done are building a new linked-list node or get a linked-list node
155       information from a built node. The linked-list nodes have two forms according to 2 dimensions addressing
156       capability. The linear addressing nodes contains the information of all DMA channel features except the 2
157       dimension addressing features and the 2 dimensions addressing nodes contain the information of all available
158       features.
159 
160           (+) Use HAL_DMAEx_List_BuildNode() to build the DMA linked-list node according to the specified parameters.
161               Build operation allow to convert the specified parameter in values known by the DMA channel and place them
162               in memory.
163               Placing DMA linked-list in SRAM must be done in accordance to product specification to ensure that the
164               link access port can access to the specified SRAM.
165               (++) The DMA linked-list node parameter address should be 32bit aligned and should not exceed the 64 KByte
166               addressable space.
167 
168           (+) Use HAL_DMAEx_List_GetNodeConfig() to get the specified configuration parameter on building node.
169               This API can be used when need to change few parameter to build new node.
170 
171     *** Inserting nodes to linked-list queue ***
172     [..]
173       In order to build a sequence of DMA transaction with different configuration, we need to insert built node at
174       linked-list queue (node present an elementary DMA transaction) in linked-list queue on any position to have the
175       full flexibility of ordering nodes or extend the sequence of queue transactions.
176 
177           (+) Use HAL_DMAEx_List_InsertNode() to insert new built node in any queue position of linked-list queue
178               according to selecting previous node. When calling this API with previous node parameter is NULL, the
179               inserted node will be placed at the head of the linked-list queue.
180               (++) This API must be used after HAL_DMAEx_List_BuildNode() otherwise an error will be returned.
181               (++) This API must be called for static queues format.
182               (++) This API shall be avoided when adding new node at the head or the tail of queue (overhead of
183                    footprint and performance : use HAL_DMAEx_List_InsertNode_Head() or HAL_DMAEx_List_InsertNode_Tail()
184                    instead).
185 
186           (+) Use HAL_DMAEx_List_InsertNode_Head() to insert new built node at the head of linked-list queue. The head
187               node will not be overwritten but will be the second queue node.
188               (++) This API must be used after HAL_DMAEx_List_BuildNode() otherwise an error will be returned.
189               (++) This API must be called for static queues format.
190 
191           (+) Use HAL_DMAEx_List_InsertNode_Tail() to insert new built node at the tail of linked-list queue. The tail
192               node will not be overwritten but will be the penultimate queue node.
193               (++) This API must be used after HAL_DMAEx_List_BuildNode() otherwise an error will be returned.
194               (++) This API must be called for static queues format.
195 
196     *** Removing nodes from linked-list queue ***
197     [..]
198       There is some cases when removing a node from linked-list queue is needed (need to remove an elementary DMA
199       transaction). Removing node allows to unlink a node from DMA linked-list queue (NOT DELETED), so the removed node
200       can be reused for another queue or to be added to the same queue without need to rebuild it in next step.
201 
202           (+) Use HAL_DMAEx_List_RemoveNode() to remove any yet built and inserted node from linked-list queue according
203               to selected node.
204               (++) This API must be called for static queues format.
205               (++) This API shall be avoided when removing the head or the tail of linked-list queue (overhead of
206                    footprint and performance : use HAL_DMAEx_List_RemoveNode_Head() or HAL_DMAEx_List_RemoveNode_Tail()
207                    instead).
208 
209           (+) Use HAL_DMAEx_List_RemoveNode_Head() to remove the head node from linked-list queue.
210               (++) This API must be called for static queues format.
211 
212           (+) Use HAL_DMAEx_List_RemoveNode_Tail() to remove the tail node from linked-list queue.
213               (++) This API must be called for static queues format.
214 
215     *** Replacing nodes on linked-list queue ***
216     [..]
217       There is some cases when replacing a node from linked-list queue is needed (need to replace an elementary DMA
218       transfer, by another one that have not the same configuration). Replacing node allows to unlink the node to be
219       replaced from DMA linked-list queue (NOT DELETED) and link instead a new node. So the replaced node can be reused
220       for another queue or to be added to the same queue without need to rebuild it in next step and the new node cannot
221       be reused except when remove it or replaced in next step.
222 
223           (+) Use HAL_DMAEx_List_ReplaceNode() to replace any yet built and inserted node on linked-list queue according
224               to selected node.
225               (++) This API must be called for static queues format.
226               (++) This API shall be avoided when replacing the head or the tail linked-list queue (overhead of
227                    footprint and performance : use HAL_DMAEx_List_ReplaceNode_Head() or
228                    HAL_DMAEx_List_ReplaceNode_Tail() instead).
229 
230           (+) Use HAL_DMAEx_List_ReplaceNode_Head() to replace the head node of linked-list queue.
231               (++) This API must be called for static queues format.
232 
233           (+) Use HAL_DMAEx_List_ReplaceNode_Tail() to replace the tail node from linked-list queue.
234               (++) This API must be called for static queues format.
235 
236     *** Reset linked-list queue ***
237     [..]
238       After finishing using a linked-list queue, it can be reset and cleared and it's content nodes will be
239       unlinked (NOT DELETED) and reused on another queue.
240 
241           (+) Use HAL_DMAEx_List_ResetQ() to reset a linked-list queue and unlink all it's content nodes.
242               (++) This API must be called for ready state queues.
243               (++) This API must be called for static queues format.
244 
245     *** Inserting linked-list queue ***
246     [..]
247       To ensure the flexibility of building linked-list queue by their targeted functionalities (Example: 3 nodes for
248       action 1 and 5 nodes for action 2), it is possible to build a queue for action 1 that contains action 1 nodes and
249       a queue for action 2 that contains action 2 nodes then concatenating the 2 queues. So, there are some cases where
250       the management of linked-list at queue granularity is needed.
251 
252           (+) Use HAL_DMAEx_List_InsertQ() to insert source linked-list queue to a destination linked-list queue
253               according to selecting previous node.
254               (++) This API must be called for static queues format.
255               (++) This API shall be avoided when inserting source linked-list queue at the head or the tail of
256                    destination queue (overhead of footprint and performance : use HAL_DMAEx_List_InsertQ_Head() or
257                    HAL_DMAEx_List_InsertQ_Tail() instead).
258 
259           (+) Use HAL_DMAEx_List_InsertQ_Head() to insert a source linked-list queue at the head of linked-list
260               destination queue.
261               (++) This API must be called for static queues format.
262 
263           (+) Use HAL_DMAEx_List_InsertQ_Tail() to insert a source linked-list queue at the tail of linked-list
264               destination queue.
265               (++) This API must be called for static queues format.
266 
267     *** Circularizing linked-list queue ***
268     [..]
269       In order to perform tasks in infinite loop with DMA channel, it is possible to circularize the linked-list queues.
270       Circularizing queue allows to link last linked-list queue node to any previous node of the same queue (This node
271       is named first circular queue). When the first circular node is the head node, all linked-list queue nodes will be
272       executed in infinite loop. When the first circular node is not the head nodes, all precedent nodes are executed
273       once and all remaining nodes are executed in an infinite loop.
274 
275           (+) Use HAL_DMAEx_List_SetCircularModeConfig() to circularize the linked-list queue according to first
276               circular node selected.
277               (++) This API must be called for static queues format.
278               (++) This API shall be avoided when first circular node is the head linked-list queue node (overhead of
279                    footprint and performance : use HAL_DMAEx_List_SetCircularMode() instead).
280 
281           (+) Use HAL_DMAEx_List_SetCircularMode() to circularize the linked-list queue with linking last queue node
282               with first queue node.
283               (++) This API must be called for static queues format.
284 
285           (+) Use HAL_DMAEx_List_ClearCircularMode() to clear any linked-list queue circular configuration.
286               (++) This API must be called for static queues format.
287 
288 
289     *** Converting linked-list queue ***
290     [..]
291       To have the best DMA channel linked-list queue execution, it is recommended to convert yet build linked-list queue
292       to dynamic format (Static is the default format). When linked-list queue becomes dynamic, all queue nodes are
293       optimized and only changed parameters will be updated between nodes. So, the DMA will fetch only changes
294       parameters instead of the whole node.
295 
296           (+) Use HAL_DMAEx_List_ConvertQToDynamic() to convert a linked-list queue to dynamic format.
297               (++) This API must be called for ready state queues.
298               (++) This API must be called for static queues format.
299               (++) This API must be called as the last API before starting the DMA channel in linked-list mode.
300 
301           (+) Use HAL_DMAEx_List_ConvertQToStatic() to convert a linked-list queue to static format.
302               (++) This API must be called for ready state queues.
303               (++) This API must be called for dynamic queues format.
304               (++) This API must be called as the first API after the full execution of linked-list queue when the
305                    execution mode is linear (not circular) if it is dynamic and a linked-list queue management is
306                    needed.
307               (++) This API must be called as the first API after the aborting the execution of the current linked-list
308                    queue when the execution mode is linear (not circular) if it is dynamic and a linked-list queue
309                    management is needed.
310 
311     [..]
312       When converting a circular queue to dynamic format and when the first circular node is the last queue node, it is
313       recommended to duplicate the last circular node in order to ensure the full optimization when calling
314       HAL_DMAEx_List_ConvertQToDynamic() API. In this case, updated information are only addresses which allow to reduce
315       4 words of update for linear nodes per node execution and 6 words update for 2 dimensions addressing nodes per
316       node execution.
317 
318 
319     *** Linking linked-list queue to DMA channel ***
320     [..]
321       In order to have the possibility of the creation of an infinity queues (limited by available memory size), the
322       building of linked-list queue is fully independent from DMA channels. It is possible to build all needed queues if
323       their size is less then available memory at startup time, then linking each time when needed a linked-list queue
324       to an idle DMA channel.
325 
326           (+) Use HAL_DMAEx_List_LinkQ() to link a ready linked-list queue to ready DMA channel.
327               (++) This API supports the two format of linked-list (Static and dynamic).
328               (++) This API must be called for ready state queues and DMA channels.
329 
330           (+) Use HAL_DMAEx_List_ConvertQToStatic() to unlink a ready linked-list queue to ready DMA channel.
331               (++) This API supports the two format of linked-list (Static and dynamic).
332               (++) This API must be called for ready state queues and DMA channels.
333 
334     *** User sequence ***
335     [..]
336       To use cleanly the DMA linked-list library, ensure to apply the following call sequences :
337 
338           (+) Linear transfer :
339               Linked-list queue building
340               (++) HAL_DMAEx_List_BuildNode()
341               (++) HAL_DMAEx_List_InsertNode_Tail()
342                               .
343                               .
344                               .
345               (++) HAL_DMAEx_List_BuildNode()
346               (++) HAL_DMAEx_List_InsertNode_Tail()
347               (++) HAL_DMAEx_List_ConvertQToDynamic()
348               Linked-list queue execution
349               (++) HAL_DMAEx_List_Init()
350               (++) HAL_DMAEx_List_LinkQ()
351               (++) HAL_DMAEx_List_Start() / HAL_DMAEx_List_Start_IT()
352               (++) HAL_DMAEx_List_UnLinkQ()
353               (++) HAL_DMAEx_List_DeInit()
354 
355           (+) Circular transfer :
356               Linked-list queue building
357               (++) HAL_DMAEx_List_BuildNode()
358               (++) HAL_DMAEx_List_InsertNode_Tail()
359                               .
360                               .
361                               .
362               (++) HAL_DMAEx_List_BuildNode()
363               (++) HAL_DMAEx_List_InsertNode_Tail()
364               (++) HAL_DMAEx_List_SetCircularModeConfig() / HAL_DMAEx_List_SetCircularMode()
365               (++) HAL_DMAEx_List_ConvertQToDynamic()
366               Linked-list queue execution
367               (++) HAL_DMAEx_List_Init()
368               (++) HAL_DMAEx_List_LinkQ()
369               (++) HAL_DMAEx_List_Start() / HAL_DMAEx_List_Start_IT()
370               (++) HAL_DMA_Abort() / HAL_DMA_Abort_IT()
371               (++) HAL_DMAEx_List_UnLinkQ()
372               (++) HAL_DMAEx_List_DeInit()
373 
374 
375     *** Data Handling ***
376     =====================
377     [..]
378       In order to avoid some CPU data processing in several cases, the DMA channel provides some features related to
379       FIFO capabilities titled data handling.
380                 (++) Padding pattern
381                      Padding selected pattern (zero padding or sign extension) when the source data width is smaller
382                      than the destination data width at single level.
383                      Zero padding       (Source : 0xABAB ------> Destination : 0xABAB0000)
384                      Sign bit extension (Source : 0x0ABA ------> Destination : 0x00000ABA)
385                                         (Source : 0xFABA ------> Destination : 0xFFFFFABA)
386                 (++) Truncation :
387                      Truncate section from the source data single when the source data width is bigger than the
388                      destination data width.
389                      Left truncation  (Source : 0xABABCDCD ------> Destination : 0xCDCD)
390                      Right truncation (Source : 0xABABCDCD ------> Destination : 0xABAB)
391                 (++) Pack/Unpack :
392                      Pack a set of data when source data width is smaller than the destination data width.
393                      Unpack a set of data when source data width is bigger than the destination data width.
394                      Pack   (Source : 0xAB, 0xCD ------> Destination : 0xABCD)
395                      UnPack (Source : 0xABCD     ------> Destination : 0xAB, 0xCD)
396                 (++) Exchange :
397                      Exchange data at byte and half-word on the destination and at byte level on the source.
398                      Considering source and destination are both word type. Exchange operation can be as follows.
399                      In examples below, one exchange setting is enabled at a time.
400                      Source byte exchange only (Source : 0xAB12CD34 ------> Destination : 0xABCD1234)
401                      Destination byte exchange only (Source : 0xAB12CD34 ------> Destination : 0x12AB34CD)
402                      Destination half-word exchange only (Source : 0xAB12CD34 ------> Destination : 0xCD34AB12)
403                      In addition, in case of double-word, Exchange data at word level on the destination is also
404                      available.
405                      Considering source and destination are both double-word type.
406                      word exchange only (Source : 0xAB12CD34EF567890 ------> Destination : 0xEF567890AB12CD34)
407 
408           (+) Use HAL_DMAEx_ConfigDataHandling() to configure data handling features. Previous elementary explained
409               can be combined according to application needs.
410               (++) This API is complementary of normal transfers.
411               (++) This API must not be called for linked-list transfers as data handling information are configured at
412                    node level.
413 
414     *** User sequence ***
415     [..]
416       To configure cleanly the DMA channel data handling, ensure to apply the following call sequence :
417 
418           (+) Linear transfer :
419               (++) HAL_DMA_Init()
420               (++) HAL_DMAEx_ConfigDataHandling()
421               (++) HAL_DMA_Start()
422 
423     *** Repeated Block ***
424     ======================
425     [..]
426       When available, this feature is used when the data size is higher then 65535 bytes (Maximum block size) or for
427       scattering / gathering data.
428                 (++) Gather data
429                      Source            Destination
430                      0xAA              0xAA
431                      0xBB              0xAA
432                      0xAA      ==>     0xAA
433                      0xCC
434                      0xAA
435                 (++) Scatter data
436                      Source            Destination
437                      0xAA              0xAA
438                      0xAA              0xBB
439                      0xAA      ==>     0xAA
440                                        0xBB
441                                        0xAA
442 
443           (+) Use HAL_DMAEx_ConfigRepeatBlock() to configure data repeated block feature. Jump addresses and
444               incrementing or decrementing on source and destination can be combined to have the need application
445               behavior.
446               (++) This API is complementary of normal transfers.
447               (++) This API must not be called for linked-list transfers as repeated block information are configured at
448                    node level.
449               (++) This API must be called only for DMA channel that supports repeated block feature.
450 
451     *** User sequence ***
452     [..]
453       To configure cleanly the DMA channel repeated block, ensure to apply the following call sequence :
454 
455           (+) Linear transfer :
456               (++) HAL_DMA_Init()
457               (++) HAL_DMAEx_ConfigRepeatBlock()
458               (++) HAL_DMA_Start()
459 
460     *** Trigger Configuration ***
461     =============================
462     [..]
463       When application needs that DMA transfers are conditioned by internal or external events, the trigger feature can
464       do that. Trigger signals are a set of device signal that are linked to DMA trigger inputs that allows to start the
465       DMA transfers.
466       To setup a trigger transfers, three DMA channel parameters are needed:
467 
468           (+) Trigger mode
469               This parameter specifies the trig level.
470                (++) Block level
471                (++) Repeated block level
472                (++) Node level
473                (++) Single / Burst level
474 
475           (+) Trigger polarity
476               This parameter specifies the DMA trigger sensitivity (Rising or falling).
477 
478           (+) Trigger selection
479               This parameter specifies the DMA trigger hardware signal.
480 
481           (+) Use HAL_DMAEx_ConfigTrigger() to configure trigger feature.
482               (++) This API is complementary to normal transfers APIs.
483               (++) This API must not be called for linked-list transfers as trigger information are configured at
484                    node level.
485 
486     *** User sequence ***
487     [..]
488       To configure cleanly the DMA channel trigger, ensure to apply the following call sequence :
489           (+) Linear transfer :
490               (++) HAL_DMA_Init()
491               (++) HAL_DMAEx_ConfigTrigger()
492               (++) HAL_DMA_Start()
493 
494     *** Suspend and resume operation ***
495     ====================================
496     [..]
497       There are several cases when needs to suspend a DMA current transfer (Example: liberate bandwidth for more
498       priority DMA channel transfer). Suspending DMA channel (same as abort) is available in polling (blocking mode) and
499       interrupt (non-blocking mode) modes. When suspended, a DMA channel can be instantly resumed.
500 
501           (+) Use HAL_DMAEx_Suspend() to suspend an ongoing DMA channel transfer in polling mode (Blocking mode).
502 
503           (+) Use HAL_DMAEx_Suspend_IT() to suspend an ongoing DMA channel transfer in interrupt mode (Non-blocking
504               mode).
505 
506           (+) Use HAL_DMAEx_Resume() to resume a suspended DMA channel transfer execution.
507 
508     *** FIFO status ***
509     ===================
510     [..]
511       In several cases, the information of FIFO level is useful to inform at application level how to process remaining
512       data. When not empty, the DMA channel FIFO cannot be flashed only by reset.
513 
514           (+) Use HAL_DMAEx_GetFifoLevel() to get the DMA channel FIFO level (available beats in FIFO).
515 
516     @endverbatim
517   **********************************************************************************************************************
518   */
519 
520 /* Includes ----------------------------------------------------------------------------------------------------------*/
521 #include "stm32n6xx_hal.h"
522 
523 /** @addtogroup STM32N6xx_HAL_Driver
524   * @{
525   */
526 
527 /** @defgroup DMAEx DMAEx
528   * @brief DMA Extended HAL module driver
529   * @{
530   */
531 
532 #ifdef HAL_DMA_MODULE_ENABLED
533 
534 /* Private types -----------------------------------------------------------------------------------------------------*/
535 /* Private variables -------------------------------------------------------------------------------------------------*/
536 /* Private Constants -------------------------------------------------------------------------------------------------*/
537 /* Private macros ----------------------------------------------------------------------------------------------------*/
538 /* Private function prototypes ---------------------------------------------------------------------------------------*/
539 static void DMA_List_Init(DMA_HandleTypeDef const *const hdma);
540 static void DMA_List_BuildNode(DMA_NodeConfTypeDef const *const pNodeConfig,
541                                DMA_NodeTypeDef *const pNode);
542 static void DMA_List_GetNodeConfig(DMA_NodeConfTypeDef *const pNodeConfig,
543                                    DMA_NodeTypeDef const *const pNode);
544 static uint32_t DMA_List_CheckNodesBaseAddresses(DMA_NodeTypeDef const *const pNode1,
545                                                  DMA_NodeTypeDef const *const pNode2,
546                                                  DMA_NodeTypeDef const *const pNode3);
547 static uint32_t DMA_List_CheckNodesTypes(DMA_NodeTypeDef const *const pNode1,
548                                          DMA_NodeTypeDef const *const pNode2,
549                                          DMA_NodeTypeDef const *const pNode3);
550 static void DMA_List_GetCLLRNodeInfo(DMA_NodeTypeDef const *const pNode,
551                                      uint32_t *const cllr_mask,
552                                      uint32_t *const cllr_offset);
553 static uint32_t DMA_List_FindNode(DMA_QListTypeDef const *const pQList,
554                                   DMA_NodeTypeDef const *const pNode,
555                                   DMA_NodeInQInfoTypeDef *const NodeInfo);
556 static void DMA_List_ResetQueueNodes(DMA_QListTypeDef const *const pQList,
557                                      DMA_NodeInQInfoTypeDef const *const NodeInfo);
558 static void DMA_List_FillNode(DMA_NodeTypeDef const *const pSrcNode,
559                               DMA_NodeTypeDef *const pDestNode);
560 static void DMA_List_ConvertNodeToDynamic(uint32_t ContextNodeAddr,
561                                           uint32_t CurrentNodeAddr,
562                                           uint32_t RegisterNumber);
563 static void DMA_List_ConvertNodeToStatic(uint32_t ContextNodeAddr,
564                                          uint32_t CurrentNodeAddr,
565                                          uint32_t RegisterNumber);
566 static void DMA_List_UpdateDynamicQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
567                                                  uint32_t LastNode_IsCircular);
568 static void DMA_List_UpdateStaticQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
569                                                 uint32_t operation);
570 static void DMA_List_FormatNode(DMA_NodeTypeDef *const pNode,
571                                 uint32_t RegisterIdx,
572                                 uint32_t RegisterNumber,
573                                 uint32_t Format);
574 static void DMA_List_ClearUnusedFields(DMA_NodeTypeDef *const pNode,
575                                        uint32_t FirstUnusedField);
576 static void DMA_List_CleanQueue(DMA_QListTypeDef *const pQList);
577 
578 /* Exported functions ------------------------------------------------------------------------------------------------*/
579 
580 /** @addtogroup DMAEx_Exported_Functions
581   * @{
582   */
583 
584 /** @addtogroup DMAEx_Exported_Functions_Group1
585   *
586 @verbatim
587   ======================================================================================================================
588                  ##### Linked-List Initialization and De-Initialization Functions #####
589   ======================================================================================================================
590     [..]
591       This section provides functions allowing to initialize and de-initialize the DMA channel in linked-list mode.
592     [..]
593       (+) The HAL_DMAEx_List_Init() function follows the DMA channel linked-list mode configuration procedures as
594           described in reference manual.
595       (+) The HAL_DMAEx_List_DeInit() function allows to de-initialize the DMA channel in linked-list mode.
596 
597 @endverbatim
598   * @{
599   */
600 
601 /**
602   * @brief  Initialize the DMA channel in linked-list mode according to the specified parameters in the
603   *         DMA_InitLinkedListTypeDef and create the associated handle.
604   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
605   *                specified DMA Channel.
606   * @retval HAL status.
607   */
HAL_DMAEx_List_Init(DMA_HandleTypeDef * const hdma)608 HAL_StatusTypeDef HAL_DMAEx_List_Init(DMA_HandleTypeDef *const hdma)
609 {
610   /* Get tick number */
611   uint32_t tickstart = HAL_GetTick();
612 
613   /* Check the DMA channel handle parameter */
614   if (hdma == NULL)
615   {
616     return HAL_ERROR;
617   }
618 
619   /* Check the parameters */
620   assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
621   assert_param(IS_DMA_PRIORITY(hdma->InitLinkedList.Priority));
622   assert_param(IS_DMA_LINK_STEP_MODE(hdma->InitLinkedList.LinkStepMode));
623   assert_param(IS_DMA_TCEM_LINKEDLIST_EVENT_MODE(hdma->InitLinkedList.TransferEventMode));
624   assert_param(IS_DMA_LINKEDLIST_MODE(hdma->InitLinkedList.LinkedListMode));
625   /* Check DMA channel instance */
626   if ((IS_HPDMA_INSTANCE(hdma->Instance) != 0U) || (IS_GPDMA_INSTANCE(hdma->Instance) != 0U))
627   {
628     assert_param(IS_DMA_LINK_ALLOCATED_PORT(hdma->InitLinkedList.LinkAllocatedPort));
629   }
630 
631   /* Allocate lock resource */
632   __HAL_UNLOCK(hdma);
633 
634   /* Change DMA peripheral state */
635   hdma->State = HAL_DMA_STATE_BUSY;
636 
637   /* Disable the DMA channel */
638   __HAL_DMA_DISABLE(hdma);
639 
640   /* Check if the DMA channel is effectively disabled */
641   while ((hdma->Instance->CCR & DMA_CCR_EN) != 0U)
642   {
643     /* Check for the Timeout */
644     if ((HAL_GetTick() - tickstart) > HAL_TIMEOUT_DMA_ABORT)
645     {
646       /* Update error code */
647       hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;
648 
649       /* Change the DMA state */
650       hdma->State = HAL_DMA_STATE_ERROR;
651 
652       return HAL_ERROR;
653     }
654   }
655 
656   /* Initialize the DMA channel registers */
657   DMA_List_Init(hdma);
658 
659   /* Update DMA channel operation mode */
660   hdma->Mode = hdma->InitLinkedList.LinkedListMode;
661 
662   /* Update the DMA channel error code */
663   hdma->ErrorCode = HAL_DMA_ERROR_NONE;
664 
665   /* Update the DMA channel state */
666   hdma->State = HAL_DMA_STATE_READY;
667 
668   return HAL_OK;
669 }
670 
671 /**
672   * @brief  DeInitialize the DMA channel when it is configured in linked-list mode.
673   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
674   *                specified DMA Channel.
675   * @retval HAL status.
676   */
HAL_DMAEx_List_DeInit(DMA_HandleTypeDef * const hdma)677 HAL_StatusTypeDef HAL_DMAEx_List_DeInit(DMA_HandleTypeDef *const hdma)
678 {
679 
680   /* Get DMA instance */
681   DMA_TypeDef *p_dma_instance;
682 
683   /* Get tick number */
684   uint32_t tickstart = HAL_GetTick();
685 
686   /* Check the DMA peripheral handle parameter */
687   if (hdma == NULL)
688   {
689     return HAL_ERROR;
690   }
691 
692   /* Check the parameters */
693   assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
694 
695 
696   /* Get DMA instance */
697   p_dma_instance = GET_DMA_INSTANCE(hdma);
698 
699   /* Disable the selected DMA Channel */
700   __HAL_DMA_DISABLE(hdma);
701 
702   /* Check if the DMA channel is effectively disabled */
703   while ((hdma->Instance->CCR & DMA_CCR_EN) != 0U)
704   {
705     /* Check for the Timeout */
706     if ((HAL_GetTick() - tickstart) > HAL_TIMEOUT_DMA_ABORT)
707     {
708       /* Update error code */
709       hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;
710 
711       /* Change the DMA state */
712       hdma->State = HAL_DMA_STATE_ERROR;
713 
714       return HAL_ERROR;
715     }
716   }
717 
718   /* Reset DMA Channel registers */
719   hdma->Instance->CCR   = 0U;
720   hdma->Instance->CLBAR = 0U;
721   hdma->Instance->CTR1  = 0U;
722   hdma->Instance->CTR2  = 0U;
723   hdma->Instance->CBR1  = 0U;
724   hdma->Instance->CSAR  = 0U;
725   hdma->Instance->CDAR  = 0U;
726   hdma->Instance->CLLR  = 0U;
727 
728   /* Reset 2D Addressing registers */
729   if (IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance) != 0U)
730   {
731     hdma->Instance->CTR3 = 0U;
732     hdma->Instance->CBR2 = 0U;
733   }
734 
735 
736   /* Clear privilege attribute */
737   CLEAR_BIT(p_dma_instance->PRIVCFGR, (1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU)));
738 
739 
740 #if defined (CPU_IN_SECURE_STATE)
741   /* Clear secure attribute */
742   CLEAR_BIT(p_dma_instance->SECCFGR, (1UL << (GET_DMA_CHANNEL(hdma) & 0x1FU)));
743 #endif /* CPU_IN_SECURE_STATE */
744 
745   /* Clear all flags */
746   __HAL_DMA_CLEAR_FLAG(hdma, (DMA_FLAG_TC | DMA_FLAG_HT | DMA_FLAG_DTE | DMA_FLAG_ULE | DMA_FLAG_USE | DMA_FLAG_SUSP |
747                               DMA_FLAG_TO));
748 
749   /* Clean all callbacks */
750   hdma->XferCpltCallback     = NULL;
751   hdma->XferHalfCpltCallback = NULL;
752   hdma->XferErrorCallback    = NULL;
753   hdma->XferAbortCallback    = NULL;
754   hdma->XferSuspendCallback  = NULL;
755 
756   /* Check the linked-list queue */
757   if (hdma->LinkedListQueue != NULL)
758   {
759     /* Update the queue state and error code */
760     hdma->LinkedListQueue->State     = HAL_DMA_QUEUE_STATE_READY;
761     hdma->LinkedListQueue->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
762 
763     /* Clean DMA queue */
764     hdma->LinkedListQueue = NULL;
765   }
766 
767   /* Clean DMA parent */
768   if (hdma->Parent != NULL)
769   {
770     hdma->Parent = NULL;
771   }
772 
773   /* Update DMA channel operation mode */
774   hdma->Mode = DMA_NORMAL;
775 
776   /* Update the DMA channel error code */
777   hdma->ErrorCode = HAL_DMA_ERROR_NONE;
778 
779   /* Update the DMA channel state */
780   hdma->State = HAL_DMA_STATE_RESET;
781 
782   /* Release Lock */
783   __HAL_UNLOCK(hdma);
784 
785   return HAL_OK;
786 }
787 /**
788   * @}
789   */
790 
791 /** @addtogroup DMAEx_Exported_Functions_Group2
792   *
793 @verbatim
794   ======================================================================================================================
795                          ##### Linked-List IO Operation Functions #####
796   ======================================================================================================================
797     [..]
798       This section provides functions allowing to :
799       (+) Configure to start DMA transfer in linked-list mode.
800 
801     [..]
802       (+) The HAL_DMAEx_List_Start() function allows to start the DMA channel transfer in linked-list mode (Blocking
803           mode).
804       (+) The HAL_DMAEx_List_Start_IT() function allows to start the DMA channel transfer in linked-list mode
805           (Non-blocking mode).
806               (++) It is mandatory to register a linked-list queue to be executed by a DMA channel before starting
807                    transfer otherwise a HAL_ERROR will be returned.
808 
809 @endverbatim
810   * @{
811   */
812 
813 /**
814   * @brief  Start the DMA channel transfer in linked-list mode (Blocking mode).
815   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
816   *                specified DMA Channel.
817   * @retval HAL status.
818   */
HAL_DMAEx_List_Start(DMA_HandleTypeDef * const hdma)819 HAL_StatusTypeDef HAL_DMAEx_List_Start(DMA_HandleTypeDef *const hdma)
820 {
821   HAL_DMA_StateTypeDef dma_state;
822   uint32_t ccr_value;
823   uint32_t cllr_mask;
824 
825   /* Check the DMA peripheral handle and the linked-list queue parameters */
826   if ((hdma == NULL) || (hdma->LinkedListQueue == NULL))
827   {
828     return HAL_ERROR;
829   }
830 
831   /* Check DMA channel state */
832   dma_state = hdma->State;
833   ccr_value = hdma->Instance->CCR & DMA_CCR_LSM;
834   if ((dma_state == HAL_DMA_STATE_READY) || ((dma_state == HAL_DMA_STATE_BUSY) && (ccr_value != 0U)))
835   {
836     /* Check DMA channel state is ready */
837     if (hdma->State == HAL_DMA_STATE_READY)
838     {
839       /* Process locked */
840       __HAL_LOCK(hdma);
841 
842       /* Update the DMA channel and the queue states */
843       hdma->State                  = HAL_DMA_STATE_BUSY;
844       hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_BUSY;
845 
846       /* Update the DMA channel and the queue error codes */
847       hdma->ErrorCode                  = HAL_DMA_ERROR_NONE;
848       hdma->LinkedListQueue->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
849 
850       /* Get CLLR register mask and offset */
851       DMA_List_GetCLLRNodeInfo(hdma->LinkedListQueue->Head, &cllr_mask, NULL);
852 
853       /* Update DMA registers for linked-list transfer */
854       hdma->Instance->CLBAR = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLBAR_LBA);
855       hdma->Instance->CLLR  = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLLR_LA) | cllr_mask;
856     }
857 
858     /* Enable DMA channel */
859     __HAL_DMA_ENABLE(hdma);
860   }
861   else
862   {
863     /* Update the DMA channel error code */
864     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
865 
866     /* Process unlocked */
867     __HAL_UNLOCK(hdma);
868 
869     return HAL_ERROR;
870   }
871 
872   return HAL_OK;
873 }
874 
875 /**
876   * @brief  Starts the DMA channel transfer in linked-list mode with interrupts enabled (Non-blocking mode).
877   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
878   *                specified DMA Channel.
879   * @retval HAL status.
880   */
HAL_DMAEx_List_Start_IT(DMA_HandleTypeDef * const hdma)881 HAL_StatusTypeDef HAL_DMAEx_List_Start_IT(DMA_HandleTypeDef *const hdma)
882 {
883   HAL_DMA_StateTypeDef dma_state;
884   uint32_t ccr_value;
885   uint32_t cllr_mask;
886 
887   /* Check the DMA peripheral handle and the linked-list queue parameters */
888   if ((hdma == NULL) || (hdma->LinkedListQueue == NULL))
889   {
890     return HAL_ERROR;
891   }
892 
893   /* Check DMA channel state */
894   dma_state = hdma->State;
895   ccr_value = hdma->Instance->CCR & DMA_CCR_LSM;
896   if ((dma_state == HAL_DMA_STATE_READY) || ((dma_state == HAL_DMA_STATE_BUSY) && (ccr_value != 0U)))
897   {
898     /* Check DMA channel state is ready */
899     if (hdma->State == HAL_DMA_STATE_READY)
900     {
901       /* Process locked */
902       __HAL_LOCK(hdma);
903 
904       /* Update the DMA channel and the queue states */
905       hdma->State                  = HAL_DMA_STATE_BUSY;
906       hdma->LinkedListQueue->State = HAL_DMA_QUEUE_STATE_BUSY;
907 
908       /* Update the DMA channel and the queue error codes */
909       hdma->ErrorCode                  = HAL_DMA_ERROR_NONE;
910       hdma->LinkedListQueue->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
911 
912       /* Enable common interrupts: Transfer Complete and Transfer Errors ITs */
913       __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_DTE | DMA_IT_ULE | DMA_IT_USE | DMA_IT_TO));
914 
915       /* Check half transfer complete callback */
916       if (hdma->XferHalfCpltCallback != NULL)
917       {
918         /* If half transfer complete callback is set, enable the corresponding IT */
919         __HAL_DMA_ENABLE_IT(hdma, DMA_IT_HT);
920       }
921 
922       /* Check suspend callback */
923       if (hdma->XferSuspendCallback != NULL)
924       {
925         /* If transfer suspend callback is set, enable the corresponding IT */
926         __HAL_DMA_ENABLE_IT(hdma, DMA_IT_SUSP);
927       }
928 
929       /* Get CLLR register mask and offset */
930       DMA_List_GetCLLRNodeInfo(hdma->LinkedListQueue->Head, &cllr_mask, NULL);
931 
932       /* Update DMA registers for linked-list transfer */
933       hdma->Instance->CLBAR = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLBAR_LBA);
934       hdma->Instance->CLLR  = ((uint32_t)hdma->LinkedListQueue->Head & DMA_CLLR_LA) | cllr_mask;
935     }
936 
937     /* Enable DMA channel */
938     __HAL_DMA_ENABLE(hdma);
939   }
940   else
941   {
942     /* Change the error code */
943     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
944 
945     /* Process unlocked */
946     __HAL_UNLOCK(hdma);
947 
948     return HAL_ERROR;
949   }
950 
951   return HAL_OK;
952 }
953 /**
954   * @}
955   */
956 
957 /** @addtogroup DMAEx_Exported_Functions_Group3
958   *
959 @verbatim
960   ======================================================================================================================
961                          ##### Linked-List Management Functions #####
962   ======================================================================================================================
963     [..]
964       This section provides functions allowing to :
965       (+) Build linked-list node.
966       (+) Get linked-list node configuration.
967       (+) Insert node to linked-list queue in any queue position.
968       (+) Remove any node from linked-list queue.
969       (+) Replace any node from linked-list queue.
970       (+) Reset linked-list queue.
971       (+) Insert linked-list queue in any queue position.
972       (+) Set circular mode configuration to linked-list queue.
973       (+) Clear circular mode configuration from linked-list queue.
974       (+) Convert static linked-list queue to dynamic format.
975       (+) Convert dynamic linked-list queue to static format.
976       (+) Link linked-list queue to DMA channel.
977       (+) Unlink linked-list queue from DMA channel.
978 
979     [..]
980       (+) The HAL_DMAEx_List_BuildNode() function allows to build linked-list node.
981           Node type can be :
982               (++) 2 dimensions addressing node.
983               (++) Linear addressing node.
984 
985       (+) The HAL_DMAEx_List_GetNodeConfig() function allows to get the linked-list node configuration from built node.
986 
987       (+) The HAL_DMAEx_List_InsertNode() function allows to insert built linked-list node to static linked-list queue
988           according to selected position.
989 
990       (+) The HAL_DMAEx_List_InsertNode_Head() and HAL_DMAEx_List_InsertNode_Tail() functions allow to insert built
991           linked-list node to the head (respectively the tail) of static linked-list queue.
992 
993       (+) The HAL_DMAEx_List_RemoveNode() function allows to remove selected built linked-list node from static
994           linked-list queue.
995 
996       (+) The HAL_DMAEx_List_RemoveNode_Head() and HAL_DMAEx_List_RemoveNode_Tail() functions allow to remove the head
997           (respectively the tail) built linked-list node from static linked-list queue.
998 
999       (+) The HAL_DMAEx_List_ReplaceNode() function allows to replace selected built linked-list node from static
1000           linked-list queue.
1001 
1002       (+) The HAL_DMAEx_List_ReplaceNode_Head() and HAL_DMAEx_List_ReplaceNode_Tail() functions allow to replace the
1003           head (respectively the tail) built linked-list node of static linked-list queue.
1004 
1005       (+) The HAL_DMAEx_List_ResetQ() function allows to reset static linked-list queue and unlink all built linked-list
1006           nodes.
1007 
1008       (+) The HAL_DMAEx_List_InsertQ() function allows to insert static linked-list source queue to static linked-list
1009           destination queue according to selected position.
1010 
1011       (+) The HAL_DMAEx_List_InsertQ_Head() and HAL_DMAEx_List_InsertQ_Tail() functions allow to insert static
1012           linked-list source queue to the head (respectively the tail) of static linked-list destination queue.
1013 
1014       (+) The HAL_DMAEx_List_SetCircularModeConfig() function allows to link the last static linked-list queue node to
1015           the selected first circular node.
1016 
1017       (+) The HAL_DMAEx_List_SetCircularMode() function allows to link the last static linked-list queue node to the
1018           first static linked-list queue node.
1019 
1020       (+) The HAL_DMAEx_List_ClearCircularMode() function allows to unlink the last static linked-list queue node from
1021           any first circular node position.
1022 
1023       (+) The HAL_DMAEx_List_ConvertQToDynamic() function allows to convert the static linked-list queue to dynamic
1024           format. (Optimized queue execution)
1025 
1026       (+) The HAL_DMAEx_List_ConvertQToStatic() function allows to convert the dynamic linked-list queue to static
1027           format. (Not optimized queue execution)
1028 
1029       (+) The HAL_DMAEx_List_LinkQ() function allows to link the (Dynamic / Static) linked-list queue to DMA channel to
1030           be executed.
1031 
1032       (+) The HAL_DMAEx_List_UnLinkQ() function allows to unlink the (Dynamic / Static) linked-list queue from DMA
1033           channel when execution is completed.
1034 
1035 @endverbatim
1036   * @{
1037   */
1038 
1039 /**
1040   * @brief  Build a DMA channel node according to the specified parameters in the DMA_NodeConfTypeDef.
1041   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
1042   *                       specified DMA linked-list Node.
1043   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
1044   *                       configurations.
1045   * @note   The DMA linked-list node parameter address should be 32bit aligned and should not exceed the 64 KByte
1046   *         addressable space.
1047   * @note   Warning if AXI port is selected with HPDMA, the maximum source (and destination) length should be less
1048   *         than 17. Otherwise, an error will be returned and no initialization performed.
1049   * @retval HAL status.
1050   */
HAL_DMAEx_List_BuildNode(DMA_NodeConfTypeDef const * const pNodeConfig,DMA_NodeTypeDef * const pNode)1051 HAL_StatusTypeDef HAL_DMAEx_List_BuildNode(DMA_NodeConfTypeDef const *const pNodeConfig,
1052                                            DMA_NodeTypeDef *const pNode)
1053 {
1054   /* Check the node configuration and physical node parameters */
1055   if ((pNodeConfig == NULL) || (pNode == NULL))
1056   {
1057     return HAL_ERROR;
1058   }
1059 
1060   /* Check node type parameter */
1061   assert_param(IS_DMA_NODE_TYPE(pNodeConfig->NodeType));
1062 
1063   /* Check DMA channel basic transfer parameters */
1064   assert_param(IS_DMA_SOURCE_INC(pNodeConfig->Init.SrcInc));
1065   assert_param(IS_DMA_DESTINATION_INC(pNodeConfig->Init.DestInc));
1066   assert_param(IS_DMA_SOURCE_DATA_WIDTH(pNodeConfig->Init.SrcDataWidth));
1067   assert_param(IS_DMA_DESTINATION_DATA_WIDTH(pNodeConfig->Init.DestDataWidth));
1068   assert_param(IS_DMA_DATA_ALIGNMENT(pNodeConfig->DataHandlingConfig.DataAlignment));
1069   assert_param(IS_DMA_REQUEST(pNodeConfig->Init.Request));
1070   assert_param(IS_DMA_DIRECTION(pNodeConfig->Init.Direction));
1071   assert_param(IS_DMA_TCEM_EVENT_MODE(pNodeConfig->Init.TransferEventMode));
1072   assert_param(IS_DMA_BLOCK_HW_REQUEST(pNodeConfig->Init.BlkHWRequest));
1073   assert_param(IS_DMA_MODE(pNodeConfig->Init.Mode));
1074 
1075   /* Check DMA channel parameters */
1076   if ((pNodeConfig->NodeType & (DMA_CHANNEL_TYPE_GPDMA | DMA_CHANNEL_TYPE_HPDMA)) != 0U)
1077   {
1078     assert_param(IS_DMA_BURST_LENGTH(pNodeConfig->Init.SrcBurstLength));
1079     assert_param(IS_DMA_BURST_LENGTH(pNodeConfig->Init.DestBurstLength));
1080     assert_param(IS_DMA_DATA_EXCHANGE(pNodeConfig->DataHandlingConfig.DataExchange));
1081     assert_param(IS_DMA_TRANSFER_ALLOCATED_PORT(pNodeConfig->Init.TransferAllocatedPort));
1082   }
1083 
1084   /* Check DMA channel trigger parameters */
1085   assert_param(IS_DMA_TRIGGER_POLARITY(pNodeConfig->TriggerConfig.TriggerPolarity));
1086   if (pNodeConfig->TriggerConfig.TriggerPolarity != DMA_TRIG_POLARITY_MASKED)
1087   {
1088     assert_param(IS_DMA_TRIGGER_MODE(pNodeConfig->TriggerConfig.TriggerMode));
1089     assert_param(IS_DMA_TRIGGER_SELECTION(pNodeConfig->TriggerConfig.TriggerSelection));
1090   }
1091 
1092   /* Check DMA channel repeated block parameters */
1093   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
1094   {
1095     assert_param(IS_DMA_REPEAT_COUNT(pNodeConfig->RepeatBlockConfig.RepeatCount));
1096     assert_param(IS_DMA_BURST_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.SrcAddrOffset));
1097     assert_param(IS_DMA_BURST_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.DestAddrOffset));
1098     assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset));
1099     assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset));
1100   }
1101 
1102   /* Check DMA channel security and privilege attributes parameters */
1103 #if defined (CPU_IN_SECURE_STATE)
1104   assert_param(IS_DMA_ATTRIBUTES(pNodeConfig->SrcSecure));
1105   assert_param(IS_DMA_ATTRIBUTES(pNodeConfig->DestSecure));
1106 #endif /* CPU_IN_SECURE_STATE */
1107 
1108   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_HPDMA) == DMA_CHANNEL_TYPE_HPDMA)
1109   {
1110     if (((pNodeConfig->Init.TransferAllocatedPort & DMA_CTR1_SAP) == DMA_SRC_ALLOCATED_PORT0) &&
1111         (pNodeConfig->Init.SrcBurstLength > 16U))
1112     {
1113       return HAL_ERROR;
1114     }
1115     if (((pNodeConfig->Init.TransferAllocatedPort & DMA_CTR1_DAP) == DMA_DEST_ALLOCATED_PORT0) &&
1116         (pNodeConfig->Init.DestBurstLength > 16U))
1117     {
1118       return HAL_ERROR;
1119     }
1120   }
1121 
1122   /* Build the DMA channel node */
1123   DMA_List_BuildNode(pNodeConfig, pNode);
1124 
1125   return HAL_OK;
1126 }
1127 
1128 /**
1129   * @brief  Get a DMA channel node configuration.
1130   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
1131   *                       specified DMA linked-list Node.
1132   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
1133   *                       configurations.
1134   * @retval HAL status.
1135   */
HAL_DMAEx_List_GetNodeConfig(DMA_NodeConfTypeDef * const pNodeConfig,DMA_NodeTypeDef const * const pNode)1136 HAL_StatusTypeDef HAL_DMAEx_List_GetNodeConfig(DMA_NodeConfTypeDef *const pNodeConfig,
1137                                                DMA_NodeTypeDef const *const pNode)
1138 {
1139   /* Check the node configuration and physical node parameters */
1140   if ((pNodeConfig == NULL) || (pNode == NULL))
1141   {
1142     return HAL_ERROR;
1143   }
1144 
1145   /* Get the DMA channel node configuration */
1146   DMA_List_GetNodeConfig(pNodeConfig, pNode);
1147 
1148   return HAL_OK;
1149 }
1150 
1151 /**
1152   * @brief  Insert new node in any queue position of linked-list queue according to selecting previous node.
1153   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
1154   * @param  pPrevNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list previous node registers
1155   *                     configurations.
1156   * @param  pNewNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
1157   *                     configurations.
1158   * @retval HAL status.
1159   */
HAL_DMAEx_List_InsertNode(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pPrevNode,DMA_NodeTypeDef * const pNewNode)1160 HAL_StatusTypeDef HAL_DMAEx_List_InsertNode(DMA_QListTypeDef *const pQList,
1161                                             DMA_NodeTypeDef *const pPrevNode,
1162                                             DMA_NodeTypeDef *const pNewNode)
1163 {
1164   uint32_t cllr_mask;
1165   uint32_t cllr_offset;
1166   DMA_NodeInQInfoTypeDef node_info;
1167 
1168   /* Check the queue and the new node parameters */
1169   if ((pQList == NULL) || (pNewNode == NULL))
1170   {
1171     return HAL_ERROR;
1172   }
1173 
1174   /* Check queue type */
1175   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1176   {
1177     /* Update the queue error code */
1178     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1179 
1180     return HAL_ERROR;
1181   }
1182 
1183   /* Check nodes base addresses */
1184   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pPrevNode, pNewNode) != 0U)
1185   {
1186     /* Update the queue error code */
1187     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
1188 
1189     return HAL_ERROR;
1190   }
1191 
1192   /* Check nodes types compatibility */
1193   if (DMA_List_CheckNodesTypes(pQList->Head, pPrevNode, pNewNode) != 0U)
1194   {
1195     /* Update the queue error code */
1196     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1197 
1198     return HAL_ERROR;
1199   }
1200 
1201   /* Update the queue state */
1202   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
1203 
1204   /* Update the queue error code */
1205   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1206 
1207   /* Get CLLR register mask and offset */
1208   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
1209 
1210   /* Empty queue */
1211   if (pQList->Head == NULL)
1212   {
1213     /* Add only new node to queue */
1214     if (pPrevNode == NULL)
1215     {
1216       pQList->Head       = pNewNode;
1217       pQList->NodeNumber = 1U;
1218     }
1219     /* Add previous node then new node to queue */
1220     else
1221     {
1222       pQList->Head                          = pPrevNode;
1223       pPrevNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1224       pQList->NodeNumber                    = 2U;
1225     }
1226   }
1227   /* Not empty queue */
1228   else
1229   {
1230     /* Add new node at the head of queue */
1231     if (pPrevNode == NULL)
1232     {
1233       pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
1234       pQList->Head                         = pNewNode;
1235     }
1236     /* Add new node according to selected position */
1237     else
1238     {
1239       /* Find node and get its position in selected queue */
1240       node_info.cllr_offset = cllr_offset;
1241       if (DMA_List_FindNode(pQList, pPrevNode, &node_info) == 0U)
1242       {
1243         /* Selected node is the last queue node */
1244         if (node_info.currentnode_pos == pQList->NodeNumber)
1245         {
1246           /* Check if queue is circular */
1247           if (pQList->FirstCircularNode != NULL)
1248           {
1249             pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
1250           }
1251 
1252           pPrevNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1253         }
1254         /* Selected node is not the last queue node */
1255         else
1256         {
1257           pNewNode->LinkRegisters[cllr_offset] = pPrevNode->LinkRegisters[cllr_offset];
1258           pPrevNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1259         }
1260       }
1261       else
1262       {
1263         /* Update the queue error code */
1264         pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
1265 
1266         return HAL_ERROR;
1267       }
1268     }
1269 
1270     /* Increment queue node number */
1271     pQList->NodeNumber++;
1272   }
1273 
1274   /* Update the queue error code */
1275   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1276 
1277   /* Update the queue state */
1278   pQList->State = HAL_DMA_QUEUE_STATE_READY;
1279 
1280   return HAL_OK;
1281 }
1282 
1283 /**
1284   * @brief  Insert new node at the head of linked-list queue.
1285   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
1286   * @param  pNewNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
1287   *                     configurations.
1288   * @retval HAL status.
1289   */
HAL_DMAEx_List_InsertNode_Head(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pNewNode)1290 HAL_StatusTypeDef HAL_DMAEx_List_InsertNode_Head(DMA_QListTypeDef *const pQList,
1291                                                  DMA_NodeTypeDef *const pNewNode)
1292 {
1293   uint32_t cllr_mask;
1294   uint32_t cllr_offset;
1295 
1296   /* Check the queue and the new node parameters */
1297   if ((pQList == NULL) || (pNewNode == NULL))
1298   {
1299     return HAL_ERROR;
1300   }
1301 
1302   /* Check queue type */
1303   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1304   {
1305     /* Update the queue error code */
1306     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1307 
1308     return HAL_ERROR;
1309   }
1310 
1311   /* Check nodes base addresses */
1312   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pNewNode, NULL) != 0U)
1313   {
1314     /* Update the queue error code */
1315     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
1316 
1317     return HAL_ERROR;
1318   }
1319 
1320   /* Check nodes types compatibility */
1321   if (DMA_List_CheckNodesTypes(pQList->Head, pNewNode, NULL) != 0U)
1322   {
1323     /* Update the queue error code */
1324     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1325 
1326     return HAL_ERROR;
1327   }
1328 
1329   /* Update the queue state */
1330   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
1331 
1332   /* Update the queue error code */
1333   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1334 
1335   /* Empty queue */
1336   if (pQList->Head == NULL)
1337   {
1338     pQList->Head = pNewNode;
1339   }
1340   /* Not empty queue */
1341   else
1342   {
1343     /* Get CLLR register mask and offset */
1344     DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
1345 
1346     pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
1347     pQList->Head                         = pNewNode;
1348   }
1349 
1350   /* Increment queue node number */
1351   pQList->NodeNumber++;
1352 
1353   /* Update the queue error code */
1354   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1355 
1356   /* Update the queue state */
1357   pQList->State = HAL_DMA_QUEUE_STATE_READY;
1358 
1359   return HAL_OK;
1360 }
1361 
1362 /**
1363   * @brief  Insert new node at the tail of linked-list queue.
1364   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
1365   * @param  pNewNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
1366   *                     configurations.
1367   * @retval HAL status.
1368   */
HAL_DMAEx_List_InsertNode_Tail(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pNewNode)1369 HAL_StatusTypeDef HAL_DMAEx_List_InsertNode_Tail(DMA_QListTypeDef *const pQList,
1370                                                  DMA_NodeTypeDef *const pNewNode)
1371 {
1372   uint32_t cllr_mask;
1373   uint32_t cllr_offset;
1374   DMA_NodeInQInfoTypeDef node_info;
1375 
1376   /* Check the queue and the new node parameters */
1377   if ((pQList == NULL) || (pNewNode == NULL))
1378   {
1379     return HAL_ERROR;
1380   }
1381 
1382   /* Check queue type */
1383   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1384   {
1385     /* Update the queue error code */
1386     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1387 
1388     return HAL_ERROR;
1389   }
1390 
1391   /* Check nodes base addresses */
1392   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pNewNode, NULL) != 0U)
1393   {
1394     /* Update the queue error code */
1395     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
1396 
1397     return HAL_ERROR;
1398   }
1399 
1400   /* Check nodes types compatibility */
1401   if (DMA_List_CheckNodesTypes(pQList->Head, pNewNode, NULL) != 0U)
1402   {
1403     /* Update the queue error code */
1404     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1405 
1406     return HAL_ERROR;
1407   }
1408 
1409   /* Empty queue */
1410   if (pQList->Head == NULL)
1411   {
1412     pQList->Head = pNewNode;
1413   }
1414   /* Not empty queue */
1415   else
1416   {
1417     /* Get CLLR register mask and offset */
1418     DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
1419 
1420     /* Find node and get its position in selected queue */
1421     node_info.cllr_offset = cllr_offset;
1422     (void)DMA_List_FindNode(pQList, NULL, &node_info);
1423 
1424     /* Check if queue is circular */
1425     if (pQList->FirstCircularNode != NULL)
1426     {
1427       pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
1428     }
1429 
1430     ((DMA_NodeTypeDef *)node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
1431       ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1432   }
1433 
1434   /* Increment queue node number */
1435   pQList->NodeNumber++;
1436 
1437   /* Update the queue error code */
1438   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1439 
1440   /* Update the queue state */
1441   pQList->State = HAL_DMA_QUEUE_STATE_READY;
1442 
1443   /* Prevent MISRA-C2012-Rule-2.2_b */
1444   UNUSED(node_info);
1445 
1446   return HAL_OK;
1447 }
1448 
1449 /**
1450   * @brief  Remove node from any linked-list queue position.
1451   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
1452   * @param  pNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list previous node registers
1453   *                  configurations.
1454   * @retval HAL status.
1455   */
HAL_DMAEx_List_RemoveNode(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pNode)1456 HAL_StatusTypeDef HAL_DMAEx_List_RemoveNode(DMA_QListTypeDef *const pQList,
1457                                             DMA_NodeTypeDef *const pNode)
1458 {
1459   uint32_t previousnode_addr;
1460   uint32_t cllr_offset;
1461   DMA_NodeInQInfoTypeDef node_info;
1462 
1463   /* Check the queue and the node parameters */
1464   if ((pQList == NULL) || (pNode == NULL))
1465   {
1466     return HAL_ERROR;
1467   }
1468 
1469   /* Check the queue */
1470   if (pQList->Head == NULL)
1471   {
1472     /* Update the queue error code */
1473     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
1474 
1475     return HAL_ERROR;
1476   }
1477 
1478   /* Check queue type */
1479   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1480   {
1481     /* Update the queue error code */
1482     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1483 
1484     return HAL_ERROR;
1485   }
1486 
1487   /* Update the queue state */
1488   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
1489 
1490   /* Update the queue error code */
1491   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1492 
1493   /* Get CLLR register mask and offset */
1494   DMA_List_GetCLLRNodeInfo(pNode, NULL, &cllr_offset);
1495 
1496   /* Find node and get its position in selected queue */
1497   node_info.cllr_offset = cllr_offset;
1498   if (DMA_List_FindNode(pQList, pNode, &node_info) == 0U)
1499   {
1500     /* Removed node is the head node */
1501     if (node_info.currentnode_pos == 1U)
1502     {
1503       /* Check if first circular node queue is the first node */
1504       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)node_info.currentnode_addr))
1505       {
1506         /* Find last queue node */
1507         (void)DMA_List_FindNode(pQList, NULL, &node_info);
1508 
1509         /* Clear last node link */
1510         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1511 
1512         /* Clear first circular node */
1513         pQList->FirstCircularNode = NULL;
1514       }
1515 
1516       /* Update the queue head node */
1517       pQList->Head = (DMA_NodeTypeDef *)(((uint32_t)pQList->Head & DMA_CLBAR_LBA) +
1518                                          (pNode->LinkRegisters[cllr_offset] & DMA_CLLR_LA));
1519       /* Unlink node to be removed */
1520       pNode->LinkRegisters[cllr_offset] = 0U;
1521     }
1522     /* Removed node is the last node */
1523     else if (node_info.currentnode_pos == pQList->NodeNumber)
1524     {
1525       /* Clear CLLR for previous node */
1526       ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] = 0U;
1527 
1528       /* Clear CLLR for last node */
1529       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1530 
1531       /* Clear first circular node */
1532       pQList->FirstCircularNode = NULL;
1533     }
1534     /* Removed node is in the middle */
1535     else
1536     {
1537       /* Store previous node address to be updated later */
1538       previousnode_addr = node_info.previousnode_addr;
1539 
1540       /* Check if first circular node queue is the current node */
1541       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)node_info.currentnode_addr))
1542       {
1543         /* Find last queue node */
1544         (void)DMA_List_FindNode(pQList, NULL, &node_info);
1545 
1546         /* Clear last node link */
1547         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1548 
1549         /* Clear first circular node */
1550         pQList->FirstCircularNode = NULL;
1551       }
1552 
1553       /* Link previous node */
1554       ((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[cllr_offset] = pNode->LinkRegisters[cllr_offset];
1555 
1556       /* Unlink node to be removed */
1557       pNode->LinkRegisters[cllr_offset] = 0U;
1558     }
1559 
1560     /* Decrement node number */
1561     pQList->NodeNumber--;
1562   }
1563   else
1564   {
1565     /* Update the queue error code */
1566     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
1567 
1568     return HAL_ERROR;
1569   }
1570 
1571   /* Check if queue is empty */
1572   if (pQList->NodeNumber == 0U)
1573   {
1574     /* Clean empty queue parameter */
1575     DMA_List_CleanQueue(pQList);
1576   }
1577   else
1578   {
1579     /* Update the queue error code */
1580     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1581 
1582     /* Update the queue state */
1583     pQList->State = HAL_DMA_QUEUE_STATE_READY;
1584   }
1585 
1586   /* Prevent MISRA-C2012-Rule-2.2_b */
1587   UNUSED(node_info);
1588 
1589   return HAL_OK;
1590 }
1591 
1592 /**
1593   * @brief  Remove the head node from linked-list queue.
1594   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
1595   * @retval HAL status.
1596   */
HAL_DMAEx_List_RemoveNode_Head(DMA_QListTypeDef * const pQList)1597 HAL_StatusTypeDef HAL_DMAEx_List_RemoveNode_Head(DMA_QListTypeDef *const pQList)
1598 {
1599   uint32_t cllr_offset;
1600   uint32_t current_addr;
1601   DMA_NodeInQInfoTypeDef node_info;
1602 
1603   /* Check the queue parameter */
1604   if (pQList == NULL)
1605   {
1606     return HAL_ERROR;
1607   }
1608 
1609   /* Check the queue */
1610   if (pQList->Head == NULL)
1611   {
1612     /* Update the queue error code */
1613     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
1614 
1615     return HAL_ERROR;
1616   }
1617 
1618   /* Check queue type */
1619   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1620   {
1621     /* Update the queue error code */
1622     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1623 
1624     return HAL_ERROR;
1625   }
1626 
1627   /* Update the queue state */
1628   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
1629 
1630   /* Update the queue error code */
1631   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1632 
1633   /* Get CLLR register mask and offset */
1634   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
1635 
1636   /* Queue contains only one node */
1637   if (pQList->NodeNumber == 1U)
1638   {
1639     pQList->Head->LinkRegisters[cllr_offset] = 0U;
1640     pQList->FirstCircularNode = 0U;
1641     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1642   }
1643   /* Queue contains more then one node */
1644   else
1645   {
1646     /* Check if first circular node queue is the first node */
1647     if (pQList->FirstCircularNode == pQList->Head)
1648     {
1649       /* Find last queue node */
1650       node_info.cllr_offset = cllr_offset;
1651       (void)DMA_List_FindNode(pQList, NULL, &node_info);
1652 
1653       /* Clear last node link */
1654       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1655 
1656       /* Clear first circular node */
1657       pQList->FirstCircularNode = NULL;
1658     }
1659 
1660     current_addr = pQList->Head->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
1661     pQList->Head->LinkRegisters[cllr_offset] = 0U;
1662     pQList->Head = ((DMA_NodeTypeDef *)(current_addr + ((uint32_t)pQList->Head & DMA_CLBAR_LBA)));
1663   }
1664 
1665   /* Decrement node number */
1666   pQList->NodeNumber--;
1667 
1668   /* Check if queue is empty */
1669   if (pQList->NodeNumber == 0U)
1670   {
1671     /* Clean empty queue parameter */
1672     DMA_List_CleanQueue(pQList);
1673   }
1674   else
1675   {
1676     /* Update the queue error code */
1677     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1678 
1679     /* Update the queue state */
1680     pQList->State = HAL_DMA_QUEUE_STATE_READY;
1681   }
1682 
1683   /* Prevent MISRA-C2012-Rule-2.2_b */
1684   UNUSED(node_info);
1685 
1686   return HAL_OK;
1687 }
1688 
1689 /**
1690   * @brief  Remove the tail node from linked-list queue.
1691   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
1692   * @retval HAL status.
1693   */
HAL_DMAEx_List_RemoveNode_Tail(DMA_QListTypeDef * const pQList)1694 HAL_StatusTypeDef HAL_DMAEx_List_RemoveNode_Tail(DMA_QListTypeDef *const pQList)
1695 {
1696   uint32_t cllr_offset;
1697   DMA_NodeInQInfoTypeDef node_info;
1698 
1699   /* Check the queue parameter */
1700   if (pQList == NULL)
1701   {
1702     return HAL_ERROR;
1703   }
1704 
1705   /* Check the queue */
1706   if (pQList->Head == NULL)
1707   {
1708     /* Update the queue error code */
1709     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
1710 
1711     return HAL_ERROR;
1712   }
1713 
1714   /* Check queue type */
1715   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1716   {
1717     /* Update the queue error code */
1718     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1719 
1720     return HAL_ERROR;
1721   }
1722 
1723   /* Update the queue state */
1724   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
1725 
1726   /* Update the queue error code */
1727   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1728 
1729   /* Get CLLR register mask and offset */
1730   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
1731 
1732   /* Queue contains only one node */
1733   if (pQList->NodeNumber == 1U)
1734   {
1735     pQList->Head->LinkRegisters[cllr_offset] = 0U;
1736     pQList->FirstCircularNode = 0U;
1737     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1738   }
1739   /* Queue contains more then one node */
1740   else
1741   {
1742     /* Find node and get its position in selected queue */
1743     node_info.cllr_offset = cllr_offset;
1744     (void)DMA_List_FindNode(pQList, NULL, &node_info);
1745 
1746     /* Clear CLLR for previous node */
1747     ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] = 0U;
1748 
1749     /* Clear CLLR for last node */
1750     ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1751 
1752     /* Clear first circular node */
1753     pQList->FirstCircularNode = NULL;
1754   }
1755 
1756   /* Decrement node number */
1757   pQList->NodeNumber--;
1758 
1759   /* Check if queue is empty */
1760   if (pQList->NodeNumber == 0U)
1761   {
1762     /* Clean empty queue parameter */
1763     DMA_List_CleanQueue(pQList);
1764   }
1765   else
1766   {
1767     /* Update the queue error code */
1768     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1769 
1770     /* Update the queue state */
1771     pQList->State = HAL_DMA_QUEUE_STATE_READY;
1772   }
1773 
1774   /* Prevent MISRA-C2012-Rule-2.2_b */
1775   UNUSED(node_info);
1776 
1777   return HAL_OK;
1778 }
1779 
1780 /**
1781   * @brief  Replace node in linked-list queue.
1782   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
1783   * @param  pOldNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list old node registers
1784   *                    configurations.
1785   * @param  pNewNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
1786   *                    configurations.
1787   * @retval HAL status.
1788   */
HAL_DMAEx_List_ReplaceNode(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pOldNode,DMA_NodeTypeDef * const pNewNode)1789 HAL_StatusTypeDef HAL_DMAEx_List_ReplaceNode(DMA_QListTypeDef *const pQList,
1790                                              DMA_NodeTypeDef *const pOldNode,
1791                                              DMA_NodeTypeDef *const pNewNode)
1792 {
1793   uint32_t cllr_mask;
1794   uint32_t cllr_offset;
1795   DMA_NodeInQInfoTypeDef node_info;
1796 
1797   /* Check the queue and the nodes parameters */
1798   if ((pQList == NULL) || (pOldNode == NULL) || (pNewNode == NULL))
1799   {
1800     return HAL_ERROR;
1801   }
1802 
1803   /* Check the queue */
1804   if (pQList->Head == NULL)
1805   {
1806     /* Update the queue error code */
1807     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
1808 
1809     return HAL_ERROR;
1810   }
1811 
1812   /* Check queue type */
1813   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1814   {
1815     /* Update the queue error code */
1816     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1817 
1818     return HAL_ERROR;
1819   }
1820 
1821   /* Check nodes base addresses */
1822   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pOldNode, pNewNode) != 0U)
1823   {
1824     /* Update the queue error code */
1825     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
1826 
1827     return HAL_ERROR;
1828   }
1829 
1830   /* Check nodes types compatibility */
1831   if (DMA_List_CheckNodesTypes(pQList->Head, pOldNode, pNewNode) != 0U)
1832   {
1833     /* Update the queue error code */
1834     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1835 
1836     return HAL_ERROR;
1837   }
1838 
1839   /* Update the queue state */
1840   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
1841 
1842   /* Update the queue error code */
1843   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1844 
1845   /* Get CLLR register mask and offset */
1846   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
1847 
1848   /* Find node and get its position in selected queue */
1849   node_info.cllr_offset = cllr_offset;
1850   if (DMA_List_FindNode(pQList, pOldNode, &node_info) == 0U)
1851   {
1852     /* Replaced node is the head node */
1853     if (node_info.currentnode_pos == 1U)
1854     {
1855       pNewNode->LinkRegisters[cllr_offset] =
1856         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset];
1857       pQList->Head = pNewNode;
1858       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1859 
1860       /* Check if first circular node queue is the first node */
1861       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)node_info.currentnode_addr))
1862       {
1863         /* Find last queue node */
1864         (void)DMA_List_FindNode(pQList, NULL, &node_info);
1865 
1866         /* Clear last node link */
1867         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
1868           ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1869 
1870         /* Set new node as first circular node */
1871         pQList->FirstCircularNode = pNewNode;
1872       }
1873     }
1874     /* Replaced node is the last */
1875     else if (node_info.currentnode_pos == pQList->NodeNumber)
1876     {
1877       ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] =
1878         ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1879       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1880 
1881       /* Check if first circular node queue is the last node */
1882       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)(node_info.currentnode_addr)))
1883       {
1884         /* Link first circular node to new node */
1885         pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1886 
1887         /* Set new node as first circular node */
1888         pQList->FirstCircularNode = pNewNode;
1889       }
1890       /* Check if first circular node queue is not the last node */
1891       else if (pQList->FirstCircularNode != NULL)
1892       {
1893         /* Link first circular node to new node */
1894         pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
1895       }
1896       else
1897       {
1898         /* Prevent MISRA-C2012-Rule-15.7 */
1899       }
1900     }
1901     /* Replaced node is in the middle */
1902     else
1903     {
1904       ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] =
1905         ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1906       pNewNode->LinkRegisters[cllr_offset] =
1907         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset];
1908       ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
1909 
1910       /* Check if first circular node queue is the current node */
1911       if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)(node_info.currentnode_addr)))
1912       {
1913         /* Find last node and get its position in selected queue */
1914         (void)DMA_List_FindNode(pQList, NULL, &node_info);
1915 
1916         /* Link last queue node to new node */
1917         ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
1918           ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
1919 
1920         /* Set new node as first circular node */
1921         pQList->FirstCircularNode = pNewNode;
1922       }
1923     }
1924   }
1925   else
1926   {
1927     /* Update the queue error code */
1928     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
1929 
1930     return HAL_ERROR;
1931   }
1932 
1933   /* Update the queue error code */
1934   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
1935 
1936   /* Update the queue state */
1937   pQList->State = HAL_DMA_QUEUE_STATE_READY;
1938 
1939   /* Prevent MISRA-C2012-Rule-2.2_b */
1940   UNUSED(node_info);
1941 
1942   return HAL_OK;
1943 }
1944 
1945 /**
1946   * @brief  Replace the head node of linked-list queue.
1947   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
1948   * @param  pNewNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
1949   *                    configurations.
1950   * @retval HAL status.
1951   */
HAL_DMAEx_List_ReplaceNode_Head(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pNewNode)1952 HAL_StatusTypeDef HAL_DMAEx_List_ReplaceNode_Head(DMA_QListTypeDef *const pQList,
1953                                                   DMA_NodeTypeDef *const pNewNode)
1954 {
1955   uint32_t cllr_offset;
1956   uint32_t cllr_mask;
1957   DMA_NodeInQInfoTypeDef node_info;
1958 
1959   /* Check the queue and the new node parameters */
1960   if ((pQList == NULL) || (pNewNode == NULL))
1961   {
1962     return HAL_ERROR;
1963   }
1964 
1965   /* Check the queue */
1966   if (pQList->Head == NULL)
1967   {
1968     /* Update the queue error code */
1969     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
1970 
1971     return HAL_ERROR;
1972   }
1973 
1974   /* Check queue type */
1975   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
1976   {
1977     /* Update the queue error code */
1978     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1979 
1980     return HAL_ERROR;
1981   }
1982 
1983   /* Check nodes base addresses */
1984   if (DMA_List_CheckNodesBaseAddresses(pQList->Head, pNewNode, NULL) != 0U)
1985   {
1986     /* Update the queue error code */
1987     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
1988 
1989     return HAL_ERROR;
1990   }
1991 
1992   /* Check nodes types compatibility */
1993   if (DMA_List_CheckNodesTypes(pQList->Head, pNewNode, NULL) != 0U)
1994   {
1995     /* Update the queue error code */
1996     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
1997 
1998     return HAL_ERROR;
1999   }
2000 
2001   /* Update the queue state */
2002   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2003 
2004   /* Update the queue error code */
2005   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2006 
2007   /* Get CLLR register mask and offset */
2008   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
2009 
2010   /* Check if first circular node queue is the first node */
2011   if (pQList->FirstCircularNode == pQList->Head)
2012   {
2013     /* Find last queue node */
2014     node_info.cllr_offset = cllr_offset;
2015     (void)DMA_List_FindNode(pQList, NULL, &node_info);
2016 
2017     /* Clear last node link */
2018     ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2019       ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
2020 
2021     /* Set new node as first circular node */
2022     pQList->FirstCircularNode = pNewNode;
2023   }
2024 
2025   /* Replace head node */
2026   pNewNode->LinkRegisters[cllr_offset] = pQList->Head->LinkRegisters[cllr_offset];
2027   pQList->Head->LinkRegisters[cllr_offset] = 0U;
2028   pQList->Head = pNewNode;
2029 
2030   /* Update the queue error code */
2031   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2032 
2033   /* Update the queue state */
2034   pQList->State = HAL_DMA_QUEUE_STATE_READY;
2035 
2036   /* Prevent MISRA-C2012-Rule-2.2_b */
2037   UNUSED(node_info);
2038 
2039   return HAL_OK;
2040 }
2041 
2042 /**
2043   * @brief  Replace the tail node of linked-list queue.
2044   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
2045   * @param  pNewNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list new node registers
2046   *                    configurations.
2047   * @retval HAL status.
2048   */
HAL_DMAEx_List_ReplaceNode_Tail(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pNewNode)2049 HAL_StatusTypeDef HAL_DMAEx_List_ReplaceNode_Tail(DMA_QListTypeDef *const pQList,
2050                                                   DMA_NodeTypeDef *const pNewNode)
2051 {
2052   uint32_t cllr_mask;
2053   uint32_t cllr_offset;
2054   DMA_NodeInQInfoTypeDef node_info;
2055 
2056   /* Check the queue and the new node parameters */
2057   if ((pQList == NULL) || (pNewNode == NULL))
2058   {
2059     return HAL_ERROR;
2060   }
2061 
2062   /* Check the queue */
2063   if (pQList->Head == NULL)
2064   {
2065     /* Update the queue error code */
2066     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2067 
2068     return HAL_ERROR;
2069   }
2070 
2071   /* Check queue type */
2072   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
2073   {
2074     /* Update the queue error code */
2075     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2076 
2077     return HAL_ERROR;
2078   }
2079 
2080   /* Update the queue state */
2081   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2082 
2083   /* Update the queue error code */
2084   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2085 
2086   /* Get CLLR register mask and offset */
2087   DMA_List_GetCLLRNodeInfo(pNewNode, &cllr_mask, &cllr_offset);
2088 
2089   /* Find last node and get its position in selected queue */
2090   node_info.cllr_offset = cllr_offset;
2091   (void)DMA_List_FindNode(pQList, NULL, &node_info);
2092 
2093   /* Link previous node to new node */
2094   ((DMA_NodeTypeDef *)(node_info.previousnode_addr))->LinkRegisters[cllr_offset] =
2095     ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
2096 
2097   /* Clear CLLR for current node */
2098   ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
2099 
2100   /* Check if first circular node queue is the last node */
2101   if (pQList->FirstCircularNode == ((DMA_NodeTypeDef *)(node_info.currentnode_addr)))
2102   {
2103     /* Link first circular node to new node */
2104     pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pNewNode & DMA_CLLR_LA) | cllr_mask;
2105 
2106     /* Set new node as first circular node */
2107     pQList->FirstCircularNode = pNewNode;
2108   }
2109   /* Check if first circular node queue is not the last node */
2110   else if (pQList->FirstCircularNode != NULL)
2111   {
2112     /* Link first circular node to new node */
2113     pNewNode->LinkRegisters[cllr_offset] = ((uint32_t)pQList->FirstCircularNode & DMA_CLLR_LA) | cllr_mask;
2114   }
2115   else
2116   {
2117     /* Prevent MISRA-C2012-Rule-15.7 */
2118   }
2119 
2120   /* Check if queue contains one node */
2121   if (pQList->NodeNumber == 1U)
2122   {
2123     pQList->Head = pNewNode;
2124   }
2125 
2126   /* Update the queue error code */
2127   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2128 
2129   /* Update the queue state */
2130   pQList->State = HAL_DMA_QUEUE_STATE_READY;
2131 
2132   return HAL_OK;
2133 }
2134 
2135 /**
2136   * @brief  Reset the linked-list queue and unlink queue nodes.
2137   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
2138   * @retval HAL status.
2139   */
HAL_DMAEx_List_ResetQ(DMA_QListTypeDef * const pQList)2140 HAL_StatusTypeDef HAL_DMAEx_List_ResetQ(DMA_QListTypeDef *const pQList)
2141 {
2142   uint32_t cllr_offset;
2143   DMA_NodeInQInfoTypeDef node_info;
2144 
2145   /* Check the queue parameter */
2146   if (pQList == NULL)
2147   {
2148     return HAL_ERROR;
2149   }
2150 
2151   /* Check queue state */
2152   if (pQList->State == HAL_DMA_QUEUE_STATE_BUSY)
2153   {
2154     /* Update the queue error code */
2155     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_BUSY;
2156 
2157     return HAL_ERROR;
2158   }
2159 
2160   /* Check queue type */
2161   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
2162   {
2163     /* Update the queue error code */
2164     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2165 
2166     return HAL_ERROR;
2167   }
2168 
2169   /* Update the queue state */
2170   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2171 
2172   /* Update the queue error code */
2173   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2174 
2175   /* Check the queue */
2176   if (pQList->Head != NULL)
2177   {
2178     /* Get CLLR register mask and offset */
2179     DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
2180 
2181     /* Reset selected queue nodes */
2182     node_info.cllr_offset = cllr_offset;
2183     DMA_List_ResetQueueNodes(pQList, &node_info);
2184   }
2185 
2186   /* Reset head node address */
2187   pQList->Head = NULL;
2188 
2189   /* Reset node number */
2190   pQList->NodeNumber = 0U;
2191 
2192   /* Reset first circular node */
2193   pQList->FirstCircularNode = NULL;
2194 
2195   /* Update the queue error code */
2196   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2197 
2198   /* Update the queue state */
2199   pQList->State = HAL_DMA_QUEUE_STATE_RESET;
2200 
2201   return HAL_OK;
2202 }
2203 
2204 /**
2205   * @brief  Insert a source linked-list queue to a destination linked-list queue according to selecting previous node.
2206   * @param  pSrcQList  : Pointer to a DMA_QListTypeDef structure that contains source queue information.
2207   * @param  pPrevNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list previous node registers
2208   *                      configurations.
2209   * @param  pDestQList : Pointer to a DMA_QListTypeDef structure that contains destination queue information.
2210   * @retval HAL status.
2211   */
HAL_DMAEx_List_InsertQ(DMA_QListTypeDef * const pSrcQList,DMA_NodeTypeDef const * const pPrevNode,DMA_QListTypeDef * const pDestQList)2212 HAL_StatusTypeDef HAL_DMAEx_List_InsertQ(DMA_QListTypeDef *const pSrcQList,
2213                                          DMA_NodeTypeDef const *const pPrevNode,
2214                                          DMA_QListTypeDef *const pDestQList)
2215 {
2216   uint32_t cllr_mask;
2217   uint32_t cllr_offset;
2218   DMA_NodeInQInfoTypeDef src_q_node_info;
2219   DMA_NodeInQInfoTypeDef dest_q_node_info;
2220 
2221   /* Check the source and destination queues and the previous node parameters */
2222   if ((pSrcQList == NULL) || (pDestQList == NULL))
2223   {
2224     return HAL_ERROR;
2225   }
2226 
2227   /* Check the source queue */
2228   if (pSrcQList->Head == NULL)
2229   {
2230     /* Update the queue error code */
2231     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2232 
2233     return HAL_ERROR;
2234   }
2235 
2236   /* Check the source queue type */
2237   if (pSrcQList->Type == QUEUE_TYPE_DYNAMIC)
2238   {
2239     /* Update the queue error code */
2240     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2241 
2242     return HAL_ERROR;
2243   }
2244 
2245   /* Check the destination queue type */
2246   if (pDestQList->Type == QUEUE_TYPE_DYNAMIC)
2247   {
2248     /* Update the queue error code */
2249     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2250 
2251     return HAL_ERROR;
2252   }
2253 
2254   /* Check the source queue circularity */
2255   if (pSrcQList->FirstCircularNode != NULL)
2256   {
2257     /* Update the source queue error code */
2258     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2259 
2260     return HAL_ERROR;
2261   }
2262 
2263   /* Check nodes base addresses */
2264   if (DMA_List_CheckNodesBaseAddresses(pSrcQList->Head, pPrevNode, pDestQList->Head) != 0U)
2265   {
2266     /* Update the source queue error code */
2267     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
2268 
2269     /* Update the destination queue error code */
2270     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
2271 
2272     return HAL_ERROR;
2273   }
2274 
2275   /* Check nodes types compatibility */
2276   if (DMA_List_CheckNodesTypes(pSrcQList->Head, pPrevNode, pDestQList->Head) != 0U)
2277   {
2278     /* Update the source queue error code */
2279     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2280 
2281     /* Update the destination queue error code */
2282     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2283 
2284     return HAL_ERROR;
2285   }
2286 
2287   /* Update the source queue state */
2288   pSrcQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2289 
2290   /* Update the source queue error code */
2291   pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2292 
2293   /* Update the destination queue state */
2294   pDestQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2295 
2296   /* Update the destination queue error code */
2297   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2298 
2299   /* Get CLLR register mask and offset */
2300   DMA_List_GetCLLRNodeInfo(pSrcQList->Head, &cllr_mask, &cllr_offset);
2301 
2302   /* Empty destination queue */
2303   if (pDestQList->Head == NULL)
2304   {
2305     pDestQList->Head       = pSrcQList->Head;
2306     pDestQList->NodeNumber = pSrcQList->NodeNumber;
2307   }
2308   /* Not empty destination queue */
2309   else
2310   {
2311     /* Previous node is empty */
2312     if (pPrevNode == NULL)
2313     {
2314       /* Find node and get its position in selected queue */
2315       src_q_node_info.cllr_offset = cllr_offset;
2316       (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
2317 
2318       /* Check if first circular node queue is the first node */
2319       if (pDestQList->FirstCircularNode == pDestQList->Head)
2320       {
2321         /* Find node and get its position in selected queue */
2322         dest_q_node_info.cllr_offset = cllr_offset;
2323         (void)DMA_List_FindNode(pDestQList, NULL, &dest_q_node_info);
2324 
2325         /* Link destination queue tail node to new first circular node */
2326         ((DMA_NodeTypeDef *)dest_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
2327           ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
2328 
2329         /* Set the head node of source queue as the first circular node */
2330         pDestQList->FirstCircularNode = pSrcQList->Head;
2331       }
2332 
2333       /* Link the last node of source queue to the fist node of destination queue */
2334       ((DMA_NodeTypeDef *)(src_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2335         ((uint32_t)pDestQList->Head & DMA_CLLR_LA) | cllr_mask;
2336       pDestQList->Head        = pSrcQList->Head;
2337       pDestQList->NodeNumber += pSrcQList->NodeNumber;
2338     }
2339     /* Previous node is not empty */
2340     else
2341     {
2342       /* Find node and get its position in selected queue */
2343       dest_q_node_info.cllr_offset = cllr_offset;
2344       if (DMA_List_FindNode(pDestQList, pPrevNode, &dest_q_node_info) == 0U)
2345       {
2346         /* Selected node is the last destination queue node */
2347         if (dest_q_node_info.currentnode_pos == pDestQList->NodeNumber)
2348         {
2349           /* Link the first node of source queue to the last node of destination queue */
2350           ((DMA_NodeTypeDef *)(dest_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2351             ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
2352           pDestQList->NodeNumber += pSrcQList->NodeNumber;
2353 
2354           /* Check if first circular node queue is not empty */
2355           if (pDestQList->FirstCircularNode != NULL)
2356           {
2357             /* Find node and get its position in selected queue */
2358             src_q_node_info.cllr_offset = cllr_offset;
2359             (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
2360 
2361             /* Find first circular node */
2362             (void)DMA_List_FindNode(pDestQList, pDestQList->FirstCircularNode, &dest_q_node_info);
2363 
2364             /* Link last source queue node to first destination queue */
2365             ((DMA_NodeTypeDef *)src_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
2366               (dest_q_node_info.currentnode_addr & DMA_CLLR_LA) | cllr_mask;
2367           }
2368         }
2369         /* Selected node is not the last destination queue node */
2370         else
2371         {
2372           /* Link the first node of source queue to the previous node of destination queue */
2373           ((DMA_NodeTypeDef *)(dest_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2374             ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
2375 
2376           /* Find node and get its position in selected queue */
2377           src_q_node_info.cllr_offset = cllr_offset;
2378           (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
2379 
2380           /* Link the last node of source queue to the next node of destination queue */
2381           ((DMA_NodeTypeDef *)(src_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2382             (dest_q_node_info.nextnode_addr & DMA_CLLR_LA) | cllr_mask;
2383 
2384           /* Update queues counter */
2385           pDestQList->NodeNumber += pSrcQList->NodeNumber;
2386         }
2387       }
2388       else
2389       {
2390         /* Update the destination queue error code */
2391         pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
2392 
2393         return HAL_ERROR;
2394       }
2395     }
2396   }
2397 
2398   /* Clean the source queue variable as it is obsolete */
2399   DMA_List_CleanQueue(pSrcQList);
2400 
2401   /* Update the destination queue error code */
2402   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2403 
2404   /* Update the destination queue state */
2405   pDestQList->State = HAL_DMA_QUEUE_STATE_READY;
2406 
2407   /* Prevent MISRA-C2012-Rule-2.2_b */
2408   UNUSED(src_q_node_info);
2409   UNUSED(dest_q_node_info);
2410 
2411   return HAL_OK;
2412 }
2413 
2414 /**
2415   * @brief  Insert a source linked-list queue at the head of destination queue.
2416   * @param  pSrcQList  : Pointer to a DMA_QListTypeDef structure that contains source queue information.
2417   * @param  pDestQList : Pointer to a DMA_QListTypeDef structure that contains destination queue information.
2418   * @retval HAL status.
2419   */
HAL_DMAEx_List_InsertQ_Head(DMA_QListTypeDef * const pSrcQList,DMA_QListTypeDef * const pDestQList)2420 HAL_StatusTypeDef HAL_DMAEx_List_InsertQ_Head(DMA_QListTypeDef *const pSrcQList,
2421                                               DMA_QListTypeDef *const pDestQList)
2422 {
2423   uint32_t cllr_mask;
2424   uint32_t cllr_offset;
2425   DMA_NodeInQInfoTypeDef src_q_node_info;
2426   DMA_NodeInQInfoTypeDef dest_q_node_info;
2427 
2428   /* Check the source and destination queues and the previous node parameters */
2429   if ((pSrcQList == NULL) || (pDestQList == NULL))
2430   {
2431     return HAL_ERROR;
2432   }
2433 
2434   /* Check the source queue */
2435   if (pSrcQList->Head == NULL)
2436   {
2437     /* Update the queue error code */
2438     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2439 
2440     return HAL_ERROR;
2441   }
2442 
2443   /* Check the source queue type */
2444   if (pSrcQList->Type == QUEUE_TYPE_DYNAMIC)
2445   {
2446     /* Update the queue error code */
2447     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2448 
2449     return HAL_ERROR;
2450   }
2451 
2452   /* Check the destination queue type */
2453   if (pDestQList->Type == QUEUE_TYPE_DYNAMIC)
2454   {
2455     /* Update the queue error code */
2456     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2457 
2458     return HAL_ERROR;
2459   }
2460 
2461   /* Check nodes base addresses */
2462   if (DMA_List_CheckNodesBaseAddresses(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
2463   {
2464     /* Update the source queue error code */
2465     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
2466 
2467     /* Update the destination queue error code */
2468     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
2469 
2470     return HAL_ERROR;
2471   }
2472 
2473   /* Check nodes types compatibility */
2474   if (DMA_List_CheckNodesTypes(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
2475   {
2476     /* Update the source queue error code */
2477     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2478 
2479     /* Update the destination queue error code */
2480     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2481 
2482     return HAL_ERROR;
2483   }
2484 
2485   /* Update the source queue state */
2486   pSrcQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2487 
2488   /* Update the source queue error code */
2489   pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2490 
2491   /* Update the destination queue state */
2492   pDestQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2493 
2494   /* Update the destination queue error code */
2495   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2496 
2497   /* Get CLLR register mask and offset */
2498   DMA_List_GetCLLRNodeInfo(pSrcQList->Head, &cllr_mask, &cllr_offset);
2499 
2500   /* Empty destination queue */
2501   if (pDestQList->Head == NULL)
2502   {
2503     pDestQList->Head       = pSrcQList->Head;
2504     pDestQList->NodeNumber = pSrcQList->NodeNumber;
2505   }
2506   /* Not empty destination queue */
2507   else
2508   {
2509     /* Find node and get its position in selected queue */
2510     src_q_node_info.cllr_offset = cllr_offset;
2511     (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
2512 
2513     /* Check if first circular node queue is the first node */
2514     if (pDestQList->FirstCircularNode == pDestQList->Head)
2515     {
2516       /* Find node and get its position in selected queue */
2517       dest_q_node_info.cllr_offset = cllr_offset;
2518       (void)DMA_List_FindNode(pDestQList, NULL, &dest_q_node_info);
2519 
2520       /* Link destination queue tail node to new first circular node */
2521       ((DMA_NodeTypeDef *)dest_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
2522         ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
2523 
2524       /* Set the head node of source queue as the first circular node */
2525       pDestQList->FirstCircularNode = pSrcQList->Head;
2526     }
2527 
2528     /* Link the last node of source queue to the fist node of destination queue */
2529     ((DMA_NodeTypeDef *)(src_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2530       ((uint32_t)pDestQList->Head & DMA_CLLR_LA) | cllr_mask;
2531     pDestQList->Head        = pSrcQList->Head;
2532     pDestQList->NodeNumber += pSrcQList->NodeNumber;
2533   }
2534 
2535   /* Clean the source queue variable as it is obsolete */
2536   DMA_List_CleanQueue(pSrcQList);
2537 
2538   /* Update the destination queue error code */
2539   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2540 
2541   /* Update the destination queue state */
2542   pDestQList->State = HAL_DMA_QUEUE_STATE_READY;
2543 
2544   /* Prevent MISRA-C2012-Rule-2.2_b */
2545   UNUSED(src_q_node_info);
2546   UNUSED(dest_q_node_info);
2547 
2548   return HAL_OK;
2549 }
2550 
2551 /**
2552   * @brief  Insert a source linked-list queue at the tail of destination queue.
2553   * @param  pSrcQList  : Pointer to a DMA_QListTypeDef structure that contains source queue information.
2554   * @param  pDestQList : Pointer to a DMA_QListTypeDef structure that contains destination queue information.
2555   * @retval HAL status.
2556   */
HAL_DMAEx_List_InsertQ_Tail(DMA_QListTypeDef * const pSrcQList,DMA_QListTypeDef * const pDestQList)2557 HAL_StatusTypeDef HAL_DMAEx_List_InsertQ_Tail(DMA_QListTypeDef *const pSrcQList,
2558                                               DMA_QListTypeDef *const pDestQList)
2559 {
2560   uint32_t cllr_mask;
2561   uint32_t cllr_offset;
2562   DMA_NodeInQInfoTypeDef src_q_node_info;
2563   DMA_NodeInQInfoTypeDef dest_q_node_info;
2564 
2565   /* Check the source and destination queues and the previous node parameters */
2566   if ((pSrcQList == NULL) || (pDestQList == NULL))
2567   {
2568     return HAL_ERROR;
2569   }
2570 
2571   /* Check the source queue */
2572   if (pSrcQList->Head == NULL)
2573   {
2574     /* Update the queue error code */
2575     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2576 
2577     return HAL_ERROR;
2578   }
2579 
2580   /* Check the source queue type */
2581   if (pSrcQList->Type == QUEUE_TYPE_DYNAMIC)
2582   {
2583     /* Update the queue error code */
2584     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2585 
2586     return HAL_ERROR;
2587   }
2588 
2589   /* Check the destination queue type */
2590   if (pDestQList->Type == QUEUE_TYPE_DYNAMIC)
2591   {
2592     /* Update the queue error code */
2593     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2594 
2595     return HAL_ERROR;
2596   }
2597 
2598   /* Check nodes base addresses */
2599   if (DMA_List_CheckNodesBaseAddresses(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
2600   {
2601     /* Update the source queue error code */
2602     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
2603 
2604     /* Update the destination queue error code */
2605     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_OUTOFRANGE;
2606 
2607     return HAL_ERROR;
2608   }
2609 
2610   /* Check nodes types compatibility */
2611   if (DMA_List_CheckNodesTypes(pSrcQList->Head, pDestQList->Head, NULL) != 0U)
2612   {
2613     /* Update the source queue error code */
2614     pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2615 
2616     /* Update the destination queue error code */
2617     pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2618 
2619     return HAL_ERROR;
2620   }
2621 
2622   /* Update the source queue state */
2623   pSrcQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2624 
2625   /* Update the source queue error code */
2626   pSrcQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2627 
2628   /* Update the destination queue state */
2629   pDestQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2630 
2631   /* Update the destination queue error code */
2632   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2633 
2634   /* Get CLLR register mask and offset */
2635   DMA_List_GetCLLRNodeInfo(pSrcQList->Head, &cllr_mask, &cllr_offset);
2636 
2637   /* Empty destination queue */
2638   if (pDestQList->Head == NULL)
2639   {
2640     pDestQList->Head       = pSrcQList->Head;
2641     pDestQList->NodeNumber = pSrcQList->NodeNumber;
2642   }
2643   /* Not empty destination queue */
2644   else
2645   {
2646     /* Find node and get its position in selected queue */
2647     dest_q_node_info.cllr_offset = cllr_offset;
2648     (void)DMA_List_FindNode(pDestQList, NULL, &dest_q_node_info);
2649 
2650     /* Update source queue last node CLLR to link it with destination first node */
2651     ((DMA_NodeTypeDef *)(dest_q_node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2652       ((uint32_t)pSrcQList->Head & DMA_CLLR_LA) | cllr_mask;
2653     pDestQList->NodeNumber += pSrcQList->NodeNumber;
2654 
2655     /* Check if first circular node queue is not empty */
2656     if (pDestQList->FirstCircularNode != NULL)
2657     {
2658       /* Find node and get its position in selected queue */
2659       src_q_node_info.cllr_offset = cllr_offset;
2660       (void)DMA_List_FindNode(pSrcQList, NULL, &src_q_node_info);
2661 
2662       /* Find first circular node */
2663       (void)DMA_List_FindNode(pDestQList, pDestQList->FirstCircularNode, &dest_q_node_info);
2664 
2665       /* Link last source queue node to first destination queue */
2666       ((DMA_NodeTypeDef *)src_q_node_info.currentnode_addr)->LinkRegisters[cllr_offset] =
2667         (dest_q_node_info.currentnode_addr & DMA_CLLR_LA) | cllr_mask;
2668     }
2669   }
2670 
2671   /* Clean the source queue variable as it is obsolete */
2672   DMA_List_CleanQueue(pSrcQList);
2673 
2674   /* Update the destination queue error code */
2675   pDestQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2676 
2677   /* Update the destination queue state */
2678   pDestQList->State = HAL_DMA_QUEUE_STATE_READY;
2679 
2680   /* Prevent MISRA-C2012-Rule-2.2_b */
2681   UNUSED(src_q_node_info);
2682 
2683   return HAL_OK;
2684 }
2685 
2686 /**
2687   * @brief  Set circular mode configuration for linked-list queue.
2688   * @param  pQList             : Pointer to a DMA_QListTypeDef structure that contains queue information.
2689   * @param  pFirstCircularNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list first circular node
2690   *                              registers configurations.
2691   * @retval HAL status.
2692   */
HAL_DMAEx_List_SetCircularModeConfig(DMA_QListTypeDef * const pQList,DMA_NodeTypeDef * const pFirstCircularNode)2693 HAL_StatusTypeDef HAL_DMAEx_List_SetCircularModeConfig(DMA_QListTypeDef *const pQList,
2694                                                        DMA_NodeTypeDef *const pFirstCircularNode)
2695 {
2696   uint32_t cllr_mask;
2697   uint32_t cllr_offset;
2698   DMA_NodeInQInfoTypeDef node_info;
2699 
2700   /* Check the queue and the first circular node parameters */
2701   if ((pQList == NULL) || (pFirstCircularNode == NULL))
2702   {
2703     return HAL_ERROR;
2704   }
2705 
2706   /* Check the queue */
2707   if (pQList->Head == NULL)
2708   {
2709     /* Update the queue error code */
2710     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2711 
2712     return HAL_ERROR;
2713   }
2714 
2715   /* Check queue circular mode */
2716   if (pQList->FirstCircularNode != NULL)
2717   {
2718     if (pQList->FirstCircularNode == pFirstCircularNode)
2719     {
2720       return HAL_OK;
2721     }
2722     else
2723     {
2724       /* Update the queue error code */
2725       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2726 
2727       return HAL_ERROR;
2728     }
2729   }
2730 
2731   /* Check queue type */
2732   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
2733   {
2734     /* Update the queue error code */
2735     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2736 
2737     return HAL_ERROR;
2738   }
2739 
2740   /* Update the queue state */
2741   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2742 
2743   /* Update the queue error code */
2744   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2745 
2746   /* Get CLLR register mask and offset */
2747   DMA_List_GetCLLRNodeInfo(pFirstCircularNode, &cllr_mask, &cllr_offset);
2748 
2749   /* Find the first circular node and get its position in selected queue */
2750   node_info.cllr_offset = cllr_offset;
2751   if (DMA_List_FindNode(pQList, pFirstCircularNode, &node_info) == 0U)
2752   {
2753     /* Find the last queue node and get its position in selected queue */
2754     (void)DMA_List_FindNode(pQList, NULL, &node_info);
2755 
2756     /* Set circular mode */
2757     ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2758       ((uint32_t)pFirstCircularNode & DMA_CLLR_LA) | cllr_mask;
2759 
2760     /* Update first circular node in queue */
2761     pQList->FirstCircularNode = pFirstCircularNode;
2762   }
2763   else
2764   {
2765     /* Update the queue error code */
2766     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NOTFOUND;
2767 
2768     return HAL_ERROR;
2769   }
2770 
2771   /* Update the queue error code */
2772   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2773 
2774   /* Update the queue state */
2775   pQList->State = HAL_DMA_QUEUE_STATE_READY;
2776 
2777   /* Prevent MISRA-C2012-Rule-2.2_b */
2778   UNUSED(node_info);
2779 
2780   return HAL_OK;
2781 }
2782 
2783 /**
2784   * @brief  Set circular mode for linked-list queue.
2785   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
2786   * @retval HAL status.
2787   */
HAL_DMAEx_List_SetCircularMode(DMA_QListTypeDef * const pQList)2788 HAL_StatusTypeDef HAL_DMAEx_List_SetCircularMode(DMA_QListTypeDef *const pQList)
2789 {
2790   uint32_t cllr_mask;
2791   uint32_t cllr_offset;
2792   DMA_NodeInQInfoTypeDef node_info;
2793 
2794   /* Check the queue parameter */
2795   if (pQList == NULL)
2796   {
2797     return HAL_ERROR;
2798   }
2799 
2800   /* Check the queue */
2801   if (pQList->Head == NULL)
2802   {
2803     /* Update the queue error code */
2804     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2805 
2806     return HAL_ERROR;
2807   }
2808 
2809   /* Check queue circular mode */
2810   if (pQList->FirstCircularNode != NULL)
2811   {
2812     if (pQList->FirstCircularNode == pQList->Head)
2813     {
2814       return HAL_OK;
2815     }
2816     else
2817     {
2818       /* Update the queue error code */
2819       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2820 
2821       return HAL_ERROR;
2822     }
2823   }
2824 
2825   /* Check queue type */
2826   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
2827   {
2828     /* Update the queue error code */
2829     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2830 
2831     return HAL_ERROR;
2832   }
2833 
2834   /* Update the queue state */
2835   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2836 
2837   /* Update the queue error code */
2838   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2839 
2840   /* Get CLLR register mask and offset */
2841   DMA_List_GetCLLRNodeInfo(pQList->Head, &cllr_mask, &cllr_offset);
2842 
2843   /* Find the last queue node and get its position in selected queue */
2844   node_info.cllr_offset = cllr_offset;
2845   (void)DMA_List_FindNode(pQList, NULL, &node_info);
2846 
2847   /* Set circular mode */
2848   ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] =
2849     ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
2850 
2851   /* Update linked-list circular state */
2852   pQList->FirstCircularNode = pQList->Head;
2853 
2854   /* Update the queue error code */
2855   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2856 
2857   /* Update the queue state */
2858   pQList->State = HAL_DMA_QUEUE_STATE_READY;
2859 
2860   /* Prevent MISRA-C2012-Rule-2.2_b */
2861   UNUSED(node_info);
2862 
2863   return HAL_OK;
2864 }
2865 
2866 /**
2867   * @brief  Clear circular mode for linked-list queue.
2868   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
2869   * @retval HAL status.
2870   */
HAL_DMAEx_List_ClearCircularMode(DMA_QListTypeDef * const pQList)2871 HAL_StatusTypeDef HAL_DMAEx_List_ClearCircularMode(DMA_QListTypeDef *const pQList)
2872 {
2873   uint32_t cllr_offset;
2874   DMA_NodeInQInfoTypeDef node_info;
2875 
2876   /* Check the queue parameter */
2877   if (pQList == NULL)
2878   {
2879     return HAL_ERROR;
2880   }
2881 
2882   /* Check the queue */
2883   if (pQList->Head == NULL)
2884   {
2885     /* Update the queue error code */
2886     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2887 
2888     return HAL_ERROR;
2889   }
2890 
2891   /* Check queue circular mode */
2892   if (pQList->FirstCircularNode == NULL)
2893   {
2894     return HAL_OK;
2895   }
2896 
2897   /* Check queue type */
2898   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
2899   {
2900     /* Update the queue error code */
2901     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
2902 
2903     return HAL_ERROR;
2904   }
2905 
2906   /* Update the queue state */
2907   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2908 
2909   /* Update the queue error code */
2910   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2911 
2912   /* Get CLLR register offset */
2913   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
2914 
2915   /* Find the last queue node and get its position in selected queue */
2916   node_info.cllr_offset = cllr_offset;
2917   (void)DMA_List_FindNode(pQList, NULL, &node_info);
2918 
2919   /* Clear circular mode */
2920   ((DMA_NodeTypeDef *)(node_info.currentnode_addr))->LinkRegisters[cllr_offset] = 0U;
2921 
2922   /* Update linked-list circular configuration */
2923   pQList->FirstCircularNode = NULL;
2924 
2925   /* Update the queue error code */
2926   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2927 
2928   /* Update the queue state */
2929   pQList->State = HAL_DMA_QUEUE_STATE_READY;
2930 
2931   /* Prevent MISRA-C2012-Rule-2.2_b */
2932   UNUSED(node_info);
2933 
2934   return HAL_OK;
2935 }
2936 
2937 /**
2938   * @brief  Convert a linked-list queue to dynamic (Optimized DMA queue execution).
2939   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
2940   * @retval HAL status.
2941   */
HAL_DMAEx_List_ConvertQToDynamic(DMA_QListTypeDef * const pQList)2942 HAL_StatusTypeDef HAL_DMAEx_List_ConvertQToDynamic(DMA_QListTypeDef *const pQList)
2943 {
2944   uint32_t cllr_offset;
2945   uint32_t currentnode_addr;
2946   DMA_NodeTypeDef context_node;
2947   DMA_NodeInQInfoTypeDef node_info;
2948 
2949   /* Check the queue parameter */
2950   if (pQList == NULL)
2951   {
2952     return HAL_ERROR;
2953   }
2954 
2955   /* Check the queue */
2956   if (pQList->Head == NULL)
2957   {
2958     /* Update the queue error code */
2959     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
2960 
2961     return HAL_ERROR;
2962   }
2963 
2964   /* Check if queue is dynamic */
2965   if (pQList->Type == QUEUE_TYPE_DYNAMIC)
2966   {
2967     return HAL_OK;
2968   }
2969 
2970   /* Update the queue state */
2971   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
2972 
2973   /* Update the queue error code */
2974   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
2975 
2976   /* Get CLLR register mask and offset */
2977   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
2978 
2979   /* Check queue circularity */
2980   if (pQList->FirstCircularNode != 0U)
2981   {
2982     /* Find the last queue node and get its position in selected queue */
2983     node_info.cllr_offset = cllr_offset;
2984     (void)DMA_List_FindNode(pQList, NULL, &node_info);
2985   }
2986 
2987   /* Set current node address */
2988   currentnode_addr = (uint32_t)pQList->Head;
2989 
2990   /* Store register value */
2991   DMA_List_FillNode(pQList->Head, &context_node);
2992 
2993   /* Convert all nodes to dyncamic (Bypass head node) */
2994   for (uint32_t node_count = 1U; node_count < pQList->NodeNumber; node_count++)
2995   {
2996     /* Update node address */
2997     MODIFY_REG(currentnode_addr, DMA_CLLR_LA, (context_node.LinkRegisters[cllr_offset] & DMA_CLLR_LA));
2998 
2999     /* Bypass the first circular node when first circular node isn't the last queue node */
3000     if (((uint32_t)pQList->FirstCircularNode != 0U)                         &&
3001         ((uint32_t)pQList->FirstCircularNode != node_info.currentnode_addr) &&
3002         ((uint32_t)pQList->FirstCircularNode == currentnode_addr))
3003     {
3004       /* Copy first circular node to context node */
3005       DMA_List_FillNode(pQList->FirstCircularNode, &context_node);
3006     }
3007     else
3008     {
3009       /* Convert current node to dynamic */
3010       DMA_List_ConvertNodeToDynamic((uint32_t)&context_node, currentnode_addr, (cllr_offset + 1U));
3011     }
3012   }
3013 
3014   /* Check if first circular node is the last node queue */
3015   if (((uint32_t)pQList->FirstCircularNode != 0U) &&
3016       ((uint32_t)pQList->FirstCircularNode != node_info.currentnode_addr))
3017   {
3018     /* Update all queue nodes CLLR */
3019     DMA_List_UpdateDynamicQueueNodesCLLR(pQList, LASTNODE_ISNOT_CIRCULAR);
3020   }
3021   else
3022   {
3023     /* Update all queue nodes CLLR */
3024     DMA_List_UpdateDynamicQueueNodesCLLR(pQList, LASTNODE_IS_CIRCULAR);
3025   }
3026 
3027   /* Set queue type */
3028   pQList->Type = QUEUE_TYPE_DYNAMIC;
3029 
3030   /* Update the queue error code */
3031   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
3032 
3033   /* Update the queue state */
3034   pQList->State = HAL_DMA_QUEUE_STATE_READY;
3035 
3036   return HAL_OK;
3037 }
3038 
3039 /**
3040   * @brief  Convert a linked-list queue to static (Not optimized DMA queue execution).
3041   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
3042   * @retval HAL status.
3043   */
HAL_DMAEx_List_ConvertQToStatic(DMA_QListTypeDef * const pQList)3044 HAL_StatusTypeDef HAL_DMAEx_List_ConvertQToStatic(DMA_QListTypeDef *const pQList)
3045 {
3046   uint32_t cllr_offset;
3047   uint32_t currentnode_addr;
3048   DMA_NodeTypeDef context_node;
3049 
3050   /* Check the queue parameter */
3051   if (pQList == NULL)
3052   {
3053     return HAL_ERROR;
3054   }
3055 
3056   /* Check the queue */
3057   if (pQList->Head == NULL)
3058   {
3059     /* Update the queue error code */
3060     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_EMPTY;
3061 
3062     return HAL_ERROR;
3063   }
3064 
3065   /* Check if queue is static */
3066   if (pQList->Type == QUEUE_TYPE_STATIC)
3067   {
3068     return HAL_OK;
3069   }
3070 
3071   /* Set current node address */
3072   currentnode_addr = (uint32_t)pQList->Head;
3073 
3074   /* Update the queue state */
3075   pQList->State = HAL_DMA_QUEUE_STATE_BUSY;
3076 
3077   /* Update the queue error code */
3078   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
3079 
3080   /* Get CLLR register mask and offset */
3081   DMA_List_GetCLLRNodeInfo(pQList->Head, NULL, &cllr_offset);
3082 
3083   /* Set all CLLR queue nodes to their default positions */
3084   DMA_List_UpdateStaticQueueNodesCLLR(pQList, UPDATE_CLLR_POSITION);
3085 
3086   /* Convert all nodes to static (Bypass head node) */
3087   for (uint32_t node_count = 1U; node_count < pQList->NodeNumber; node_count++)
3088   {
3089     /* Update context node register values */
3090     DMA_List_FillNode((DMA_NodeTypeDef *)currentnode_addr, &context_node);
3091 
3092     /* Update node address */
3093     MODIFY_REG(currentnode_addr, DMA_CLLR_LA, (context_node.LinkRegisters[cllr_offset] & DMA_CLLR_LA));
3094 
3095     /* Convert current node to static */
3096     DMA_List_ConvertNodeToStatic((uint32_t)&context_node, currentnode_addr, (cllr_offset + 1U));
3097   }
3098 
3099   /* Set all CLLR queue nodes to their default values */
3100   DMA_List_UpdateStaticQueueNodesCLLR(pQList, UPDATE_CLLR_VALUE);
3101 
3102   /* Set queue type */
3103   pQList->Type = QUEUE_TYPE_STATIC;
3104 
3105   /* Update the queue error code */
3106   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
3107 
3108   /* Update the queue state */
3109   pQList->State = HAL_DMA_QUEUE_STATE_READY;
3110 
3111   return HAL_OK;
3112 }
3113 
3114 /**
3115   * @brief  Link linked-list queue to a DMA channel.
3116   * @param  hdma   : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
3117   *                  specified DMA Channel.
3118   * @param  pQList : Pointer to a DMA_QListTypeDef structure that contains queue information.
3119   * @retval HAL status.
3120   */
HAL_DMAEx_List_LinkQ(DMA_HandleTypeDef * const hdma,DMA_QListTypeDef * const pQList)3121 HAL_StatusTypeDef HAL_DMAEx_List_LinkQ(DMA_HandleTypeDef *const hdma,
3122                                        DMA_QListTypeDef *const pQList)
3123 {
3124   HAL_DMA_StateTypeDef state;
3125 
3126   /* Check the DMA channel handle and the queue parameters */
3127   if ((hdma == NULL) || (pQList == NULL))
3128   {
3129     return HAL_ERROR;
3130   }
3131 
3132   /* Get DMA state */
3133   state = hdma->State;
3134 
3135   /* Check DMA channel state */
3136   if ((hdma->State == HAL_DMA_STATE_BUSY) || (state == HAL_DMA_STATE_SUSPEND))
3137   {
3138     /* Update the DMA channel error code */
3139     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
3140 
3141     /* Process unlocked */
3142     __HAL_UNLOCK(hdma);
3143 
3144     return HAL_ERROR;
3145   }
3146 
3147   /* Check queue state */
3148   if (pQList->State == HAL_DMA_QUEUE_STATE_BUSY)
3149   {
3150     /* Update the queue error code */
3151     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_BUSY;
3152 
3153     return HAL_ERROR;
3154   }
3155 
3156   /* Check linearity compatibility */
3157   if ((IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance) == 0U) &&
3158       ((pQList->Head->NodeInfo & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR))
3159   {
3160     /* Update the queue error code */
3161     pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_UNSUPPORTED;
3162 
3163     return HAL_ERROR;
3164   }
3165 
3166   /* Check circularity compatibility */
3167   if (hdma->Mode == DMA_LINKEDLIST_CIRCULAR)
3168   {
3169     /* Check first circular node */
3170     if (pQList->FirstCircularNode == NULL)
3171     {
3172       /* Update the queue error code */
3173       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
3174 
3175       return HAL_ERROR;
3176     }
3177   }
3178   else
3179   {
3180     /* Check first circular node */
3181     if (pQList->FirstCircularNode != NULL)
3182     {
3183       /* Update the queue error code */
3184       pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_INVALIDTYPE;
3185 
3186       return HAL_ERROR;
3187     }
3188   }
3189 
3190   /* Register queue to DMA handle */
3191   hdma->LinkedListQueue = pQList;
3192 
3193   return HAL_OK;
3194 }
3195 
3196 /**
3197   * @brief  Unlink linked-list queue from a DMA channel.
3198   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
3199   *                specified DMA Channel.
3200   * @retval HAL status.
3201   */
HAL_DMAEx_List_UnLinkQ(DMA_HandleTypeDef * const hdma)3202 HAL_StatusTypeDef HAL_DMAEx_List_UnLinkQ(DMA_HandleTypeDef *const hdma)
3203 {
3204   HAL_DMA_StateTypeDef state;
3205 
3206   /* Check the DMA channel parameter */
3207   if (hdma == NULL)
3208   {
3209     return HAL_ERROR;
3210   }
3211 
3212   /* Get DMA state */
3213   state = hdma->State;
3214 
3215   /* Check DMA channel state */
3216   if ((hdma->State == HAL_DMA_STATE_BUSY) || (state == HAL_DMA_STATE_SUSPEND))
3217   {
3218     /* Update the DMA channel error code */
3219     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
3220 
3221     /* Process unlocked */
3222     __HAL_UNLOCK(hdma);
3223 
3224     return HAL_ERROR;
3225   }
3226 
3227   /* Clear queue information from DMA channel handle */
3228   hdma->LinkedListQueue = NULL;
3229 
3230   return HAL_OK;
3231 }
3232 /**
3233   * @}
3234   */
3235 
3236 /** @addtogroup DMAEx_Exported_Functions_Group4
3237   *
3238 @verbatim
3239   ======================================================================================================================
3240              ##### Data handling, repeated block and trigger configuration functions #####
3241   ======================================================================================================================
3242     [..]
3243       This section provides functions allowing to :
3244       (+) Configure DMA channel data handling.
3245       (+) Configure DMA channel repeated block.
3246       (+) Configure DMA channel trigger.
3247 
3248     [..]
3249       (+) The HAL_DMAEx_ConfigDataHandling() function allows to configure DMA channel data handling.
3250               (++) GPDMA or HPDMA data handling : byte-based reordering, packing/unpacking, padding/truncation,
3251                                                   sign extension and left/right alignment.
3252 
3253       (+) The HAL_DMAEx_ConfigTrigger() function allows to configure DMA channel HW triggers.
3254 
3255       (+) The HAL_DMAEx_ConfigRepeatBlock() function allows to configure DMA channel repeated block.
3256               (++) This feature is available only for channel that supports 2 dimensions addressing capability.
3257 
3258 @endverbatim
3259   * @{
3260   */
3261 
3262 /**
3263   * @brief  Configure the DMA channel data handling according to the specified parameters in the
3264   *         DMA_DataHandlingConfTypeDef.
3265   * @param  hdma                : Pointer to a DMA_HandleTypeDef structure that contains the configuration information
3266   *                               for the specified DMA Channel.
3267   * @param  pConfigDataHandling : Pointer to a DMA_DataHandlingConfTypeDef structure that contains the data handling
3268   *                               configuration.
3269   * @retval HAL status.
3270   */
HAL_DMAEx_ConfigDataHandling(DMA_HandleTypeDef * const hdma,DMA_DataHandlingConfTypeDef const * const pConfigDataHandling)3271 HAL_StatusTypeDef HAL_DMAEx_ConfigDataHandling(DMA_HandleTypeDef *const hdma,
3272                                                DMA_DataHandlingConfTypeDef const *const pConfigDataHandling)
3273 {
3274   /* Check the DMA peripheral handle and data handling parameters */
3275   if ((hdma == NULL) || (pConfigDataHandling == NULL))
3276   {
3277     return HAL_ERROR;
3278   }
3279 
3280   /* Check the parameters */
3281   assert_param(IS_DMA_DATA_ALIGNMENT(pConfigDataHandling->DataAlignment));
3282   assert_param(IS_DMA_DATA_EXCHANGE(pConfigDataHandling->DataExchange));
3283 
3284   /* Check DMA channel state */
3285   if (hdma->State == HAL_DMA_STATE_READY)
3286   {
3287     MODIFY_REG(hdma->Instance->CTR1, (DMA_CTR1_DWX | DMA_CTR1_DHX | DMA_CTR1_DBX | DMA_CTR1_SBX | DMA_CTR1_PAM),
3288                (pConfigDataHandling->DataAlignment | pConfigDataHandling->DataExchange));
3289   }
3290   else
3291   {
3292     /* Update the DMA channel error code */
3293     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
3294 
3295     /* Process unlocked */
3296     __HAL_UNLOCK(hdma);
3297 
3298     return HAL_ERROR;
3299   }
3300 
3301   return HAL_OK;
3302 }
3303 
3304 /**
3305   * @brief  Configure the DMA channel trigger according to the specified parameters in the DMA_TriggerConfTypeDef.
3306   * @param  hdma           : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for
3307   *                          the specified DMA Channel.
3308   * @param  pConfigTrigger : Pointer to a DMA_TriggerConfTypeDef structure that contains the trigger configuration.
3309   * @retval HAL status.
3310   */
HAL_DMAEx_ConfigTrigger(DMA_HandleTypeDef * const hdma,DMA_TriggerConfTypeDef const * const pConfigTrigger)3311 HAL_StatusTypeDef HAL_DMAEx_ConfigTrigger(DMA_HandleTypeDef *const hdma,
3312                                           DMA_TriggerConfTypeDef const *const pConfigTrigger)
3313 {
3314   /* Check the DMA peripheral handle and trigger parameters */
3315   if ((hdma == NULL) || (pConfigTrigger == NULL))
3316   {
3317     return HAL_ERROR;
3318   }
3319 
3320   /* Check the parameters */
3321   assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
3322   assert_param(IS_DMA_TRIGGER_POLARITY(pConfigTrigger->TriggerPolarity));
3323   assert_param(IS_DMA_TRIGGER_MODE(pConfigTrigger->TriggerMode));
3324   assert_param(IS_DMA_TRIGGER_SELECTION(pConfigTrigger->TriggerSelection));
3325 
3326   /* Check DMA channel state */
3327   if (hdma->State == HAL_DMA_STATE_READY)
3328   {
3329     MODIFY_REG(hdma->Instance->CTR2, (DMA_CTR2_TRIGPOL | DMA_CTR2_TRIGSEL | DMA_CTR2_TRIGM),
3330                (pConfigTrigger->TriggerPolarity | pConfigTrigger->TriggerMode |
3331                 (pConfigTrigger->TriggerSelection << DMA_CTR2_TRIGSEL_Pos)));
3332   }
3333   else
3334   {
3335     /* Update the DMA channel error code */
3336     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
3337 
3338     /* Process unlocked */
3339     __HAL_UNLOCK(hdma);
3340 
3341     return HAL_ERROR;
3342   }
3343 
3344   return HAL_OK;
3345 }
3346 
3347 /**
3348   * @brief  Configure the DMA channel repeated block according to the specified parameters in the
3349   *         DMA_RepeatBlockConfTypeDef.
3350   * @param  hdma               : Pointer to a DMA_HandleTypeDef structure that contains the configuration information
3351   *                              for the specified DMA Channel.
3352   * @param  pConfigRepeatBlock : Pointer to a DMA_RepeatBlockConfTypeDef structure that contains the repeated block
3353   *                              configuration.
3354   * @retval HAL status.
3355   */
HAL_DMAEx_ConfigRepeatBlock(DMA_HandleTypeDef * const hdma,DMA_RepeatBlockConfTypeDef const * const pConfigRepeatBlock)3356 HAL_StatusTypeDef HAL_DMAEx_ConfigRepeatBlock(DMA_HandleTypeDef *const hdma,
3357                                               DMA_RepeatBlockConfTypeDef const *const pConfigRepeatBlock)
3358 {
3359   uint32_t tmpreg1;
3360   uint32_t tmpreg2;
3361 
3362   /* Check the DMA peripheral handle and repeated block parameters */
3363   if ((hdma == NULL) || (pConfigRepeatBlock == NULL))
3364   {
3365     return HAL_ERROR;
3366   }
3367 
3368   /* Check parameters */
3369   assert_param(IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance));
3370   assert_param(IS_DMA_REPEAT_COUNT(pConfigRepeatBlock->RepeatCount));
3371   assert_param(IS_DMA_BURST_ADDR_OFFSET(pConfigRepeatBlock->SrcAddrOffset));
3372   assert_param(IS_DMA_BURST_ADDR_OFFSET(pConfigRepeatBlock->DestAddrOffset));
3373   assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pConfigRepeatBlock->BlkSrcAddrOffset));
3374   assert_param(IS_DMA_BLOCK_ADDR_OFFSET(pConfigRepeatBlock->BlkDestAddrOffset));
3375 
3376   /* Check DMA channel state */
3377   if (hdma->State == HAL_DMA_STATE_READY)
3378   {
3379     /* Store repeat block count */
3380     tmpreg1 = ((pConfigRepeatBlock->RepeatCount - 1U) << DMA_CBR1_BRC_Pos);
3381 
3382     /* Check the sign of single/burst destination address offset value */
3383     if (pConfigRepeatBlock->DestAddrOffset < 0)
3384     {
3385       /* Store single/burst destination address offset configuration (signed case) */
3386       tmpreg1 |= DMA_CBR1_DDEC;
3387       tmpreg2 = (uint32_t)(- pConfigRepeatBlock->DestAddrOffset);
3388       tmpreg2 = tmpreg2 << DMA_CTR3_DAO_Pos;
3389     }
3390     else
3391     {
3392       /* Store single/burst destination address offset configuration (unsigned case) */
3393       tmpreg2 = ((uint32_t)pConfigRepeatBlock->DestAddrOffset << DMA_CTR3_DAO_Pos);
3394     }
3395 
3396     /* Check the sign of single/burst source address offset value */
3397     if (pConfigRepeatBlock->SrcAddrOffset < 0)
3398     {
3399       /* Store single/burst source address offset configuration (signed case) */
3400       tmpreg1 |= DMA_CBR1_SDEC;
3401       tmpreg2 |= (uint32_t)(- pConfigRepeatBlock->SrcAddrOffset);
3402     }
3403     else
3404     {
3405       /* Store single/burst source address offset configuration (unsigned case) */
3406       tmpreg2 |= (uint32_t)pConfigRepeatBlock->SrcAddrOffset;
3407     }
3408 
3409     /* Write DMA Channel Transfer Register 3 (CTR3) */
3410     WRITE_REG(hdma->Instance->CTR3, tmpreg2);
3411 
3412     /* Check the sign of block destination address offset value */
3413     if (pConfigRepeatBlock->BlkDestAddrOffset < 0)
3414     {
3415       /* Store block destination address offset configuration (signed case) */
3416       tmpreg1 |= DMA_CBR1_BRDDEC;
3417       tmpreg2 = (uint32_t)(- pConfigRepeatBlock->BlkDestAddrOffset);
3418       tmpreg2 = tmpreg2 << DMA_CBR2_BRDAO_Pos;
3419     }
3420     else
3421     {
3422       /* Store block destination address offset configuration (unsigned case) */
3423       tmpreg2 = ((uint32_t)pConfigRepeatBlock->BlkDestAddrOffset << DMA_CBR2_BRDAO_Pos);
3424     }
3425 
3426     /* Check the sign of block source address offset value */
3427     if (pConfigRepeatBlock->BlkSrcAddrOffset < 0)
3428     {
3429       /* Store block source address offset configuration (signed case) */
3430       tmpreg1 |= DMA_CBR1_BRSDEC;
3431       tmpreg2 |= (uint32_t)(- pConfigRepeatBlock->BlkSrcAddrOffset);
3432     }
3433     else
3434     {
3435       /* Store block source address offset configuration (unsigned case) */
3436       tmpreg2 |= (uint32_t)pConfigRepeatBlock->BlkSrcAddrOffset;
3437     }
3438 
3439     /* Write DMA Channel block register 2 (CBR2) */
3440     WRITE_REG(hdma->Instance->CBR2, tmpreg2);
3441 
3442     /* Write DMA Channel block register 1 (CBR1) */
3443     WRITE_REG(hdma->Instance->CBR1, tmpreg1);
3444   }
3445   else
3446   {
3447     /* Update the DMA channel error code */
3448     hdma->ErrorCode = HAL_DMA_ERROR_BUSY;
3449 
3450     /* Process unlocked */
3451     __HAL_UNLOCK(hdma);
3452 
3453     return HAL_ERROR;
3454   }
3455 
3456   return HAL_OK;
3457 }
3458 /**
3459   * @}
3460   */
3461 
3462 /** @addtogroup DMAEx_Exported_Functions_Group5
3463   *
3464 @verbatim
3465   ======================================================================================================================
3466                          ##### Suspend and resume operation functions #####
3467   ======================================================================================================================
3468     [..]
3469       This section provides functions allowing to :
3470       (+) Suspend any ongoing DMA channel transfer.
3471       (+) Resume any suspended DMA channel transfer.
3472 
3473     [..]
3474       (+) The HAL_DMAEx_Suspend() function allows to suspend any ongoing DMA channel transfer in polling mode (Blocking
3475           mode).
3476 
3477       (+) The HAL_DMAEx_Suspend_IT() function allows to suspend any ongoing DMA channel transfer in interrupt mode
3478          (Non-blocking mode).
3479 
3480       (+) The HAL_DMAEx_Resume() function allows to resume any suspended DMA channel transfer.
3481 
3482 @endverbatim
3483   * @{
3484   */
3485 
3486 /**
3487   * @brief  Suspend any ongoing DMA channel transfer in polling mode (Blocking mode).
3488   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
3489   *                specified DMA channel.
3490   * @note   After suspending a DMA channel, a check for wait until the DMA channel is effectively suspended is added. If
3491   *         a channel is suspended while a data transfer is ongoing, the current data will be transferred and the
3492   *         channel will be effectively suspended only after the transfer of this single/burst data is finished.
3493   * @retval HAL status.
3494   */
HAL_DMAEx_Suspend(DMA_HandleTypeDef * const hdma)3495 HAL_StatusTypeDef HAL_DMAEx_Suspend(DMA_HandleTypeDef *const hdma)
3496 {
3497   /* Get tick number */
3498   uint32_t tickstart = HAL_GetTick();
3499 
3500   /* Check the DMA peripheral handle */
3501   if (hdma == NULL)
3502   {
3503     return HAL_ERROR;
3504   }
3505 
3506   /* Check DMA channel state */
3507   if (hdma->State != HAL_DMA_STATE_BUSY)
3508   {
3509     /* Update the DMA channel error code */
3510     hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
3511 
3512     /* Process unlocked */
3513     __HAL_UNLOCK(hdma);
3514 
3515     return HAL_ERROR;
3516   }
3517   else
3518   {
3519     /* Suspend the channel */
3520     hdma->Instance->CCR |= DMA_CCR_SUSP;
3521 
3522     /* Check if the DMA channel is suspended */
3523     while ((hdma->Instance->CSR & DMA_CSR_SUSPF) == 0U)
3524     {
3525       /* Check for the timeout */
3526       if ((HAL_GetTick() - tickstart) > HAL_TIMEOUT_DMA_ABORT)
3527       {
3528         /* Update the DMA channel error code */
3529         hdma->ErrorCode |= HAL_DMA_ERROR_TIMEOUT;
3530 
3531         /* Update the DMA channel state */
3532         hdma->State = HAL_DMA_STATE_ERROR;
3533 
3534         /* Process Unlocked */
3535         __HAL_UNLOCK(hdma);
3536 
3537         return HAL_ERROR;
3538       }
3539     }
3540 
3541     /* Update the DMA channel state */
3542     hdma->State = HAL_DMA_STATE_SUSPEND;
3543   }
3544 
3545   return HAL_OK;
3546 }
3547 
3548 /**
3549   * @brief  Suspend any ongoing DMA channel transfer in polling mode (Non-blocking mode).
3550   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
3551   *                specified DMA Channel.
3552   * @retval HAL status.
3553   */
HAL_DMAEx_Suspend_IT(DMA_HandleTypeDef * const hdma)3554 HAL_StatusTypeDef HAL_DMAEx_Suspend_IT(DMA_HandleTypeDef *const hdma)
3555 {
3556   /* Check the DMA peripheral handle parameter */
3557   if (hdma == NULL)
3558   {
3559     return HAL_ERROR;
3560   }
3561 
3562   /* Check DMA channel state */
3563   if (hdma->State != HAL_DMA_STATE_BUSY)
3564   {
3565     /* Update the DMA channel error code */
3566     hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
3567 
3568     /* Process unlocked */
3569     __HAL_UNLOCK(hdma);
3570 
3571     return HAL_ERROR;
3572   }
3573   else
3574   {
3575     /* Suspend the DMA channel and activate suspend interrupt */
3576     hdma->Instance->CCR |= (DMA_CCR_SUSP | DMA_CCR_SUSPIE);
3577   }
3578 
3579   return HAL_OK;
3580 }
3581 
3582 /**
3583   * @brief  Resume any suspended DMA channel transfer.
3584   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
3585   *                specified DMA Channel.
3586   * @retval HAL status.
3587   */
HAL_DMAEx_Resume(DMA_HandleTypeDef * const hdma)3588 HAL_StatusTypeDef HAL_DMAEx_Resume(DMA_HandleTypeDef *const hdma)
3589 {
3590   /* Check the DMA peripheral handle parameter */
3591   if (hdma == NULL)
3592   {
3593     return HAL_ERROR;
3594   }
3595 
3596   /* Check DMA channel state */
3597   if (hdma->State != HAL_DMA_STATE_SUSPEND)
3598   {
3599     /* Update the DMA channel error code */
3600     hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
3601 
3602     /* Process unlocked */
3603     __HAL_UNLOCK(hdma);
3604 
3605     return HAL_ERROR;
3606   }
3607   else
3608   {
3609     /* Resume the DMA channel */
3610     hdma->Instance->CCR &= (~DMA_CCR_SUSP);
3611 
3612     /* Clear the suspend flag */
3613     hdma->Instance->CFCR |= DMA_CFCR_SUSPF;
3614 
3615     /* Update the DMA channel state */
3616     hdma->State = HAL_DMA_STATE_BUSY;
3617   }
3618 
3619   return HAL_OK;
3620 }
3621 /**
3622   * @}
3623   */
3624 
3625 /** @addtogroup DMAEx_Exported_Functions_Group6
3626   *
3627 @verbatim
3628   ======================================================================================================================
3629                                ##### Fifo status function #####
3630   ======================================================================================================================
3631     [..]
3632       This section provides function allowing to get DMA channel FIFO level.
3633 
3634     [..]
3635       (+) The HAL_DMAEx_GetFifoLevel() function allows to return the number of available write beats in the FIFO, in
3636           units of the programmed destination data.
3637               (++) This API is available only for DMA channels that supports FIFO.
3638 
3639 @endverbatim
3640   * @{
3641   */
3642 
3643 /**
3644   * @brief  Get and returns the DMA channel FIFO level.
3645   * @param  hdma : Pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
3646   *                specified DMA Channel.
3647   * @retval Returns the number of available beats in FIFO.
3648   */
HAL_DMAEx_GetFifoLevel(DMA_HandleTypeDef const * const hdma)3649 uint32_t HAL_DMAEx_GetFifoLevel(DMA_HandleTypeDef const *const hdma)
3650 {
3651   return ((hdma->Instance->CSR & DMA_CSR_FIFOL) >> DMA_CSR_FIFOL_Pos);
3652 }
3653 /**
3654   * @}
3655   */
3656 
3657 /**
3658   * @}
3659   */
3660 
3661 /* Private functions -------------------------------------------------------------------------------------------------*/
3662 /** @defgroup DMAEx_Private_Functions DMAEx Private Functions
3663   * @brief    DMAEx Private Functions
3664   * @{
3665   */
3666 
3667 /**
3668   * @brief  Initialize the DMA handle according to the specified parameters in the DMA_InitTypeDef.
3669   * @param  hdma : pointer to a DMA_HandleTypeDef structure that contains the configuration information for the
3670   *                specified DMA Channel.
3671   * @retval None.
3672   */
DMA_List_Init(DMA_HandleTypeDef const * const hdma)3673 static void DMA_List_Init(DMA_HandleTypeDef const *const hdma)
3674 {
3675   uint32_t tmpreg;
3676 
3677   /* Prepare DMA Channel Control Register (CCR) value */
3678   tmpreg = hdma->InitLinkedList.Priority | hdma->InitLinkedList.LinkStepMode;
3679 
3680   /* Check DMA channel instance */
3681   if ((IS_HPDMA_INSTANCE(hdma->Instance) != 0U) || (IS_GPDMA_INSTANCE(hdma->Instance) != 0U))
3682   {
3683     tmpreg |= hdma->InitLinkedList.LinkAllocatedPort;
3684   }
3685 
3686   /* Write DMA Channel Control Register (CCR) */
3687   MODIFY_REG(hdma->Instance->CCR, DMA_CCR_PRIO | DMA_CCR_LAP | DMA_CCR_LSM, tmpreg);
3688 
3689   /* Write DMA Channel Control Register (CTR1) */
3690   WRITE_REG(hdma->Instance->CTR1, 0U);
3691 
3692   /* Write DMA Channel Control Register (CTR2) */
3693   WRITE_REG(hdma->Instance->CTR2, hdma->InitLinkedList.TransferEventMode);
3694 
3695   /* Write DMA Channel Control Register (CBR1) */
3696   WRITE_REG(hdma->Instance->CBR1, 0U);
3697 
3698   /* Write DMA Channel Control Register (CSAR) */
3699   WRITE_REG(hdma->Instance->CSAR, 0U);
3700 
3701   /* Write DMA Channel Control Register (CDAR) */
3702   WRITE_REG(hdma->Instance->CDAR, 0U);
3703 
3704   /* If 2D Addressing is supported by current channel */
3705   if (IS_DMA_2D_ADDRESSING_INSTANCE(hdma->Instance) != 0U)
3706   {
3707     /* Write DMA Channel Control Register (CTR3) */
3708     WRITE_REG(hdma->Instance->CTR3, 0U);
3709 
3710     /* Write DMA Channel Control Register (CBR2) */
3711     WRITE_REG(hdma->Instance->CBR2, 0U);
3712   }
3713 
3714   /* Write DMA Channel linked-list address register (CLLR) */
3715   WRITE_REG(hdma->Instance->CLLR, 0U);
3716 }
3717 
3718 /**
3719   * @brief  Build a DMA channel node according to the specified parameters in the DMA_NodeConfTypeDef.
3720   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
3721   *                       specified DMA linked-list Node.
3722   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
3723   *                       configurations.
3724   * @retval None.
3725   */
DMA_List_BuildNode(DMA_NodeConfTypeDef const * const pNodeConfig,DMA_NodeTypeDef * const pNode)3726 static void DMA_List_BuildNode(DMA_NodeConfTypeDef const *const pNodeConfig,
3727                                DMA_NodeTypeDef *const pNode)
3728 {
3729   int32_t blockoffset;
3730 
3731   /* Update CTR1 register value ***************************************************************************************/
3732   /* Prepare DMA channel transfer register (CTR1) value */
3733   pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] = pNodeConfig->Init.DestInc                     |
3734                                                    pNodeConfig->Init.DestDataWidth               |
3735                                                    pNodeConfig->DataHandlingConfig.DataAlignment |
3736                                                    pNodeConfig->Init.SrcInc                      |
3737                                                    pNodeConfig->Init.SrcDataWidth;
3738 
3739 #if defined (CPU_IN_SECURE_STATE)
3740   /* set source channel security attribute */
3741   if (pNodeConfig->SrcSecure == DMA_CHANNEL_SRC_SEC)
3742   {
3743     pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] |= DMA_CTR1_SSEC;
3744   }
3745 
3746   /* set destination channel security attribute */
3747   if (pNodeConfig->DestSecure == DMA_CHANNEL_DEST_SEC)
3748   {
3749     pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] |= DMA_CTR1_DSEC;
3750   }
3751 #endif /* CPU_IN_SECURE_STATE */
3752 
3753   /* Add parameters related to DMA configuration */
3754   if ((pNodeConfig->NodeType & (DMA_CHANNEL_TYPE_GPDMA | DMA_CHANNEL_TYPE_HPDMA)) != 0U)
3755   {
3756     /* Prepare DMA channel transfer register (CTR1) value */
3757     pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] |=
3758       (pNodeConfig->Init.TransferAllocatedPort | pNodeConfig->DataHandlingConfig.DataExchange |
3759        (((pNodeConfig->Init.DestBurstLength - 1U) << DMA_CTR1_DBL_1_Pos) & DMA_CTR1_DBL_1)    |
3760        (((pNodeConfig->Init.SrcBurstLength - 1U) << DMA_CTR1_SBL_1_Pos) & DMA_CTR1_SBL_1));
3761   }
3762   /*********************************************************************************** CTR1 register value is updated */
3763 
3764 
3765   /* Update CTR2 register value ***************************************************************************************/
3766   /* Prepare DMA channel transfer register 2 (CTR2) value */
3767   pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] = pNodeConfig->Init.TransferEventMode |
3768                                                    (pNodeConfig->Init.Request & (DMA_CTR2_REQSEL | DMA_CTR2_SWREQ));
3769 
3770   /* Check for memory to peripheral transfer */
3771   if ((pNodeConfig->Init.Direction) == DMA_MEMORY_TO_PERIPH)
3772   {
3773     /* Check for GPDMA OR HPDMA */
3774     if ((pNodeConfig->NodeType & (DMA_CHANNEL_TYPE_GPDMA | DMA_CHANNEL_TYPE_HPDMA)) != 0U)
3775     {
3776       pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |= DMA_CTR2_DREQ;
3777     }
3778   }
3779   /* Memory to memory transfer */
3780   else if ((pNodeConfig->Init.Direction) == DMA_MEMORY_TO_MEMORY)
3781   {
3782     pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |= DMA_CTR2_SWREQ;
3783   }
3784   else
3785   {
3786     /* Prevent MISRA-C2012-Rule-15.7 */
3787   }
3788 
3789   /* Configure HW Peripheral flow control selection */
3790   pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |= pNodeConfig->Init.Mode;
3791 
3792   /* Check if trigger feature is active */
3793   if (pNodeConfig->TriggerConfig.TriggerPolarity != DMA_TRIG_POLARITY_MASKED)
3794   {
3795     /* Prepare DMA channel transfer register 2 (CTR2) value */
3796     pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] |=
3797       pNodeConfig->TriggerConfig.TriggerMode | pNodeConfig->TriggerConfig.TriggerPolarity |
3798       ((pNodeConfig->TriggerConfig.TriggerSelection << DMA_CTR2_TRIGSEL_Pos) & DMA_CTR2_TRIGSEL);
3799   }
3800   /*********************************************************************************** CTR2 register value is updated */
3801 
3802 
3803   /* Update CBR1 register value ***************************************************************************************/
3804   /* Prepare DMA channel block register 1 (CBR1) value */
3805   pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] = (pNodeConfig->DataSize & DMA_CBR1_BNDT);
3806 
3807   /* If 2D addressing is supported by the selected DMA channel */
3808   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
3809   {
3810     /* Set the new CBR1 Register value */
3811     pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |=
3812       (((pNodeConfig->RepeatBlockConfig.RepeatCount - 1U) << DMA_CBR1_BRC_Pos) & DMA_CBR1_BRC);
3813 
3814     /* If the source address offset is negative, set SDEC bit */
3815     if (pNodeConfig->RepeatBlockConfig.SrcAddrOffset < 0)
3816     {
3817       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_SDEC;
3818     }
3819     else
3820     {
3821       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_SDEC);
3822     }
3823 
3824     /* If the destination address offset is negative, set DDEC bit */
3825     if (pNodeConfig->RepeatBlockConfig.DestAddrOffset < 0)
3826     {
3827       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_DDEC;
3828     }
3829     else
3830     {
3831       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_DDEC);
3832     }
3833 
3834     /* If the repeated block source address offset is negative, set BRSEC bit */
3835     if (pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset < 0)
3836     {
3837       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_BRSDEC;
3838     }
3839     else
3840     {
3841       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_BRSDEC);
3842     }
3843 
3844     /* if the repeated block destination address offset is negative, set BRDEC bit */
3845     if (pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset < 0)
3846     {
3847       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] |= DMA_CBR1_BRDDEC;
3848     }
3849     else
3850     {
3851       pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] &= (~DMA_CBR1_BRDDEC);
3852     }
3853   }
3854   /*********************************************************************************** CBR1 register value is updated */
3855 
3856 
3857   /* Update CSAR register value ***************************************************************************************/
3858   pNode->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET] = pNodeConfig->SrcAddress;
3859   /*********************************************************************************** CSAR register value is updated */
3860 
3861 
3862   /* Update CDAR register value ***************************************************************************************/
3863   pNode->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] = pNodeConfig->DstAddress;
3864   /*********************************************************************************** CDAR register value is updated */
3865 
3866   /* Check if the selected channel is 2D addressing */
3867   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
3868   {
3869     /* Update CTR3 register value *************************************************************************************/
3870     /* Write new CTR3 Register value : source address offset */
3871     if (pNodeConfig->RepeatBlockConfig.SrcAddrOffset < 0)
3872     {
3873       blockoffset = (- pNodeConfig->RepeatBlockConfig.SrcAddrOffset);
3874       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] = ((uint32_t)blockoffset & DMA_CTR3_SAO);
3875     }
3876     else
3877     {
3878       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] =
3879         ((uint32_t)pNodeConfig->RepeatBlockConfig.SrcAddrOffset & DMA_CTR3_SAO);
3880     }
3881 
3882     /* Write new CTR3 Register value : destination address offset */
3883     if (pNodeConfig->RepeatBlockConfig.DestAddrOffset < 0)
3884     {
3885       blockoffset = (- pNodeConfig->RepeatBlockConfig.DestAddrOffset);
3886       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] |= (((uint32_t)blockoffset << DMA_CTR3_DAO_Pos) & DMA_CTR3_DAO);
3887     }
3888     else
3889     {
3890       pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] |=
3891         (((uint32_t)pNodeConfig->RepeatBlockConfig.DestAddrOffset << DMA_CTR3_DAO_Pos) & DMA_CTR3_DAO);
3892     }
3893     /********************************************************************************* CTR3 register value is updated */
3894 
3895 
3896     /* Update CBR2 register value *************************************************************************************/
3897     /* Write new CBR2 Register value : repeated block source address offset */
3898     if (pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset < 0)
3899     {
3900       blockoffset = (- pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset);
3901       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] = ((uint32_t)blockoffset & DMA_CBR2_BRSAO);
3902     }
3903     else
3904     {
3905       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] =
3906         ((uint32_t)pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset & DMA_CBR2_BRSAO);
3907     }
3908 
3909     /* Write new CBR2 Register value : repeated block destination address offset */
3910     if (pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset < 0)
3911     {
3912       blockoffset = (- pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset);
3913       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] |=
3914         (((uint32_t)blockoffset & DMA_CBR2_BRSAO) << DMA_CBR2_BRDAO_Pos);
3915     }
3916     else
3917     {
3918       pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] |=
3919         (((uint32_t)pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset << DMA_CBR2_BRDAO_Pos) & DMA_CBR2_BRDAO);
3920     }
3921     /********************************************************************************* CBR2 register value is updated */
3922 
3923     /* Update CLLR register value *************************************************************************************/
3924     /* Reset CLLR Register value : channel linked-list address register offset */
3925     pNode->LinkRegisters[NODE_CLLR_2D_DEFAULT_OFFSET] = 0U;
3926     /********************************************************************************* CLLR register value is cleared */
3927   }
3928   else
3929   {
3930     /* Update CLLR register value *************************************************************************************/
3931     /* Reset CLLR Register value : channel linked-list address register offset */
3932     pNode->LinkRegisters[NODE_CLLR_LINEAR_DEFAULT_OFFSET] = 0U;
3933     /********************************************************************************* CLLR register value is cleared */
3934   }
3935 
3936   /* Update node information value ************************************************************************************/
3937   /* Set node information */
3938   pNode->NodeInfo = pNodeConfig->NodeType;
3939   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
3940   {
3941     pNode->NodeInfo |= (NODE_CLLR_2D_DEFAULT_OFFSET << NODE_CLLR_IDX_POS);
3942   }
3943   else
3944   {
3945     pNode->NodeInfo |= (NODE_CLLR_LINEAR_DEFAULT_OFFSET << NODE_CLLR_IDX_POS);
3946   }
3947   /******************************************************************************** Node information value is updated */
3948 }
3949 
3950 /**
3951   * @brief  Get a DMA channel node configuration.
3952   * @param  pNodeConfig : Pointer to a DMA_NodeConfTypeDef structure that contains the configuration information for the
3953   *                       specified DMA linked-list Node.
3954   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
3955   *                       configurations.
3956   * @retval None.
3957   */
DMA_List_GetNodeConfig(DMA_NodeConfTypeDef * const pNodeConfig,DMA_NodeTypeDef const * const pNode)3958 static void DMA_List_GetNodeConfig(DMA_NodeConfTypeDef *const pNodeConfig,
3959                                    DMA_NodeTypeDef const *const pNode)
3960 {
3961   uint16_t offset;
3962 
3963   /* Get node information *********************************************************************************************/
3964   pNodeConfig->NodeType = (pNode->NodeInfo & NODE_TYPE_MASK);
3965   /*************************************************************************************** Node type value is updated */
3966 
3967 
3968   /* Get CTR1 fields values *******************************************************************************************/
3969   pNodeConfig->Init.SrcInc                      = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_SINC;
3970   pNodeConfig->Init.DestInc                     = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_DINC;
3971   pNodeConfig->Init.SrcDataWidth                = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_SDW_LOG2;
3972   pNodeConfig->Init.DestDataWidth               = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_DDW_LOG2;
3973   pNodeConfig->Init.SrcBurstLength              = ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] &
3974                                                     DMA_CTR1_SBL_1) >> DMA_CTR1_SBL_1_Pos) + 1U;
3975   pNodeConfig->Init.DestBurstLength             = ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] &
3976                                                     DMA_CTR1_DBL_1) >> DMA_CTR1_DBL_1_Pos) + 1U;
3977   pNodeConfig->Init.TransferAllocatedPort       = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   &
3978                                                   (DMA_CTR1_SAP | DMA_CTR1_DAP);
3979   pNodeConfig->DataHandlingConfig.DataExchange  = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   &
3980                                                   (DMA_CTR1_SBX | DMA_CTR1_DBX | DMA_CTR1_DHX | DMA_CTR1_DWX);
3981   pNodeConfig->DataHandlingConfig.DataAlignment = pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET]   & DMA_CTR1_PAM;
3982 #if defined (CPU_IN_SECURE_STATE)
3983   if ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] & DMA_CTR1_SSEC) != 0U)
3984   {
3985     pNodeConfig->SrcSecure = DMA_CHANNEL_SRC_SEC;
3986   }
3987   else
3988   {
3989     pNodeConfig->SrcSecure = DMA_CHANNEL_SRC_NSEC;
3990   }
3991 
3992   if ((pNode->LinkRegisters[NODE_CTR1_DEFAULT_OFFSET] & DMA_CTR1_DSEC) != 0U)
3993   {
3994     pNodeConfig->DestSecure = DMA_CHANNEL_DEST_SEC;
3995   }
3996   else
3997   {
3998     pNodeConfig->DestSecure = DMA_CHANNEL_DEST_NSEC;
3999   }
4000 #endif /* CPU_IN_SECURE_STATE */
4001   /*********************************************************************************** CTR1 fields values are updated */
4002 
4003 
4004   /* Get CTR2 fields values *******************************************************************************************/
4005   if ((pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_SWREQ) != 0U)
4006   {
4007     pNodeConfig->Init.Request   = DMA_REQUEST_SW;
4008     pNodeConfig->Init.Direction = DMA_MEMORY_TO_MEMORY;
4009   }
4010   else
4011   {
4012     pNodeConfig->Init.Request   = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_REQSEL;
4013 
4014     if ((pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_DREQ) != 0U)
4015     {
4016       pNodeConfig->Init.Direction = DMA_MEMORY_TO_PERIPH;
4017     }
4018     else
4019     {
4020       pNodeConfig->Init.Direction = DMA_PERIPH_TO_MEMORY;
4021     }
4022   }
4023 
4024   pNodeConfig->Init.BlkHWRequest              = (pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] & DMA_CTR2_BREQ);
4025   pNodeConfig->TriggerConfig.TriggerMode      = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET]  & DMA_CTR2_TRIGM;
4026   pNodeConfig->TriggerConfig.TriggerPolarity  = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET]  & DMA_CTR2_TRIGPOL;
4027   pNodeConfig->TriggerConfig.TriggerSelection = (pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET] &
4028                                                  DMA_CTR2_TRIGSEL) >> DMA_CTR2_TRIGSEL_Pos;
4029   pNodeConfig->Init.TransferEventMode         = pNode->LinkRegisters[NODE_CTR2_DEFAULT_OFFSET]  & DMA_CTR2_TCEM;
4030   /*********************************************************************************** CTR2 fields values are updated */
4031 
4032 
4033   /* Get CBR1 fields **************************************************************************************************/
4034   pNodeConfig->DataSize = pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BNDT;
4035 
4036   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
4037   {
4038     pNodeConfig->RepeatBlockConfig.RepeatCount =
4039       ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BRC) >> DMA_CBR1_BRC_Pos) + 1U;
4040   }
4041   else
4042   {
4043     pNodeConfig->RepeatBlockConfig.RepeatCount = 1U;
4044   }
4045   /*********************************************************************************** CBR1 fields values are updated */
4046 
4047 
4048   /* Get CSAR field ***************************************************************************************************/
4049   pNodeConfig->SrcAddress = pNode->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET];
4050   /************************************************************************************** CSAR field value is updated */
4051 
4052 
4053   /* Get CDAR field ***************************************************************************************************/
4054   pNodeConfig->DstAddress = pNode->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET];
4055   /************************************************************************************** CDAR field value is updated */
4056 
4057   /* Check if the selected channel is 2D addressing */
4058   if ((pNodeConfig->NodeType & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
4059   {
4060     /* Get CTR3 field *************************************************************************************************/
4061     offset = (uint16_t)(pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] & DMA_CTR3_SAO);
4062     pNodeConfig->RepeatBlockConfig.SrcAddrOffset  = (int32_t)offset;
4063 
4064     offset = (uint16_t)((pNode->LinkRegisters[NODE_CTR3_DEFAULT_OFFSET] & DMA_CTR3_DAO) >> DMA_CTR3_DAO_Pos);
4065     pNodeConfig->RepeatBlockConfig.DestAddrOffset = (int32_t)offset;
4066 
4067     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_SDEC) != 0U)
4068     {
4069       pNodeConfig->RepeatBlockConfig.SrcAddrOffset *= (-1);
4070     }
4071 
4072     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_DDEC) != 0U)
4073     {
4074       pNodeConfig->RepeatBlockConfig.DestAddrOffset *= (-1);
4075     }
4076     /************************************************************************************ CTR3 field value is updated */
4077 
4078 
4079     /* Get CBR2 fields ************************************************************************************************/
4080     offset = (uint16_t)(pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] & DMA_CBR2_BRSAO);
4081     pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset = (int32_t)offset;
4082 
4083     offset = (uint16_t)((pNode->LinkRegisters[NODE_CBR2_DEFAULT_OFFSET] & DMA_CBR2_BRDAO) >> DMA_CBR2_BRDAO_Pos);
4084     pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset = (int32_t)offset;
4085 
4086     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BRSDEC) != 0U)
4087     {
4088       pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset *= (-1);
4089     }
4090 
4091     if ((pNode->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] & DMA_CBR1_BRDDEC) != 0U)
4092     {
4093       pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset *= (-1);
4094     }
4095     /************************************************************************************ CBR2 field value is updated */
4096   }
4097   else
4098   {
4099     /* Get CTR3 field *************************************************************************************************/
4100     pNodeConfig->RepeatBlockConfig.SrcAddrOffset     = 0;
4101     pNodeConfig->RepeatBlockConfig.DestAddrOffset    = 0;
4102     /************************************************************************************ CTR3 field value is updated */
4103 
4104 
4105     /* Get CBR2 fields ************************************************************************************************/
4106     pNodeConfig->RepeatBlockConfig.BlkSrcAddrOffset  = 0;
4107     pNodeConfig->RepeatBlockConfig.BlkDestAddrOffset = 0;
4108     /************************************************************************************ CBR2 field value is updated */
4109   }
4110 }
4111 
4112 /**
4113   * @brief  Check nodes base addresses compatibility.
4114   * @param  pNode1 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 1 registers configurations.
4115   * @param  pNode2 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 2 registers configurations.
4116   * @param  pNode3 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 3 registers configurations.
4117   * @retval Return 0 when nodes addresses are compatible, 1 otherwise.
4118   */
DMA_List_CheckNodesBaseAddresses(DMA_NodeTypeDef const * const pNode1,DMA_NodeTypeDef const * const pNode2,DMA_NodeTypeDef const * const pNode3)4119 static uint32_t DMA_List_CheckNodesBaseAddresses(DMA_NodeTypeDef const *const pNode1,
4120                                                  DMA_NodeTypeDef const *const pNode2,
4121                                                  DMA_NodeTypeDef const *const pNode3)
4122 {
4123   uint32_t temp = (((uint32_t)pNode1 | (uint32_t)pNode2 | (uint32_t)pNode3) & DMA_CLBAR_LBA);
4124   uint32_t ref  = 0U;
4125 
4126   /* Check node 1 address */
4127   if ((uint32_t)pNode1 != 0U)
4128   {
4129     ref = (uint32_t)pNode1;
4130   }
4131   /* Check node 2 address */
4132   else if ((uint32_t)pNode2 != 0U)
4133   {
4134     ref = (uint32_t)pNode2;
4135   }
4136   /* Check node 3 address */
4137   else if ((uint32_t)pNode3 != 0U)
4138   {
4139     ref = (uint32_t)pNode3;
4140   }
4141   else
4142   {
4143     /* Prevent MISRA-C2012-Rule-15.7 */
4144   }
4145 
4146   /* Check addresses compatibility */
4147   if (temp != ((uint32_t)ref & DMA_CLBAR_LBA))
4148   {
4149     return 1U;
4150   }
4151 
4152   return 0U;
4153 }
4154 
4155 /**
4156   * @brief  Check nodes types compatibility.
4157   * @param  pNode1 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 1 registers configurations.
4158   * @param  pNode2 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 2 registers configurations.
4159   * @param  pNode3 : Pointer to a DMA_NodeTypeDef structure that contains linked-list node 3 registers configurations.
4160   * @retval Return 0 when nodes types are compatible, otherwise nodes types are not compatible.
4161   */
DMA_List_CheckNodesTypes(DMA_NodeTypeDef const * const pNode1,DMA_NodeTypeDef const * const pNode2,DMA_NodeTypeDef const * const pNode3)4162 static uint32_t DMA_List_CheckNodesTypes(DMA_NodeTypeDef const *const pNode1,
4163                                          DMA_NodeTypeDef const *const pNode2,
4164                                          DMA_NodeTypeDef const *const pNode3)
4165 {
4166   uint32_t ref = 0U;
4167 
4168   /* Check node 1 parameter */
4169   if (pNode1 != NULL)
4170   {
4171     ref = pNode1->NodeInfo & NODE_TYPE_MASK;
4172   }
4173   /* Check node 2 parameter */
4174   else if (pNode2 != NULL)
4175   {
4176     ref = pNode2->NodeInfo & NODE_TYPE_MASK;
4177   }
4178   /* Check node 3 parameter */
4179   else if (pNode3 != NULL)
4180   {
4181     ref = pNode3->NodeInfo & NODE_TYPE_MASK;
4182   }
4183   else
4184   {
4185     /* Prevent MISRA-C2012-Rule-15.7 */
4186   }
4187 
4188   /* Check node 2 parameter */
4189   if (pNode2 != NULL)
4190   {
4191     /* Check node type compatibility */
4192     if (ref != (pNode2->NodeInfo & NODE_TYPE_MASK))
4193     {
4194       return 2U;
4195     }
4196   }
4197 
4198   /* Check node 3 parameter */
4199   if (pNode3 != NULL)
4200   {
4201     /* Check node type compatibility */
4202     if (ref != (pNode3->NodeInfo & NODE_TYPE_MASK))
4203     {
4204       return 3U;
4205     }
4206   }
4207 
4208   return 0U;
4209 }
4210 
4211 /**
4212   * @brief  Check nodes types compatibility.
4213   * @param  pNode       : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
4214   *                       configurations.
4215   * @param  cllr_mask   : Pointer to CLLR register mask value.
4216   * @param  cllr_offset : Pointer to CLLR register offset value.
4217   * @retval None.
4218   */
DMA_List_GetCLLRNodeInfo(DMA_NodeTypeDef const * const pNode,uint32_t * const cllr_mask,uint32_t * const cllr_offset)4219 static void DMA_List_GetCLLRNodeInfo(DMA_NodeTypeDef const *const pNode,
4220                                      uint32_t *const cllr_mask,
4221                                      uint32_t *const cllr_offset)
4222 {
4223   /* Check node type */
4224   if ((pNode->NodeInfo & DMA_CHANNEL_TYPE_2D_ADDR) == DMA_CHANNEL_TYPE_2D_ADDR)
4225   {
4226     /* Update CLLR register mask value */
4227     if (cllr_mask != NULL)
4228     {
4229       *cllr_mask = DMA_CLLR_UT1 | DMA_CLLR_UT2 | DMA_CLLR_UB1 | DMA_CLLR_USA | DMA_CLLR_UDA | DMA_CLLR_UT3 |
4230                    DMA_CLLR_UB2 | DMA_CLLR_ULL;
4231     }
4232 
4233     /* Update CLLR register offset */
4234     if (cllr_offset != NULL)
4235     {
4236       *cllr_offset = NODE_CLLR_2D_DEFAULT_OFFSET;
4237     }
4238   }
4239   /* Update CLLR and register number for linear addressing node */
4240   else
4241   {
4242     /* Update CLLR register mask value */
4243     if (cllr_mask != NULL)
4244     {
4245       *cllr_mask = DMA_CLLR_UT1 | DMA_CLLR_UT2 | DMA_CLLR_UB1 | DMA_CLLR_USA | DMA_CLLR_UDA | DMA_CLLR_ULL;
4246     }
4247 
4248     /* Update CLLR register offset */
4249     if (cllr_offset != NULL)
4250     {
4251       *cllr_offset = NODE_CLLR_LINEAR_DEFAULT_OFFSET;
4252     }
4253   }
4254 }
4255 
4256 /**
4257   * @brief  Find node in queue.
4258   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
4259   * @param  pNode    : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers configurations.
4260   * @param  NodeInfo : Pointer to a DMA_NodeInQInfoTypeDef structure that contains node linked to queue information.
4261   * @retval Return 0 when node is found in selected queue, otherwise node is not found.
4262   */
DMA_List_FindNode(DMA_QListTypeDef const * const pQList,DMA_NodeTypeDef const * const pNode,DMA_NodeInQInfoTypeDef * const NodeInfo)4263 static uint32_t DMA_List_FindNode(DMA_QListTypeDef const *const pQList,
4264                                   DMA_NodeTypeDef const *const pNode,
4265                                   DMA_NodeInQInfoTypeDef *const NodeInfo)
4266 {
4267   uint32_t node_idx = 0U;
4268   uint32_t currentnode_address  = 0U;
4269   uint32_t previousnode_address  = 0U;
4270   uint32_t cllr_offset = NodeInfo->cllr_offset;
4271 
4272   /* Find last node in queue */
4273   if (pNode ==  NULL)
4274   {
4275     /* Check that previous node is linked to the selected queue */
4276     while (node_idx < pQList->NodeNumber)
4277     {
4278       /* Get head node address */
4279       if (node_idx == 0U)
4280       {
4281         currentnode_address = (uint32_t)pQList->Head & DMA_CLLR_LA;
4282       }
4283       /* Calculate nodes addresses */
4284       else
4285       {
4286         previousnode_address = currentnode_address;
4287         currentnode_address =
4288           ((DMA_NodeTypeDef *)(currentnode_address +
4289                                ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
4290       }
4291 
4292       /* Increment node index */
4293       node_idx++;
4294     }
4295   }
4296   /* Find selected node node in queue */
4297   else
4298   {
4299     /* Check that previous node is linked to the selected queue */
4300     while ((node_idx < pQList->NodeNumber) && (currentnode_address != ((uint32_t)pNode & DMA_CLLR_LA)))
4301     {
4302       /* Get head node address */
4303       if (node_idx == 0U)
4304       {
4305         currentnode_address = (uint32_t)pQList->Head & DMA_CLLR_LA;
4306       }
4307       /* Calculate nodes addresses */
4308       else
4309       {
4310         previousnode_address = currentnode_address;
4311         currentnode_address =
4312           ((DMA_NodeTypeDef *)(currentnode_address +
4313                                ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
4314       }
4315 
4316       /* Increment node index */
4317       node_idx++;
4318     }
4319   }
4320 
4321   /* Check stored address */
4322   if (pNode != NULL)
4323   {
4324     if (currentnode_address != ((uint32_t)pNode & DMA_CLLR_LA))
4325     {
4326       return 1U;
4327     }
4328   }
4329 
4330   /* Update current node position */
4331   NodeInfo->currentnode_pos = node_idx;
4332 
4333   /* Update previous node address */
4334   NodeInfo->previousnode_addr = previousnode_address | ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
4335 
4336   /* Update current node address */
4337   NodeInfo->currentnode_addr = currentnode_address | ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
4338 
4339   /* Update next node address */
4340   if (((DMA_NodeTypeDef *)NodeInfo->currentnode_addr)->LinkRegisters[cllr_offset] != 0U)
4341   {
4342     NodeInfo->nextnode_addr = (((DMA_NodeTypeDef *)NodeInfo->currentnode_addr)->LinkRegisters[cllr_offset] &
4343                                DMA_CLLR_LA) | ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
4344   }
4345 
4346   return 0U;
4347 }
4348 
4349 /**
4350   * @brief  Reset queue nodes.
4351   * @param  pQList   : Pointer to a DMA_QListTypeDef structure that contains queue information.
4352   * @param  NodeInfo : Pointer to a DMA_NodeInQInfoTypeDef structure that contains node linked to queue information.
4353   * @retval None.
4354   */
DMA_List_ResetQueueNodes(DMA_QListTypeDef const * const pQList,DMA_NodeInQInfoTypeDef const * const NodeInfo)4355 static void DMA_List_ResetQueueNodes(DMA_QListTypeDef const *const pQList,
4356                                      DMA_NodeInQInfoTypeDef const *const NodeInfo)
4357 {
4358   uint32_t node_idx = 0U;
4359   uint32_t currentnode_address  = 0U;
4360   uint32_t previousnode_address;
4361   uint32_t cllr_offset = NodeInfo->cllr_offset;
4362 
4363   /* Check that previous node is linked to the selected queue */
4364   while (node_idx < pQList->NodeNumber)
4365   {
4366     /* Get head node address */
4367     if (node_idx == 0U)
4368     {
4369       previousnode_address = (uint32_t)pQList->Head & DMA_CLLR_LA;
4370       currentnode_address  = (pQList->Head->LinkRegisters[cllr_offset] & DMA_CLLR_LA);
4371     }
4372     /* Calculate nodes addresses */
4373     else
4374     {
4375       previousnode_address = currentnode_address;
4376       currentnode_address =
4377         ((DMA_NodeTypeDef *)(currentnode_address +
4378                              ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] & DMA_CLLR_LA;
4379     }
4380 
4381     /* Reset node */
4382     ((DMA_NodeTypeDef *)(previousnode_address +
4383                          ((uint32_t)pQList->Head & DMA_CLBAR_LBA)))->LinkRegisters[cllr_offset] = 0U;
4384 
4385     /* Increment node index */
4386     node_idx++;
4387   }
4388 }
4389 
4390 /**
4391   * @brief  Fill source node registers values by destination nodes registers values.
4392   * @param  pSrcNode  : Pointer to a DMA_NodeTypeDef structure that contains linked-list source node registers
4393   *                     configurations.
4394   * @param  pDestNode : Pointer to a DMA_NodeTypeDef structure that contains linked-list destination node registers
4395   *                     configurations.
4396   * @retval None.
4397   */
DMA_List_FillNode(DMA_NodeTypeDef const * const pSrcNode,DMA_NodeTypeDef * const pDestNode)4398 static void DMA_List_FillNode(DMA_NodeTypeDef const *const pSrcNode,
4399                               DMA_NodeTypeDef *const pDestNode)
4400 {
4401   /* Repeat for all register nodes */
4402   for (uint32_t reg_idx = 0U; reg_idx < NODE_MAXIMUM_SIZE; reg_idx++)
4403   {
4404     pDestNode->LinkRegisters[reg_idx] = pSrcNode->LinkRegisters[reg_idx];
4405   }
4406 
4407   /* Fill node information */
4408   pDestNode->NodeInfo = pSrcNode->NodeInfo;
4409 }
4410 
4411 /**
4412   * @brief  Convert node to dynamic.
4413   * @param  ContextNodeAddr : The context node address.
4414   * @param  CurrentNodeAddr : The current node address to be converted.
4415   * @param  RegisterNumber  : The register number to be converted.
4416   * @retval None.
4417   */
DMA_List_ConvertNodeToDynamic(uint32_t ContextNodeAddr,uint32_t CurrentNodeAddr,uint32_t RegisterNumber)4418 static void DMA_List_ConvertNodeToDynamic(uint32_t ContextNodeAddr,
4419                                           uint32_t CurrentNodeAddr,
4420                                           uint32_t RegisterNumber)
4421 {
4422   uint32_t currentnode_reg_counter = 0U;
4423   uint32_t contextnode_reg_counter = 0U;
4424   uint32_t cllr_idx = RegisterNumber - 1U;
4425   DMA_NodeTypeDef *context_node = (DMA_NodeTypeDef *)ContextNodeAddr;
4426   DMA_NodeTypeDef *current_node = (DMA_NodeTypeDef *)CurrentNodeAddr;
4427   uint32_t update_link[NODE_MAXIMUM_SIZE] = {DMA_CLLR_UT1, DMA_CLLR_UT2, DMA_CLLR_UB1, DMA_CLLR_USA,
4428                                              DMA_CLLR_UDA, DMA_CLLR_UT3, DMA_CLLR_UB2, DMA_CLLR_ULL
4429                                             };
4430 
4431   /* Update ULL position according to register number */
4432   update_link[cllr_idx] = update_link[NODE_MAXIMUM_SIZE - 1U];
4433 
4434   /* Repeat for all node registers */
4435   while (contextnode_reg_counter != RegisterNumber)
4436   {
4437     /* Check if register values are equal (exception for CSAR, CDAR and CLLR registers) */
4438     if ((context_node->LinkRegisters[contextnode_reg_counter]  ==
4439          current_node->LinkRegisters[currentnode_reg_counter]) &&
4440         (contextnode_reg_counter != NODE_CSAR_DEFAULT_OFFSET)  &&
4441         (contextnode_reg_counter != NODE_CDAR_DEFAULT_OFFSET)  &&
4442         (contextnode_reg_counter != (RegisterNumber - 1U)))
4443     {
4444       /* Format the node according to unused registers */
4445       DMA_List_FormatNode(current_node, currentnode_reg_counter, RegisterNumber, NODE_DYNAMIC_FORMAT);
4446 
4447       /* Update CLLR index */
4448       cllr_idx --;
4449 
4450       /* Update CLLR fields */
4451       current_node->LinkRegisters[cllr_idx] &= ~update_link[contextnode_reg_counter];
4452     }
4453     else
4454     {
4455       /* Update context node register fields with new values */
4456       context_node->LinkRegisters[contextnode_reg_counter] = current_node->LinkRegisters[currentnode_reg_counter];
4457 
4458       /* Update CLLR fields */
4459       current_node->LinkRegisters[cllr_idx] |= update_link[contextnode_reg_counter];
4460 
4461       /* Increment current node number register counter */
4462       currentnode_reg_counter++;
4463     }
4464 
4465     /* Increment context node number register counter */
4466     contextnode_reg_counter++;
4467   }
4468 
4469   /* Update node information */
4470   MODIFY_REG(current_node->NodeInfo, NODE_CLLR_IDX, ((currentnode_reg_counter - 1U) << NODE_CLLR_IDX_POS));
4471 
4472   /* Clear unused node fields */
4473   DMA_List_ClearUnusedFields(current_node, currentnode_reg_counter);
4474 }
4475 
4476 /**
4477   * @brief  Convert node to static.
4478   * @param  ContextNodeAddr : The context node address.
4479   * @param  CurrentNodeAddr : The current node address to be converted.
4480   * @param  RegisterNumber  : The register number to be converted.
4481   * @retval None.
4482   */
DMA_List_ConvertNodeToStatic(uint32_t ContextNodeAddr,uint32_t CurrentNodeAddr,uint32_t RegisterNumber)4483 static void DMA_List_ConvertNodeToStatic(uint32_t ContextNodeAddr,
4484                                          uint32_t CurrentNodeAddr,
4485                                          uint32_t RegisterNumber)
4486 {
4487   uint32_t contextnode_reg_counter = 0U;
4488   uint32_t cllr_idx;
4489   uint32_t cllr_mask;
4490   const DMA_NodeTypeDef *context_node = (DMA_NodeTypeDef *)ContextNodeAddr;
4491   DMA_NodeTypeDef *current_node = (DMA_NodeTypeDef *)CurrentNodeAddr;
4492   uint32_t update_link[NODE_MAXIMUM_SIZE] = {DMA_CLLR_UT1, DMA_CLLR_UT2, DMA_CLLR_UB1, DMA_CLLR_USA,
4493                                              DMA_CLLR_UDA, DMA_CLLR_UT3, DMA_CLLR_UB2, DMA_CLLR_ULL
4494                                             };
4495 
4496   /* Update ULL position according to register number */
4497   update_link[RegisterNumber - 1U] = update_link[NODE_MAXIMUM_SIZE - 1U];
4498 
4499   /* Get context node CLLR information */
4500   cllr_idx  = (context_node->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
4501   cllr_mask = context_node->LinkRegisters[cllr_idx];
4502 
4503   /* Repeat for all node registers */
4504   while (contextnode_reg_counter != RegisterNumber)
4505   {
4506     /* Check if node field is dynamic */
4507     if ((cllr_mask & update_link[contextnode_reg_counter]) == 0U)
4508     {
4509       /* Format the node according to unused registers */
4510       DMA_List_FormatNode(current_node, contextnode_reg_counter, RegisterNumber, NODE_STATIC_FORMAT);
4511 
4512       /* Update node field */
4513       current_node->LinkRegisters[contextnode_reg_counter] = context_node->LinkRegisters[contextnode_reg_counter];
4514     }
4515 
4516     /* Increment context node number register counter */
4517     contextnode_reg_counter++;
4518   }
4519 
4520   /* Update node information */
4521   MODIFY_REG(current_node->NodeInfo, NODE_CLLR_IDX, ((RegisterNumber - 1U) << NODE_CLLR_IDX_POS));
4522 }
4523 
4524 /**
4525   * @brief  Format the node according to unused registers.
4526   * @param  pNode           : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
4527   *                           configurations.
4528   * @param  RegisterIdx     : The first register index to be formatted.
4529   * @param  RegisterNumber  : The number of node registers.
4530   * @param  Format          : The format type.
4531   * @retval None.
4532   */
DMA_List_FormatNode(DMA_NodeTypeDef * const pNode,uint32_t RegisterIdx,uint32_t RegisterNumber,uint32_t Format)4533 static void DMA_List_FormatNode(DMA_NodeTypeDef *const pNode,
4534                                 uint32_t RegisterIdx,
4535                                 uint32_t RegisterNumber,
4536                                 uint32_t Format)
4537 {
4538   if (Format == NODE_DYNAMIC_FORMAT)
4539   {
4540     /* Repeat for all registers to be formatted */
4541     for (uint32_t reg_idx = RegisterIdx; reg_idx < (RegisterNumber - 1U); reg_idx++)
4542     {
4543       pNode->LinkRegisters[reg_idx] = pNode->LinkRegisters[reg_idx + 1U];
4544     }
4545   }
4546   else
4547   {
4548     /* Repeat for all registers to be formatted */
4549     for (uint32_t reg_idx = (RegisterNumber - 2U); reg_idx > RegisterIdx; reg_idx--)
4550     {
4551       pNode->LinkRegisters[reg_idx] = pNode->LinkRegisters[reg_idx - 1U];
4552     }
4553   }
4554 }
4555 
4556 /**
4557   * @brief  Clear unused register fields.
4558   * @param  pNode            : Pointer to a DMA_NodeTypeDef structure that contains linked-list node registers
4559   *                            configurations.
4560   * @param  FirstUnusedField : The first unused field to be cleared.
4561   * @retval None.
4562   */
DMA_List_ClearUnusedFields(DMA_NodeTypeDef * const pNode,uint32_t FirstUnusedField)4563 static void DMA_List_ClearUnusedFields(DMA_NodeTypeDef *const pNode,
4564                                        uint32_t FirstUnusedField)
4565 {
4566   /* Repeat for all unused fields */
4567   for (uint32_t reg_idx = FirstUnusedField; reg_idx < NODE_MAXIMUM_SIZE; reg_idx++)
4568   {
4569     pNode->LinkRegisters[reg_idx] = 0U;
4570   }
4571 }
4572 
4573 /**
4574   * @brief  Update CLLR for all dynamic queue nodes.
4575   * @param  pQList :              Pointer to a DMA_QListTypeDef structure that contains queue information.
4576   * @param  LastNode_IsCircular : The first circular node is the last queue node or not.
4577   * @retval None.
4578   */
DMA_List_UpdateDynamicQueueNodesCLLR(DMA_QListTypeDef const * const pQList,uint32_t LastNode_IsCircular)4579 static void DMA_List_UpdateDynamicQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
4580                                                  uint32_t LastNode_IsCircular)
4581 {
4582   uint32_t previous_cllr_offset;
4583   uint32_t current_cllr_offset = 0U;
4584   uint32_t previousnode_addr;
4585   uint32_t currentnode_addr = (uint32_t)pQList->Head;
4586   uint32_t cllr_mask;
4587   uint32_t node_idx = 0U;
4588 
4589   /*  Repeat for all register nodes */
4590   while (node_idx < pQList->NodeNumber)
4591   {
4592     /* Get head node address */
4593     if (node_idx == 0U)
4594     {
4595       /* Get current node information */
4596       current_cllr_offset = (((DMA_NodeTypeDef *)currentnode_addr)->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
4597     }
4598     /* Calculate nodes addresses */
4599     else
4600     {
4601       /* Get previous node information */
4602       previousnode_addr = currentnode_addr;
4603       previous_cllr_offset = current_cllr_offset;
4604 
4605       /* Get current node information */
4606       currentnode_addr = (((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[previous_cllr_offset] & DMA_CLLR_LA) +
4607                          ((uint32_t)pQList->Head & DMA_CLBAR_LBA);
4608       current_cllr_offset = (((DMA_NodeTypeDef *)currentnode_addr)->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
4609 
4610       /* Calculate CLLR register value to be updated */
4611       cllr_mask = (((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] & ~DMA_CLLR_LA) |
4612                   (((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[previous_cllr_offset] & DMA_CLLR_LA);
4613 
4614       /* Set new CLLR value to previous node */
4615       ((DMA_NodeTypeDef *)(previousnode_addr))->LinkRegisters[previous_cllr_offset] = cllr_mask;
4616     }
4617 
4618     /* Increment node index */
4619     node_idx++;
4620   }
4621 
4622   /* Check queue circularity */
4623   if (pQList->FirstCircularNode != 0U)
4624   {
4625     /* First circular queue is not last queue node */
4626     if (LastNode_IsCircular == 0U)
4627     {
4628       /* Get CLLR node information */
4629       DMA_List_GetCLLRNodeInfo(((DMA_NodeTypeDef *)currentnode_addr), &cllr_mask, NULL);
4630 
4631       /* Update CLLR register for last circular node */
4632       ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] =
4633         ((uint32_t)pQList->Head & DMA_CLLR_LA) | cllr_mask;
4634     }
4635     /* First circular queue is last queue node */
4636     else
4637     {
4638       /* Disable CLLR updating */
4639       ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] &= ~DMA_CLLR_ULL;
4640     }
4641   }
4642   else
4643   {
4644     /* Clear CLLR register for last node */
4645     ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] = 0U;
4646   }
4647 }
4648 
4649 /**
4650   * @brief  Update CLLR for all static queue nodes.
4651   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
4652   * @param  operation : The operation type.
4653   * @retval None.
4654   */
DMA_List_UpdateStaticQueueNodesCLLR(DMA_QListTypeDef const * const pQList,uint32_t operation)4655 static void DMA_List_UpdateStaticQueueNodesCLLR(DMA_QListTypeDef const *const pQList,
4656                                                 uint32_t operation)
4657 {
4658   uint32_t currentnode_addr = (uint32_t)pQList->Head;
4659   uint32_t current_cllr_offset = ((uint32_t)pQList->Head->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
4660   uint32_t cllr_default_offset;
4661   uint32_t cllr_default_mask;
4662   uint32_t cllr_mask;
4663   uint32_t node_idx = 0U;
4664 
4665   /* Get CLLR node information */
4666   DMA_List_GetCLLRNodeInfo(pQList->Head, &cllr_default_mask, &cllr_default_offset);
4667 
4668   /*  Repeat for all register nodes (Bypass last queue node) */
4669   while (node_idx < pQList->NodeNumber)
4670   {
4671     if (operation == UPDATE_CLLR_POSITION)
4672     {
4673       /* Get CLLR value */
4674       cllr_mask = ((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset];
4675     }
4676     else
4677     {
4678       /* Calculate CLLR value */
4679       cllr_mask = (((DMA_NodeTypeDef *)currentnode_addr)->LinkRegisters[current_cllr_offset] & DMA_CLLR_LA) |
4680                   cllr_default_mask;
4681     }
4682 
4683     /* Set new CLLR value to default position */
4684     if ((node_idx == (pQList->NodeNumber - 1U)) && (pQList->FirstCircularNode == NULL))
4685     {
4686       ((DMA_NodeTypeDef *)(currentnode_addr))->LinkRegisters[cllr_default_offset] = 0U;
4687     }
4688     else
4689     {
4690       ((DMA_NodeTypeDef *)(currentnode_addr))->LinkRegisters[cllr_default_offset] = cllr_mask;
4691     }
4692 
4693     /* Update current node address with next node address */
4694     currentnode_addr = (currentnode_addr & DMA_CLBAR_LBA) | (cllr_mask & DMA_CLLR_LA);
4695 
4696     /* Update current CLLR offset with next CLLR offset */
4697     current_cllr_offset = (((DMA_NodeTypeDef *)currentnode_addr)->NodeInfo & NODE_CLLR_IDX) >> NODE_CLLR_IDX_POS;
4698 
4699     /* Increment node index */
4700     node_idx++;
4701   }
4702 }
4703 
4704 /**
4705   * @brief  Clean linked-list queue variable.
4706   * @param  pQList    : Pointer to a DMA_QListTypeDef structure that contains queue information.
4707   * @retval None.
4708   */
DMA_List_CleanQueue(DMA_QListTypeDef * const pQList)4709 static void DMA_List_CleanQueue(DMA_QListTypeDef *const pQList)
4710 {
4711   /* Clear head node */
4712   pQList->Head = NULL;
4713 
4714   /* Clear first circular queue node */
4715   pQList->FirstCircularNode = NULL;
4716 
4717   /* Reset node number */
4718   pQList->NodeNumber = 0U;
4719 
4720   /* Reset queue state */
4721   pQList->State = HAL_DMA_QUEUE_STATE_RESET;
4722 
4723   /* Reset queue error code */
4724   pQList->ErrorCode = HAL_DMA_QUEUE_ERROR_NONE;
4725 
4726   /* Reset queue type */
4727   pQList->Type = QUEUE_TYPE_STATIC;
4728 }
4729 /**
4730   * @}
4731   */
4732 
4733 #endif /* HAL_DMA_MODULE_ENABLED */
4734 /**
4735   * @}
4736   */
4737 
4738 /**
4739   * @}
4740   */
4741