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