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