1 /**
2   ******************************************************************************
3   * @file    stm32h7xx_hal_sd_ex.c
4   * @author  MCD Application Team
5   * @brief   SD card Extended HAL module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the Secure Digital (SD) peripheral:
8   *           + Extended features functions
9   *
10   ******************************************************************************
11   * @attention
12   *
13   * Copyright (c) 2017 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 SD Extension HAL driver can be used as follows:
27    (+) Configure Buffer0 and Buffer1 start address and Buffer size using HAL_SDEx_ConfigDMAMultiBuffer() function.
28    (+) Start Read and Write for multibuffer mode using HAL_SDEx_ReadBlocksDMAMultiBuffer()
29        and HAL_SDEx_WriteBlocksDMAMultiBuffer() functions.
30 
31   @endverbatim
32   ******************************************************************************
33   */
34 
35 /* Includes ------------------------------------------------------------------*/
36 #include "stm32h7xx_hal.h"
37 
38 /** @addtogroup STM32H7xx_HAL_Driver
39   * @{
40   */
41 
42 /** @defgroup SDEx SDEx
43   * @brief SD Extended HAL module driver
44   * @{
45   */
46 
47 #if defined (SDMMC1) || defined (SDMMC2)
48 #ifdef HAL_SD_MODULE_ENABLED
49 
50 /* Private typedef -----------------------------------------------------------*/
51 /* Private define ------------------------------------------------------------*/
52 /* Private macro -------------------------------------------------------------*/
53 /* Private variables ---------------------------------------------------------*/
54 /* Private function prototypes -----------------------------------------------*/
55 /* Private functions ---------------------------------------------------------*/
56 /* Exported functions --------------------------------------------------------*/
57 /** @addtogroup SDEx_Exported_Functions
58   * @{
59   */
60 
61 /** @addtogroup SDEx_Exported_Functions_Group1
62   *  @brief   Multibuffer functions
63   *
64 @verbatim
65   ==============================================================================
66           ##### Multibuffer functions #####
67   ==============================================================================
68   [..]
69     This section provides functions allowing to configure the multibuffer mode and start read and write
70     multibuffer mode for SD HAL driver.
71 
72 @endverbatim
73   * @{
74   */
75 
76 /**
77   * @brief  Configure DMA Dual Buffer mode. The Data transfer is managed by an Internal DMA.
78   * @param  hsd: SD handle
79   * @param  pDataBuffer0: Pointer to the buffer0 that will contain/receive the transferred data
80   * @param  pDataBuffer1: Pointer to the buffer1 that will contain/receive the transferred data
81   * @param  BufferSize: Size of Buffer0 in Blocks. Buffer0 and Buffer1 must have the same size.
82   * @retval HAL status
83   */
HAL_SDEx_ConfigDMAMultiBuffer(SD_HandleTypeDef * hsd,uint32_t * pDataBuffer0,uint32_t * pDataBuffer1,uint32_t BufferSize)84 HAL_StatusTypeDef HAL_SDEx_ConfigDMAMultiBuffer(SD_HandleTypeDef *hsd, uint32_t *pDataBuffer0, uint32_t *pDataBuffer1,
85                                                 uint32_t BufferSize)
86 {
87   if (hsd->State == HAL_SD_STATE_READY)
88   {
89     hsd->Instance->IDMABASE0 = (uint32_t) pDataBuffer0;
90     hsd->Instance->IDMABASE1 = (uint32_t) pDataBuffer1;
91     hsd->Instance->IDMABSIZE = (uint32_t)(BLOCKSIZE * BufferSize);
92 
93     return HAL_OK;
94   }
95   else
96   {
97     return HAL_BUSY;
98   }
99 }
100 
101 /**
102   * @brief  Reads block(s) from a specified address in a card. The received Data will be stored in Buffer0 and Buffer1.
103   *         Buffer0, Buffer1 and BufferSize need to be configured by function HAL_SDEx_ConfigDMAMultiBuffer before
104   *         call this function.
105   * @param  hsd: SD handle
106   * @param  BlockAdd: Block Address from where data is to be read
107   * @param  NumberOfBlocks: Total number of blocks to read
108   * @retval HAL status
109   */
HAL_SDEx_ReadBlocksDMAMultiBuffer(SD_HandleTypeDef * hsd,uint32_t BlockAdd,uint32_t NumberOfBlocks)110 HAL_StatusTypeDef HAL_SDEx_ReadBlocksDMAMultiBuffer(SD_HandleTypeDef *hsd, uint32_t BlockAdd, uint32_t NumberOfBlocks)
111 {
112   SDMMC_DataInitTypeDef config;
113   uint32_t errorstate;
114   uint32_t DmaBase0_reg;
115   uint32_t DmaBase1_reg;
116   uint32_t add = BlockAdd;
117 
118   if (hsd->State == HAL_SD_STATE_READY)
119   {
120     if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
121     {
122       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
123       return HAL_ERROR;
124     }
125 
126     DmaBase0_reg = hsd->Instance->IDMABASE0;
127     DmaBase1_reg = hsd->Instance->IDMABASE1;
128 
129     if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
130     {
131       hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
132       return HAL_ERROR;
133     }
134 
135     /* Initialize data control register */
136     hsd->Instance->DCTRL = 0;
137     /* Clear old Flags*/
138     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
139 
140     hsd->ErrorCode = HAL_SD_ERROR_NONE;
141     hsd->State = HAL_SD_STATE_BUSY;
142 
143     if (hsd->SdCard.CardType != CARD_SDHC_SDXC)
144     {
145       add *= 512U;
146     }
147 
148     /* Configure the SD DPSM (Data Path State Machine) */
149     config.DataTimeOut   = SDMMC_DATATIMEOUT;
150     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
151     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
152     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
153     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
154     config.DPSM          = SDMMC_DPSM_DISABLE;
155     (void)SDMMC_ConfigData(hsd->Instance, &config);
156 
157     hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
158 
159     __SDMMC_CMDTRANS_ENABLE(hsd->Instance);
160 
161     hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
162 
163     /* Read Blocks in DMA mode */
164     hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
165 
166     /* Read Multi Block command */
167     errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
168     if (errorstate != HAL_SD_ERROR_NONE)
169     {
170       hsd->State = HAL_SD_STATE_READY;
171       hsd->ErrorCode |= errorstate;
172       return HAL_ERROR;
173     }
174 
175     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND |
176                              SDMMC_IT_IDMABTC));
177 
178     return HAL_OK;
179   }
180   else
181   {
182     return HAL_BUSY;
183   }
184 
185 }
186 
187 /**
188   * @brief  Write block(s) to a specified address in a card. The transferred Data are stored in Buffer0 and Buffer1.
189   *         Buffer0, Buffer1 and BufferSize need to be configured by function HAL_SDEx_ConfigDMAMultiBuffer before
190   *   call this function.
191   * @param  hsd: SD handle
192   * @param  BlockAdd: Block Address from where data is to be read
193   * @param  NumberOfBlocks: Total number of blocks to read
194   * @retval HAL status
195   */
HAL_SDEx_WriteBlocksDMAMultiBuffer(SD_HandleTypeDef * hsd,uint32_t BlockAdd,uint32_t NumberOfBlocks)196 HAL_StatusTypeDef HAL_SDEx_WriteBlocksDMAMultiBuffer(SD_HandleTypeDef *hsd, uint32_t BlockAdd, uint32_t NumberOfBlocks)
197 {
198   SDMMC_DataInitTypeDef config;
199   uint32_t errorstate;
200   uint32_t DmaBase0_reg;
201   uint32_t DmaBase1_reg;
202   uint32_t add = BlockAdd;
203 
204   if (hsd->State == HAL_SD_STATE_READY)
205   {
206     if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
207     {
208       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
209       return HAL_ERROR;
210     }
211 
212     DmaBase0_reg = hsd->Instance->IDMABASE0;
213     DmaBase1_reg = hsd->Instance->IDMABASE1;
214     if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
215     {
216       hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
217       return HAL_ERROR;
218     }
219 
220     /* Initialize data control register */
221     hsd->Instance->DCTRL = 0;
222 
223     hsd->ErrorCode = HAL_SD_ERROR_NONE;
224 
225     hsd->State = HAL_SD_STATE_BUSY;
226 
227     if (hsd->SdCard.CardType != CARD_SDHC_SDXC)
228     {
229       add *= 512U;
230     }
231 
232     /* Configure the SD DPSM (Data Path State Machine) */
233     config.DataTimeOut   = SDMMC_DATATIMEOUT;
234     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
235     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
236     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
237     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
238     config.DPSM          = SDMMC_DPSM_DISABLE;
239     (void)SDMMC_ConfigData(hsd->Instance, &config);
240 
241     __SDMMC_CMDTRANS_ENABLE(hsd->Instance);
242 
243     hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
244 
245     /* Write Blocks in DMA mode */
246     hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
247 
248     /* Write Multi Block command */
249     errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
250     if (errorstate != HAL_SD_ERROR_NONE)
251     {
252       hsd->State = HAL_SD_STATE_READY;
253       hsd->ErrorCode |= errorstate;
254       return HAL_ERROR;
255     }
256 
257     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
258                              SDMMC_IT_IDMABTC));
259 
260     return HAL_OK;
261   }
262   else
263   {
264     return HAL_BUSY;
265   }
266 }
267 
268 
269 /**
270   * @brief  Change the DMA Buffer0 or Buffer1 address on the fly.
271   * @param  hsd:           pointer to a SD_HandleTypeDef structure.
272   * @param  Buffer:        the buffer to be changed, This parameter can be one of
273   *                        the following values: SD_DMA_BUFFER0 or SD_DMA_BUFFER1
274   * @param  pDataBuffer:   The new address
275   * @note   The BUFFER0 address can be changed only when the current transfer use
276   *         BUFFER1 and the BUFFER1 address can be changed only when the current
277   *         transfer use BUFFER0.
278   * @retval HAL status
279   */
HAL_SDEx_ChangeDMABuffer(SD_HandleTypeDef * hsd,HAL_SDEx_DMABuffer_MemoryTypeDef Buffer,uint32_t * pDataBuffer)280 HAL_StatusTypeDef HAL_SDEx_ChangeDMABuffer(SD_HandleTypeDef *hsd, HAL_SDEx_DMABuffer_MemoryTypeDef Buffer,
281                                            uint32_t *pDataBuffer)
282 {
283   if (Buffer == SD_DMA_BUFFER0)
284   {
285     /* change the buffer0 address */
286     hsd->Instance->IDMABASE0 = (uint32_t)pDataBuffer;
287   }
288   else
289   {
290     /* change the memory1 address */
291     hsd->Instance->IDMABASE1 = (uint32_t)pDataBuffer;
292   }
293 
294   return HAL_OK;
295 }
296 
297 
298 /**
299   * @}
300   */
301 
302 /**
303   * @}
304   */
305 
306 #endif /* HAL_SD_MODULE_ENABLED */
307 #endif /* SDMMC1 || SDMMC2 */
308 
309 /**
310   * @}
311   */
312 
313 /**
314   * @}
315   */
316