博客
关于我
【STM32H7教程】第87章 STM32H7的SDMMC总线基础知识和HAL库API
阅读量:527 次
发布时间:2019-03-07

本文共 21510 字,大约阅读时间需要 71 分钟。

STM32H7 SDMMC总线基础知识与HAL库API应用教程


87.1 初学者重要提示

对于SDMMC控制SD卡或者eMMC,掌握本章的知识点就够用了,更深入的认识可以看STM32H7的参考手册。

注意,操作SD卡是采用的函数HAL_SD_XXXX,而操作eMMC是采用的函数HAL_MMC_XXXX,也就是说他们采用的函数前缀是不同的。

SD卡官网:链接

SDMMC驱动eMMC支持1线,4线和8线模式,其中8线模式的最高速度可达208MB/S,实际速度受IO最大速度限制。

SDMMC驱动SD卡支持1线和4线模式。

STM32H7的SDMMC也支持eMMC:


87.2 SDMMC总线基础知识

87.2.1 SDMMC总线的硬件框图

通过这个框图,我们可以得到如下信息:

  • sdmmc_ker_ck输入:SDMMC内核时钟。

  • sdmmc_hclk输入:AHB时钟。

  • sdmmc_it输出:SDMMC全局中断。

  • sdmmc_dataend_trg输出:MDMA的SDMMC数据接收触发信号。

  • SDMMC_CMD:SD/SDIO/MMC卡双向/响应信号。

  • SDMMC_D[7:0]:SD/SDIO/MMC卡双向数据线。

  • SDMMC_CKIN:来自SD/SDIO/MMC卡的外部驱动器的时钟反馈(用于SDR12,SDR25,SDR50和DDR50)。

  • SDMMC_CK:SD/SDIO/MMC卡的时钟。

  • SDMMC_CDIR:SDMMC_CMD信号的SD/SDIO/MMC卡I/O方向指示。

  • SDMMC_D123DIR:SDMMC_D[3:1]数据线的SD/SDIO/MMC卡I/O方向指示。

  • SDMMC_D0DIR:SDMMC_D0数据线的SD/SDIO/MMC卡I/O方向指示。


87.2.2 SDMMC时钟

SDMMC控制器的时钟来源:

  • SDMMC1和SDMMC2时钟源是一样的:

87.2.3 SDMMC1和SDMMC2支持的RAM空间区别

注:大家应用时要特别注意这个问题。

使用STM32H7的SDIO1仅支持AXI SRAM,而SDIO2是AXI,SRAM1, SRAM2和SRAM3都支持的。


87.2.4 SDMMC支持的速度

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

  • SD卡支持1线和4线模式。

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

  • eMMC支持8线模式。

关于这两个数据表,注意以下几点:

  • 驱动SD卡最大支持4bit,驱动eMMC最大支持8bit。

  • 针对信号电压1.8V或者1.2V,STM32H7需要外接专门的PHY芯片才可以驱动。

  • 最大IO翻转限制说的是SDR50,SDR104这种高速通信。平时用的DS,HS这种,无压力,刷满速不成问题。


87.2.5 SDMMC支持UHS-I模式

STM32H7的SDIO外接支持UHS-I 模式 (SDR12, SDR25, SDR50, SDR104和DDR50)需要1.8的电平转换器。STM32H7参考手册给了一个型号ST6G3244ME:


87.2.6 SDMMC自带的DMA控制器IDMA

STM32H7的SDMMC自带了专用的DMA控制器IDMA,支持突发,也支持双缓冲。为什么要自带DMA控制器?主要原因是STM32H7的通用DMA1和DMA2已经无法满足SDMMC高速通信速度。在本教程的第62章专门为大家测试过。通过让SDMMC自带控制器,这个问题就迎刃而解。


87.3 SDMMC总线的HAL库用法

87.3.1 SDMMC总线结构体SD_TypeDef

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 - 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;

87.3.2 SDMMC总线初始化结构体SD_InitTypeDef

下面是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;

87.3.3 SDMMC接SD卡信息结构体HAL_SD_CardInfoTypeDef

下面是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;

87.3.4 SDMMC总线句柄结构体SD_HandleTypeDef

下面是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;

87.4 SDMMC总线源文件stm32h7xx_hal_sd.c

此文件涉及到的函数较多,这里把几个常用的函数做个说明:

  • HAL_SD_Init:用于初始化SD卡。

  • HAL_SD_DeInit:用于复位SD总线初始化。

  • HAL_SD_ReadBlocks:用于读取SD卡数据。

  • HAL_SD_WriteBlocks:用于写入SD卡数据。

  • HAL_SD_ReadBlocks_DMA:用于读取SD卡数据,DMA方式。

  • HAL_SD_WriteBlocks_DMA:用于写入SD卡数据,DMA方式。

  • HAL_SD_Erase:用于擦除SD卡的指定区域。


87.4.1 函数HAL_SD_Init

函数原型:

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;}

87.4.2 函数HAL_SD_DeInit

函数原型:

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   }  /* 关闭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;}

87.4.3 函数HAL_SD_ReadBlocks

函数原型:

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;  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;}

87.4.4 函数HAL_SD_WriteBlocks

函数原型:

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;  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_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;}

87.5 总结

本章节就为大家讲解这么多,更多SDMMC知识可以看STM32H7的参考手册。

转载地址:http://sqjjz.baihongyu.com/

你可能感兴趣的文章
nodejs 运行CMD命令
查看>>
Nodejs+Express+Mysql实现简单用户管理增删改查
查看>>
nodejs+nginx获取真实ip
查看>>
nodejs-mime类型
查看>>
NodeJs——(11)控制权转移next
查看>>
NodeJS、NPM安装配置步骤(windows版本)
查看>>
NodeJS、NPM安装配置步骤(windows版本)
查看>>
nodejs下的express安装
查看>>
nodejs与javascript中的aes加密
查看>>
nodejs中Express 路由统一设置缓存的小技巧
查看>>
nodejs中express的使用
查看>>
Nodejs中搭建一个静态Web服务器,通过读取文件获取响应类型
查看>>
Nodejs中的fs模块的使用
查看>>
NodeJS使用淘宝npm镜像站的各种姿势
查看>>
NodeJs入门知识
查看>>
nodejs包管理工具对比:npm、Yarn、cnpm、npx
查看>>
NodeJs单元测试之 API性能测试
查看>>
nodejs图片转换字节保存
查看>>
nodejs在Liunx上的部署生产方式-PM2
查看>>
nodejs基于art-template模板引擎生成
查看>>