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