STM32H735xx HAL User Manual
stm32h7xx_hal_mmc_ex.c
Go to the documentation of this file.
00001 /**
00002   ******************************************************************************
00003   * @file    stm32h7xx_hal_mmc_ex.c
00004   * @author  MCD Application Team
00005   * @brief   MMC card Extended HAL module driver.
00006   *          This file provides firmware functions to manage the following
00007   *          functionalities of the Secure Digital (MMC) peripheral:
00008   *           + Extended features functions
00009   *
00010   ******************************************************************************
00011   * @attention
00012   *
00013   * Copyright (c) 2017 STMicroelectronics.
00014   * All rights reserved.
00015   *
00016   * This software is licensed under terms that can be found in the LICENSE file
00017   * in the root directory of this software component.
00018   * If no LICENSE file comes with this software, it is provided AS-IS.
00019   *
00020   ******************************************************************************
00021   @verbatim
00022   ==============================================================================
00023                         ##### How to use this driver #####
00024   ==============================================================================
00025   [..]
00026    The MMC Extension HAL driver can be used as follows:
00027    (+) Configure Buffer0 and Buffer1 start address and Buffer size using HAL_MMCEx_ConfigDMAMultiBuffer() function.
00028 
00029    (+) Start Read and Write for multibuffer mode using HAL_MMCEx_ReadBlocksDMAMultiBuffer() and
00030        HAL_MMCEx_WriteBlocksDMAMultiBuffer() functions.
00031 
00032   @endverbatim
00033   ******************************************************************************
00034   */
00035 
00036 /* Includes ------------------------------------------------------------------*/
00037 #include "stm32h7xx_hal.h"
00038 
00039 /** @addtogroup STM32H7xx_HAL_Driver
00040   * @{
00041   */
00042 
00043 /** @defgroup MMCEx MMCEx
00044   * @brief MMC Extended HAL module driver
00045   * @{
00046   */
00047 
00048 #ifdef HAL_MMC_MODULE_ENABLED
00049 
00050 /* Private typedef -----------------------------------------------------------*/
00051 /* Private define ------------------------------------------------------------*/
00052 /* Private macro -------------------------------------------------------------*/
00053 /* Private variables ---------------------------------------------------------*/
00054 /* Private function prototypes -----------------------------------------------*/
00055 /* Private functions ---------------------------------------------------------*/
00056 /* Exported functions --------------------------------------------------------*/
00057 /** @addtogroup MMCEx_Exported_Functions
00058   * @{
00059   */
00060 
00061 
00062 
00063 /** @addtogroup MMCEx_Exported_Functions_Group1
00064   *  @brief   Multibuffer functions
00065   *
00066 @verbatim
00067   ==============================================================================
00068           ##### Multibuffer functions #####
00069   ==============================================================================
00070   [..]
00071     This section provides functions allowing to configure the multibuffer mode and start read and write
00072     multibuffer mode for MMC HAL driver.
00073 
00074 @endverbatim
00075   * @{
00076   */
00077 
00078 /**
00079   * @brief  Configure DMA Dual Buffer mode. The Data transfer is managed by an Internal DMA.
00080   * @param  hmmc: MMC handle
00081   * @param  pDataBuffer0: Pointer to the buffer0 that will contain/receive the transferred data
00082   * @param  pDataBuffer1: Pointer to the buffer1 that will contain/receive the transferred data
00083   * @param  BufferSize: Size of Buffer0 in Blocks. Buffer0 and Buffer1 must have the same size.
00084   * @retval HAL status
00085   */
00086 HAL_StatusTypeDef HAL_MMCEx_ConfigDMAMultiBuffer(MMC_HandleTypeDef *hmmc, uint32_t *pDataBuffer0,
00087                                                  uint32_t *pDataBuffer1, uint32_t BufferSize)
00088 {
00089   if (hmmc->State == HAL_MMC_STATE_READY)
00090   {
00091     hmmc->Instance->IDMABASE0 = (uint32_t) pDataBuffer0 ;
00092     hmmc->Instance->IDMABASE1 = (uint32_t) pDataBuffer1 ;
00093     hmmc->Instance->IDMABSIZE = (uint32_t)(MMC_BLOCKSIZE * BufferSize);
00094 
00095     return HAL_OK;
00096   }
00097   else
00098   {
00099     return HAL_BUSY;
00100   }
00101 }
00102 
00103 /**
00104   * @brief  Reads block(s) from a specified address in a card. The received Data will be stored in Buffer0 and Buffer1.
00105   *         Buffer0, Buffer1 and BufferSize need to be configured by function HAL_MMCEx_ConfigDMAMultiBuffer before
00106   *         call this function.
00107   * @param  hmmc: MMC handle
00108   * @param  BlockAdd: Block Address from where data is to be read
00109   * @param  NumberOfBlocks: Total number of blocks to read
00110   * @retval HAL status
00111   */
00112 HAL_StatusTypeDef HAL_MMCEx_ReadBlocksDMAMultiBuffer(MMC_HandleTypeDef *hmmc, uint32_t BlockAdd,
00113                                                      uint32_t NumberOfBlocks)
00114 {
00115   SDMMC_DataInitTypeDef config;
00116   uint32_t DmaBase0_reg;
00117   uint32_t DmaBase1_reg;
00118   uint32_t errorstate;
00119   uint32_t add = BlockAdd;
00120 
00121   if (hmmc->State == HAL_MMC_STATE_READY)
00122   {
00123     if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
00124     {
00125       hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
00126       return HAL_ERROR;
00127     }
00128 
00129     /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
00130     if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
00131     {
00132       if ((NumberOfBlocks % 8U) != 0U)
00133       {
00134         /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
00135         hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
00136         return HAL_ERROR;
00137       }
00138 
00139       if ((BlockAdd % 8U) != 0U)
00140       {
00141         /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
00142         hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
00143         return HAL_ERROR;
00144       }
00145     }
00146 
00147     DmaBase0_reg = hmmc->Instance->IDMABASE0;
00148     DmaBase1_reg = hmmc->Instance->IDMABASE1;
00149 
00150     if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
00151     {
00152       hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
00153       return HAL_ERROR;
00154     }
00155 
00156     /* Initialize data control register */
00157     hmmc->Instance->DCTRL = 0;
00158 
00159     hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
00160     hmmc->State = HAL_MMC_STATE_BUSY;
00161 
00162     if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
00163     {
00164       add *= 512U;
00165     }
00166 
00167     /* Configure the MMC DPSM (Data Path State Machine) */
00168     config.DataTimeOut   = SDMMC_DATATIMEOUT;
00169     config.DataLength    = MMC_BLOCKSIZE * NumberOfBlocks;
00170     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
00171     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
00172     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
00173     config.DPSM          = SDMMC_DPSM_DISABLE;
00174     (void)SDMMC_ConfigData(hmmc->Instance, &config);
00175 
00176     hmmc->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
00177 
00178     __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
00179 
00180     hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
00181 
00182     /* Read Blocks in DMA mode */
00183     hmmc->Context = (MMC_CONTEXT_READ_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
00184 
00185     /* Read Multi Block command */
00186     errorstate = SDMMC_CmdReadMultiBlock(hmmc->Instance, add);
00187     if (errorstate != HAL_MMC_ERROR_NONE)
00188     {
00189       hmmc->State = HAL_MMC_STATE_READY;
00190       hmmc->ErrorCode |= errorstate;
00191       return HAL_ERROR;
00192     }
00193 
00194     __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND |
00195                                SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
00196 
00197     return HAL_OK;
00198   }
00199   else
00200   {
00201     return HAL_BUSY;
00202   }
00203 
00204 }
00205 
00206 /**
00207   * @brief  Write block(s) to a specified address in a card. The transferred Data are stored in Buffer0 and Buffer1.
00208   *         Buffer0, Buffer1 and BufferSize need to be configured by function HAL_MMCEx_ConfigDMAMultiBuffer before
00209   *         call this function.
00210   * @param  hmmc: MMC handle
00211   * @param  BlockAdd: Block Address from where data is to be read
00212   * @param  NumberOfBlocks: Total number of blocks to read
00213   * @retval HAL status
00214   */
00215 HAL_StatusTypeDef HAL_MMCEx_WriteBlocksDMAMultiBuffer(MMC_HandleTypeDef *hmmc, uint32_t BlockAdd,
00216                                                       uint32_t NumberOfBlocks)
00217 {
00218   SDMMC_DataInitTypeDef config;
00219   uint32_t errorstate;
00220   uint32_t DmaBase0_reg;
00221   uint32_t DmaBase1_reg;
00222   uint32_t add = BlockAdd;
00223 
00224   if (hmmc->State == HAL_MMC_STATE_READY)
00225   {
00226     if ((BlockAdd + NumberOfBlocks) > (hmmc->MmcCard.LogBlockNbr))
00227     {
00228       hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
00229       return HAL_ERROR;
00230     }
00231 
00232     /* Check the case of 4kB blocks (field DATA SECTOR SIZE of extended CSD register) */
00233     if (((hmmc->Ext_CSD[(MMC_EXT_CSD_DATA_SEC_SIZE_INDEX / 4)] >> MMC_EXT_CSD_DATA_SEC_SIZE_POS) & 0x000000FFU) != 0x0U)
00234     {
00235       if ((NumberOfBlocks % 8U) != 0U)
00236       {
00237         /* The number of blocks should be a multiple of 8 sectors of 512 bytes = 4 KBytes */
00238         hmmc->ErrorCode |= HAL_MMC_ERROR_BLOCK_LEN_ERR;
00239         return HAL_ERROR;
00240       }
00241 
00242       if ((BlockAdd % 8U) != 0U)
00243       {
00244         /* The address should be aligned to 8 (corresponding to 4 KBytes blocks) */
00245         hmmc->ErrorCode |= HAL_MMC_ERROR_ADDR_MISALIGNED;
00246         return HAL_ERROR;
00247       }
00248     }
00249 
00250     DmaBase0_reg = hmmc->Instance->IDMABASE0;
00251     DmaBase1_reg = hmmc->Instance->IDMABASE1;
00252 
00253     if ((hmmc->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U))
00254     {
00255       hmmc->ErrorCode = HAL_MMC_ERROR_ADDR_OUT_OF_RANGE;
00256       return HAL_ERROR;
00257     }
00258 
00259     /* Initialize data control register */
00260     hmmc->Instance->DCTRL = 0;
00261 
00262     hmmc->ErrorCode = HAL_MMC_ERROR_NONE;
00263 
00264     hmmc->State = HAL_MMC_STATE_BUSY;
00265 
00266     if ((hmmc->MmcCard.CardType) != MMC_HIGH_CAPACITY_CARD)
00267     {
00268       add *= 512U;
00269     }
00270 
00271     /* Configure the MMC DPSM (Data Path State Machine) */
00272     config.DataTimeOut   = SDMMC_DATATIMEOUT;
00273     config.DataLength    = MMC_BLOCKSIZE * NumberOfBlocks;
00274     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
00275     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
00276     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
00277     config.DPSM          = SDMMC_DPSM_DISABLE;
00278     (void)SDMMC_ConfigData(hmmc->Instance, &config);
00279 
00280     __SDMMC_CMDTRANS_ENABLE(hmmc->Instance);
00281 
00282     hmmc->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0;
00283 
00284     /* Write Blocks in DMA mode */
00285     hmmc->Context = (MMC_CONTEXT_WRITE_MULTIPLE_BLOCK | MMC_CONTEXT_DMA);
00286 
00287     /* Write Multi Block command */
00288     errorstate = SDMMC_CmdWriteMultiBlock(hmmc->Instance, add);
00289     if (errorstate != HAL_MMC_ERROR_NONE)
00290     {
00291       hmmc->State = HAL_MMC_STATE_READY;
00292       hmmc->ErrorCode |= errorstate;
00293       return HAL_ERROR;
00294     }
00295 
00296     __HAL_MMC_ENABLE_IT(hmmc, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND |
00297                                SDMMC_FLAG_IDMATE | SDMMC_FLAG_IDMABTC));
00298 
00299     return HAL_OK;
00300   }
00301   else
00302   {
00303     return HAL_BUSY;
00304   }
00305 }
00306 
00307 
00308 /**
00309   * @brief  Change the DMA Buffer0 or Buffer1 address on the fly.
00310   * @param  hmmc:           pointer to a MMC_HandleTypeDef structure.
00311   * @param  Buffer:        the buffer to be changed, This parameter can be one of
00312   *                        the following values: MMC_DMA_BUFFER0 or MMC_DMA_BUFFER1
00313   * @param  pDataBuffer:   The new address
00314   * @note   The BUFFER0 address can be changed only when the current transfer use
00315   *         BUFFER1 and the BUFFER1 address can be changed only when the current
00316   *         transfer use BUFFER0.
00317   * @retval HAL status
00318   */
00319 HAL_StatusTypeDef HAL_MMCEx_ChangeDMABuffer(MMC_HandleTypeDef *hmmc, HAL_MMCEx_DMABuffer_MemoryTypeDef Buffer,
00320                                             uint32_t *pDataBuffer)
00321 {
00322   if (Buffer == MMC_DMA_BUFFER0)
00323   {
00324     /* change the buffer0 address */
00325     hmmc->Instance->IDMABASE0 = (uint32_t)pDataBuffer;
00326   }
00327   else
00328   {
00329     /* change the memory1 address */
00330     hmmc->Instance->IDMABASE1 = (uint32_t)pDataBuffer;
00331   }
00332 
00333   return HAL_OK;
00334 }
00335 
00336 
00337 /**
00338   * @}
00339   */
00340 
00341 /**
00342   * @}
00343   */
00344 
00345 #endif /* HAL_MMC_MODULE_ENABLED */
00346 
00347 /**
00348   * @}
00349   */
00350 
00351 /**
00352   * @}
00353   */