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