你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的SDMMC总线基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-11-6 23:38
87.1 初学者重要提示
  对于SDMMC控制SD卡或者eMMC,掌握本章的知识点就够用了,更深入的认识可以看STM32H7的参考手册。
  注意,操作SD卡是采用的函数HAL_SD_XXXX,而操作eMMC是采用的函数HAL_MMC_XXXX,也就是说他们采用的函数前缀是不同的。
  SDMMC驱动eMMC支持1线,4线和8线模式,其中8线模式的最高速度可达208MB/S,实际速度受IO最大速度限制。
  SDMMC驱动SD卡支持1线和4线模式。
  STM32H7的SDMMC也支持eMMC:
  
87.2 SDMMC总线基础知识
87.2.1 SDMMC总线的硬件框图
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SDMMC的基本功能,然后再看手册了解细节。

6eea62abe623396815a50adc87205b83.png


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

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控制器的时钟来源:

676ec31792fcb80bee640ed979d48084.png


SDMMC1和SDMMC2时钟源是一样的:

79b1c69986d1ee5bc090bf1676f396fd.png


87.2.3 SDMMC1和SDMMC2支持的RAM空间区别
注:大家应用时要特别注意这个问题。

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

6a5491d2f4a8740d838af58d034b7597.png


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

b70ce31107b38ea820dbc28c3caec38e.png


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

843bf7a054944ba7d5d137ca84e1d4ed.png


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

  驱动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:

2b8e4430b8a60dc5a1b342d7c7f75f52.png


85f975745619c9afc64f8889289dad58.png


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中可以找到这个类型定义:

  1. #define SD_TypeDef          SDMMC_TypeDef
  2. typedef struct
  3. {
  4.   __IO uint32_t POWER;          /*!< SDMMC power control register,             Address offset: 0x00  */
  5.   __IO uint32_t CLKCR;          /*!< SDMMC clock control register,             Address offset: 0x04  */
  6.   __IO uint32_t ARG;            /*!< SDMMC argument register,                  Address offset: 0x08  */
  7.   __IO uint32_t CMD;            /*!< SDMMC command register,                   Address offset: 0x0C  */
  8.   __I uint32_t  RESPCMD;        /*!< SDMMC command response register,          Address offset: 0x10  */
  9.   __I uint32_t  RESP1;          /*!< SDMMC response 1 register,                Address offset: 0x14  */
  10.   __I uint32_t  RESP2;          /*!< SDMMC response 2 register,                Address offset: 0x18  */
  11.   __I uint32_t  RESP3;          /*!< SDMMC response 3 register,                Address offset: 0x1C  */
  12.   __I uint32_t  RESP4;          /*!< SDMMC response 4 register,                Address offset: 0x20  */
  13.   __IO uint32_t DTIMER;         /*!< SDMMC data timer register,                Address offset: 0x24  */
  14.   __IO uint32_t DLEN;           /*!< SDMMC data length register,               Address offset: 0x28  */
  15.   __IO uint32_t DCTRL;          /*!< SDMMC data control register,              Address offset: 0x2C  */
  16.   __I uint32_t  DCOUNT;         /*!< SDMMC data counter register,              Address offset: 0x30  */
  17.   __I uint32_t  STA;            /*!< SDMMC status register,                    Address offset: 0x34  */
  18.   __IO uint32_t ICR;            /*!< SDMMC interrupt clear register,           Address offset: 0x38  */
  19.   __IO uint32_t MASK;           /*!< SDMMC mask register,                      Address offset: 0x3C  */
  20.   __IO uint32_t ACKTIME;        /*!< SDMMC Acknowledgement timer register,     Address offset: 0x40  */
  21.   uint32_t      RESERVED0[3];   /*!< Reserved, 0x44 - 0x4C - 0x4C                                    */
  22.   __IO uint32_t IDMACTRL;       /*!< SDMMC DMA control register,               Address offset: 0x50  */
  23.   __IO uint32_t IDMABSIZE;      /*!< SDMMC DMA buffer size register,           Address offset: 0x54  */
  24.   __IO uint32_t IDMABASE0;      /*!< SDMMC DMA buffer 0 base address register, Address offset: 0x58  */
  25.   __IO uint32_t IDMABASE1;      /*!< SDMMC DMA buffer 1 base address register, Address offset: 0x5C  */
  26.   uint32_t      RESERVED1[8];   /*!< Reserved, 0x60-0x7C                                             */
  27.   __IO uint32_t FIFO;           /*!< SDMMC data FIFO register,                 Address offset: 0x80  */
  28.   uint32_t      RESERVED2[222]; /*!< Reserved, 0x84-0x3F8                                            */
  29.   __IO uint32_t IPVR;           /*!< SDMMC data FIFO register,                 Address offset: 0x3FC */
  30. } SDMMC_TypeDef;
复制代码

这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。

__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:

  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

下面我们看下SDMMC的定义,在stm32h743xx.h文件。

  1. #define PERIPH_BASE           (0x40000000UL)
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000UL)
  3. #define D2_AHB2PERIPH_BASE    (PERIPH_BASE + 0x08020000UL)

  4. #define SDMMC1_BASE           (D1_AHB1PERIPH_BASE + 0x7000UL)
  5. #define SDMMC2_BASE           (D2_AHB2PERIPH_BASE + 0x2400UL)

  6. #define SDMMC1              ((SDMMC_TypeDef *) SDMMC1_BASE)
  7. #define SDMMC2              ((SDMMC_TypeDef *) SDMMC2_BASE) <----- 展开这个宏,(SDMMC_TypeDef *)0x48022400
复制代码

我们访问SDMMC1的CMD寄存器可以采用这种形式:SDMMC1->CMD = 0。

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

  1. #define SD_InitTypeDef      SDMMC_InitTypeDef
  2. typedef struct
  3. {
  4.   uint32_t ClockEdge;            
  5.   uint32_t ClockPowerSave;      
  6.   uint32_t BusWide;            
  7.   uint32_t HardwareFlowControl;  
  8.   uint32_t ClockDiv;            
  9. #if (USE_SD_TRANSCEIVER != 0U)
  10.   uint32_t TranceiverPresent;   
  11. #endif
  12. }SDMMC_InitTypeDef;
复制代码

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

  ClockEdge
用于设置SDMMC的数据或者命令变化的时钟沿。
  1. #define SDMMC_CLOCK_EDGE_RISING               ((uint32_t)0x00000000U)
  2. #define SDMMC_CLOCK_EDGE_FALLING              SDMMC_CLKCR_NEGEDGE
复制代码

  ClockPowerSave
用于设置空闲状态,是否输出时钟。
  1. #define SDMMC_CLOCK_POWER_SAVE_DISABLE         ((uint32_t)0x00000000U)
  2. #define SDMMC_CLOCK_POWER_SAVE_ENABLE          SDMMC_CLKCR_PWRSAV
复制代码

  BusWide
用于设置SDMMC总线位宽。
  1. #define SDMMC_BUS_WIDE_1B                      ((uint32_t)0x00000000U)
  2. #define SDMMC_BUS_WIDE_4B                      SDMMC_CLKCR_WIDBUS_0
  3. #define SDMMC_BUS_WIDE_8B                      SDMMC_CLKCR_WIDBUS_1
复制代码

  HardwareFlowControl
用于设置时候使能硬件流控制。
  1. #define SDMMC_HARDWARE_FLOW_CONTROL_DISABLE    ((uint32_t)0x00000000U)
  2. #define SDMMC_HARDWARE_FLOW_CONTROL_ENABLE     SDMMC_CLKCR_HWFC_EN
复制代码

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

  TranceiverPresent
用于设置是否带1.8V收发器。
  1. #define SDMMC_TRANSCEIVER_UNKNOWN             ((uint32_t)0x00000000U)
  2. #define SDMMC_TRANSCEIVER_NOT_PRESENT         ((uint32_t)0x00000001U)
  3. #define SDMMC_TRANSCEIVER_PRESENT             ((uint32_t)0x00000002U)
复制代码

87.3.3 SDMMC接SD卡信息结构体HAL_SD_CardInfoTypeDef
下面是SDMMC总线的卡信息结构体:
  1. typedef struct
  2. {
  3.   uint32_t CardType;                     /*!< Specifies the card Type                         */
  4.   uint32_t CardVersion;                  /*!< Specifies the card version                      */
  5.   uint32_t Class;                        /*!< Specifies the class of the card class           */
  6.   uint32_t RelCardAdd;                   /*!< Specifies the Relative Card Address             */
  7.   uint32_t BlockNbr;                     /*!< Specifies the Card Capacity in blocks           */
  8.   uint32_t BlockSize;                    /*!< Specifies one block size in bytes               */
  9.   uint32_t LogBlockNbr;                  /*!< Specifies the Card logical Capacity in blocks   */
  10.   uint32_t LogBlockSize;                 /*!< Specifies logical block size in bytes           */
  11.   uint32_t CardSpeed;                    /*!< Specifies the card Speed                        */
  12. }HAL_SD_CardInfoTypeDef;
复制代码

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

CardType
卡类型。
  1. /*!< SD Standard Capacity <2Go                        */
  2. #define CARD_SDSC                  ((uint32_t)0x00000000U)
  3. /*!< SD High Capacity <32Go, SD Extended Capacity <2To  */
  4. #define CARD_SDHC_SDXC             ((uint32_t)0x00000001U)  
  5. #define CARD_SECURED               ((uint32_t)0x00000003U)
复制代码

  CardVersion
卡版本。
  1. #define CARD_V1_X                  ((uint32_t)0x00000000U)
  2. #define CARD_V2_X                  ((uint32_t)0x00000001U)
复制代码

  Class
卡类型。

  RelCardAdd
卡相对地址。

  BlockNbr
整个卡的块数。

  BlockSize
每个块的字节数。

  LogBlockNbr
整个卡的逻辑块数。

  LogBlockSize
逻辑块大小
  1. #define SPI_FIRSTBIT_MSB                              (0x00000000UL)
  2. #define SPI_FIRSTBIT_LSB                              SPI_CFG2_LSBFRST
复制代码

CardSpeed
用于设置是否使能SPI总线的TI模式。
  1. /*!< Normal Speed Card <12.5Mo/s , Spec Version 1.01    */
  2. #define CARD_NORMAL_SPEED        ((uint32_t)0x00000000U)  

  3. /*!< High Speed Card <25Mo/s , Spec version 2.00        */
  4. #define CARD_HIGH_SPEED          ((uint32_t)0x00000100U)

  5. /*!< UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards
  6.      and <104Mo/s for SDR104, Spec version 3.01        */
  7. #define CARD_ULTRA_HIGH_SPEED    ((uint32_t)0x00000200U)  
复制代码

87.3.4 SDMMC总线句柄结构体SD_HandleTypeDef
下面是SDMMC句柄结构体:

  1. #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
  2. typedef struct __SD_HandleTypeDef
  3. #else
  4. typedef struct
  5. #endif /* USE_HAL_SD_REGISTER_CALLBACKS */
  6. {
  7.   SD_TypeDef                   *Instance;        /*!< SD registers base address           */
  8.   SD_InitTypeDef               Init;             /*!< SD required parameters              */
  9.   HAL_LockTypeDef              Lock;             /*!< SD locking object                   */
  10.   uint8_t                      *pTxBuffPtr;      /*!< Pointer to SD Tx transfer Buffer    */
  11.   uint32_t                     TxXferSize;       /*!< SD Tx Transfer size                 */
  12.   uint8_t                      *pRxBuffPtr;      /*!< Pointer to SD Rx transfer Buffer    */
  13.   uint32_t                     RxXferSize;       /*!< SD Rx Transfer size                 */
  14.   __IO uint32_t                Context;          /*!< SD transfer context                 */
  15.   __IO HAL_SD_StateTypeDef     State;            /*!< SD card State                       */
  16.   __IO uint32_t                ErrorCode;        /*!< SD Card Error codes                 */
  17.   HAL_SD_CardInfoTypeDef       SdCard;           /*!< SD Card information                 */
  18.   uint32_t                     CSD[4];           /*!< SD card specific data table         */
  19.   uint32_t                     CID[4];           /*!< SD card identification number table */

  20. #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
  21.   void (* TxCpltCallback)                 (struct __SD_HandleTypeDef *hsd);
  22.   void (* RxCpltCallback)                 (struct __SD_HandleTypeDef *hsd);
  23.   void (* ErrorCallback)                  (struct __SD_HandleTypeDef *hsd);
  24.   void (* AbortCpltCallback)              (struct __SD_HandleTypeDef *hsd);
  25.   void (* Read_DMADblBuf0CpltCallback)    (struct __SD_HandleTypeDef *hsd);
  26.   void (* Read_DMADblBuf1CpltCallback)    (struct __SD_HandleTypeDef *hsd);
  27.   void (* Write_DMADblBuf0CpltCallback)   (struct __SD_HandleTypeDef *hsd);
  28.   void (* Write_DMADblBuf1CpltCallback)   (struct __SD_HandleTypeDef *hsd);
  29. #if (USE_SD_TRANSCEIVER != 0U)
  30.   void (* DriveTransceiver_1_8V_Callback) (FlagStatus status);
  31. #endif /* USE_SD_TRANSCEIVER */

  32.   void (* MspInitCallback)                (struct __SD_HandleTypeDef *hsd);
  33.   void (* MspDeInitCallback)              (struct __SD_HandleTypeDef *hsd);
  34. #endif /* USE_HAL_SD_REGISTER_CALLBACKS */
  35. }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
函数原型:

  1. HAL_StatusTypeDef HAL_SD_Init(SD_HandleTypeDef *hsd)
  2. {
  3.   HAL_SD_CardStatusTypeDef CardStatus;
  4.   uint32_t speedgrade, unitsize;
  5.   uint32_t tickstart;

  6.   /* 检查句柄是否有效 */
  7.   if(hsd == NULL)
  8.   {
  9.     return HAL_ERROR;
  10.   }

  11.   /* 检查参数 */
  12.   assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance));
  13.   assert_param(IS_SDMMC_CLOCK_EDGE(hsd->Init.ClockEdge));
  14.   assert_param(IS_SDMMC_CLOCK_POWER_SAVE(hsd->Init.ClockPowerSave));
  15.   assert_param(IS_SDMMC_BUS_WIDE(hsd->Init.BusWide));
  16.   assert_param(IS_SDMMC_HARDWARE_FLOW_CONTROL(hsd->Init.HardwareFlowControl));
  17.   assert_param(IS_SDMMC_CLKDIV(hsd->Init.ClockDiv));

  18.   if(hsd->State == HAL_SD_STATE_RESET)
  19.   {
  20.     /* 开锁 */
  21.     hsd->Lock = HAL_UNLOCKED;

  22. #if (USE_SD_TRANSCEIVER != 0U)
  23.     /* 兼容 */
  24.     if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_UNKNOWN)
  25.     {
  26.       hsd->Init.TranceiverPresent = SDMMC_TRANSCEIVER_PRESENT;
  27.     }
  28. #endif
  29. #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
  30.     /* 复位回调 */
  31.     hsd->TxCpltCallback    = HAL_SD_TxCpltCallback;
  32.     hsd->RxCpltCallback    = HAL_SD_RxCpltCallback;
  33.     hsd->ErrorCallback     = HAL_SD_ErrorCallback;
  34.     hsd->AbortCpltCallback = HAL_SD_AbortCallback;
  35.     hsd->Read_DMADblBuf0CpltCallback = HAL_SDEx_Read_DMADoubleBuf0CpltCallback;
  36.     hsd->Read_DMADblBuf1CpltCallback = HAL_SDEx_Read_DMADoubleBuf1CpltCallback;
  37.     hsd->Write_DMADblBuf0CpltCallback = HAL_SDEx_Write_DMADoubleBuf0CpltCallback;
  38.     hsd->Write_DMADblBuf1CpltCallback = HAL_SDEx_Write_DMADoubleBuf1CpltCallback;
  39. #if (USE_SD_TRANSCEIVER != 0U)
  40.     if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT)
  41.     {
  42.       hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback;
  43.     }
  44. #endif

  45.     if(hsd->MspInitCallback == NULL)
  46.     {
  47.       hsd->MspInitCallback = HAL_SD_MspInit;
  48.     }

  49.     /* 初始化底层 */
  50.     hsd->MspInitCallback(hsd);
  51. #else
  52.     /* 初始化底层硬件 GPIO, CLOCK, CORTEX...etc */
  53.     HAL_SD_MspInit(hsd);
  54. #endif /* USE_HAL_SD_REGISTER_CALLBACKS */
  55.   }

  56.   hsd->State = HAL_SD_STATE_BUSY;

  57.   /* 初始化卡参数 */
  58.   if (HAL_SD_InitCard(hsd) != HAL_OK)
  59.   {
  60.     return HAL_ERROR;
  61.   }

  62.   if( HAL_SD_GetCardStatus(hsd, &CardStatus) != HAL_OK)
  63.   {
  64.     return HAL_ERROR;
  65.   }
  66.   /* 获取卡速度等信息 */
  67.   speedgrade = CardStatus.UhsSpeedGrade;
  68.   unitsize = CardStatus.UhsAllocationUnitSize;
  69.   if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U)))
  70.   {
  71.     hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED;
  72.   }
  73.   else
  74.   {
  75.     if (hsd->SdCard.CardType == CARD_SDHC_SDXC)
  76.     {
  77.       hsd->SdCard.CardSpeed  = CARD_HIGH_SPEED;
  78.     }
  79.     else
  80.     {
  81.       hsd->SdCard.CardSpeed  = CARD_NORMAL_SPEED;
  82.     }

  83.   }
  84.   /* 配置总线位宽 */
  85.   if(HAL_SD_ConfigWideBusOperation(hsd, hsd->Init.BusWide) != HAL_OK)
  86.   {
  87.     return HAL_ERROR;
  88.   }

  89.   /* 验证卡初始化后是否就绪 */
  90.   tickstart = HAL_GetTick();
  91.   while((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER))
  92.   {
  93.     if((HAL_GetTick()-tickstart) >=  SDMMC_DATATIMEOUT)
  94.     {
  95.       hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT;
  96.       hsd->State= HAL_SD_STATE_READY;
  97.       return HAL_TIMEOUT;
  98.     }
  99.   }

  100.   hsd->ErrorCode = HAL_SD_ERROR_NONE;

  101.   hsd->Context = SD_CONTEXT_NONE;

  102.   hsd->State = HAL_SD_STATE_READY;

  103.   return HAL_OK;
  104. }
复制代码

函数描述:

此函数用于初始化SD卡。

函数参数:

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

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

解决办法有三

方法1:用户自己初始化SD和涉及到的GPIO等。

方法2:定义SD_HandleTypeDef SdHandle为全局变量。

方法3:下面的方法

  1. if(HAL_SD_DeInit(&SdHandle) != HAL_OK)
  2. {
  3.     Error_Handler();
  4. }  
  5. if(HAL_SD_Init(&SdHandle) != HAL_OK)
  6. {
  7.     Error_Handler();
  8. }
复制代码

使用举例:

  1. SD_HandleTypeDef uSdHandle;

  2. uSdHandle.Instance = SDMMC1;

  3. /* if CLKDIV = 0 then SDMMC Clock frequency = SDMMC Kernel Clock
  4.      else SDMMC Clock frequency = SDMMC Kernel Clock / [2 * CLKDIV].
  5.      200MHz / (2*2) = 50MHz
  6. */
  7. uSdHandle.Init.ClockDiv            = 2;
  8. uSdHandle.Init.ClockPowerSave      = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  9. uSdHandle.Init.ClockEdge           = SDMMC_CLOCK_EDGE_RISING;
  10. uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  11. uSdHandle.Init.BusWide             = SDMMC_BUS_WIDE_4B;
  12. if(HAL_SD_Init(&uSdHandle) != HAL_OK)
  13. {
  14.    sd_state = MSD_ERROR;
  15. }
复制代码

87.4.2 函数HAL_SD_DeInit
函数原型:

  1. HAL_StatusTypeDef HAL_SD_DeInit(SD_HandleTypeDef *hsd)
  2. {
  3.   /* 检查SD卡句柄是否有效 */
  4.   if(hsd == NULL)
  5.   {
  6.     return HAL_ERROR;
  7.   }

  8.   /* 检查参数 */
  9.   assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance));

  10.   hsd->State = HAL_SD_STATE_BUSY;

  11. #if (USE_SD_TRANSCEIVER != 0U)
  12.   /* 关闭1.8V模式 */
  13.   if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT)
  14.   {
  15. #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
  16.     if(hsd->DriveTransceiver_1_8V_Callback == NULL)
  17.     {
  18.       hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback;
  19.     }
  20.     hsd->DriveTransceiver_1_8V_Callback(RESET);
  21. #else
  22.     HAL_SD_DriveTransceiver_1_8V_Callback(RESET);
  23. #endif
  24.   }                                                                        
  25. #endif

  26.   /* 关闭SD卡电源 */
  27.   SD_PowerOFF(hsd);

  28. #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
  29.   if(hsd->MspDeInitCallback == NULL)
  30.   {
  31.     hsd->MspDeInitCallback = HAL_SD_MspDeInit;
  32.   }

  33.   /* 复位底层硬件 */
  34.   hsd->MspDeInitCallback(hsd);
  35. #else
  36.   /* 复位底层硬件 */
  37.   HAL_SD_MspDeInit(hsd);
  38. #endif

  39.   hsd->ErrorCode = HAL_SD_ERROR_NONE;
  40.   hsd->State = HAL_SD_STATE_RESET;

  41.   return HAL_OK;
  42. }
复制代码

函数描述:

用于复位SD总线初始化。

函数参数:

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

  1. HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
  2. {
  3.   SDMMC_DataInitTypeDef config;
  4.   uint32_t errorstate;
  5.   uint32_t tickstart = HAL_GetTick();
  6.   uint32_t count, data, dataremaining;
  7.   uint32_t add = BlockAdd;
  8.   uint8_t *tempbuff = pData;

  9.   if(NULL == pData)
  10.   {
  11.     hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
  12.     return HAL_ERROR;
  13.   }

  14.   if(hsd->State == HAL_SD_STATE_READY)
  15.   {
  16.     hsd->ErrorCode = HAL_SD_ERROR_NONE;

  17.     if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
  18.     {
  19.       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
  20.       return HAL_ERROR;
  21.     }

  22.     hsd->State = HAL_SD_STATE_BUSY;

  23.     /* 初始化数据控制寄存器 */
  24.     hsd->Instance->DCTRL = 0U;

  25.     if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
  26.     {
  27.       add *= 512U;
  28.     }

  29.     /* 配置SD DPSM (Data Path State Machine) */
  30.     config.DataTimeOut   = SDMMC_DATATIMEOUT;
  31.     config.DataLength    = NumberOfBlocks * BLOCKSIZE;
  32.     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
  33.     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
  34.     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
  35.     config.DPSM          = SDMMC_DPSM_DISABLE;
  36.     (void)SDMMC_ConfigData(hsd->Instance, &config);
  37.     __SDMMC_CMDTRANS_ENABLE( hsd->Instance);

  38.     /* 查询方式块读取 */
  39.     if(NumberOfBlocks > 1U)
  40.     {
  41.       hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK;

  42.       /* 多块读取命令 */
  43.       errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
  44.     }
  45.     else
  46.     {
  47.       hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK;

  48.       /* 单块读取命令 */
  49.       errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);
  50.     }
  51.     if(errorstate != HAL_SD_ERROR_NONE)
  52.     {
  53.       /* 清除所有静态标志 */
  54.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  55.       hsd->ErrorCode |= errorstate;
  56.       hsd->State = HAL_SD_STATE_READY;
  57.       hsd->Context = SD_CONTEXT_NONE;
  58.       return HAL_ERROR;
  59.     }

  60.     /* 查询SDMMC标志 */
  61.     dataremaining = config.DataLength;
  62.     while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND))
  63.     {
  64.       if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) && (dataremaining >= 32U))
  65.       {
  66.         /* 从SDMMC Rx FIFO读取数据 */
  67.         for(count = 0U; count < 8U; count++)
  68.         {
  69.           data = SDMMC_ReadFIFO(hsd->Instance);
  70.           *tempbuff = (uint8_t)(data & 0xFFU);
  71.           tempbuff++;
  72.           *tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
  73.           tempbuff++;
  74.           *tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
  75.           tempbuff++;
  76.           *tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
  77.           tempbuff++;
  78.         }
  79.         dataremaining -= 32U;
  80.       }

  81.       if(((HAL_GetTick()-tickstart) >=  Timeout) || (Timeout == 0U))
  82.       {
  83.         /* 清除所有静态标志 */
  84.         __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  85.         hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
  86.         hsd->State= HAL_SD_STATE_READY;
  87.         hsd->Context = SD_CONTEXT_NONE;
  88.         return HAL_TIMEOUT;
  89.       }
  90.     }
  91.     __SDMMC_CMDTRANS_DISABLE( hsd->Instance);

  92.     /* 多块读取发送停止传输命令 */
  93.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U))
  94.     {
  95.       if(hsd->SdCard.CardType != CARD_SECURED)
  96.       {
  97.         /* 发送停止传输命令 */
  98.         errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
  99.         if(errorstate != HAL_SD_ERROR_NONE)
  100.         {
  101.           /* 清除所有静态标志 */
  102.           __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  103.           hsd->ErrorCode |= errorstate;
  104.           hsd->State = HAL_SD_STATE_READY;
  105.           hsd->Context = SD_CONTEXT_NONE;
  106.           return HAL_ERROR;
  107.         }
  108.       }
  109.     }

  110.     /* 获取错误状态 */
  111.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT))
  112.     {
  113.       /* 清除所有静态标志 */
  114.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  115.       hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
  116.       hsd->State = HAL_SD_STATE_READY;
  117.       hsd->Context = SD_CONTEXT_NONE;
  118.       return HAL_ERROR;
  119.     }
  120.     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL))
  121.     {
  122.       /* 清除所有静态标志 */
  123.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  124.       hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
  125.       hsd->State = HAL_SD_STATE_READY;
  126.       hsd->Context = SD_CONTEXT_NONE;
  127.       return HAL_ERROR;
  128.     }
  129.     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR))
  130.     {
  131.       /* 清除所有静态标志 */
  132.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  133.       hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN;
  134.       hsd->State = HAL_SD_STATE_READY;
  135.       hsd->Context = SD_CONTEXT_NONE;
  136.       return HAL_ERROR;
  137.     }
  138.     else
  139.     {
  140.       /* 什么都不做 */
  141.     }

  142.     /* 清除所有静态标志 */
  143.     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);

  144.     hsd->State = HAL_SD_STATE_READY;

  145.     return HAL_OK;
  146.   }
  147.   else
  148.   {
  149.     hsd->ErrorCode |= HAL_SD_ERROR_BUSY;
  150.     return HAL_ERROR;
  151.   }
  152. }
复制代码

函数描述:

此函数主要用于SD卡数据读取。

函数参数:

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

  1. /**
  2.   * @brief  Reads block(s) from a specified address in an SD card, in polling mode.
  3.   * @param  pData: Pointer to the buffer that will contain the data to transmit
  4.   * @param  ReadAddr: Address from where data is to be read
  5.   * @param  NumOfBlocks: Number of SD blocks to read
  6.   * @param  Timeout: Timeout for read operation
  7.   * @retval SD status
  8.   */
  9. uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout)
  10. {

  11.   if( HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) == HAL_OK)
  12.   {
  13.     return MSD_OK;
  14.   }
  15.   else
  16.   {
  17.     return MSD_ERROR;
  18.   }

  19. }
复制代码

87.4.4 函数HAL_SD_WriteBlocks
函数原型:

  1. HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
  2. {
  3.   SDMMC_DataInitTypeDef config;
  4.   uint32_t errorstate;
  5.   uint32_t tickstart = HAL_GetTick();
  6.   uint32_t count, data, dataremaining;
  7.   uint32_t add = BlockAdd;
  8.   uint8_t *tempbuff = pData;

  9.   if(NULL == pData)
  10.   {
  11.     hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
  12.     return HAL_ERROR;
  13.   }

  14.   if(hsd->State == HAL_SD_STATE_READY)
  15.   {
  16.     hsd->ErrorCode = HAL_SD_ERROR_NONE;

  17.     if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
  18.     {
  19.       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
  20.       return HAL_ERROR;
  21.     }

  22.     hsd->State = HAL_SD_STATE_BUSY;

  23.     /* 初始化数据控制寄存器 */
  24.     hsd->Instance->DCTRL = 0U;

  25.     if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
  26.     {
  27.       add *= 512U;
  28.     }

  29.     /* 配置SD DPSM */
  30.     config.DataTimeOut   = SDMMC_DATATIMEOUT;
  31.     config.DataLength    = NumberOfBlocks * BLOCKSIZE;
  32.     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
  33.     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
  34.     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
  35.     config.DPSM          = SDMMC_DPSM_DISABLE;
  36.     (void)SDMMC_ConfigData(hsd->Instance, &config);
  37.     __SDMMC_CMDTRANS_ENABLE( hsd->Instance);

  38.     /* 查询方式块写操作 */
  39.     if(NumberOfBlocks > 1U)
  40.     {
  41.       hsd->Context = SD_CONTEXT_WRITE_MULTIPLE_BLOCK;

  42.       /* 写多块命令 */
  43.       errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
  44.     }
  45.     else
  46.     {
  47.       hsd->Context = SD_CONTEXT_WRITE_SINGLE_BLOCK;

  48.       /* 写单块命令 */
  49.       errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);
  50.     }
  51.     if(errorstate != HAL_SD_ERROR_NONE)
  52.     {
  53.       /* 清除所有静态命令 */
  54.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  55.       hsd->ErrorCode |= errorstate;
  56.       hsd->State = HAL_SD_STATE_READY;
  57.       hsd->Context = SD_CONTEXT_NONE;
  58.       return HAL_ERROR;
  59.     }

  60.     /* 查询方式块写操作 */
  61.     dataremaining = config.DataLength;
  62.     while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND))
  63.     {
  64.       if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) && (dataremaining >= 32U))
  65.       {
  66.         /* 写数据到SDMMC Tx FIFO */
  67.         for(count = 0U; count < 8U; count++)
  68.         {
  69.           data = (uint32_t)(*tempbuff);
  70.           tempbuff++;
  71.           data |= ((uint32_t)(*tempbuff) << 8U);
  72.           tempbuff++;
  73.           data |= ((uint32_t)(*tempbuff) << 16U);
  74.           tempbuff++;
  75.           data |= ((uint32_t)(*tempbuff) << 24U);
  76.           tempbuff++;
  77.           (void)SDMMC_WriteFIFO(hsd->Instance, &data);
  78.         }
  79.         dataremaining -= 32U;
  80.       }

  81.       if(((HAL_GetTick()-tickstart) >=  Timeout) || (Timeout == 0U))
  82.       {
  83.         /* 清除所有静态标志 */
  84.         __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  85.         hsd->ErrorCode |= errorstate;
  86.         hsd->State = HAL_SD_STATE_READY;
  87.         hsd->Context = SD_CONTEXT_NONE;
  88.         return HAL_TIMEOUT;
  89.       }
  90.     }
  91.     __SDMMC_CMDTRANS_DISABLE( hsd->Instance);

  92.     /* 多块写操作,发送停止传输命令 */
  93.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U))
  94.     {
  95.       if(hsd->SdCard.CardType != CARD_SECURED)
  96.       {
  97.         /* 发送停止传输命令 */
  98.         errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
  99.         if(errorstate != HAL_SD_ERROR_NONE)
  100.         {
  101.           /* 清除所有静态传输标志 */
  102.           __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  103.           hsd->ErrorCode |= errorstate;
  104.           hsd->State = HAL_SD_STATE_READY;
  105.           hsd->Context = SD_CONTEXT_NONE;
  106.           return HAL_ERROR;
  107.         }
  108.       }
  109.     }

  110.     /* Get error state */
  111.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT))
  112.     {
  113.       /* 清除所有静态传输标志 */
  114.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  115.       hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
  116.       hsd->State = HAL_SD_STATE_READY;
  117.       hsd->Context = SD_CONTEXT_NONE;
  118.       return HAL_ERROR;
  119.     }
  120.     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL))
  121.     {
  122.       /* 清除所有静态传输标志 */
  123.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  124.       hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
  125.       hsd->State = HAL_SD_STATE_READY;
  126.       hsd->Context = SD_CONTEXT_NONE;
  127.       return HAL_ERROR;
  128.     }
  129.     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR))
  130.     {
  131.       /* 清除所有静态传输标志 */
  132.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  133.       hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN;
  134.       hsd->State = HAL_SD_STATE_READY;
  135.       hsd->Context = SD_CONTEXT_NONE;
  136.       return HAL_ERROR;
  137.     }
  138.     else
  139.     {
  140.       /* 什么都不做 */
  141.     }

  142.       /* 清除所有静态传输标志 */
  143.     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);

  144.     hsd->State = HAL_SD_STATE_READY;

  145.     return HAL_OK;
  146.   }
  147.   else
  148.   {
  149.     hsd->ErrorCode |= HAL_SD_ERROR_BUSY;
  150.     return HAL_ERROR;
  151.   }
  152. }
复制代码

函数描述:

此函数主要用于向SD卡写入数据。

函数参数:

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

  1. /**
  2.   * @brief  Writes block(s) to a specified address in an SD card, in polling mode.
  3.   * @param  pData: Pointer to the buffer that will contain the data to transmit
  4.   * @param  WriteAddr: Address from where data is to be written
  5.   * @param  NumOfBlocks: Number of SD blocks to write
  6.   * @param  Timeout: Timeout for write operation
  7.   * @retval SD status
  8.   */
  9. uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout)
  10. {

  11.   if( HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) == HAL_OK)
  12.   {
  13.     return MSD_OK;
  14.   }
  15.   else
  16.   {
  17.     return MSD_ERROR;
  18.   }
  19. }
复制代码

87.4.5 函数HAL_SD_ReadBlocks_DMA
函数原型:

  1. HAL_StatusTypeDef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
  2. {
  3.   SDMMC_DataInitTypeDef config;
  4.   uint32_t errorstate;
  5.   uint32_t add = BlockAdd;

  6.   if(NULL == pData)
  7.   {
  8.     hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
  9.     return HAL_ERROR;
  10.   }

  11.   if(hsd->State == HAL_SD_STATE_READY)
  12.   {
  13.     hsd->ErrorCode = HAL_SD_ERROR_NONE;

  14.     if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
  15.     {
  16.       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
  17.       return HAL_ERROR;
  18.     }

  19.     hsd->State = HAL_SD_STATE_BUSY;

  20.   /* 初始化数据控制寄存器 */
  21.     hsd->Instance->DCTRL = 0U;

  22.     hsd->pRxBuffPtr = pData;
  23.     hsd->RxXferSize = BLOCKSIZE * NumberOfBlocks;

  24.     if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
  25.     {
  26.       add *= 512U;
  27.     }

  28.   /* 配置SD DPSM (Data Path State Machine) */
  29.     config.DataTimeOut   = SDMMC_DATATIMEOUT;
  30.     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
  31.     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
  32.     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_SDMMC;
  33.     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
  34.     config.DPSM          = SDMMC_DPSM_DISABLE;
  35.     (void)SDMMC_ConfigData(hsd->Instance, &config);

  36.     __SDMMC_CMDTRANS_ENABLE( hsd->Instance);
  37.     hsd->Instance->IDMABASE0 = (uint32_t) pData ;
  38.     hsd->Instance->IDMACTRL  = SDMMC_ENABLE_IDMA_SINGLE_BUFF;

  39.   /* DMA方式读取多个块 */
  40.     if(NumberOfBlocks > 1U)
  41.     {
  42.       hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);

  43.    /* DMA方式读取多块命令 */
  44.       errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
  45.     }
  46.     else
  47.     {
  48.       hsd->Context = (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_DMA);

  49.    /* 读取单块命令 */
  50.       errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);
  51.     }
  52.     if(errorstate != HAL_SD_ERROR_NONE)
  53.     {
  54.    /* 清除所有静态标志 */
  55.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  56.       hsd->ErrorCode |= errorstate;
  57.       hsd->State = HAL_SD_STATE_READY;
  58.       hsd->Context = SD_CONTEXT_NONE;
  59.       return HAL_ERROR;
  60.     }

  61.   /* 使能传输中断 */
  62.     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND));


  63.     return HAL_OK;
  64.   }
  65.   else
  66.   {
  67.     return HAL_BUSY;
  68.   }
  69. }
复制代码

函数描述:

此函数主要用于SD卡数据读取,DMA方式。

函数参数:

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

  1. /**
  2. * @brief  Reads block(s) from a specified address in an SD card, in DMA mode.
  3. * @param  pData: Pointer to the buffer that will contain the data to transmit
  4. * @param  ReadAddr: Address from where data is to be read
  5. * @param  NumOfBlocks: Number of SD blocks to read
  6. * @retval SD status
  7. */
  8. uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
  9. {

  10.   if( HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks) == HAL_OK)
  11.   {
  12.     return MSD_OK;
  13.   }
  14.   else
  15.   {
  16.     return MSD_ERROR;
  17.   }
  18. }
复制代码

87.4.6 函数HAL_SD_WriteBlocks_DMA
函数原型:

  1. HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
  2. {
  3.   SDMMC_DataInitTypeDef config;
  4.   uint32_t errorstate;
  5.   uint32_t add = BlockAdd;

  6.   if(NULL == pData)
  7.   {
  8.     hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
  9.     return HAL_ERROR;
  10.   }

  11.   if(hsd->State == HAL_SD_STATE_READY)
  12.   {
  13.     hsd->ErrorCode = HAL_SD_ERROR_NONE;

  14.     if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
  15.     {
  16.       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
  17.       return HAL_ERROR;
  18.     }

  19.     hsd->State = HAL_SD_STATE_BUSY;

  20.   /* 初始化数据控制寄存器 */
  21.     hsd->Instance->DCTRL = 0U;

  22.     hsd->pTxBuffPtr = pData;
  23.     hsd->TxXferSize = BLOCKSIZE * NumberOfBlocks;

  24.     if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
  25.     {
  26.       add *= 512U;
  27.     }

  28.   /* 配置SD DPSM (Data Path State Machine) */
  29.     config.DataTimeOut   = SDMMC_DATATIMEOUT;
  30.     config.DataLength    = BLOCKSIZE * NumberOfBlocks;
  31.     config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
  32.     config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
  33.     config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
  34.     config.DPSM          = SDMMC_DPSM_DISABLE;
  35.     (void)SDMMC_ConfigData(hsd->Instance, &config);


  36.     __SDMMC_CMDTRANS_ENABLE( hsd->Instance);

  37.     hsd->Instance->IDMABASE0 = (uint32_t) pData ;
  38.     hsd->Instance->IDMACTRL  = SDMMC_ENABLE_IDMA_SINGLE_BUFF;

  39.   /* 查询模式写块 */
  40.     if(NumberOfBlocks > 1U)
  41.     {
  42.       hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);

  43.     /* 多块写命令 */
  44.       errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);
  45.     }
  46.     else
  47.     {
  48.       hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_DMA);

  49.     /* 单块写命令 */
  50.       errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);
  51.     }
  52.     if(errorstate != HAL_SD_ERROR_NONE)
  53.     {
  54.     /* 清除静态标志 */
  55.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  56.       hsd->ErrorCode |= errorstate;
  57.       hsd->State = HAL_SD_STATE_READY;
  58.       hsd->Context = SD_CONTEXT_NONE;
  59.       return HAL_ERROR;
  60.     }

  61.   /* 使能传输中断 Enable */
  62.     __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND));

  63.     return HAL_OK;
  64.   }
  65.   else
  66.   {
  67.     return HAL_BUSY;
  68.   }
  69. }
复制代码

函数描述:

此函数主要用于向SD卡写入数据,DMA方式。

函数参数:

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

  1. /**
  2. * @brief  Writes block(s) to a specified address in an SD card, in DMA mode.
  3. * @param  pData: Pointer to the buffer that will contain the data to transmit
  4. * @param  WriteAddr: Address from where data is to be written
  5. * @param  NumOfBlocks: Number of SD blocks to write
  6. * @retval SD status
  7. */
  8. uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
  9. {

  10.   if( HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) == HAL_OK)
  11.   {
  12.     return MSD_OK;
  13.   }
  14.   else
  15.   {
  16.     return MSD_ERROR;
  17.   }
  18. }
复制代码

87.4.7 函数HAL_SD_Erase
函数原型:

  1. HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, uint32_t BlockEndAdd)
  2. {
  3.   uint32_t errorstate;
  4.   uint32_t start_add = BlockStartAdd;
  5.   uint32_t end_add = BlockEndAdd;

  6.   if(hsd->State == HAL_SD_STATE_READY)
  7.   {
  8.     hsd->ErrorCode = HAL_SD_ERROR_NONE;

  9.     if(end_add < start_add)
  10.     {
  11.       hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
  12.       return HAL_ERROR;
  13.     }

  14.     if(end_add > (hsd->SdCard.LogBlockNbr))
  15.     {
  16.       hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
  17.       return HAL_ERROR;
  18.     }

  19.     hsd->State = HAL_SD_STATE_BUSY;

  20.   /* 检测是否支持擦除命令 */
  21.     if(((hsd->SdCard.Class) & SDMMC_CCCC_ERASE) == 0U)
  22.     {
  23.       /* 清除所有静态标志 */
  24.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  25.       hsd->ErrorCode |= HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;
  26.       hsd->State = HAL_SD_STATE_READY;
  27.       return HAL_ERROR;
  28.     }

  29.     if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)
  30.     {
  31.     /* 清除所有静态标志 */
  32.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  33.       hsd->ErrorCode |= HAL_SD_ERROR_LOCK_UNLOCK_FAILED;
  34.       hsd->State = HAL_SD_STATE_READY;
  35.       return HAL_ERROR;
  36.     }

  37.   /* 对于高容量卡,获取起始块和结束块 */
  38.     if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
  39.     {
  40.       start_add *= 512U;
  41.       end_add   *= 512U;
  42.     }

  43.     /* 根据sd-card spec 1.0 ERASE_GROUP_START (CMD32) 和 erase_group_end(CMD33) */
  44.     if(hsd->SdCard.CardType != CARD_SECURED)
  45.     {
  46.     /* 发送CMD32 SD_ERASE_GRP_START命令带地址参数 */
  47.       errorstate = SDMMC_CmdSDEraseStartAdd(hsd->Instance, start_add);
  48.       if(errorstate != HAL_SD_ERROR_NONE)
  49.       {
  50.         /* 清除所有静态标志 */
  51.         __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  52.         hsd->ErrorCode |= errorstate;
  53.         hsd->State = HAL_SD_STATE_READY;
  54.         return HAL_ERROR;
  55.       }

  56.       /* 发送CMD33 SD_ERASE_GRP_END命令,带地址参数 */
  57.       errorstate = SDMMC_CmdSDEraseEndAdd(hsd->Instance, end_add);
  58.       if(errorstate != HAL_SD_ERROR_NONE)
  59.       {
  60.         /* 清除所有静态标志 */
  61.         __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  62.         hsd->ErrorCode |= errorstate;
  63.         hsd->State = HAL_SD_STATE_READY;
  64.         return HAL_ERROR;
  65.       }
  66.     }

  67.     /* 发送CMD38 ERASE命令 */
  68.     errorstate = SDMMC_CmdErase(hsd->Instance, 0UL);
  69.     if(errorstate != HAL_SD_ERROR_NONE)
  70.     {
  71.       /* 清除所有静态标志 */
  72.       __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
  73.       hsd->ErrorCode |= errorstate;
  74.       hsd->State = HAL_SD_STATE_READY;
  75.       return HAL_ERROR;
  76.     }

  77.     hsd->State = HAL_SD_STATE_READY;

  78.     return HAL_OK;
  79.   }
  80.   else
  81.   {
  82.     return HAL_BUSY;
  83.   }
  84. }
复制代码

函数描述:

此函数主要用于SD卡擦除。

函数参数:

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

  1. /**
  2. * @brief  Erases the specified memory area of the given SD card.
  3. * @param  StartAddr: Start byte address
  4. * @param  EndAddr: End byte address
  5. * @retval SD status
  6. */
  7. uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr)
  8. {

  9.   if( HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) == HAL_OK)
  10.   {
  11.     return MSD_OK;
  12.   }
  13.   else
  14.   {
  15.     return MSD_ERROR;
  16.   }
  17. }
复制代码

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


收藏 评论0 发布时间:2021-11-6 23:38

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版