1 /**
2   ******************************************************************************
3   * @file    stm32f7xx_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   @verbatim
11   ==============================================================================
12                         ##### How to use this driver #####
13   ==============================================================================
14   [..]
15   The DMA Extension HAL driver can be used as follows:
16    (+) Start a multi buffer transfer using the HAL_DMA_MultiBufferStart() function
17        for polling mode or HAL_DMA_MultiBufferStart_IT() for interrupt mode.
18 
19      -@-  In Memory-to-Memory transfer mode, Multi (Double) Buffer mode is not allowed.
20      -@-  When Multi (Double) Buffer mode is enabled, the transfer is circular by default.
21      -@-  In Multi (Double) buffer mode, it is possible to update the base address for
22           the AHB memory port on the fly (DMA_SxM0AR or DMA_SxM1AR) when the stream is enabled.
23 
24   @endverbatim
25   ******************************************************************************
26   * @attention
27   *
28   * Copyright (c) 2017 STMicroelectronics.
29   * All rights reserved.
30   *
31   * This software is licensed under terms that can be found in the LICENSE file in
32   * the root directory of this software component.
33   * If no LICENSE file comes with this software, it is provided AS-IS.
34   *
35   ******************************************************************************
36   */
37 
38 /* Includes ------------------------------------------------------------------*/
39 #include "stm32f7xx_hal.h"
40 
41 /** @addtogroup STM32F7xx_HAL_Driver
42   * @{
43   */
44 
45 /** @defgroup DMAEx DMAEx
46   * @brief DMA Extended HAL module driver
47   * @{
48   */
49 
50 #ifdef HAL_DMA_MODULE_ENABLED
51 
52 /* Private types -------------------------------------------------------------*/
53 /* Private variables ---------------------------------------------------------*/
54 /* Private Constants ---------------------------------------------------------*/
55 /* Private macros ------------------------------------------------------------*/
56 /* Private functions ---------------------------------------------------------*/
57 /** @addtogroup DMAEx_Private_Functions
58   * @{
59   */
60 
61 static void DMA_MultiBufferSetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
62 
63 /**
64   * @}
65   */
66 
67 /* Exported functions ---------------------------------------------------------*/
68 
69 /** @addtogroup DMAEx_Exported_Functions
70   * @{
71   */
72 
73 
74 /** @addtogroup DMAEx_Exported_Functions_Group1
75   *
76 @verbatim
77  ===============================================================================
78                 #####  Extended features functions  #####
79  ===============================================================================
80     [..]  This section provides functions allowing to:
81       (+) Configure the source, destination address and data length and
82           Start MultiBuffer DMA transfer
83       (+) Configure the source, destination address and data length and
84           Start MultiBuffer DMA transfer with interrupt
85       (+) Change on the fly the memory0 or memory1 address.
86 
87 @endverbatim
88   * @{
89   */
90 
91 
92 /**
93   * @brief  Starts the multi_buffer DMA Transfer.
94   * @param  hdma       pointer to a DMA_HandleTypeDef structure that contains
95   *                     the configuration information for the specified DMA Stream.
96   * @param  SrcAddress The source memory Buffer address
97   * @param  DstAddress The destination memory Buffer address
98   * @param  SecondMemAddress The second memory Buffer address in case of multi buffer Transfer
99   * @param  DataLength The length of data to be transferred from source to destination
100   * @retval HAL status
101   */
HAL_DMAEx_MultiBufferStart(DMA_HandleTypeDef * hdma,uint32_t SrcAddress,uint32_t DstAddress,uint32_t SecondMemAddress,uint32_t DataLength)102 HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)
103 {
104   HAL_StatusTypeDef status = HAL_OK;
105 
106   /* Check the parameters */
107   assert_param(IS_DMA_BUFFER_SIZE(DataLength));
108 
109   /* Memory-to-memory transfer not supported in double buffering mode */
110   if (hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)
111   {
112     hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
113     status = HAL_ERROR;
114   }
115   else
116   {
117     /* Process Locked */
118     __HAL_LOCK(hdma);
119 
120     if(HAL_DMA_STATE_READY == hdma->State)
121     {
122       /* Change DMA peripheral state */
123       hdma->State = HAL_DMA_STATE_BUSY;
124 
125       /* Enable the double buffer mode */
126       hdma->Instance->CR |= (uint32_t)DMA_SxCR_DBM;
127 
128       /* Configure DMA Stream destination address */
129       hdma->Instance->M1AR = SecondMemAddress;
130 
131       /* Configure the source, destination address and the data length */
132       DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength);
133 
134       /* Enable the peripheral */
135       __HAL_DMA_ENABLE(hdma);
136     }
137     else
138     {
139       /* Return error status */
140       status = HAL_BUSY;
141     }
142   }
143   return status;
144 }
145 
146 /**
147   * @brief  Starts the multi_buffer DMA Transfer with interrupt enabled.
148   * @param  hdma       pointer to a DMA_HandleTypeDef structure that contains
149   *                     the configuration information for the specified DMA Stream.
150   * @param  SrcAddress The source memory Buffer address
151   * @param  DstAddress The destination memory Buffer address
152   * @param  SecondMemAddress The second memory Buffer address in case of multi buffer Transfer
153   * @param  DataLength The length of data to be transferred from source to destination
154   * @retval HAL status
155   */
HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef * hdma,uint32_t SrcAddress,uint32_t DstAddress,uint32_t SecondMemAddress,uint32_t DataLength)156 HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)
157 {
158   HAL_StatusTypeDef status = HAL_OK;
159 
160   /* Check the parameters */
161   assert_param(IS_DMA_BUFFER_SIZE(DataLength));
162 
163   /* Memory-to-memory transfer not supported in double buffering mode */
164   if (hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)
165   {
166     hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
167     return HAL_ERROR;
168   }
169 
170   /* Process locked */
171   __HAL_LOCK(hdma);
172 
173   if(HAL_DMA_STATE_READY == hdma->State)
174   {
175     /* Change DMA peripheral state */
176     hdma->State = HAL_DMA_STATE_BUSY;
177 
178     /* Initialize the error code */
179     hdma->ErrorCode = HAL_DMA_ERROR_NONE;
180 
181     /* Enable the Double buffer mode */
182     hdma->Instance->CR |= (uint32_t)DMA_SxCR_DBM;
183 
184     /* Configure DMA Stream destination address */
185     hdma->Instance->M1AR = SecondMemAddress;
186 
187     /* Configure the source, destination address and the data length */
188     DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength);
189 
190     /* Clear all flags */
191     __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
192     __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
193     __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma));
194     __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_DME_FLAG_INDEX(hdma));
195     __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_FE_FLAG_INDEX(hdma));
196 
197     /* Enable Common interrupts*/
198     hdma->Instance->CR  |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
199     hdma->Instance->FCR |= DMA_IT_FE;
200 
201     if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL))
202     {
203       hdma->Instance->CR  |= DMA_IT_HT;
204     }
205 
206     /* Enable the peripheral */
207     __HAL_DMA_ENABLE(hdma);
208   }
209   else
210   {
211     /* Process unlocked */
212     __HAL_UNLOCK(hdma);
213 
214     /* Return error status */
215     status = HAL_BUSY;
216   }
217   return status;
218 }
219 
220 /**
221   * @brief  Change the memory0 or memory1 address on the fly.
222   * @param  hdma       pointer to a DMA_HandleTypeDef structure that contains
223   *                     the configuration information for the specified DMA Stream.
224   * @param  Address    The new address
225   * @param  memory     the memory to be changed, This parameter can be one of
226   *                     the following values:
227   *                      MEMORY0 /
228   *                      MEMORY1
229   * @note   The MEMORY0 address can be changed only when the current transfer use
230   *         MEMORY1 and the MEMORY1 address can be changed only when the current
231   *         transfer use MEMORY0.
232   * @retval HAL status
233   */
HAL_DMAEx_ChangeMemory(DMA_HandleTypeDef * hdma,uint32_t Address,HAL_DMA_MemoryTypeDef memory)234 HAL_StatusTypeDef HAL_DMAEx_ChangeMemory(DMA_HandleTypeDef *hdma, uint32_t Address, HAL_DMA_MemoryTypeDef memory)
235 {
236   if(memory == MEMORY0)
237   {
238     /* change the memory0 address */
239     hdma->Instance->M0AR = Address;
240   }
241   else
242   {
243     /* change the memory1 address */
244     hdma->Instance->M1AR = Address;
245   }
246 
247   return HAL_OK;
248 }
249 
250 /**
251   * @}
252   */
253 
254 /**
255   * @}
256   */
257 
258 /** @addtogroup DMAEx_Private_Functions
259   * @{
260   */
261 
262 /**
263   * @brief  Set the DMA Transfer parameter.
264   * @param  hdma       pointer to a DMA_HandleTypeDef structure that contains
265   *                     the configuration information for the specified DMA Stream.
266   * @param  SrcAddress The source memory Buffer address
267   * @param  DstAddress The destination memory Buffer address
268   * @param  DataLength The length of data to be transferred from source to destination
269   * @retval HAL status
270   */
DMA_MultiBufferSetConfig(DMA_HandleTypeDef * hdma,uint32_t SrcAddress,uint32_t DstAddress,uint32_t DataLength)271 static void DMA_MultiBufferSetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
272 {
273   /* Configure DMA Stream data length */
274   hdma->Instance->NDTR = DataLength;
275 
276   /* Peripheral to Memory */
277   if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
278   {
279     /* Configure DMA Stream destination address */
280     hdma->Instance->PAR = DstAddress;
281 
282     /* Configure DMA Stream source address */
283     hdma->Instance->M0AR = SrcAddress;
284   }
285   /* Memory to Peripheral */
286   else
287   {
288     /* Configure DMA Stream source address */
289     hdma->Instance->PAR = SrcAddress;
290 
291     /* Configure DMA Stream destination address */
292     hdma->Instance->M0AR = DstAddress;
293   }
294 }
295 
296 /**
297   * @}
298   */
299 
300 #endif /* HAL_DMA_MODULE_ENABLED */
301 /**
302   * @}
303   */
304 
305 /**
306   * @}
307   */
308 
309