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