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