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