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