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,const SDMMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)199 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_ReadBlocks(SD_HandleTypeDef *hsd,
200                                                     const SDMMC_DMALinkedListTypeDef *pLinkedList,
201                                                     uint32_t BlockAdd, uint32_t NumberOfBlocks)
202 {
203   SDMMC_DataInitTypeDef config;
204   uint32_t errorstate;
205   uint32_t DmaBase0_reg;
206   uint32_t DmaBase1_reg;
207   uint32_t add = BlockAdd;
208 
209   if (hsd->State == HAL_SD_STATE_READY)
210   {
211     if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
212     {
213       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
214       return HAL_ERROR;
215     }
216 
217     hsd->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
218     hsd->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
219 
220     hsd->Instance->IDMABAR   = (uint32_t) pLinkedList->pHeadNode;
221     hsd->Instance->IDMALAR   = (uint32_t) SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
222                                sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
223 
224     DmaBase0_reg = hsd->Instance->IDMABASER;
225     DmaBase1_reg = hsd->Instance->IDMABAR;
226 
227     if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
228     {
229       hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
230       return HAL_ERROR;
231     }
232 
233     /* Initialize data control register */
234     hsd->Instance->DCTRL = 0;
235     /* Clear old Flags*/
236     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
237 
238     hsd->ErrorCode = HAL_SD_ERROR_NONE;
239     hsd->State = HAL_SD_STATE_BUSY;
240 
241     if (hsd->SdCard.CardType != CARD_SDHC_SDXC)
242     {
243       add *= 512U;
244     }
245 
246     /* Configure the SD DPSM (Data Path State Machine) */
247     config.DataTimeOut   = SDMMC_DATATIMEOUT;
248     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
249     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
250     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
251     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
252     config.DPSM          = SDMMC_DPSM_DISABLE;
253     (void)SDMMC_ConfigData(hsd->Instance, &config);
254 
255     hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
256 
257     __SDMMC_CMDTRANS_ENABLE(hsd->Instance);
258 
259     hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
260 
261     /* Read Blocks in DMA mode */
262     hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
263 
264     /* Read Multi Block command */
265     errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
266     if (errorstate != HAL_SD_ERROR_NONE)
267     {
268       hsd->State = HAL_SD_STATE_READY;
269       hsd->ErrorCode |= errorstate;
270       return HAL_ERROR;
271     }
272 
273     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND |
274                              SDMMC_IT_IDMABTC));
275 
276     return HAL_OK;
277   }
278   else
279   {
280     return HAL_BUSY;
281   }
282 
283 }
284 
285 /**
286   * @brief  Write block(s) to a specified address in a card. The transferred Data are stored linked list nodes buffers .
287   *         linked list should be prepared before call this function .
288   * @param  hsd: SD handle
289   * @param  pLinkedList: pointer to first linked list node
290   * @param  BlockAdd: Block Address from where data is to be read
291   * @param  NumberOfBlocks: Total number of blocks to read
292   * @retval HAL status
293   */
HAL_SDEx_DMALinkedList_WriteBlocks(SD_HandleTypeDef * hsd,const SDMMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)294 HAL_StatusTypeDef HAL_SDEx_DMALinkedList_WriteBlocks(SD_HandleTypeDef *hsd,
295                                                      const SDMMC_DMALinkedListTypeDef *pLinkedList,
296                                                      uint32_t BlockAdd, uint32_t NumberOfBlocks)
297 
298 {
299   SDMMC_DataInitTypeDef config;
300   uint32_t errorstate;
301   uint32_t DmaBase0_reg;
302   uint32_t DmaBase1_reg;
303   uint32_t add = BlockAdd;
304 
305   if (hsd->State == HAL_SD_STATE_READY)
306   {
307     if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
308     {
309       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
310       return HAL_ERROR;
311     }
312 
313     hsd->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
314     hsd->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
315 
316     hsd->Instance->IDMABAR = (uint32_t)  pLinkedList->pHeadNode;
317     hsd->Instance->IDMALAR = (uint32_t)  SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
318                              sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
319 
320     DmaBase0_reg = hsd->Instance->IDMABASER;
321     DmaBase1_reg = hsd->Instance->IDMABAR;
322 
323     if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
324     {
325       hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
326       return HAL_ERROR;
327     }
328 
329     /* Initialize data control register */
330     hsd->Instance->DCTRL = 0;
331 
332     hsd->ErrorCode = HAL_SD_ERROR_NONE;
333 
334     hsd->State = HAL_SD_STATE_BUSY;
335 
336     if (hsd->SdCard.CardType != CARD_SDHC_SDXC)
337     {
338       add *= 512U;
339     }
340 
341     /* Configure the SD DPSM (Data Path State Machine) */
342     config.DataTimeOut   = SDMMC_DATATIMEOUT;
343     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
344     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
345     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
346     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
347     config.DPSM          = SDMMC_DPSM_DISABLE;
348     (void)SDMMC_ConfigData(hsd->Instance, &config);
349 
350     __SDMMC_CMDTRANS_ENABLE(hsd->Instance);
351 
352     hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
353 
354     /* Write Blocks in DMA mode */
355     hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
356 
357     /* Write Multi Block command */
358     errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
359     if (errorstate != HAL_SD_ERROR_NONE)
360     {
361       hsd->State = HAL_SD_STATE_READY;
362       hsd->ErrorCode |= errorstate;
363       return HAL_ERROR;
364     }
365 
366     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
367                              SDMMC_IT_IDMABTC));
368 
369     return HAL_OK;
370   }
371   else
372   {
373     return HAL_BUSY;
374   }
375 }
376 
377 
378 /**
379   * @}
380   */
381 
382 /**
383   * @}
384   */
385 
386 #endif /* HAL_SD_MODULE_ENABLED */
387 #endif /* SDMMC1 || SDMMC2 */
388 
389 /**
390   * @}
391   */
392 
393 /**
394   * @}
395   */
396