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