1 /**
2 ******************************************************************************
3 * @file stm32h5xx_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) 2022 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 "stm32h5xx_hal.h"
37
38 /** @addtogroup STM32H5xx_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