1 /**
2 ******************************************************************************
3 * @file stm32n6xx_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) 2023 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 "stm32n6xx_hal.h"
38
39 /** @addtogroup STM32N6xx_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 /** @addtogroup MMCEx_Exported_Functions_Group1
64 * @brief Linked List management functions
65 *
66 @verbatim
67 ===============================================================================
68 ##### Linked List management functions #####
69 ===============================================================================
70 [..]
71 This subsection provides a set of functions allowing to manage the needed functions.
72
73 @endverbatim
74 * @{
75 */
76
77 /**
78 * @brief Build Linked List node.
79 * @param pNode: Pointer to new node to add.
80 * @param pNodeConf: Pointer to configuration parameters for new node to add.
81 * @retval HAL status
82 */
HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef * pNode,MMC_DMALinkNodeConfTypeDef * pNodeConf)83 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_BuildNode(MMC_DMALinkNodeTypeDef *pNode,
84 MMC_DMALinkNodeConfTypeDef *pNodeConf)
85 {
86
87 if (SDMMC_DMALinkedList_BuildNode(pNode, pNodeConf) != SDMMC_ERROR_NONE)
88 {
89 return (HAL_ERROR);
90 }
91 else
92 {
93 return (HAL_OK);
94 }
95
96 }
97 /**
98 * @brief Insert Linked List node.
99 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
100 * @param pPrevNode: Pointer to previous node.
101 * @param pNewNode: Pointer to new node to insert.
102 * @retval HAL status
103 */
HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pPrevNode,MMC_DMALinkNodeTypeDef * pNewNode)104 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_InsertNode(MMC_DMALinkedListTypeDef *pLinkedList,
105 MMC_DMALinkNodeTypeDef *pPrevNode,
106 MMC_DMALinkNodeTypeDef *pNewNode)
107 {
108
109 if (SDMMC_DMALinkedList_InsertNode(pLinkedList, pPrevNode, pNewNode) != SDMMC_ERROR_NONE)
110 {
111 return (HAL_ERROR);
112 }
113 else
114 {
115 return (HAL_OK);
116 }
117
118 }
119 /**
120 * @brief Remove Linked List node.
121 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
122 * @param pNode: Pointer to node to remove.
123 * @retval HAL status
124 */
HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef * pLinkedList,MMC_DMALinkNodeTypeDef * pNode)125 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_RemoveNode(MMC_DMALinkedListTypeDef *pLinkedList,
126 MMC_DMALinkNodeTypeDef *pNode)
127 {
128
129 if (SDMMC_DMALinkedList_RemoveNode(pLinkedList, pNode) != SDMMC_ERROR_NONE)
130 {
131 return (HAL_ERROR);
132 }
133 else
134 {
135 return (HAL_OK);
136 }
137 }
138
139 /**
140 * @brief Lock Linked List node.
141 * @param pNode: Pointer to node to remove.
142 * @retval HAL status
143 */
HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef * pNode)144 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_LockNode(MMC_DMALinkNodeTypeDef *pNode)
145 {
146
147 if (SDMMC_DMALinkedList_LockNode(pNode) != SDMMC_ERROR_NONE)
148 {
149 return HAL_ERROR;
150 }
151 else
152 {
153 return HAL_OK;
154 }
155 }
156
157 /**
158 * @brief Unlock Linked List node.
159 * @param pNode: Pointer to node to remove.
160 * @retval HAL status
161 */
HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef * pNode)162 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_UnlockNode(MMC_DMALinkNodeTypeDef *pNode)
163 {
164
165 if (SDMMC_DMALinkedList_UnlockNode(pNode) != SDMMC_ERROR_NONE)
166 {
167 return HAL_ERROR;
168 }
169 else
170 {
171 return HAL_OK;
172 }
173 }
174
175 /**
176 * @brief Enable Circular mode for DMA Linked List mode.
177 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
178 * @retval HAL status
179 */
HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)180 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_EnableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
181 {
182
183 if (SDMMC_DMALinkedList_EnableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
184 {
185 return HAL_ERROR;
186 }
187 else
188 {
189 return HAL_OK;
190 }
191 }
192 /**
193 * @brief Disable Circular mode for DMA Linked List mode.
194 * @param pLinkedList: Pointer to the linkedlist that contains transfer nodes
195 * @retval HAL status
196 */
HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef * pLinkedList)197 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_DisableCircularMode(MMC_DMALinkedListTypeDef *pLinkedList)
198 {
199
200 if (SDMMC_DMALinkedList_DisableCircularMode(pLinkedList) != SDMMC_ERROR_NONE)
201 {
202 return HAL_ERROR;
203 }
204 else
205 {
206 return HAL_OK;
207 }
208 }
209
210
211 /**
212 * @brief Reads block(s) from a specified address in a card. The received Data will be stored in linked list buffers.
213 * linked list should be prepared before call this function .
214 * @param hmmc: MMC handle
215 * @param pLinkedList: pointer to first linked list node
216 * @param BlockAdd: Block Address from where data is to be read
217 * @param NumberOfBlocks: Total number of blocks to read
218 * @retval HAL status
219 */
HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef * hmmc,const MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)220 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_ReadBlocks(MMC_HandleTypeDef *hmmc,
221 const 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,const MMC_DMALinkedListTypeDef * pLinkedList,uint32_t BlockAdd,uint32_t NumberOfBlocks)330 HAL_StatusTypeDef HAL_MMCEx_DMALinkedList_WriteBlocks(MMC_HandleTypeDef *hmmc,
331 const MMC_DMALinkedListTypeDef *pLinkedList,
332 uint32_t BlockAdd, uint32_t NumberOfBlocks)
333 {
334 SDMMC_DataInitTypeDef config;
335 uint32_t errorstate;
336 uint32_t DmaBase0_reg;
337 uint32_t DmaBase1_reg;
338 uint32_t add = BlockAdd;
339
340 if (hmmc->State == HAL_MMC_STATE_READY)
341 {
342 if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
343 {
344 hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
345 return HAL_ERROR;
346 }
347
348 /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
349 if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
350 {
351 if ((NumberOfBlocks % 8U) != 0U)
352 {
353 /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
354 hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
355 return HAL_ERROR;
356 }
357
358 if ((BlockAdd % 8U) != 0U)
359 {
360 /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
361 hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
362 return HAL_ERROR;
363 }
364 }
365
366 hmmc->Instance->IDMABASER = (uint32_t) pLinkedList->pHeadNode->IDMABASER;
367 hmmc->Instance->IDMABSIZE = (uint32_t) pLinkedList->pHeadNode->IDMABSIZE;
368
369 hmmc->Instance->IDMABAR = (uint32_t) pLinkedList->pHeadNode;
370 hmmc->Instance->IDMALAR = (uint32_t) SDMMC_IDMALAR_ABR | SDMMC_IDMALAR_ULS | SDMMC_IDMALAR_ULA |
371 sizeof(SDMMC_DMALinkNodeTypeDef) ; /* Initial configuration */
372
373 DmaBase0_reg = hmmc->Instance->IDMABASER;
374 DmaBase1_reg = hmmc->Instance->IDMABAR;
375
376 if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
377 {
378 hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
379 return HAL_ERROR;
380 }
381
382 /* Initialize data control register */
383 hmmc->Instance->DCTRL = 0;
384
385 hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
386
387 hmmc->State = HAL_MMC_STATE_BUSY;
388
389 if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
390 {
391 add *= 512U;
392 }
393
394 /* Configure the MMC DPSM (Data Path State Machine) */
395 config.DataTimeOut = SDMMC_DATATIMEOUT;
396 config.DataLength = MMC_BLOCKSIZE * NumberOfBlocks;
397 config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
398 config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD;
399 config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;
400 config.DPSM = SDMMC_DPSM_DISABLE;
401 (void)SDMMC_ConfigData(hmmc->Instance, &config);
402
403 __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
404
405 hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
406
407 /* Write Blocks in DMA mode */
408 hmmc->Context = (MMC_CONTEXT_WRITE_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
409
410 /* Write Multi Block command */
411 errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
412 if (errorstate != HAL_MMC_ERROR_NONE)
413 {
414 hmmc->State = HAL_MMC_STATE_READY;
415 hmmc->ErrorCode |= errorstate;
416 return HAL_ERROR;
417 }
418
419 __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
420 SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
421
422 return HAL_OK;
423 }
424 else
425 {
426 return HAL_BUSY;
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