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