1 /**
2 ******************************************************************************
3 * @file stm32u5xx_hal_mmc_ex.c
4 * @author MCD Application Team
5 * @brief MMC card Extended HAL module driver.
6 * This file provides firmware functions to manage the following
7 * functionalities of the Secure Digital (MMC) 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 MMC Extension HAL driver can be used as follows:
27 (+) Configure Buffer0 and Buffer1 start address and Buffer size using HAL_MMCEx_ConfigDMAMultiBuffer() function.
28
29 (+) Start Read and Write for multibuffer mode using HAL_MMCEx_ReadBlocksDMAMultiBuffer() and
30 HAL_MMCEx_WriteBlocksDMAMultiBuffer() functions.
31
32 @endverbatim
33 ******************************************************************************
34 */
35
36 /* Includes ------------------------------------------------------------------*/
37 #include "stm32u5xx_hal.h"
38
39 /** @addtogroup STM32U5xx_HAL_Driver
40 * @{
41 */
42
43 /** @defgroup MMCEx MMCEx
44 * @brief MMC Extended HAL module driver
45 * @{
46 */
47
48 #if defined (SDMMC1) || defined (SDMMC2)
49 #ifdef HAL_MMC_MODULE_ENABLED
50
51 /* Private typedef -----------------------------------------------------------*/
52 /* Private define ------------------------------------------------------------*/
53 /* Private macro -------------------------------------------------------------*/
54 /* Private variables ---------------------------------------------------------*/
55 /* Private function prototypes -----------------------------------------------*/
56 /* Private functions ---------------------------------------------------------*/
57 /* Exported functions --------------------------------------------------------*/
58 /** @addtogroup MMCEx_Exported_Functions
59 * @{
60 */
61
62
63
64 /** @addtogroup MMCEx_Exported_Functions_Group1
65 * @brief Linked List management functions
66 *
67 @verbatim
68 ===============================================================================
69 ##### Linked List management functions #####
70 ===============================================================================
71 [..]
72 This subsection provides a set of functions allowing to manage the needed functions.
73
74 @endverbatim
75 * @{
76 */
77
78 /**
79 * @brief Build Linked List node.
80 * @param pNode: Pointer to new node to add.
81 * @param pNodeConf: Pointer to configuration parameters for new node to add.
82 * @retval HAL status
83 */
HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef * pNode,MMC_DMALinkNodeConfTypeDef * pNodeConf)84 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef *pNode,
85 MMC_DMALinkNodeConfTypeDef *pNodeConf)
86 {
87
88 if (SDMMC_DMALinkedList_BuildNode(pNode, pNodeConf) != SDMMC_ERROR_NONE)
89 {
90 return (HAL_ERROR);
91 }
92 else
93 {
94 return (HAL_OK);
95 }
96
97 }
98 /**
99 * @brief Insert Linked List node.
100 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
101 * @param pPrevNode: Pointer to previous node.
102 * @param pNewNode: Pointer to new node to insert.
103 * @retval HAL status
104 */
HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pPrevNode,MMC_DMALinkNodeTypeDef * pNewNode)105 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef *pLinkedList,
106 MMC_DMALinkNodeTypeDef *pPrevNode,
107 MMC_DMALinkNodeTypeDef *pNewNode)
108 {
109
110 if (SDMMC_DMALinkedList_InsertNode(pLinkedList, pPrevNode, pNewNode) != SDMMC_ERROR_NONE)
111 {
112 return (HAL_ERROR);
113 }
114 else
115 {
116 return (HAL_OK);
117 }
118
119 }
120 /**
121 * @brief Remove Linked List node.
122 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
123 * @param pNode: Pointer to node to remove.
124 * @retval HAL status
125 */
HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pNode)126 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef *pLinkedList,
127 MMC_DMALinkNodeTypeDef *pNode)
128 {
129
130 if (SDMMC_DMALinkedList_RemoveNode(pLinkedList, pNode) != SDMMC_ERROR_NONE)
131 {
132 return (HAL_ERROR);
133 }
134 else
135 {
136 return (HAL_OK);
137 }
138 }
139
140 /**
141 * @brief Lock Linked List node.
142 * @param pNode: Pointer to node to remove.
143 * @retval HAL status
144 */
HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef * pNode)145 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef *pNode)
146 {
147
148 if (SDMMC_DMALinkedList_LockNode(pNode) != SDMMC_ERROR_NONE)
149 {
150 return HAL_ERROR;
151 }
152 else
153 {
154 return HAL_OK;
155 }
156 }
157
158 /**
159 * @brief Unlock Linked List node.
160 * @param pNode: Pointer to node to remove.
161 * @retval HAL status
162 */
HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef * pNode)163 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef *pNode)
164 {
165
166 if (SDMMC_DMALinkedList_UnlockNode(pNode) != SDMMC_ERROR_NONE)
167 {
168 return HAL_ERROR;
169 }
170 else
171 {
172 return HAL_OK;
173 }
174 }
175
176 /**
177 * @brief Enable Circular mode for DMA Linked List mode.
178 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
179 * @retval HAL status
180 */
HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)181 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
182 {
183
184 if (SDMMC_DMALinkedList_EnableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
185 {
186 return HAL_ERROR;
187 }
188 else
189 {
190 return HAL_OK;
191 }
192 }
193 /**
194 * @brief Disable Circular mode for DMA Linked List mode.
195 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
196 * @retval HAL status
197 */
HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)198 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
199 {
200
201 if (SDMMC_DMALinkedList_DisableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
202 {
203 return HAL_ERROR;
204 }
205 else
206 {
207 return HAL_OK;
208 }
209 }
210
211
212 /**
213 * @brief Reads block(s) from a specified address in a card. The received Data will be stored in linked list buffers.
214 * linked list should be prepared before call this function .
215 * @param hmmc: MMC handle
216 * @param pLinkedList: pointer to first linked list node
217 * @param BlockAdd: Block Address from where data is to be read
218 * @param NumberOfBlocks: Total number of blocks to read
219 * @retval HAL status
220 */
HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef * hmmc,MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)221 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef *hmmc, MMC_DMALinkedListTypeDef *pLinkedList,
222 uint32_t BlockAdd, uint32_t NumberOfBlocks)
223 {
224 SDMMC_DataInitTypeDef config;
225 uint32_t DmaBase0_reg;
226 uint32_t DmaBase1_reg;
227 uint32_t errorstate;
228 uint32_t add = BlockAdd;
229
230 if (hmmc->State == HAL_MMC_STATE_READY)
231 {
232 if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
233 {
234 hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
235 return HAL_ERROR;
236 }
237
238 /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
239 if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
240 {
241 if ((NumberOfBlocks % 8U) != 0U)
242 {
243 /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
244 hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
245 return HAL_ERROR;
246 }
247
248 if ((BlockAdd % 8U) != 0U)
249 {
250 /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
251 hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
252 return HAL_ERROR;
253 }
254 }
255
256 hmmc->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
257 hmmc->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
258 hmmc->Instance->IDMABAR = (uint32_t) pLinkedList->pHeadNode;
259 hmmc->Instance->IDMALAR = (uint32_t) SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
260 sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
261
262 DmaBase0_reg = hmmc->Instance->IDMABASER;
263 DmaBase1_reg = hmmc->Instance->IDMABAR;
264
265 if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
266 {
267 hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
268 return HAL_ERROR;
269 }
270
271 /* Initialize data control register */
272 hmmc->Instance->DCTRL = 0;
273
274 hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
275 hmmc->State = HAL_MMC_STATE_BUSY;
276
277 if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
278 {
279 add *= 512U;
280 }
281
282 /* Configure the MMC DPSM (Data Path State Machine) */
283 config.DataTimeOut = SDMMC_DATATIMEOUT;
284 config.DataLength = MMC_BLOCKSIZE * NumberOfBlocks;
285 config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
286 config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC;
287 config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;
288 config.DPSM = SDMMC_DPSM_DISABLE;
289 (void)SDMMC_ConfigData(hmmc->Instance, &config);
290
291 hmmc->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
292
293 __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
294
295 hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
296
297 /* Read Blocks in DMA mode */
298 hmmc->Context = (MMC_CONTEXT_READ_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
299
300 /* Read Multi Block command */
301 errorstate = SDMMC_CmdReadMultiBlock(hmmc->Instance, add);
302 if (errorstate != HAL_MMC_ERROR_NONE)
303 {
304 hmmc->State = HAL_MMC_STATE_READY;
305 hmmc->ErrorCode |= errorstate;
306 return HAL_ERROR;
307 }
308
309 __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND |
310 SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
311
312 return HAL_OK;
313 }
314 else
315 {
316 return HAL_BUSY;
317 }
318
319 }
320
321 /**
322 * @brief Write block(s) to a specified address in a card. The transferred Data are stored linked list nodes buffers .
323 * linked list should be prepared before call this function .
324 * @param hmmc: MMC handle
325 * @param pLinkedList: pointer to first linked list node
326 * @param BlockAdd: Block Address from where data is to be read
327 * @param NumberOfBlocks: Total number of blocks to read
328 * @retval HAL status
329 */
HAL_MMCEx_DMALinkedList_WriteBlocks(MMC_HandleTypeDef * hmmc,MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)330 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_WriteBlocks(MMC_HandleTypeDef *hmmc, MMC_DMALinkedListTypeDef *pLinkedList,
331 uint32_t BlockAdd, uint32_t NumberOfBlocks)
332 {
333 SDMMC_DataInitTypeDef config;
334 uint32_t errorstate;
335 uint32_t DmaBase0_reg;
336 uint32_t DmaBase1_reg;
337 uint32_t add = BlockAdd;
338
339 if (hmmc->State == HAL_MMC_STATE_READY)
340 {
341 if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
342 {
343 hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
344 return HAL_ERROR;
345 }
346
347 /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
348 if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
349 {
350 if ((NumberOfBlocks % 8U) != 0U)
351 {
352 /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
353 hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
354 return HAL_ERROR;
355 }
356
357 if ((BlockAdd % 8U) != 0U)
358 {
359 /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
360 hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
361 return HAL_ERROR;
362 }
363 }
364
365 hmmc->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
366 hmmc->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
367
368 hmmc->Instance->IDMABAR = (uint32_t) pLinkedList->pHeadNode;
369 hmmc->Instance->IDMALAR = (uint32_t) SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
370 sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
371
372 DmaBase0_reg = hmmc->Instance->IDMABASER;
373 DmaBase1_reg = hmmc->Instance->IDMABAR;
374
375 if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
376 {
377 hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
378 return HAL_ERROR;
379 }
380
381 /* Initialize data control register */
382 hmmc->Instance->DCTRL = 0;
383
384 hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
385
386 hmmc->State = HAL_MMC_STATE_BUSY;
387
388 if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
389 {
390 add *= 512U;
391 }
392
393 /* Configure the MMC DPSM (Data Path State Machine) */
394 config.DataTimeOut = SDMMC_DATATIMEOUT;
395 config.DataLength = MMC_BLOCKSIZE * NumberOfBlocks;
396 config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
397 config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD;
398 config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;
399 config.DPSM = SDMMC_DPSM_DISABLE;
400 (void)SDMMC_ConfigData(hmmc->Instance, &config);
401
402 __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
403
404 hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
405
406 /* Write Blocks in DMA mode */
407 hmmc->Context = (MMC_CONTEXT_WRITE_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
408
409 /* Write Multi Block command */
410 errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
411 if (errorstate != HAL_MMC_ERROR_NONE)
412 {
413 hmmc->State = HAL_MMC_STATE_READY;
414 hmmc->ErrorCode |= errorstate;
415 return HAL_ERROR;
416 }
417
418 __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
419 SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
420
421 return HAL_OK;
422 }
423 else
424 {
425 return HAL_BUSY;
426 }
427 }
428
429
430
431 /**
432 * @}
433 */
434
435 /**
436 * @}
437 */
438
439 #endif /* HAL_MMC_MODULE_ENABLED */
440 #endif /* SDMMC1 || SDMMC2 */
441
442 /**
443 * @}
444 */
445
446 /**
447 * @}
448 */
449