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