本文共 21510 字,大约阅读时间需要 71 分钟。
对于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:
通过这个框图,我们可以得到如下信息:
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方向指示。
SDMMC控制器的时钟来源:
注:大家应用时要特别注意这个问题。
使用STM32H7的SDIO1仅支持AXI SRAM,而SDIO2是AXI,SRAM1, SRAM2和SRAM3都支持的。
驱动SD卡支持的最大总线速度:
驱动eMMC支持的最大总线速度:
关于这两个数据表,注意以下几点:
驱动SD卡最大支持4bit,驱动eMMC最大支持8bit。
针对信号电压1.8V或者1.2V,STM32H7需要外接专门的PHY芯片才可以驱动。
最大IO翻转限制说的是SDR50,SDR104这种高速通信。平时用的DS,HS这种,无压力,刷满速不成问题。
STM32H7的SDIO外接支持UHS-I 模式 (SDR12, SDR25, SDR50, SDR104和DDR50)需要1.8的电平转换器。STM32H7参考手册给了一个型号ST6G3244ME:
STM32H7的SDMMC自带了专用的DMA控制器IDMA,支持突发,也支持双缓冲。为什么要自带DMA控制器?主要原因是STM32H7的通用DMA1和DMA2已经无法满足SDMMC高速通信速度。在本教程的第62章专门为大家测试过。通过让SDMMC自带控制器,这个问题就迎刃而解。
SDMMC总线相关的寄存器是通过HAL库中的结构体SD_TypeDef定义,在stm32h743xx.h中可以找到这个类型定义:
#define SD_TypeDef SDMMC_TypeDeftypedef struct{ __IO uint32_t POWER; /*!< SDMMC power control register, Address offset: 0x00 */ __IO uint32_t CLKCR; /*!< SDMMC clock control register, Address offset: 0x04 */ __IO uint32_t ARG; /*!< SDMMC argument register, Address offset: 0x08 */ __IO uint32_t CMD; /*!< SDMMC command register, Address offset: 0x0C */ __I uint32_t RESPCMD; /*!< SDMMC command response register, Address offset: 0x10 */ __I uint32_t RESP1; /*!< SDMMC response 1 register, Address offset: 0x14 */ __I uint32_t RESP2; /*!< SDMMC response 2 register, Address offset: 0x18 */ __I uint32_t RESP3; /*!< SDMMC response 3 register, Address offset: 0x1C */ __I uint32_t RESP4; /*!< SDMMC response 4 register, Address offset: 0x20 */ __IO uint32_t DTIMER; /*!< SDMMC data timer register, Address offset: 0x24 */ __IO uint32_t DLEN; /*!< SDMMC data length register, Address offset: 0x28 */ __IO uint32_t DCTRL; /*!< SDMMC data control register, Address offset: 0x2C */ __I uint32_t DCOUNT; /*!< SDMMC data counter register, Address offset: 0x30 */ __I uint32_t STA; /*!< SDMMC status register, Address offset: 0x34 */ __IO uint32_t ICR; /*!< SDMMC interrupt clear register, Address offset: 0x38 */ __IO uint32_t MASK; /*!< SDMMC mask register, Address offset: 0x3C */ __IO uint32_t ACKTIME; /*!< SDMMC Acknowledgement timer register, Address offset: 0x40 */ uint32_t RESERVED0[3]; /*!< Reserved, 0x44 - 0x4C - 0x4C - 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; 下面是SDMMC总线的初始化结构体:
#define SD_InitTypeDef SDMMC_InitTypeDeftypedef struct{ uint32_t ClockEdge; uint32_t ClockPowerSave; uint32_t BusWide; uint32_t HardwareFlowControl; uint32_t ClockDiv; #if (USE_SD_TRANSCEIVER != 0U) uint32_t TranceiverPresent; #endif }SDMMC_InitTypeDef; 下面是SDMMC总线的卡信息结构体:
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; 下面是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; 此文件涉及到的函数较多,这里把几个常用的函数做个说明:
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卡的指定区域。
函数原型:
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;} 函数原型:
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;} 函数原型:
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;} 函数原型:
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;} 本章节就为大家讲解这么多,更多SDMMC知识可以看STM32H7的参考手册。
转载地址:http://sqjjz.baihongyu.com/