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