1 /**
2 ******************************************************************************
3 * @file stm32l5xx_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
7 * functionalities of the DMA Extension peripheral:
8 * + Extended features functions
9 *
10 ******************************************************************************
11 * @attention
12 *
13 * Copyright (c) 2019 STMicroelectronics.
14 * All rights reserved.
15 *
16 * This software is licensed under terms that can be found in the LICENSE file
17 * in the root directory of this software component.
18 * If no LICENSE file comes with this software, it is provided AS-IS.
19 *
20 ******************************************************************************
21 @verbatim
22 ==============================================================================
23 ##### How to use this driver #####
24 ==============================================================================
25 [..]
26 The DMA Extension HAL driver can be used as follows:
27
28 (+) Configure the DMA_MUX Synchronization Block using HAL_DMAEx_ConfigMuxSync function.
29 (+) Configure the DMA_MUX Request Generator Block using HAL_DMAEx_ConfigMuxRequestGenerator function.
30 Functions HAL_DMAEx_EnableMuxRequestGenerator and HAL_DMAEx_DisableMuxRequestGenerator can then be used
31 to respectively enable/disable the request generator.
32
33 (+) To handle the DMAMUX Interrupts, the function HAL_DMAEx_MUX_IRQHandler should be called from
34 the DMAMUX IRQ handler i.e DMAMUX1_OVR_IRQHandler.
35 As only one interrupt line is available for all DMAMUX channels and request generators , HAL_DMAEx_MUX_IRQHandler should be
36 called with, as parameter, the appropriate DMA handle as many as used DMAs in the user project
37 (exception done if a given DMA is not using the DMAMUX SYNC block neither a request generator)
38
39 -@- In Memory-to-Memory transfer mode, Multi (Double) Buffer mode is not allowed.
40 -@- When Multi (Double) Buffer mode is enabled, the transfer is circular by default.
41 -@- In Multi (Double) buffer mode, it is possible to update the base address for
42 the AHB memory port on the fly (DMA_CM0ARx or DMA_CM1ARx) when the channel is enabled.
43
44
45 @endverbatim
46 ******************************************************************************
47 */
48
49 /* Includes ------------------------------------------------------------------*/
50 #include "stm32l5xx_hal.h"
51
52 /** @addtogroup STM32L5xx_HAL_Driver
53 * @{
54 */
55
56 /** @defgroup DMAEx DMAEx
57 * @brief DMA Extended HAL module driver
58 * @{
59 */
60
61 #ifdef HAL_DMA_MODULE_ENABLED
62
63 /* Private typedef -----------------------------------------------------------*/
64 /* Private define ------------------------------------------------------------*/
65 /* Private macro -------------------------------------------------------------*/
66 /* Private variables ---------------------------------------------------------*/
67 /* Private Constants ---------------------------------------------------------*/
68 /* Private function prototypes -----------------------------------------------*/
69 /** @addtogroup DMAEx_Private_Functions
70 * @{
71 */
72
73 static void DMA_MultiBufferSetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
74
75 /**
76 * @}
77 */
78
79
80 /* Private functions ---------------------------------------------------------*/
81
82
83 /** @defgroup DMAEx_Exported_Functions DMAEx Exported Functions
84 * @{
85 */
86
87 /** @defgroup DMAEx_Exported_Functions_Group1 DMAEx Extended features functions
88 * @brief Extended features functions
89 *
90 @verbatim
91 ===============================================================================
92 ##### Extended features functions #####
93 ===============================================================================
94 [..] This section provides functions allowing to:
95
96 (+) Configure the DMAMUX Synchronization Block using HAL_DMAEx_ConfigMuxSync function.
97 (+) Configure the DMAMUX Request Generator Block using HAL_DMAEx_ConfigMuxRequestGenerator function.
98 Functions HAL_DMAEx_EnableMuxRequestGenerator and HAL_DMAEx_DisableMuxRequestGenerator can then be used
99 to respectively enable/disable the request generator.
100
101 @endverbatim
102 * @{
103 */
104
105 /**
106 * @brief Starts the multi_buffer DMA Transfer.
107 * @note The multi_buffer transfer operates in circular transfer only.
108 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
109 * the configuration information for the specified DMA channel.
110 * @param SrcAddress: The source memory Buffer address
111 * @param DstAddress: The destination memory Buffer address
112 * @param SecondMemAddress: The second memory Buffer address in case of multi buffer Transfer
113 * @param DataLength: The length of data to be transferred from source to destination
114 * @retval HAL status
115 */
HAL_DMAEx_MultiBufferStart(DMA_HandleTypeDef * hdma,uint32_t SrcAddress,uint32_t DstAddress,uint32_t SecondMemAddress,uint32_t DataLength)116 HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)
117 {
118 HAL_StatusTypeDef status = HAL_OK;
119
120 /* Check the parameters */
121 assert_param(IS_DMA_BUFFER_SIZE(DataLength));
122
123 /* Memory-to-memory transfer not supported in double buffering mode */
124 if (hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)
125 {
126 hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
127 status = HAL_ERROR;
128 }
129 else
130 {
131 /* Process Locked */
132 __HAL_LOCK(hdma);
133
134 if(hdma->State == HAL_DMA_STATE_READY)
135 {
136 /* Change DMA peripheral state */
137 hdma->State = HAL_DMA_STATE_BUSY;
138
139 /* Initialize the error code */
140 hdma->ErrorCode = HAL_DMA_ERROR_NONE;
141
142 /* Enable the double buffer mode */
143 hdma->Instance->CCR |= (uint32_t) (DMA_CCR_DBM | DMA_CCR_CIRC);
144
145 /* Configure DMA channel destination address */
146 hdma->Instance->CM1AR = SecondMemAddress;
147
148 /* Configure the source, destination address and the data length */
149 DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength);
150
151 /* Clear all flags */
152 hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << (hdma->ChannelIndex & 0x1CU));
153
154 /* Clear the DMAMUX synchro overrun flag */
155 hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;
156
157 if(hdma->DMAmuxRequestGen != 0U)
158 {
159 /* Clear the DMAMUX request generator overrun flag */
160 hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
161 }
162
163 /* Enable the peripheral */
164 __HAL_DMA_ENABLE(hdma);
165 }
166 else
167 {
168 /* Process Unlocked */
169 __HAL_UNLOCK(hdma);
170 status = HAL_BUSY;
171 }
172 }
173 return status;
174 }
175
176 /**
177 * @brief Starts the multi_buffer DMA Transfer with interrupt enabled.
178 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
179 * the configuration information for the specified DMA Channel.
180 * @param SrcAddress: The source memory Buffer address
181 * @param DstAddress: The destination memory Buffer address
182 * @param SecondMemAddress: The second memory Buffer address in case of multi buffer Transfer
183 * @param DataLength: The length of data to be transferred from source to destination
184 * @retval HAL status
185 */
HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef * hdma,uint32_t SrcAddress,uint32_t DstAddress,uint32_t SecondMemAddress,uint32_t DataLength)186 HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)
187 {
188 HAL_StatusTypeDef status = HAL_OK;
189
190 /* Check the parameters */
191 assert_param(IS_DMA_BUFFER_SIZE(DataLength));
192
193 /* Memory-to-memory transfer not supported in double buffering mode */
194 /* double buffering mode not supported for BDMA (D3 DMA) */
195 if(hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)
196 {
197 hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
198 return HAL_ERROR;
199 }
200
201 /* Process locked */
202 __HAL_LOCK(hdma);
203
204 if(hdma->State == HAL_DMA_STATE_READY)
205 {
206 /* Change DMA peripheral state */
207 hdma->State = HAL_DMA_STATE_BUSY;
208
209 /* Initialize the error code */
210 hdma->ErrorCode = HAL_DMA_ERROR_NONE;
211
212 /* Disable the peripheral */
213 __HAL_DMA_DISABLE(hdma);
214
215 /* Enable the double buffer mode */
216 /* Circular mode has to be Enable when double buffer mode is used */
217 hdma->Instance->CCR |= (uint32_t) (DMA_CCR_DBM | DMA_CCR_CIRC);
218
219 /* Configure DMA channel destination address */
220 hdma->Instance->CM1AR = SecondMemAddress;
221
222 /* Configure the source, destination address and the data length */
223 DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength);
224
225 /* Clear all flags */
226 hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << (hdma->ChannelIndex & 0x1CU));
227
228 /* Clear the DMAMUX synchro overrun flag */
229 hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;
230
231 if(hdma->DMAmuxRequestGen != 0U)
232 {
233 /* Clear the DMAMUX request generator overrun flag */
234 hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
235 }
236
237 /* Enable common interrupts */
238 if(NULL != hdma->XferHalfCpltCallback )
239 {
240 /* Enable the Half transfer complete interrupt as well */
241 __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));
242 }
243 else
244 {
245 __HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
246 __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_TE));
247 }
248
249 /* Check if DMAMUX Synchronization is enabled*/
250 if((hdma->DMAmuxChannel->CCR & DMAMUX_CxCR_SE) != 0U)
251 {
252 /* Enable DMAMUX sync overrun IT*/
253 hdma->DMAmuxChannel->CCR |= DMAMUX_CxCR_SOIE;
254 }
255
256 if(hdma->DMAmuxRequestGen != 0U)
257 {
258 /* if using DMAMUX request generator, enable the DMAMUX request generator overrun IT*/
259 /* enable the request gen overrun IT*/
260 hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_OIE;
261 }
262
263 /* Enable the peripheral */
264 __HAL_DMA_ENABLE(hdma);
265 }
266 else
267 {
268 /* Process Unlocked */
269 __HAL_UNLOCK(hdma);
270
271 /* Remain BUSY */
272 status = HAL_BUSY;
273 }
274 return status;
275 }
276
277 /**
278 * @brief Change the memory0 or memory1 address on the fly.
279 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
280 * the configuration information for the specified DMA Channel.
281 * @param Address: The new address
282 * @param memory: the memory to be changed, This parameter can be one of
283 * the following values:
284 * MEMORY0 /
285 * MEMORY1
286 * @note The MEMORY0 address can be changed only when the current transfer use
287 * MEMORY1 and the MEMORY1 address can be changed only when the current
288 * transfer use MEMORY0.
289 * @retval HAL status
290 */
HAL_DMAEx_ChangeMemory(DMA_HandleTypeDef * hdma,uint32_t Address,HAL_DMA_MemoryTypeDef memory)291 HAL_StatusTypeDef HAL_DMAEx_ChangeMemory(DMA_HandleTypeDef *hdma, uint32_t Address, HAL_DMA_MemoryTypeDef memory)
292 {
293 if(memory == MEMORY0)
294 {
295 /* change the memory0 address */
296 hdma->Instance->CM0AR = Address;
297 }
298 else
299 {
300 /* change the memory1 address */
301 hdma->Instance->CM1AR = Address;
302 }
303
304 return HAL_OK;
305 }
306
307 /**
308 * @brief Configure the DMAMUX synchronization parameters for a given DMA channel (instance).
309 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
310 * the configuration information for the specified DMA channel.
311 * @param pSyncConfig : pointer to HAL_DMA_MuxSyncConfigTypeDef : contains the DMAMUX synchronization parameters
312 * @retval HAL status
313 */
HAL_DMAEx_ConfigMuxSync(DMA_HandleTypeDef * hdma,HAL_DMA_MuxSyncConfigTypeDef * pSyncConfig)314 HAL_StatusTypeDef HAL_DMAEx_ConfigMuxSync(DMA_HandleTypeDef *hdma, HAL_DMA_MuxSyncConfigTypeDef *pSyncConfig)
315 {
316 /* Check the parameters */
317 assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
318
319 assert_param(IS_DMAMUX_SYNC_SIGNAL_ID(pSyncConfig->SyncSignalID));
320
321 assert_param(IS_DMAMUX_SYNC_POLARITY(pSyncConfig-> SyncPolarity));
322 assert_param(IS_DMAMUX_SYNC_STATE(pSyncConfig->SyncEnable));
323 assert_param(IS_DMAMUX_SYNC_EVENT(pSyncConfig->EventEnable));
324 assert_param(IS_DMAMUX_SYNC_REQUEST_NUMBER(pSyncConfig->RequestNumber));
325
326 /*Check if the DMA state is ready */
327 if(hdma->State == HAL_DMA_STATE_READY)
328 {
329 /* Process Locked */
330 __HAL_LOCK(hdma);
331
332 /* Set the new synchronization parameters (and keep the request ID filled during the Init)*/
333 MODIFY_REG( hdma->DMAmuxChannel->CCR, \
334 (~DMAMUX_CxCR_DMAREQ_ID) , \
335 ((pSyncConfig->SyncSignalID) << DMAMUX_CxCR_SYNC_ID_Pos) | ((pSyncConfig->RequestNumber - 1U) << DMAMUX_CxCR_NBREQ_Pos) | \
336 pSyncConfig->SyncPolarity | ((uint32_t)pSyncConfig->SyncEnable << DMAMUX_CxCR_SE_Pos) | \
337 ((uint32_t)pSyncConfig->EventEnable << DMAMUX_CxCR_EGE_Pos));
338
339 /* Process UnLocked */
340 __HAL_UNLOCK(hdma);
341
342 return HAL_OK;
343 }
344 else
345 {
346 /*DMA State not Ready*/
347 return HAL_ERROR;
348 }
349 }
350
351 /**
352 * @brief Configure the DMAMUX request generator block used by the given DMA channel (instance).
353 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
354 * the configuration information for the specified DMA channel.
355 * @param pRequestGeneratorConfig : pointer to HAL_DMA_MuxRequestGeneratorConfigTypeDef :
356 * contains the request generator parameters.
357 *
358 * @retval HAL status
359 */
HAL_DMAEx_ConfigMuxRequestGenerator(DMA_HandleTypeDef * hdma,HAL_DMA_MuxRequestGeneratorConfigTypeDef * pRequestGeneratorConfig)360 HAL_StatusTypeDef HAL_DMAEx_ConfigMuxRequestGenerator (DMA_HandleTypeDef *hdma, HAL_DMA_MuxRequestGeneratorConfigTypeDef *pRequestGeneratorConfig)
361 {
362 /* Check the parameters */
363 assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
364
365 assert_param(IS_DMAMUX_REQUEST_GEN_SIGNAL_ID(pRequestGeneratorConfig->SignalID));
366
367 assert_param(IS_DMAMUX_REQUEST_GEN_POLARITY(pRequestGeneratorConfig->Polarity));
368 assert_param(IS_DMAMUX_REQUEST_GEN_REQUEST_NUMBER(pRequestGeneratorConfig->RequestNumber));
369
370 /* check if the DMA state is ready
371 and DMA is using a DMAMUX request generator block
372 */
373 if((hdma->State == HAL_DMA_STATE_READY) && (hdma->DMAmuxRequestGen != 0U))
374 {
375 /* Process Locked */
376 __HAL_LOCK(hdma);
377
378 /* Set the request generator new parameters */
379 hdma->DMAmuxRequestGen->RGCR = pRequestGeneratorConfig->SignalID | \
380 ((pRequestGeneratorConfig->RequestNumber - 1U) << DMAMUX_RGxCR_GNBREQ_Pos)| \
381 pRequestGeneratorConfig->Polarity;
382 /* Process UnLocked */
383 __HAL_UNLOCK(hdma);
384
385 return HAL_OK;
386 }
387 else
388 {
389 return HAL_ERROR;
390 }
391 }
392
393 /**
394 * @brief Enable the DMAMUX request generator block used by the given DMA channel (instance).
395 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
396 * the configuration information for the specified DMA channel.
397 * @retval HAL status
398 */
HAL_DMAEx_EnableMuxRequestGenerator(DMA_HandleTypeDef * hdma)399 HAL_StatusTypeDef HAL_DMAEx_EnableMuxRequestGenerator (DMA_HandleTypeDef *hdma)
400 {
401 /* Check the parameters */
402 assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
403
404 /* check if the DMA state is ready
405 and DMA is using a DMAMUX request generator block
406 */
407 if((hdma->State != HAL_DMA_STATE_RESET) && (hdma->DMAmuxRequestGen != 0))
408 {
409
410 /* Enable the request generator*/
411 hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_GE;
412
413 return HAL_OK;
414 }
415 else
416 {
417 return HAL_ERROR;
418 }
419 }
420
421 /**
422 * @brief Disable the DMAMUX request generator block used by the given DMA channel (instance).
423 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
424 * the configuration information for the specified DMA channel.
425 * @retval HAL status
426 */
HAL_DMAEx_DisableMuxRequestGenerator(DMA_HandleTypeDef * hdma)427 HAL_StatusTypeDef HAL_DMAEx_DisableMuxRequestGenerator (DMA_HandleTypeDef *hdma)
428 {
429 /* Check the parameters */
430 assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
431
432 /* check if the DMA state is ready
433 and DMA is using a DMAMUX request generator block
434 */
435 if((hdma->State != HAL_DMA_STATE_RESET) && (hdma->DMAmuxRequestGen != 0))
436 {
437
438 /* Disable the request generator*/
439 hdma->DMAmuxRequestGen->RGCR &= ~DMAMUX_RGxCR_GE;
440
441 return HAL_OK;
442 }
443 else
444 {
445 return HAL_ERROR;
446 }
447 }
448
449 /**
450 * @brief Handles DMAMUX interrupt request.
451 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
452 * the configuration information for the specified DMA channel.
453 * @retval None
454 */
HAL_DMAEx_MUX_IRQHandler(DMA_HandleTypeDef * hdma)455 void HAL_DMAEx_MUX_IRQHandler(DMA_HandleTypeDef *hdma)
456 {
457 /* Check for DMAMUX Synchronization overrun */
458 if((hdma->DMAmuxChannelStatus->CSR & hdma->DMAmuxChannelStatusMask) != 0U)
459 {
460 /* Disable the synchro overrun interrupt */
461 hdma->DMAmuxChannel->CCR &= ~DMAMUX_CxCR_SOIE;
462
463 /* Clear the DMAMUX synchro overrun flag */
464 hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;
465
466 /* Update error code */
467 hdma->ErrorCode |= HAL_DMA_ERROR_SYNC;
468
469 if(hdma->XferErrorCallback != NULL)
470 {
471 /* Transfer error callback */
472 hdma->XferErrorCallback(hdma);
473 }
474 }
475
476 if(hdma->DMAmuxRequestGen != 0)
477 {
478 /* if using a DMAMUX request generator block Check for DMAMUX request generator overrun */
479 if((hdma->DMAmuxRequestGenStatus->RGSR & hdma->DMAmuxRequestGenStatusMask) != 0U)
480 {
481 /* Disable the request gen overrun interrupt */
482 hdma->DMAmuxRequestGen->RGCR &= ~DMAMUX_RGxCR_OIE;
483
484 /* Clear the DMAMUX request generator overrun flag */
485 hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
486
487 /* Update error code */
488 hdma->ErrorCode |= HAL_DMA_ERROR_REQGEN;
489
490 if(hdma->XferErrorCallback != NULL)
491 {
492 /* Transfer error callback */
493 hdma->XferErrorCallback(hdma);
494 }
495 }
496 }
497 }
498
499 /**
500 * @}
501 */
502
503 /**
504 * @}
505 */
506
507 /** @addtogroup DMAEx_Private_Functions
508 * @{
509 */
510
511 /**
512 * @brief Set the DMA Transfer parameter.
513 * @param hdma pointer to a DMA_HandleTypeDef structure that contains
514 * the configuration information for the specified DMA channel.
515 * @param SrcAddress: The source memory Buffer address
516 * @param DstAddress: The destination memory Buffer address
517 * @param DataLength: The length of data to be transferred from source to destination
518 * @retval HAL status
519 */
DMA_MultiBufferSetConfig(DMA_HandleTypeDef * hdma,uint32_t SrcAddress,uint32_t DstAddress,uint32_t DataLength)520 static void DMA_MultiBufferSetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
521 {
522 /* Configure DMA channel data length */
523 hdma->Instance->CNDTR = DataLength;
524
525 /* Memory to Peripheral */
526 if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
527 {
528 /* Configure DMA channel destination address */
529 hdma->Instance->CPAR = DstAddress;
530
531 /* Configure DMA channel source address */
532 hdma->Instance->CM0AR = SrcAddress;
533 }
534 /* Peripheral to Memory */
535 else
536 {
537 /* Configure DMA channel source address */
538 hdma->Instance->CPAR = SrcAddress;
539
540 /* Configure DMA channel destination address */
541 hdma->Instance->CM0AR = DstAddress;
542 }
543 }
544
545 /**
546 * @}
547 */
548
549 #endif /* HAL_DMA_MODULE_ENABLED */
550
551 /**
552 * @}
553 */
554
555 /**
556 * @}
557 */
558
559