完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第87章       STM32H7的SDMMC总线基础知识和HAL库API

本章节为大家讲解SDMMC(Secure digital input/output MultiMediaCard interface)总线的基础知识和对应的HAL库API。

目录

第87章       STM32H7的SDMMC总线基础知识和HAL库API

87.1 初学者重要提示

87.2 SDMMC总线基础知识

87.2.1 SDMMC总线的硬件框图

87.2.2 SDMMC时钟

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

87.2.4 SDMMC支持的速度

87.2.5 SDMMC支持UHS-I模式

87.2.6 SDMMC自带的DMA控制器IDMA

87.3 SDMMC总线的HAL库用法

87.3.1 SDMMC总线结构体SD_TypeDef

87.3.2 SDMMC总线初始化结构体SD_InitTypeDef

87.3.3 SDMMC接SD卡信息结构体HAL_SD_CardInfoTypeDef

87.3.4 SDMMC总线句柄结构体SD_HandleTypeDef

87.4 SDMMC总线源文件stm32h7xx_hal_sd.c

87.4.1 函数HAL_SD_Init

87.4.2 函数HAL_SD_DeInit

87.4.3 函数HAL_SD_ReadBlocks

87.4.4 函数HAL_SD_WriteBlocks

87.4.5 函数HAL_SD_ReadBlocks_DMA

87.4.6 函数HAL_SD_WriteBlocks_DMA

87.4.7 函数HAL_SD_Erase

87.5 总结


87.1 初学者重要提示

  1. 对于SDMMC控制SD卡或者eMMC,掌握本章的知识点就够用了,更深入的认识可以看STM32H7的参考手册。
  2. 注意,操作SD卡是采用的函数HAL_SD_XXXX,而操作eMMC是采用的函数HAL_MMC_XXXX,也就是说他们采用的函数前缀是不同的。
  3. SD卡官网: www.sdcard.org 。
  4. SDMMC驱动eMMC支持1线,4线和8线模式,其中8线模式的最高速度可达208MB/S,实际速度受IO最大速度限制。
  5. SDMMC驱动SD卡支持1线和4线模式。
  6. STM32H7的SDMMC也支持eMMC:
    • 【普及贴】各个厂家eMMC读写速度,镁光,东芝,三星,ISSI和旺宏http://www.armbbs.cn/forum.php?mod=viewthread&tid=95954
    • H7的8线SDIO DMA驱动eMMC的裸机性能,读43MB/S,写18.8MB/Shttp://www.armbbs.cn/forum.php?mod=viewthread&tid=95953

87.2 SDMMC总线基础知识

87.2.1 SDMMC总线的硬件框图

认识一个外设,最好的方式就是看它的框图,方便我们快速的了解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方向指示。

STM32H7有两个SDMMC控制器,SDMMC1和SDMMC2,这两个控制器支持的功能是一样的。

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卡支持的最大总线速度:

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

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

  • 驱动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_TypeDef
typedef 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。

87.3.2 SDMMC总线初始化结构体SD_InitTypeDef

下面是SDMMC总线的初始化结构体:

#define SD_InitTypeDef      SDMMC_InitTypeDef
typedef 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;

下面将结构体成员逐一做个说明:

  • ClockEdge

用于设置SDMMC的数据或者命令变化的时钟沿。

#define SDMMC_CLOCK_EDGE_RISING               ((uint32_t)0x00000000U)
#define SDMMC_CLOCK_EDGE_FALLING              SDMMC_CLKCR_NEGEDGE
  • ClockPowerSave

用于设置空闲状态,是否输出时钟。

#define SDMMC_CLOCK_POWER_SAVE_DISABLE         ((uint32_t)0x00000000U)
#define SDMMC_CLOCK_POWER_SAVE_ENABLE          SDMMC_CLKCR_PWRSAV
  • BusWide

用于设置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
  • HardwareFlowControl

用于设置时候使能硬件流控制。

#define SDMMC_HARDWARE_FLOW_CONTROL_DISABLE    ((uint32_t)0x00000000U)
#define SDMMC_HARDWARE_FLOW_CONTROL_ENABLE     SDMMC_CLKCR_HWFC_EN
  • ClockDiv

用于设置SDMMC时钟分频,参数范围0到1023。

  • TranceiverPresent

用于设置是否带1.8V收发器。

#define SDMMC_TRANSCEIVER_UNKNOWN             ((uint32_t)0x00000000U)
#define SDMMC_TRANSCEIVER_NOT_PRESENT         ((uint32_t)0x00000001U)
#define SDMMC_TRANSCEIVER_PRESENT             ((uint32_t)0x00000002U)

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;

下面将结构体成员逐一做个说明:

  • CardType

卡类型。

/*!< 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)
  • CardVersion

卡版本。

#define CARD_V1_X                  ((uint32_t)0x00000000U)
#define CARD_V2_X                  ((uint32_t)0x00000001U)
  • Class

卡类型。

  • RelCardAdd

卡相对地址。

  • BlockNbr

整个卡的块数。

  • BlockSize

每个块的字节数。

  • LogBlockNbr

整个卡的逻辑块数。

  • LogBlockSize

逻辑块大小

#define SPI_FIRSTBIT_MSB                              (0x00000000UL)
#define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
  • CardSpeed

用于设置是否使能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 Cardsand <104Mo/s for SDR104, Spec version 3.01        */
#define CARD_ULTRA_HIGH_SPEED    ((uint32_t)0x00000200U)  

87.3.4 SDMMC总线句柄结构体SD_HandleTypeDef

下面是SDMMC句柄结构体:

#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
typedef struct __SD_HandleTypeDef
#else
typedef 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库内部使用和自定义回调函数。

  • SD_TypeDef   *Instance

这个参数是寄存器的例化,方便操作寄存器。

  • SD_InitTypeDef  Init

这个参数在本章节3.2小节已经进行了详细说明。

87.4 SDMMC总线源文件stm32h7xx_hal_sd.c

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

  • HAL_SD_Init
  • HAL_SD_DeInit
  • HAL_SD_ReadBlocks
  • HAL_SD_WriteBlocks
  • HAL_SD_ReadBlocks_DMA
  • HAL_SD_WriteBlocks_DMA
  • HAL_SD_Erase

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

函数描述:

此函数用于初始化SD卡。

函数参数:

  • 第1个参数是SD_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
  • 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

注意事项:

  1. 函数HAL_SD_MspInit用于初始化SD的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
  2. 如果形参hsd的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SD_HandleTypeDef SdHandle。

对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般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 Clockelse 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;
}

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);
#elseHAL_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总线初始化。

函数参数:

  • 第1个参数是SD_HandleTypeDef类型结构体指针变量。
  • 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

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;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卡数据读取。

函数参数:

  • 第1个参数是SD_HandleTypeDef类型结构体指针变量。
  • 第2个参数是接收数据的缓冲地址。
  • 第3个参数是要读取的扇区地址,即从第几个扇区开始读取(512字节为一个扇区)。
  • 第4个参数是读取的扇区数。
  • 第5个参数是传输过程的溢出时间,单位ms。
  • 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

使用举例:

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

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;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卡写入数据。

函数参数:

  • 第1个参数是SD_HandleTypeDef类型结构体指针变量。
  • 第2个参数是要写入到SD卡的数据缓冲地址。
  • 第3个参数是要写入的扇区地址,即从第几个扇区开始写入(512字节为一个扇区)。
  • 第4个参数是读取的扇区数。
  • 第5个参数是传输过程的溢出时间,单位ms。
  • 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

使用举例:

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

87.4.5 函数HAL_SD_ReadBlocks_DMA

函数原型:

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方式。

函数参数:

  • 第1个参数是SD_HandleTypeDef类型结构体指针变量。
  • 第2个参数是接收数据的缓冲地址。
  • 第3个参数是要读取的扇区地址,即从第几个扇区开始读取(512字节为一个扇区)。
  • 第4个参数是读取的扇区数。
  • 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

使用举例:

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

87.4.6 函数HAL_SD_WriteBlocks_DMA

函数原型:

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方式。

函数参数:

  • 第1个参数是SD_HandleTypeDef类型结构体指针变量。
  • 第2个参数是要写入到SD卡的数据缓冲地址。
  • 第3个参数是要写入的扇区地址,即从第几个扇区开始写入(512字节为一个扇区)。
  • 第4个参数是读取的扇区数。
  • 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

使用举例:

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

87.4.7 函数HAL_SD_Erase

函数原型:

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卡擦除。

函数参数:

  • 第1个参数是SD_HandleTypeDef类型结构体指针变量。
  • 第2个参数是擦除的起始扇区地址,地址单位是第几个扇区(512字节为一个扇区)。
  • 第3个参数是擦除的结束扇区地址,地址单位是第几个扇区(512字节为一个扇区)。
  • 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。

使用举例:

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

87.5 总结

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

【STM32H7教程】第87章 STM32H7的SDMMC总线基础知识和HAL库API相关推荐

  1. 【STM32H7教程】第72章 STM32H7的SPI总线基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第72章       STM32H7的SPI总线基础知识和HA ...

  2. 【STM32H7教程】第91章 STM32H7的FDCAN总线基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第91章       STM32H7的FDCAN总线基础知识和 ...

  3. 【STM32H7教程】第78章 STM32H7的QSPI总线基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第78章       STM32H7的QSPI总线基础知识和H ...

  4. 【STM32H7教程】第70章 STM32H7的内部Flash基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第70章       STM32H7的内部Flash基础知识和 ...

  5. 【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第29章       STM32H7的USART串口基础知识和 ...

  6. 【STM32H7教程】第65章 STM32H7的低功耗串口LPUART基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第65章       STM32H7的低功耗串口LPUART基 ...

  7. 【STM32H7教程】第55章 STM32H7的图形加速器DMA2D的基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第55章       STM32H7的图形加速器DMA2D的基 ...

  8. 【STM32H7教程】第63章 STM32H7的高分辨率定时器HRTIM基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第63章       STM32H7的高分辨率定时器HRTIM ...

  9. 【STM32F429开发板用户手册】第40章 STM32F429的LCD控制器LTDC基础知识和HAL库API

    最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255 第40章       STM32F429的LCD控制器LTDC基础 ...

最新文章

  1. 透过率和反射率的关系_光谱仪应用|色彩、透过率等四款测量系统
  2. NetBeans 时事通讯(刊号 # 5 - Apr 29, 2008)
  3. python android自动化元素定位_linux下Appium+Python移动应用自动化测试实战---3.手把手教你定位元素编写测试用例...
  4. Linux档案属性与目录配置
  5. 设备树下的platform 驱动编写
  6. 【雅礼集训2017】字符串【后缀自动机】【数据分治】
  7. 求给定精度的简单交错序列部分和(c语言)
  8. UI设计素材模板|完美日期选择器
  9. 使用Jenkins在Azure Web App上进行ASP.NET Core应用程序的持续集成和部署(CI/CD)–第4天
  10. GDAL书籍中删除数据勘误(C#语言)
  11. C# PDF控件 pdfium、moonpdflib、pdf xchange、福昕、devexpress、aspose、spire
  12. MyBatis运行动态sql及存储过程
  13. 2019年春第八周作业
  14. WPF-将DataGrid控件中的数据导出到Excel
  15. html5趣味智力答题测试,10个趣味智力题及答案
  16. 清除SQL Sever 2008数据库日志
  17. C语言求x的y次方,fun函数实现x的y次方的计算,main函数中调用fun函数
  18. 邮箱163登录入口?邮箱163注册格式是什么?
  19. python conda安装与使用教程
  20. 解决MacBook浏览器打开北京工作居住证系统问题

热门文章

  1. java做网站需要什么_java怎么做网站?java做网站要掌握哪些技术?
  2. 做网站用java 还是php_做网站用java还是php
  3. 66页三级医院智慧医院 信息化建设规划
  4. 医院信息化建设历程(1)概述
  5. 江西专升本考试作弊事件,为什么最近考试作弊事件频发?
  6. 计算机表格判断是否合格操作,关于一些刚开始接触计算机的基础知识(2)
  7. 算法-回溯backtrack
  8. 题解报告:hdu 2188 悼念512汶川大地震遇难同胞——选拔志愿者(巴什博弈)
  9. DECIMAL Data Type Characteristics
  10. 4PAM的误码率仿真