1 /**
2 ******************************************************************************
3 * @file stm32l4xx_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 (+) Set card in High Speed mode using HAL_SDEx_HighSpeed() function.
28 (+) Configure Buffer0 and Buffer1 start address and Buffer size using HAL_SDEx_ConfigDMAMultiBuffer() function.
29 (+) Start Read and Write for multibuffer mode using HAL_SDEx_ReadBlocksDMAMultiBuffer() and HAL_SDEx_WriteBlocksDMAMultiBuffer() functions.
30
31 @endverbatim
32 ******************************************************************************
33 */
34
35 /* Includes ------------------------------------------------------------------*/
36 #include "stm32l4xx_hal.h"
37
38 #if defined(STM32L4P5xx) || defined(STM32L4Q5xx) || defined(STM32L4R5xx) || defined(STM32L4R7xx) || defined(STM32L4R9xx) || defined(STM32L4S5xx) || defined(STM32L4S7xx) || defined(STM32L4S9xx)
39
40 /** @addtogroup STM32L4xx_HAL_Driver
41 * @{
42 */
43
44 /** @defgroup SDEx SDEx
45 * @brief SD Extended HAL module driver
46 * @{
47 */
48
49 #ifdef HAL_SD_MODULE_ENABLED
50
51 /* Private typedef -----------------------------------------------------------*/
52 /* Private define ------------------------------------------------------------*/
53 /* Private macro -------------------------------------------------------------*/
54 /* Private variables ---------------------------------------------------------*/
55 /* Private function prototypes -----------------------------------------------*/
56 /* Private functions ---------------------------------------------------------*/
57 extern uint32_t SD_HighSpeed(SD_HandleTypeDef *hsd);
58 /* Exported functions --------------------------------------------------------*/
59 /** @addtogroup SDEx_Exported_Functions
60 * @{
61 */
62
63 /** @addtogroup SDEx_Exported_Functions_Group1
64 * @brief High Speed function
65 *
66 @verbatim
67 ==============================================================================
68 ##### High Speed function #####
69 ==============================================================================
70 [..]
71 This section provides function allowing to configure the card in High Speed mode.
72
73 @endverbatim
74 * @{
75 */
76
77 /**
78 * @brief Switches the SD card to High Speed mode.
79 * This API must be used after "Transfer State"
80 * @note This operation should be followed by the configuration
81 * of PLL to have SDMMCCK clock between 50 and 120 MHz
82 * @param hsd SD handle
83 * @retval SD Card error state
84 */
HAL_SDEx_HighSpeed(SD_HandleTypeDef * hsd)85 uint32_t HAL_SDEx_HighSpeed(SD_HandleTypeDef *hsd)
86 {
87 return SD_HighSpeed (hsd);
88 }
89
90 /**
91 * @brief Enable/Disable the SD Transceiver 1.8V Mode Callback.
92 * @param status Voltage Switch State
93 * @retval None
94 */
HAL_SDEx_DriveTransceiver_1_8V_Callback(FlagStatus status)95 __weak void HAL_SDEx_DriveTransceiver_1_8V_Callback(FlagStatus status)
96 {
97 /* Prevent unused argument(s) compilation warning */
98 UNUSED(status);
99
100 /* NOTE : This function Should not be modified, when the callback is needed,
101 the HAL_SD_EnableTransciver could be implemented in the user file
102 */
103 }
104
105 /**
106 * @}
107 */
108
109 /** @addtogroup SDEx_Exported_Functions_Group2
110 * @brief Multibuffer functions
111 *
112 @verbatim
113 ==============================================================================
114 ##### Multibuffer functions #####
115 ==============================================================================
116 [..]
117 This section provides functions allowing to configure the multibuffer mode and start read and write
118 multibuffer mode for SD HAL driver.
119
120 @endverbatim
121 * @{
122 */
123
124 /**
125 * @brief Configure DMA Dual Buffer mode. The Data transfer is managed by an Internal DMA.
126 * @param hsd SD handle
127 * @param pDataBuffer0 Pointer to the buffer0 that will contain/receive the transferred data
128 * @param pDataBuffer1 Pointer to the buffer1 that will contain/receive the transferred data
129 * @param BufferSize Size of Buffer0 in Blocks. Buffer0 and Buffer1 must have the same size.
130 * @retval HAL status
131 */
HAL_SDEx_ConfigDMAMultiBuffer(SD_HandleTypeDef * hsd,uint32_t * pDataBuffer0,uint32_t * pDataBuffer1,uint32_t BufferSize)132 HAL_StatusTypeDef HAL_SDEx_ConfigDMAMultiBuffer(SD_HandleTypeDef *hsd, uint32_t *pDataBuffer0, uint32_t *pDataBuffer1, uint32_t BufferSize)
133 {
134 if(hsd->State == HAL_SD_STATE_READY)
135 {
136 hsd->Instance->IDMABASE0= (uint32_t) pDataBuffer0;
137 hsd->Instance->IDMABASE1= (uint32_t) pDataBuffer1;
138 hsd->Instance->IDMABSIZE= (uint32_t) (BLOCKSIZE * BufferSize);
139
140 return HAL_OK;
141 }
142 else
143 {
144 return HAL_BUSY;
145 }
146 }
147
148 /**
149 * @brief Reads block(s) from a specified address in a card. The received Data will be stored in Buffer0 and Buffer1.
150 * Buffer0, Buffer1 and BufferSize need to be configured by function HAL_SDEx_ConfigDMAMultiBuffer before call this function.
151 * @param hsd SD handle
152 * @param BlockAdd Block Address from where data is to be read
153 * @param NumberOfBlocks Total number of blocks to read
154 * @retval HAL status
155 */
HAL_SDEx_ReadBlocksDMAMultiBuffer(SD_HandleTypeDef * hsd,uint32_t BlockAdd,uint32_t NumberOfBlocks)156 HAL_StatusTypeDef HAL_SDEx_ReadBlocksDMAMultiBuffer(SD_HandleTypeDef *hsd, uint32_t BlockAdd, uint32_t NumberOfBlocks)
157 {
158 SDMMC_DataInitTypeDef config;
159 uint32_t errorstate;
160 uint32_t DmaBase0_reg, DmaBase1_reg;
161 uint32_t add = BlockAdd;
162
163 if(hsd->State == HAL_SD_STATE_READY)
164 {
165 if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
166 {
167 hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
168 return HAL_ERROR;
169 }
170
171 DmaBase0_reg = hsd->Instance->IDMABASE0;
172 DmaBase1_reg = hsd->Instance->IDMABASE1;
173 if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
174 {
175 hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
176 return HAL_ERROR;
177 }
178
179 /* Initialize data control register */
180 hsd->Instance->DCTRL = 0;
181 /* Clear old Flags*/
182 __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
183
184 hsd->ErrorCode = HAL_SD_ERROR_NONE;
185 hsd->State = HAL_SD_STATE_BUSY;
186
187 if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
188 {
189 add *= 512U;
190 }
191
192 /* Configure the SD DPSM (Data Path State Machine) */
193 config.DataTimeOut = SDMMC_DATATIMEOUT;
194 config.DataLength = BLOCKSIZE * NumberOfBlocks;
195 config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
196 config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC;
197 config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;
198 config.DPSM = SDMMC_DPSM_DISABLE;
199 (void)SDMMC_ConfigData(hsd->Instance, &config);
200
201 hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
202
203 __SDMMC_CMDTRANS_ENABLE( hsd->Instance);
204
205 hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
206
207 /* Read Blocks in DMA mode */
208 hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
209
210 /* Read Multi Block command */
211 errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
212 if(errorstate != HAL_SD_ERROR_NONE)
213 {
214 hsd->State = HAL_SD_STATE_READY;
215 hsd->ErrorCode |= errorstate;
216 return HAL_ERROR;
217 }
218
219 __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND | SDMMC_IT_IDMABTC));
220
221 return HAL_OK;
222 }
223 else
224 {
225 return HAL_BUSY;
226 }
227
228 }
229
230 /**
231 * @brief Write block(s) to a specified address in a card. The transferred Data are stored in Buffer0 and Buffer1.
232 * Buffer0, Buffer1 and BufferSize need to be configured by function HAL_SDEx_ConfigDMAMultiBuffer before call this function.
233 * @param hsd SD handle
234 * @param BlockAdd Block Address from where data is to be read
235 * @param NumberOfBlocks Total number of blocks to read
236 * @retval HAL status
237 */
HAL_SDEx_WriteBlocksDMAMultiBuffer(SD_HandleTypeDef * hsd,uint32_t BlockAdd,uint32_t NumberOfBlocks)238 HAL_StatusTypeDef HAL_SDEx_WriteBlocksDMAMultiBuffer(SD_HandleTypeDef *hsd, uint32_t BlockAdd, uint32_t NumberOfBlocks)
239 {
240 SDMMC_DataInitTypeDef config;
241 uint32_t errorstate;
242 uint32_t DmaBase0_reg, DmaBase1_reg;
243 uint32_t add = BlockAdd;
244
245 if(hsd->State == HAL_SD_STATE_READY)
246 {
247 if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
248 {
249 hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
250 return HAL_ERROR;
251 }
252
253 DmaBase0_reg = hsd->Instance->IDMABASE0;
254 DmaBase1_reg = hsd->Instance->IDMABASE1;
255 if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
256 {
257 hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
258 return HAL_ERROR;
259 }
260
261 /* Initialize data control register */
262 hsd->Instance->DCTRL = 0;
263
264 hsd->ErrorCode = HAL_SD_ERROR_NONE;
265
266 hsd->State = HAL_SD_STATE_BUSY;
267
268 if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
269 {
270 add *= 512U;
271 }
272
273 /* Configure the SD DPSM (Data Path State Machine) */
274 config.DataTimeOut = SDMMC_DATATIMEOUT;
275 config.DataLength = BLOCKSIZE * NumberOfBlocks;
276 config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
277 config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD;
278 config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;
279 config.DPSM = SDMMC_DPSM_DISABLE;
280 (void)SDMMC_ConfigData(hsd->Instance, &config);
281
282 __SDMMC_CMDTRANS_ENABLE( hsd->Instance);
283
284 hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
285
286 /* Write Blocks in DMA mode */
287 hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
288
289 /* Write Multi Block command */
290 errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
291 if(errorstate != HAL_SD_ERROR_NONE)
292 {
293 hsd->State = HAL_SD_STATE_READY;
294 hsd->ErrorCode |= errorstate;
295 return HAL_ERROR;
296 }
297
298 __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND | SDMMC_IT_IDMABTC));
299
300 return HAL_OK;
301 }
302 else
303 {
304 return HAL_BUSY;
305 }
306 }
307
308
309 /**
310 * @brief Change the DMA Buffer0 or Buffer1 address on the fly.
311 * @param hsd pointer to a SD_HandleTypeDef structure.
312 * @param Buffer the buffer to be changed, This parameter can be one of
313 * the following values: SD_DMA_BUFFER0 or SD_DMA_BUFFER1
314 * @param pDataBuffer The new address
315 * @note The BUFFER0 address can be changed only when the current transfer use
316 * BUFFER1 and the BUFFER1 address can be changed only when the current
317 * transfer use BUFFER0.
318 * @retval HAL status
319 */
HAL_SDEx_ChangeDMABuffer(SD_HandleTypeDef * hsd,HAL_SDEx_DMABuffer_MemoryTypeDef Buffer,uint32_t * pDataBuffer)320 HAL_StatusTypeDef HAL_SDEx_ChangeDMABuffer(SD_HandleTypeDef *hsd, HAL_SDEx_DMABuffer_MemoryTypeDef Buffer, uint32_t *pDataBuffer)
321 {
322 if(Buffer == SD_DMA_BUFFER0)
323 {
324 /* change the buffer0 address */
325 hsd->Instance->IDMABASE0 = (uint32_t)pDataBuffer;
326 }
327 else
328 {
329 /* change the memory1 address */
330 hsd->Instance->IDMABASE1 = (uint32_t)pDataBuffer;
331 }
332
333 return HAL_OK;
334 }
335
336 /**
337 * @brief Read DMA Buffer 0 Transfer completed callbacks
338 * @param hsd: SD handle
339 * @retval None
340 */
HAL_SDEx_Read_DMADoubleBuffer0CpltCallback(SD_HandleTypeDef * hsd)341 __weak void HAL_SDEx_Read_DMADoubleBuffer0CpltCallback(SD_HandleTypeDef *hsd)
342 {
343 /* Prevent unused argument(s) compilation warning */
344 UNUSED(hsd);
345
346 /* NOTE : This function should not be modified, when the callback is needed,
347 the HAL_SDEx_Read_DMADoubleBuffer0CpltCallback can be implemented in the user file
348 */
349 }
350
351 /**
352 * @brief Read DMA Buffer 1 Transfer completed callbacks
353 * @param hsd: SD handle
354 * @retval None
355 */
HAL_SDEx_Read_DMADoubleBuffer1CpltCallback(SD_HandleTypeDef * hsd)356 __weak void HAL_SDEx_Read_DMADoubleBuffer1CpltCallback(SD_HandleTypeDef *hsd)
357 {
358 /* Prevent unused argument(s) compilation warning */
359 UNUSED(hsd);
360
361 /* NOTE : This function should not be modified, when the callback is needed,
362 the HAL_SDEx_Read_DMADoubleBuffer1CpltCallback can be implemented in the user file
363 */
364 }
365
366 /**
367 * @brief Write DMA Buffer 0 Transfer completed callbacks
368 * @param hsd: SD handle
369 * @retval None
370 */
HAL_SDEx_Write_DMADoubleBuffer0CpltCallback(SD_HandleTypeDef * hsd)371 __weak void HAL_SDEx_Write_DMADoubleBuffer0CpltCallback(SD_HandleTypeDef *hsd)
372 {
373 /* Prevent unused argument(s) compilation warning */
374 UNUSED(hsd);
375
376 /* NOTE : This function should not be modified, when the callback is needed,
377 the HAL_SDEx_Write_DMADoubleBuffer0CpltCallback can be implemented in the user file
378 */
379 }
380
381 /**
382 * @brief Write DMA Buffer 1 Transfer completed callbacks
383 * @param hsd: SD handle
384 * @retval None
385 */
HAL_SDEx_Write_DMADoubleBuffer1CpltCallback(SD_HandleTypeDef * hsd)386 __weak void HAL_SDEx_Write_DMADoubleBuffer1CpltCallback(SD_HandleTypeDef *hsd)
387 {
388 /* Prevent unused argument(s) compilation warning */
389 UNUSED(hsd);
390
391 /* NOTE : This function should not be modified, when the callback is needed,
392 the HAL_SDEx_Write_DMADoubleBuffer0CpltCallback can be implemented in the user file
393 */
394 }
395
396 /**
397 * @}
398 */
399
400 /**
401 * @}
402 */
403
404 #endif /* HAL_SD_MODULE_ENABLED */
405
406 /**
407 * @}
408 */
409
410 /**
411 * @}
412 */
413
414 #endif /* STM32L4P5xx || STM32L4Q5xx || STM32L4R5xx || STM32L4R7xx || STM32L4R9xx || STM32L4S5xx || STM32L4S7xx || STM32L4S9xx */
415