1 /**
2   ******************************************************************************
3   * @file    stm32u5xx_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) 2021 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 "stm32u5xx_hal.h"
37 
38 /** @addtogroup STM32U5xx_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 
62 /** @addtogroup SDEx_Exported_Functions_Group1
63   *  @brief   Linked List management functions
64   *
65 @verbatim
66  ===============================================================================
67                    ##### Linked List management functions #####
68  ===============================================================================
69     [..]
70     This subsection provides a set of functions allowing to manage the needed functions.
71 
72 @endverbatim
73   * @{
74   */
75 
76 /**
77   * @brief  Build Linked List node.
78   * @param  pNode: Pointer to new node to add.
79   * @param  pNodeConf: Pointer to configuration parameters for new node to add.
80   * @retval HAL status
81   */
HAL_SDEx_DMALinkedList_BuildNode(SD_DMALinkNodeTypeDef * pNode,SD_DMALinkNodeConfTypeDef * pNodeConf)82 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_BuildNode(SD_DMALinkNodeTypeDef *pNode, SD_DMALinkNodeConfTypeDef *pNodeConf)
83 {
84 
85   (void)SDMMC_DMALinkedList_BuildNode(pNode, pNodeConf);
86 
87   return (HAL_OK);
88 
89 }
90 
91 /**
92   * @brief  Insert new Linked List node.
93   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
94   * @param  pPrevNode: Pointer to previous node.
95   * @param  pNewNode: Pointer to new node to insert.
96   * @retval HAL status
97   */
HAL_SDEx_DMALinkedList_InsertNode(SD_DMALinkedListTypeDef * pLinkedList,SD_DMALinkNodeTypeDef * pPrevNode,SD_DMALinkNodeTypeDef * pNewNode)98 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_InsertNode(SD_DMALinkedListTypeDef *pLinkedList,
99                                                     SD_DMALinkNodeTypeDef *pPrevNode, SD_DMALinkNodeTypeDef *pNewNode)
100 {
101 
102   (void)SDMMC_DMALinkedList_InsertNode(pLinkedList, pPrevNode, pNewNode);
103 
104   return (HAL_OK);
105 
106 }
107 /**
108   * @brief  Remove Linked List node.
109   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
110   * @param  pNode: Pointer to node to remove.
111   * @retval HAL status
112   */
HAL_SDEx_DMALinkedList_RemoveNode(SD_DMALinkedListTypeDef * pLinkedList,SD_DMALinkNodeTypeDef * pNode)113 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_RemoveNode(SD_DMALinkedListTypeDef *pLinkedList, SD_DMALinkNodeTypeDef *pNode)
114 {
115 
116   if (SDMMC_DMALinkedList_RemoveNode(pLinkedList, pNode) != SDMMC_ERROR_NONE)
117   {
118     return HAL_ERROR;
119   }
120   else
121   {
122     return HAL_OK;
123   }
124 }
125 
126 /**
127   * @brief  Lock Linked List node.
128   * @param  pNode: Pointer to node to remove.
129   * @retval HAL status
130   */
HAL_SDEx_DMALinkedList_LockNode(SD_DMALinkNodeTypeDef * pNode)131 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_LockNode(SD_DMALinkNodeTypeDef *pNode)
132 {
133 
134   if (SDMMC_DMALinkedList_LockNode(pNode) != SDMMC_ERROR_NONE)
135   {
136     return HAL_ERROR;
137   }
138   else
139   {
140     return HAL_OK;
141   }
142 }
143 
144 /**
145   * @brief  Unlock Linked List node.
146   * @param  pNode: Pointer to node to remove.
147   * @retval HAL status
148   */
HAL_SDEx_DMALinkedList_UnlockNode(SD_DMALinkNodeTypeDef * pNode)149 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_UnlockNode(SD_DMALinkNodeTypeDef *pNode)
150 {
151 
152   if (SDMMC_DMALinkedList_UnlockNode(pNode) != SDMMC_ERROR_NONE)
153   {
154     return HAL_ERROR;
155   }
156   else
157   {
158     return HAL_OK;
159   }
160 }
161 
162 /**
163   * @brief  Enable Circular mode for DMA Linked List.
164   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
165   * @retval HAL status
166   */
HAL_SDEx_DMALinkedList_EnableCircularMode(SD_DMALinkedListTypeDef * pLinkedList)167 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_EnableCircularMode(SD_DMALinkedListTypeDef *pLinkedList)
168 {
169 
170   (void)SDMMC_DMALinkedList_EnableCircularMode(pLinkedList);
171 
172   return HAL_OK;
173 
174 }
175 /**
176   * @brief  Disable Circular mode for DMA Linked List.
177   * @param  pLinkedList: Pointer to the linkedlist that contains transfer nodes
178   * @retval HAL status
179   */
HAL_SDEx_DMALinkedList_DisableCircularMode(SD_DMALinkedListTypeDef * pLinkedList)180 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_DisableCircularMode(SD_DMALinkedListTypeDef *pLinkedList)
181 {
182 
183   (void)SDMMC_DMALinkedList_DisableCircularMode(pLinkedList);
184 
185   return HAL_OK;
186 
187 }
188 
189 
190 /**
191   * @brief  Reads block(s) from a specified address in a card. The received Data will be stored in linked list buffers.
192   *         linked list should be prepared before call this function .
193   * @param  hsd: SD handle
194   * @param  pLinkedList: pointer to first linked list node
195   * @param  BlockAdd: Block Address from where data is to be read
196   * @param  NumberOfBlocks: Total number of blocks to read
197   * @retval HAL status
198   */
HAL_SDEx_DMALinkedList_ReadBlocks(SD_HandleTypeDef * hsd,SDMMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)199 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_ReadBlocks(SD_HandleTypeDef *hsd, SDMMC_DMALinkedListTypeDef *pLinkedList,
200                                                     uint32_t BlockAdd, uint32_t NumberOfBlocks)
201 {
202   SDMMC_DataInitTypeDef config;
203   uint32_t errorstate;
204   uint32_t DmaBase0_reg;
205   uint32_t DmaBase1_reg;
206   uint32_t add = BlockAdd;
207 
208   if (hsd->State == HAL_SD_STATE_READY)
209   {
210     if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
211     {
212       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
213       return HAL_ERROR;
214     }
215 
216     hsd->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
217     hsd->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
218 
219     hsd->Instance->IDMABAR   = (uint32_t) pLinkedList->pHeadNode;
220     hsd->Instance->IDMALAR   = (uint32_t) SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
221                                sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
222 
223     DmaBase0_reg = hsd->Instance->IDMABASER;
224     DmaBase1_reg = hsd->Instance->IDMABAR;
225 
226     if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
227     {
228       hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
229       return HAL_ERROR;
230     }
231 
232     /* Initialize data control register */
233     hsd->Instance->DCTRL = 0;
234     /* Clear old Flags*/
235     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
236 
237     hsd->ErrorCode = HAL_SD_ERROR_NONE;
238     hsd->State = HAL_SD_STATE_BUSY;
239 
240     if (hsd->SdCard.CardType != CARD_SDHC_SDXC)
241     {
242       add *= 512U;
243     }
244 
245     /* Configure the SD DPSM (Data Path State Machine) */
246     config.DataTimeOut   = SDMMC_DATATIMEOUT;
247     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
248     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
249     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
250     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
251     config.DPSM          = SDMMC_DPSM_DISABLE;
252     (void)SDMMC_ConfigData(hsd->Instance, &config);
253 
254     hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
255 
256     __SDMMC_CMDTRANS_ENABLE(hsd->Instance);
257 
258     hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
259 
260     /* Read Blocks in DMA mode */
261     hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
262 
263     /* Read Multi Block command */
264     errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
265     if (errorstate != HAL_SD_ERROR_NONE)
266     {
267       hsd->State = HAL_SD_STATE_READY;
268       hsd->ErrorCode |= errorstate;
269       return HAL_ERROR;
270     }
271 
272     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND |
273                              SDMMC_IT_IDMABTC));
274 
275     return HAL_OK;
276   }
277   else
278   {
279     return HAL_BUSY;
280   }
281 
282 }
283 
284 /**
285   * @brief  Write block(s) to a specified address in a card. The transferred Data are stored linked list nodes buffers .
286   *         linked list should be prepared before call this function .
287   * @param  hsd: SD handle
288   * @param  pLinkedList: pointer to first linked list node
289   * @param  BlockAdd: Block Address from where data is to be read
290   * @param  NumberOfBlocks: Total number of blocks to read
291   * @retval HAL status
292   */
HAL_SDEx_DMALinkedList_WriteBlocks(SD_HandleTypeDef * hsd,SDMMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)293 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_WriteBlocks(SD_HandleTypeDef *hsd, SDMMC_DMALinkedListTypeDef *pLinkedList,
294                                                      uint32_t BlockAdd, uint32_t NumberOfBlocks)
295 
296 {
297   SDMMC_DataInitTypeDef config;
298   uint32_t errorstate;
299   uint32_t DmaBase0_reg;
300   uint32_t DmaBase1_reg;
301   uint32_t add = BlockAdd;
302 
303   if (hsd->State == HAL_SD_STATE_READY)
304   {
305     if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
306     {
307       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
308       return HAL_ERROR;
309     }
310 
311     hsd->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
312     hsd->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
313 
314     hsd->Instance->IDMABAR = (uint32_t)  pLinkedList->pHeadNode;
315     hsd->Instance->IDMALAR = (uint32_t)  SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
316                              sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
317 
318     DmaBase0_reg = hsd->Instance->IDMABASER;
319     DmaBase1_reg = hsd->Instance->IDMABAR;
320 
321     if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
322     {
323       hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
324       return HAL_ERROR;
325     }
326 
327     /* Initialize data control register */
328     hsd->Instance->DCTRL = 0;
329 
330     hsd->ErrorCode = HAL_SD_ERROR_NONE;
331 
332     hsd->State = HAL_SD_STATE_BUSY;
333 
334     if (hsd->SdCard.CardType != CARD_SDHC_SDXC)
335     {
336       add *= 512U;
337     }
338 
339     /* Configure the SD DPSM (Data Path State Machine) */
340     config.DataTimeOut   = SDMMC_DATATIMEOUT;
341     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
342     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
343     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
344     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
345     config.DPSM          = SDMMC_DPSM_DISABLE;
346     (void)SDMMC_ConfigData(hsd->Instance, &config);
347 
348     __SDMMC_CMDTRANS_ENABLE(hsd->Instance);
349 
350     hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
351 
352     /* Write Blocks in DMA mode */
353     hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
354 
355     /* Write Multi Block command */
356     errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
357     if (errorstate != HAL_SD_ERROR_NONE)
358     {
359       hsd->State = HAL_SD_STATE_READY;
360       hsd->ErrorCode |= errorstate;
361       return HAL_ERROR;
362     }
363 
364     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
365                              SDMMC_IT_IDMABTC));
366 
367     return HAL_OK;
368   }
369   else
370   {
371     return HAL_BUSY;
372   }
373 }
374 
375 
376 /**
377   * @}
378   */
379 
380 /**
381   * @}
382   */
383 
384 #endif /* HAL_SD_MODULE_ENABLED */
385 #endif /* SDMMC1 || SDMMC2 */
386 
387 /**
388   * @}
389   */
390 
391 /**
392   * @}
393   */
394