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