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