本文共 37055 字,大约阅读时间需要 123 分钟。
完整教程下载地址:
本章节为大家讲解SDMMC(Secure digital input/output MultiMediaCard interface)总线的基础知识和对应的HAL库API。
目录
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SDMMC的基本功能,然后再看手册了解细节。

通过这个框图,我们可以得到如下信息:
SDMMC内核时钟。
AHB时钟。
SDMMC全局中断。
MDMA的SDMMC数据接收触发信号。
SD/SDIO/MMC卡双向/响应信号。
SD/SDIO/MMC卡双向数据线。
来自SD/SDIO/MMC卡的外部驱动器的时钟反馈(用于SDR12,SDR25,SDR50和DDR50)。
SD/SDIO/MMC卡的时钟。
SDMMC_CMD信号的SD/SDIO/MMC卡I/O方向指示。
SDMMC_D[3:1]数据线的SD/SDIO/MMC卡I/O方向指示。
SDMMC_D0数据线的SD/SDIO/MMC卡I/O方向指示。
STM32H7有两个SDMMC控制器,SDMMC1和SDMMC2,这两个控制器支持的功能是一样的。
SDMMC控制器的时钟来源:
 
SDMMC1和SDMMC2时钟源是一样的:

注:大家应用时要特别注意这个问题。
使用STM32H7的SDIO1仅支持AXI SRAM,而SDIO2是AXI,SRAM1,SRAM2和SRAM3都支持的
 
驱动SD卡支持的最大总线速度:

驱动eMMC支持的最大总线速度:

关于这两个数据表,注意以下几点:
STM32H7的SDIO外接支持UHS-I 模式 (SDR12, SDR25, SDR50, SDR104和DDR50)需要1.8的电平转换器。STM32H7参考手册给了一个型号ST6G3244ME:


STM32H7的SDMMC自带了专用的DMA控制器IDMA,支持突发,也支持双缓冲。为什么要自带DMA控制器? 主要原因是STM32H7的通用DMA1和DMA2已经无法满足SDMMC高速通信速度。在本教程的第62章专门为大家测试过。通过让SDMMC自带控制器,这个问题就迎刃而解。
SDMMC总线相关的寄存器是通过HAL库中的结构体SD_TypeDef定义,在stm32h743xx.h中可以找到这个类型定义:
#define SD_TypeDef          SDMMC_TypeDeftypedef struct{  __IO uint32_t POWER;          /*!< SDMMC power control register,             Address offset: 0x00  */  __IO uint32_t CLKCR;          /*!< SDMMC clock control register,             Address offset: 0x04  */  __IO uint32_t ARG;            /*!< SDMMC argument register,                  Address offset: 0x08  */  __IO uint32_t CMD;            /*!< SDMMC command register,                   Address offset: 0x0C  */  __I uint32_t  RESPCMD;        /*!< SDMMC command response register,          Address offset: 0x10  */  __I uint32_t  RESP1;          /*!< SDMMC response 1 register,                Address offset: 0x14  */  __I uint32_t  RESP2;          /*!< SDMMC response 2 register,                Address offset: 0x18  */  __I uint32_t  RESP3;          /*!< SDMMC response 3 register,                Address offset: 0x1C  */  __I uint32_t  RESP4;          /*!< SDMMC response 4 register,                Address offset: 0x20  */  __IO uint32_t DTIMER;         /*!< SDMMC data timer register,                Address offset: 0x24  */  __IO uint32_t DLEN;           /*!< SDMMC data length register,               Address offset: 0x28  */  __IO uint32_t DCTRL;          /*!< SDMMC data control register,              Address offset: 0x2C  */  __I uint32_t  DCOUNT;         /*!< SDMMC data counter register,              Address offset: 0x30  */  __I uint32_t  STA;            /*!< SDMMC status register,                    Address offset: 0x34  */  __IO uint32_t ICR;            /*!< SDMMC interrupt clear register,           Address offset: 0x38  */  __IO uint32_t MASK;           /*!< SDMMC mask register,                      Address offset: 0x3C  */  __IO uint32_t ACKTIME;        /*!< SDMMC Acknowledgement timer register,     Address offset: 0x40  */  uint32_t      RESERVED0[3];   /*!< Reserved, 0x44 - 0x4C - 0x4C                                    */  __IO uint32_t IDMACTRL;       /*!< SDMMC DMA control register,               Address offset: 0x50  */  __IO uint32_t IDMABSIZE;      /*!< SDMMC DMA buffer size register,           Address offset: 0x54  */  __IO uint32_t IDMABASE0;      /*!< SDMMC DMA buffer 0 base address register, Address offset: 0x58  */  __IO uint32_t IDMABASE1;      /*!< SDMMC DMA buffer 1 base address register, Address offset: 0x5C  */  uint32_t      RESERVED1[8];   /*!< Reserved, 0x60-0x7C                                             */  __IO uint32_t FIFO;           /*!< SDMMC data FIFO register,                 Address offset: 0x80  */  uint32_t      RESERVED2[222]; /*!< Reserved, 0x84-0x3F8                                            */  __IO uint32_t IPVR;           /*!< SDMMC data FIFO register,                 Address offset: 0x3FC */} SDMMC_TypeDef;   这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
#define __O volatile /*!< Defines 'write only' permissions */#define __IO volatile /*!< Defines 'read / write' permissions */
下面我们看下SDMMC的定义,在stm32h743xx.h文件。
#define PERIPH_BASE (0x40000000UL) #define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000UL)#define D2_AHB2PERIPH_BASE (PERIPH_BASE + 0x08020000UL)#define SDMMC1_BASE (D1_AHB1PERIPH_BASE + 0x7000UL)#define SDMMC2_BASE (D2_AHB2PERIPH_BASE + 0x2400UL)#define SDMMC1 ((SDMMC_TypeDef *) SDMMC1_BASE)#define SDMMC2 ((SDMMC_TypeDef *) SDMMC2_BASE) <----- 展开这个宏,(SDMMC_TypeDef *)0x48022400
我们访问SDMMC1的CMD寄存器可以采用这种形式:SDMMC1->CMD = 0。
下面是SDMMC总线的初始化结构体:
#define SD_InitTypeDef      SDMMC_InitTypeDeftypedef struct{  uint32_t ClockEdge;              uint32_t ClockPowerSave;        uint32_t BusWide;               uint32_t HardwareFlowControl;    uint32_t ClockDiv;             #if (USE_SD_TRANSCEIVER != 0U)  uint32_t TranceiverPresent;    #endif }SDMMC_InitTypeDef;   下面将结构体成员逐一做个说明:
用于设置SDMMC的数据或者命令变化的时钟沿。
#define SDMMC_CLOCK_EDGE_RISING ((uint32_t)0x00000000U)#define SDMMC_CLOCK_EDGE_FALLING SDMMC_CLKCR_NEGEDGE
用于设置空闲状态,是否输出时钟。
#define SDMMC_CLOCK_POWER_SAVE_DISABLE ((uint32_t)0x00000000U)#define SDMMC_CLOCK_POWER_SAVE_ENABLE SDMMC_CLKCR_PWRSAV
用于设置SDMMC总线位宽。
#define SDMMC_BUS_WIDE_1B ((uint32_t)0x00000000U)#define SDMMC_BUS_WIDE_4B SDMMC_CLKCR_WIDBUS_0#define SDMMC_BUS_WIDE_8B SDMMC_CLKCR_WIDBUS_1
用于设置时候使能硬件流控制。
#define SDMMC_HARDWARE_FLOW_CONTROL_DISABLE ((uint32_t)0x00000000U)#define SDMMC_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_CLKCR_HWFC_EN
用于设置SDMMC时钟分频,参数范围0到1023。
用于设置是否带1.8V收发器。
#define SDMMC_TRANSCEIVER_UNKNOWN ((uint32_t)0x00000000U)#define SDMMC_TRANSCEIVER_NOT_PRESENT ((uint32_t)0x00000001U)#define SDMMC_TRANSCEIVER_PRESENT ((uint32_t)0x00000002U)
下面是SDMMC总线的卡信息结构体:
typedef struct{  uint32_t CardType;                     /*!< Specifies the card Type                         */  uint32_t CardVersion;                  /*!< Specifies the card version                      */  uint32_t Class;                        /*!< Specifies the class of the card class           */  uint32_t RelCardAdd;                   /*!< Specifies the Relative Card Address             */  uint32_t BlockNbr;                     /*!< Specifies the Card Capacity in blocks           */  uint32_t BlockSize;                    /*!< Specifies one block size in bytes               */  uint32_t LogBlockNbr;                  /*!< Specifies the Card logical Capacity in blocks   */  uint32_t LogBlockSize;                 /*!< Specifies logical block size in bytes           */  uint32_t CardSpeed;                    /*!< Specifies the card Speed                        */}HAL_SD_CardInfoTypeDef;   下面将结构体成员逐一做个说明:
卡类型。
/*!< SD Standard Capacity <2Go */#define CARD_SDSC ((uint32_t)0x00000000U) /*!< SD High Capacity <32Go, SD Extended Capacity <2To */#define CARD_SDHC_SDXC ((uint32_t)0x00000001U) #define CARD_SECURED ((uint32_t)0x00000003U)
卡版本。
#define CARD_V1_X ((uint32_t)0x00000000U)#define CARD_V2_X ((uint32_t)0x00000001U)
卡类型。
卡相对地址。
整个卡的块数。
每个块的字节数。
整个卡的逻辑块数。
逻辑块大小
#define SPI_FIRSTBIT_MSB (0x00000000UL)#define SPI_FIRSTBIT_LSB SPI_CFG2_LSBFRST
用于设置是否使能SPI总线的TI模式。
/*!< Normal Speed Card <12.5Mo/s , Spec Version 1.01 */#define CARD_NORMAL_SPEED ((uint32_t)0x00000000U) /*!< High Speed Card <25Mo/s , Spec version 2.00 */ #define CARD_HIGH_SPEED ((uint32_t)0x00000100U) /*!< UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards and <104Mo/s for SDR104, Spec version 3.01 */#define CARD_ULTRA_HIGH_SPEED ((uint32_t)0x00000200U)
下面是SDMMC句柄结构体:
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)typedef struct __SD_HandleTypeDef#elsetypedef struct#endif /* USE_HAL_SD_REGISTER_CALLBACKS */{  SD_TypeDef                   *Instance;        /*!< SD registers base address           */  SD_InitTypeDef               Init;             /*!< SD required parameters              */  HAL_LockTypeDef              Lock;             /*!< SD locking object                   */  uint8_t                      *pTxBuffPtr;      /*!< Pointer to SD Tx transfer Buffer    */  uint32_t                     TxXferSize;       /*!< SD Tx Transfer size                 */  uint8_t                      *pRxBuffPtr;      /*!< Pointer to SD Rx transfer Buffer    */  uint32_t                     RxXferSize;       /*!< SD Rx Transfer size                 */  __IO uint32_t                Context;          /*!< SD transfer context                 */  __IO HAL_SD_StateTypeDef     State;            /*!< SD card State                       */  __IO uint32_t                ErrorCode;        /*!< SD Card Error codes                 */  HAL_SD_CardInfoTypeDef       SdCard;           /*!< SD Card information                 */  uint32_t                     CSD[4];           /*!< SD card specific data table         */  uint32_t                     CID[4];           /*!< SD card identification number table */#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)  void (* TxCpltCallback)                 (struct __SD_HandleTypeDef *hsd);  void (* RxCpltCallback)                 (struct __SD_HandleTypeDef *hsd);  void (* ErrorCallback)                  (struct __SD_HandleTypeDef *hsd);  void (* AbortCpltCallback)              (struct __SD_HandleTypeDef *hsd);  void (* Read_DMADblBuf0CpltCallback)    (struct __SD_HandleTypeDef *hsd);  void (* Read_DMADblBuf1CpltCallback)    (struct __SD_HandleTypeDef *hsd);  void (* Write_DMADblBuf0CpltCallback)   (struct __SD_HandleTypeDef *hsd);  void (* Write_DMADblBuf1CpltCallback)   (struct __SD_HandleTypeDef *hsd);#if (USE_SD_TRANSCEIVER != 0U)  void (* DriveTransceiver_1_8V_Callback) (FlagStatus status);#endif /* USE_SD_TRANSCEIVER */  void (* MspInitCallback)                (struct __SD_HandleTypeDef *hsd);  void (* MspDeInitCallback)              (struct __SD_HandleTypeDef *hsd);#endif /* USE_HAL_SD_REGISTER_CALLBACKS */}SD_HandleTypeDef;   注意事项:
条件编译USE_HAL_SD_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
#define USE_HAL_SD_REGISTER_CALLBACKS 1
通过函数HAL_SD_RegisterCallback注册回调,取消注册使用函数HAL_SD_UnRegisterCallback。
这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。
这个参数是寄存器的例化,方便操作寄存器。
这个参数在本章节3.2小节已经进行了详细说明。
此文件涉及到的函数较多,这里把几个常用的函数做个说明:
函数原型:
HAL_StatusTypeDef HAL_SD_Init(SD_HandleTypeDef *hsd){  HAL_SD_CardStatusTypeDef CardStatus;  uint32_t speedgrade, unitsize;  uint32_t tickstart;  /* 检查句柄是否有效 */  if(hsd == NULL)  {    return HAL_ERROR;  }  /* 检查参数 */  assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance));  assert_param(IS_SDMMC_CLOCK_EDGE(hsd->Init.ClockEdge));  assert_param(IS_SDMMC_CLOCK_POWER_SAVE(hsd->Init.ClockPowerSave));  assert_param(IS_SDMMC_BUS_WIDE(hsd->Init.BusWide));  assert_param(IS_SDMMC_HARDWARE_FLOW_CONTROL(hsd->Init.HardwareFlowControl));  assert_param(IS_SDMMC_CLKDIV(hsd->Init.ClockDiv));  if(hsd->State == HAL_SD_STATE_RESET)  {    /* 开锁 */    hsd->Lock = HAL_UNLOCKED;#if (USE_SD_TRANSCEIVER != 0U)    /* 兼容 */    if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_UNKNOWN)    {      hsd->Init.TranceiverPresent = SDMMC_TRANSCEIVER_PRESENT;    }#endif#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)    /* 复位回调 */    hsd->TxCpltCallback    = HAL_SD_TxCpltCallback;    hsd->RxCpltCallback    = HAL_SD_RxCpltCallback;    hsd->ErrorCallback     = HAL_SD_ErrorCallback;    hsd->AbortCpltCallback = HAL_SD_AbortCallback;    hsd->Read_DMADblBuf0CpltCallback = HAL_SDEx_Read_DMADoubleBuf0CpltCallback;    hsd->Read_DMADblBuf1CpltCallback = HAL_SDEx_Read_DMADoubleBuf1CpltCallback;    hsd->Write_DMADblBuf0CpltCallback = HAL_SDEx_Write_DMADoubleBuf0CpltCallback;    hsd->Write_DMADblBuf1CpltCallback = HAL_SDEx_Write_DMADoubleBuf1CpltCallback;#if (USE_SD_TRANSCEIVER != 0U)    if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT)    {      hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback;    }#endif     if(hsd->MspInitCallback == NULL)    {      hsd->MspInitCallback = HAL_SD_MspInit;    }    /* 初始化底层 */    hsd->MspInitCallback(hsd);#else    /* 初始化底层硬件 GPIO, CLOCK, CORTEX...etc */    HAL_SD_MspInit(hsd);#endif /* USE_HAL_SD_REGISTER_CALLBACKS */  }  hsd->State = HAL_SD_STATE_BUSY;  /* 初始化卡参数 */  if (HAL_SD_InitCard(hsd) != HAL_OK)  {    return HAL_ERROR;  }  if( HAL_SD_GetCardStatus(hsd, &CardStatus) != HAL_OK)  {    return HAL_ERROR;  }  /* 获取卡速度等信息 */  speedgrade = CardStatus.UhsSpeedGrade;  unitsize = CardStatus.UhsAllocationUnitSize;  if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U)))  {    hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED;  }  else  {    if (hsd->SdCard.CardType == CARD_SDHC_SDXC)    {      hsd->SdCard.CardSpeed  = CARD_HIGH_SPEED;    }    else    {      hsd->SdCard.CardSpeed  = CARD_NORMAL_SPEED;    }  }  /* 配置总线位宽 */  if(HAL_SD_ConfigWideBusOperation(hsd, hsd->Init.BusWide) != HAL_OK)  {    return HAL_ERROR;  }  /* 验证卡初始化后是否就绪 */  tickstart = HAL_GetTick();  while((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER))  {    if((HAL_GetTick()-tickstart) >=  SDMMC_DATATIMEOUT)    {      hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT;      hsd->State= HAL_SD_STATE_READY;      return HAL_TIMEOUT;    }  }  hsd->ErrorCode = HAL_SD_ERROR_NONE;  hsd->Context = SD_CONTEXT_NONE;  hsd->State = HAL_SD_STATE_READY;  return HAL_OK;}   函数描述:
此函数用于初始化SD卡。
函数参数:
注意事项:
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SD_STATE_RESET = 0x00U。
解决办法有三
方法1:用户自己初始化SD和涉及到的GPIO等。
方法2:定义SD_HandleTypeDef SdHandle为全局变量。
方法3:下面的方法
if(HAL_SD_DeInit(&SdHandle) != HAL_OK){    Error_Handler();}  if(HAL_SD_Init(&SdHandle) != HAL_OK){    Error_Handler();}   使用举例:
SD_HandleTypeDef uSdHandle;uSdHandle.Instance = SDMMC1;/* if CLKDIV = 0 then SDMMC Clock frequency = SDMMC Kernel Clock     else SDMMC Clock frequency = SDMMC Kernel Clock / [2 * CLKDIV].     200MHz / (2*2) = 50MHz*/uSdHandle.Init.ClockDiv            = 2; uSdHandle.Init.ClockPowerSave      = SDMMC_CLOCK_POWER_SAVE_DISABLE;uSdHandle.Init.ClockEdge           = SDMMC_CLOCK_EDGE_RISING;uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;uSdHandle.Init.BusWide             = SDMMC_BUS_WIDE_4B;if(HAL_SD_Init(&uSdHandle) != HAL_OK){   sd_state = MSD_ERROR;}   函数原型:
HAL_StatusTypeDef HAL_SD_DeInit(SD_HandleTypeDef *hsd){  /* 检查SD卡句柄是否有效 */  if(hsd == NULL)  {    return HAL_ERROR;  }  /* 检查参数 */  assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance));  hsd->State = HAL_SD_STATE_BUSY;#if (USE_SD_TRANSCEIVER != 0U)  /* 关闭1.8V模式 */  if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT)  {#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)    if(hsd->DriveTransceiver_1_8V_Callback == NULL)    {      hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback;    }    hsd->DriveTransceiver_1_8V_Callback(RESET);#else    HAL_SD_DriveTransceiver_1_8V_Callback(RESET);#endif   }                                                                         #endif  /* 关闭SD卡电源 */  SD_PowerOFF(hsd);#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)  if(hsd->MspDeInitCallback == NULL)  {    hsd->MspDeInitCallback = HAL_SD_MspDeInit;  }  /* 复位底层硬件 */  hsd->MspDeInitCallback(hsd);#else  /* 复位底层硬件 */  HAL_SD_MspDeInit(hsd);#endif   hsd->ErrorCode = HAL_SD_ERROR_NONE;  hsd->State = HAL_SD_STATE_RESET;  return HAL_OK;}   函数描述:
用于复位SD总线初始化。
函数参数:
函数原型:
HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout){  SDMMC_DataInitTypeDef config;  uint32_t errorstate;  uint32_t tickstart = HAL_GetTick();  uint32_t count, data, dataremaining;  uint32_t add = BlockAdd;  uint8_t *tempbuff = pData;  if(NULL == pData)  {    hsd->ErrorCode |= HAL_SD_ERROR_PARAM;    return HAL_ERROR;  }  if(hsd->State == HAL_SD_STATE_READY)  {    hsd->ErrorCode = HAL_SD_ERROR_NONE;    if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))    {      hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;      return HAL_ERROR;    }    hsd->State = HAL_SD_STATE_BUSY;    /* 初始化数据控制寄存器 */    hsd->Instance->DCTRL = 0U;    if(hsd->SdCard.CardType != CARD_SDHC_SDXC)    {      add *= 512U;    }    /* 配置SD DPSM (Data Path State Machine) */    config.DataTimeOut   = SDMMC_DATATIMEOUT;    config.DataLength    = NumberOfBlocks * BLOCKSIZE;    config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;    config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;    config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;    config.DPSM          = SDMMC_DPSM_DISABLE;    (void)SDMMC_ConfigData(hsd->Instance, &config);    __SDMMC_CMDTRANS_ENABLE( hsd->Instance);    /* 查询方式块读取 */    if(NumberOfBlocks > 1U)    {      hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK;      /* 多块读取命令 */      errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);    }    else    {      hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK;      /* 单块读取命令 */      errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);    }    if(errorstate != HAL_SD_ERROR_NONE)    {      /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= errorstate;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    /* 查询SDMMC标志 */    dataremaining = config.DataLength;    while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND))    {      if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) && (dataremaining >= 32U))      {        /* 从SDMMC Rx FIFO读取数据 */        for(count = 0U; count < 8U; count++)        {          data = SDMMC_ReadFIFO(hsd->Instance);          *tempbuff = (uint8_t)(data & 0xFFU);          tempbuff++;          *tempbuff = (uint8_t)((data >> 8U) & 0xFFU);          tempbuff++;          *tempbuff = (uint8_t)((data >> 16U) & 0xFFU);          tempbuff++;          *tempbuff = (uint8_t)((data >> 24U) & 0xFFU);          tempbuff++;        }        dataremaining -= 32U;      }      if(((HAL_GetTick()-tickstart) >=  Timeout) || (Timeout == 0U))      {        /* 清除所有静态标志 */        __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);        hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;        hsd->State= HAL_SD_STATE_READY;        hsd->Context = SD_CONTEXT_NONE;        return HAL_TIMEOUT;      }    }    __SDMMC_CMDTRANS_DISABLE( hsd->Instance);    /* 多块读取发送停止传输命令 */    if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U))    {      if(hsd->SdCard.CardType != CARD_SECURED)      {        /* 发送停止传输命令 */        errorstate = SDMMC_CmdStopTransfer(hsd->Instance);        if(errorstate != HAL_SD_ERROR_NONE)        {          /* 清除所有静态标志 */          __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);          hsd->ErrorCode |= errorstate;          hsd->State = HAL_SD_STATE_READY;          hsd->Context = SD_CONTEXT_NONE;          return HAL_ERROR;        }      }    }    /* 获取错误状态 */    if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT))    {      /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL))    {      /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR))    {      /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    else    {      /* 什么都不做 */    }    /* 清除所有静态标志 */    __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);    hsd->State = HAL_SD_STATE_READY;    return HAL_OK;  }  else  {    hsd->ErrorCode |= HAL_SD_ERROR_BUSY;    return HAL_ERROR;  }}   函数描述:
此函数主要用于SD卡数据读取。
函数参数:
使用举例:
/**  * @brief  Reads block(s) from a specified address in an SD card, in polling mode.  * @param  pData: Pointer to the buffer that will contain the data to transmit  * @param  ReadAddr: Address from where data is to be read  * @param  NumOfBlocks: Number of SD blocks to read  * @param  Timeout: Timeout for read operation  * @retval SD status  */uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout){  if( HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) == HAL_OK)  {    return MSD_OK;  }  else  {    return MSD_ERROR;  }}   函数原型:
HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout){  SDMMC_DataInitTypeDef config;  uint32_t errorstate;  uint32_t tickstart = HAL_GetTick();  uint32_t count, data, dataremaining;  uint32_t add = BlockAdd;  uint8_t *tempbuff = pData;  if(NULL == pData)  {    hsd->ErrorCode |= HAL_SD_ERROR_PARAM;    return HAL_ERROR;  }  if(hsd->State == HAL_SD_STATE_READY)  {    hsd->ErrorCode = HAL_SD_ERROR_NONE;    if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))    {      hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;      return HAL_ERROR;    }    hsd->State = HAL_SD_STATE_BUSY;    /* 初始化数据控制寄存器 */    hsd->Instance->DCTRL = 0U;    if(hsd->SdCard.CardType != CARD_SDHC_SDXC)    {      add *= 512U;    }    /* 配置SD DPSM */    config.DataTimeOut   = SDMMC_DATATIMEOUT;    config.DataLength    = NumberOfBlocks * BLOCKSIZE;    config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;    config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;    config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;    config.DPSM          = SDMMC_DPSM_DISABLE;    (void)SDMMC_ConfigData(hsd->Instance, &config);    __SDMMC_CMDTRANS_ENABLE( hsd->Instance);    /* 查询方式块写操作 */    if(NumberOfBlocks > 1U)    {      hsd->Context = SD_CONTEXT_WRITE_MULTIPLE_BLOCK;      /* 写多块命令 */      errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);    }    else    {      hsd->Context = SD_CONTEXT_WRITE_SINGLE_BLOCK;      /* 写单块命令 */      errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);    }    if(errorstate != HAL_SD_ERROR_NONE)    {      /* 清除所有静态命令 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= errorstate;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    /* 查询方式块写操作 */    dataremaining = config.DataLength;    while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND))    {      if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) && (dataremaining >= 32U))      {        /* 写数据到SDMMC Tx FIFO */        for(count = 0U; count < 8U; count++)        {          data = (uint32_t)(*tempbuff);          tempbuff++;          data |= ((uint32_t)(*tempbuff) << 8U);          tempbuff++;          data |= ((uint32_t)(*tempbuff) << 16U);          tempbuff++;          data |= ((uint32_t)(*tempbuff) << 24U);          tempbuff++;          (void)SDMMC_WriteFIFO(hsd->Instance, &data);        }        dataremaining -= 32U;      }      if(((HAL_GetTick()-tickstart) >=  Timeout) || (Timeout == 0U))      {        /* 清除所有静态标志 */        __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);        hsd->ErrorCode |= errorstate;        hsd->State = HAL_SD_STATE_READY;        hsd->Context = SD_CONTEXT_NONE;        return HAL_TIMEOUT;      }    }    __SDMMC_CMDTRANS_DISABLE( hsd->Instance);    /* 多块写操作,发送停止传输命令 */    if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U))    {      if(hsd->SdCard.CardType != CARD_SECURED)      {        /* 发送停止传输命令 */        errorstate = SDMMC_CmdStopTransfer(hsd->Instance);        if(errorstate != HAL_SD_ERROR_NONE)        {          /* 清除所有静态传输标志 */          __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);          hsd->ErrorCode |= errorstate;          hsd->State = HAL_SD_STATE_READY;          hsd->Context = SD_CONTEXT_NONE;          return HAL_ERROR;        }      }    }    /* Get error state */    if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT))    {      /* 清除所有静态传输标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL))    {      /* 清除所有静态传输标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR))    {      /* 清除所有静态传输标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }    else    {      /* 什么都不做 */    }      /* 清除所有静态传输标志 */    __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);    hsd->State = HAL_SD_STATE_READY;    return HAL_OK;  }  else  {    hsd->ErrorCode |= HAL_SD_ERROR_BUSY;    return HAL_ERROR;  }}   函数描述:
此函数主要用于向SD卡写入数据。
函数参数:
使用举例:
/**  * @brief  Writes block(s) to a specified address in an SD card, in polling mode.  * @param  pData: Pointer to the buffer that will contain the data to transmit  * @param  WriteAddr: Address from where data is to be written  * @param  NumOfBlocks: Number of SD blocks to write  * @param  Timeout: Timeout for write operation  * @retval SD status  */uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout){  if( HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) == HAL_OK)  {    return MSD_OK;  }  else  {    return MSD_ERROR;  }}   函数原型:
HAL_StatusTypeDef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks){  SDMMC_DataInitTypeDef config;  uint32_t errorstate;  uint32_t add = BlockAdd;  if(NULL == pData)  {    hsd->ErrorCode |= HAL_SD_ERROR_PARAM;    return HAL_ERROR;  }  if(hsd->State == HAL_SD_STATE_READY)  {    hsd->ErrorCode = HAL_SD_ERROR_NONE;    if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))    {      hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;      return HAL_ERROR;    }    hsd->State = HAL_SD_STATE_BUSY;  /* 初始化数据控制寄存器 */    hsd->Instance->DCTRL = 0U;    hsd->pRxBuffPtr = pData;    hsd->RxXferSize = BLOCKSIZE * NumberOfBlocks;    if(hsd->SdCard.CardType != CARD_SDHC_SDXC)    {      add *= 512U;    }  /* 配置SD DPSM (Data Path State Machine) */    config.DataTimeOut   = SDMMC_DATATIMEOUT;    config.DataLength    = BLOCKSIZE * NumberOfBlocks;    config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;    config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;    config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;    config.DPSM          = SDMMC_DPSM_DISABLE;    (void)SDMMC_ConfigData(hsd->Instance, &config);    __SDMMC_CMDTRANS_ENABLE( hsd->Instance);    hsd->Instance->IDMABASE0 = (uint32_t) pData ;    hsd->Instance->IDMACTRL  = SDMMC_ENABLE_IDMA_SINGLE_BUFF;  /* DMA方式读取多个块 */    if(NumberOfBlocks > 1U)    {      hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);   /* DMA方式读取多块命令 */      errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);    }    else    {      hsd->Context = (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_DMA);   /* 读取单块命令 */      errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);    }    if(errorstate != HAL_SD_ERROR_NONE)    {   /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= errorstate;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }  /* 使能传输中断 */    __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND));    return HAL_OK;  }  else  {    return HAL_BUSY;  }}   函数描述:
此函数主要用于SD卡数据读取,DMA方式。
函数参数:
使用举例:
/*** @brief  Reads block(s) from a specified address in an SD card, in DMA mode.* @param  pData: Pointer to the buffer that will contain the data to transmit* @param  ReadAddr: Address from where data is to be read* @param  NumOfBlocks: Number of SD blocks to read* @retval SD status*/uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks){  if( HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks) == HAL_OK)  {    return MSD_OK;  }  else  {    return MSD_ERROR;  }}   函数原型:
HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks){  SDMMC_DataInitTypeDef config;  uint32_t errorstate;  uint32_t add = BlockAdd;  if(NULL == pData)  {    hsd->ErrorCode |= HAL_SD_ERROR_PARAM;    return HAL_ERROR;  }  if(hsd->State == HAL_SD_STATE_READY)  {    hsd->ErrorCode = HAL_SD_ERROR_NONE;    if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))    {      hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;      return HAL_ERROR;    }    hsd->State = HAL_SD_STATE_BUSY;  /* 初始化数据控制寄存器 */    hsd->Instance->DCTRL = 0U;    hsd->pTxBuffPtr = pData;    hsd->TxXferSize = BLOCKSIZE * NumberOfBlocks;    if(hsd->SdCard.CardType != CARD_SDHC_SDXC)    {      add *= 512U;    }  /* 配置SD DPSM (Data Path State Machine) */    config.DataTimeOut   = SDMMC_DATATIMEOUT;    config.DataLength    = BLOCKSIZE * NumberOfBlocks;    config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;    config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;    config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;    config.DPSM          = SDMMC_DPSM_DISABLE;    (void)SDMMC_ConfigData(hsd->Instance, &config);    __SDMMC_CMDTRANS_ENABLE( hsd->Instance);    hsd->Instance->IDMABASE0 = (uint32_t) pData ;    hsd->Instance->IDMACTRL  = SDMMC_ENABLE_IDMA_SINGLE_BUFF;  /* 查询模式写块 */    if(NumberOfBlocks > 1U)    {      hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);    /* 多块写命令 */      errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);    }    else    {      hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_DMA);    /* 单块写命令 */      errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);    }    if(errorstate != HAL_SD_ERROR_NONE)    {    /* 清除静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= errorstate;      hsd->State = HAL_SD_STATE_READY;      hsd->Context = SD_CONTEXT_NONE;      return HAL_ERROR;    }  /* 使能传输中断 Enable */    __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND));    return HAL_OK;  }  else  {    return HAL_BUSY;  }}   函数描述:
此函数主要用于向SD卡写入数据,DMA方式。
函数参数:
使用举例:
/*** @brief  Writes block(s) to a specified address in an SD card, in DMA mode.* @param  pData: Pointer to the buffer that will contain the data to transmit* @param  WriteAddr: Address from where data is to be written* @param  NumOfBlocks: Number of SD blocks to write* @retval SD status*/uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks){  if( HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) == HAL_OK)  {    return MSD_OK;  }  else  {    return MSD_ERROR;  }}   函数原型:
HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, uint32_t BlockEndAdd){  uint32_t errorstate;  uint32_t start_add = BlockStartAdd;  uint32_t end_add = BlockEndAdd;  if(hsd->State == HAL_SD_STATE_READY)  {    hsd->ErrorCode = HAL_SD_ERROR_NONE;    if(end_add < start_add)    {      hsd->ErrorCode |= HAL_SD_ERROR_PARAM;      return HAL_ERROR;    }    if(end_add > (hsd->SdCard.LogBlockNbr))    {      hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;      return HAL_ERROR;    }    hsd->State = HAL_SD_STATE_BUSY;  /* 检测是否支持擦除命令 */    if(((hsd->SdCard.Class) & SDMMC_CCCC_ERASE) == 0U)    {      /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;      hsd->State = HAL_SD_STATE_READY;      return HAL_ERROR;    }    if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)    {    /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= HAL_SD_ERROR_LOCK_UNLOCK_FAILED;      hsd->State = HAL_SD_STATE_READY;      return HAL_ERROR;    }  /* 对于高容量卡,获取起始块和结束块 */    if(hsd->SdCard.CardType != CARD_SDHC_SDXC)    {      start_add *= 512U;      end_add   *= 512U;    }    /* 根据sd-card spec 1.0 ERASE_GROUP_START (CMD32) 和 erase_group_end(CMD33) */    if(hsd->SdCard.CardType != CARD_SECURED)    {    /* 发送CMD32 SD_ERASE_GRP_START命令带地址参数 */      errorstate = SDMMC_CmdSDEraseStartAdd(hsd->Instance, start_add);      if(errorstate != HAL_SD_ERROR_NONE)      {        /* 清除所有静态标志 */        __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);        hsd->ErrorCode |= errorstate;        hsd->State = HAL_SD_STATE_READY;        return HAL_ERROR;      }      /* 发送CMD33 SD_ERASE_GRP_END命令,带地址参数 */      errorstate = SDMMC_CmdSDEraseEndAdd(hsd->Instance, end_add);      if(errorstate != HAL_SD_ERROR_NONE)      {        /* 清除所有静态标志 */        __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);        hsd->ErrorCode |= errorstate;        hsd->State = HAL_SD_STATE_READY;        return HAL_ERROR;      }    }    /* 发送CMD38 ERASE命令 */    errorstate = SDMMC_CmdErase(hsd->Instance, 0UL);    if(errorstate != HAL_SD_ERROR_NONE)    {      /* 清除所有静态标志 */      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);      hsd->ErrorCode |= errorstate;      hsd->State = HAL_SD_STATE_READY;      return HAL_ERROR;    }    hsd->State = HAL_SD_STATE_READY;    return HAL_OK;  }  else  {    return HAL_BUSY;  }}   函数描述:
此函数主要用于SD卡擦除。
函数参数:
使用举例:
/*** @brief  Erases the specified memory area of the given SD card.* @param  StartAddr: Start byte address* @param  EndAddr: End byte address* @retval SD status*/uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr){  if( HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) == HAL_OK)  {    return MSD_OK;  }  else  {    return MSD_ERROR;  }}   本章节就为大家讲解这么多,更多SDMMC知识可以看STM32H7的参考手册。
转载地址:http://sqjjz.baihongyu.com/