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