参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
基于STM32Cube_FW_F4_V1.21.0库修改(stm32f4xx_hal_mmc.h),4bit模式,其他与SD卡驱动类似。实测写入速度
1MB/s左右。
容量计算:
Capacity = (hmmc->MmcCard.EmmcExtCsd.EXT_CSD.SEC_COUNT[3] << 24 |
hmmc->MmcCard.EmmcExtCsd.EXT_CSD.SEC_COUNT[2] << 16 |
hmmc->MmcCard.EmmcExtCsd.EXT_CSD.SEC_COUNT[1] << 8 |
hmmc->MmcCard.EmmcExtCsd.EXT_CSD.SEC_COUNT[0]) × BlockSize(512)
typedef union
{
struct _EXT_CSD
{
__IO uint8_t Reserved19[15];
__IO uint8_t CMDQ_MODE_EN;
__IO uint8_t SECURE_REMOVAL_TYPE;
__IO uint8_t PRODUCT_STATE_AWARENESS_ENABLEMENT;
__IO uint8_t MAX_PRE_LOADING_DATA_SIZE[4];
__IO uint8_t PRE_LOADING_DATA_SIZE[4];
__IO uint8_t FFU_STATUS;
__IO uint8_t Reserved18[2];
__IO uint8_t MODE_OPERATION_CODES;
__IO uint8_t MODE_CONFIG;
__IO uint8_t BARRIER_CTRL;
__IO uint8_t FLUSH_CACHE;
__IO uint8_t CACHE_CTRL;
__IO uint8_t POWER_OFF_NOTIFICATION;
__IO uint8_t PACKED_FAILURE_INDEX;
__IO uint8_t PACKED_COMMAND_STATUS;
__IO uint8_t CONTEXT_CONF[15];
__IO uint8_t EXT_PARTITIONS_ATTRIBUTE[2];
__IO uint8_t EXCEPTION_EVENTS_STATUS[2];
__IO uint8_t EXCEPTION_EVENTS_CTRL[2];
__IO uint8_t DYNCAP_NEEDED;
__IO uint8_t CLASS_6_CTRL;
__IO uint8_t INI_TIMEOUT_EMU;
__IO uint8_t DATA_SECTOR_SIZE;
__IO uint8_t USE_NATIVE_SECTOR;
__IO uint8_t NATIVE_SECTOR_SIZE;
__IO uint8_t VENDOR_SPECIFIC_FIELD[64];
__IO uint8_t Reserved17[2];
__IO uint8_t PROGRAM_CID_CSD_DDR_SUPPORT;
__IO uint8_t PERIODIC_WAKEUP;
__IO uint8_t TCASE_SUPPORT;
__IO uint8_t PRODUCTION_STATE_AWARENESS;
__IO uint8_t SEC_BAD_BLK_MGMNT;
__IO uint8_t Reserved16;
__IO uint8_t ENH_START_ADDR[4];
__IO uint8_t ENH_SIZE_MULT[3];
__IO uint8_t GP_SIZE_MULT[12];
__IO uint8_t PARTITION_SETTING_COMPLETED;
__IO uint8_t PARTITIONS_ATTRIBUTE;
__IO uint8_t MAX_ENH_SIZE_MULT[3];
__IO uint8_t PARTITIONING_SUPPORT;
__IO uint8_t HPI_MGMT;
__IO uint8_t RST_n_FUNCTION;
__IO uint8_t BKOPS_EN;
__IO uint8_t BKOPS_START;
__IO uint8_t SANITIZE_START;
__IO uint8_t WR_REL_PARAM;
__IO uint8_t WR_REL_SET;
__IO uint8_t RPMB_SIZE_MULT;
__IO uint8_t FW_CONFIG;
__IO uint8_t Reserved15;
__IO uint8_t USER_WP;
__IO uint8_t Reserved14;
__IO uint8_t BOOT_WP;
__IO uint8_t BOOT_WP_STATUS;
__IO uint8_t ERASE_GROUP_DEF;
__IO uint8_t Reserved13;
__IO uint8_t BOOT_BUS_CONDITIONS;
__IO uint8_t BOOT_CONFIG_PROT;
__IO uint8_t PARTITION_CONFIG;
__IO uint8_t Reserved12;
__IO uint8_t ERASED_MEM_CONT;
__IO uint8_t Reserved11;
__IO uint8_t BUS_WIDTH;
__IO uint8_t STROBE_SUPPORT;
__IO uint8_t HS_TIMING;
__IO uint8_t Reserved10;
__IO uint8_t POWER_CLASS;
__IO uint8_t Reserved9;
__IO uint8_t CMD_SET_REV;
__IO uint8_t Reserved8;
__IO uint8_t CMD_SET;
__IO uint8_t EXT_CSD_REV ;
__IO uint8_t Reserved7;
__IO uint8_t CSD_STRUCTURE;
__IO uint8_t Reserved6;
__IO uint8_t DEVICE_TYPE;
__IO uint8_t DRIVER_STRENGTH;
__IO uint8_t OUT_OF_INTERRUPT_TIME;
__IO uint8_t PARTITION_SWITCH_TIME;
__IO uint8_t PWR_CL_52_195;
__IO uint8_t PWR_CL_26_195;
__IO uint8_t PWR_CL_52_360;
__IO uint8_t PWR_CL_26_360;
__IO uint8_t Reserved5;
__IO uint8_t MIN_PERF_R_4_26;
__IO uint8_t MIN_PERF_W_4_26;
__IO uint8_t MIN_PERF_R_8_26_4_52;
__IO uint8_t MIN_PERF_W_8_26_4_52;
__IO uint8_t MIN_PERF_R_8_52;
__IO uint8_t MIN_PERF_W_8_52;
__IO uint8_t SECURE_WP_INFO;
__IO uint8_t SEC_COUNT[4];
__IO uint8_t SLEEP_NOTIFICATION_TIME;
__IO uint8_t S_A_TIMEOUT;
__IO uint8_t PRODUCTION_STATE_AWARENESS_TIMEOUT;
__IO uint8_t S_C_VCCQ;
__IO uint8_t S_C_VCC;
__IO uint8_t HC_WP_GRP_SIZE;
__IO uint8_t REL_WR_SEC_C;
__IO uint8_t ERASE_TIMEOUT_MULT;
__IO uint8_t HC_ERASE_GRP_SIZE;
__IO uint8_t ACC_SIZE;
__IO uint8_t BOOT_SIZE_MULTI;
__IO uint8_t Reserved4;
__IO uint8_t BOOT_INFO;
__IO uint8_t SEC_TRIM_MULT;
__IO uint8_t SEC_ERASE_MULT;
__IO uint8_t SEC_FEATURE_SUPPORT;
__IO uint8_t TRIM_MULT;
__IO uint8_t Reserved3;
__IO uint8_t MIN_PERF_DDR_R_8_52;
__IO uint8_t MIN_PERF_DDR_W_8_52;
__IO uint8_t PWR_CL_200_130;
__IO uint8_t PWR_CL_200_195;
__IO uint8_t PWR_CL_DDR_52_195;
__IO uint8_t PWR_CL_DDR_52_360;
__IO uint8_t CACHE_FLUSH_POLICY;
__IO uint8_t INI_TIMEOUT_AP;
__IO uint8_t CORRECTLY_PRG_SECTORS_NUM[4];
__IO uint8_t BKOPS_STATUS;
__IO uint8_t OWER_OFF_LONG_TIME;
__IO uint8_t GENERIC_CMD6_TIME;
__IO uint8_t CACHE_SIZE[4];
__IO uint8_t PWR_CL_DDR_200_360;
__IO uint8_t FIRMWARE_VERSION[8];
__IO uint8_t DEVICE_VERSION[2];
__IO uint8_t OPTIMAL_TRIM_UNIT_SIZE;
__IO uint8_t OPTIMAL_WRITE_SIZE;
__IO uint8_t OPTIMAL_READ_SIZE;
__IO uint8_t PRE_EOL_INFO;
__IO uint8_t DEVICE_LIFE_TIME_EST_TYP_A;
__IO uint8_t DEVICE_LIFE_TIME_EST_TYP_B;
__IO uint8_t VENDOR_PROPRIETARY_HEALTH_REPORT[32];
__IO uint8_t NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED[4];
__IO uint8_t ReservedX;
__IO uint8_t CMDQ_DEPTH;
__IO uint8_t CMDQ_SUPPORT;
__IO uint8_t Reserved2[177];
__IO uint8_t BARRIER_SUPPORT;
__IO uint8_t FFU_ARG[4];
__IO uint8_t OPERATION_CODE_TIMEOUT;
__IO uint8_t FFU_FEATURES;
__IO uint8_t SUPPORTED_MODES;
__IO uint8_t EXT_SUPPORT;
__IO uint8_t LARGE_UNIT_SIZE_M1;
__IO uint8_t CONTEXT_CAPABILITIES;
__IO uint8_t TAG_RES_SIZE;
__IO uint8_t TAG_UNIT_SIZE;
__IO uint8_t DATA_TAG_SUPPORT;
__IO uint8_t MAX_PACKED_WRITES;
__IO uint8_t MAX_PACKED_READS;
__IO uint8_t BKOPS_SUPPORT;
__IO uint8_t HPI_FEATURES;
__IO uint8_t S_CMD_SET;
__IO uint8_t EXT_SECURITY_ERR;
__IO uint8_t Reserved1[6];
} EXT_CSD;
__IO uint8_t CsdBuf[512];
} EMMC_EXT_CSD;
typedef struct
{
uint32_t CardCap; /*-----------*/
uint32_t CardType; /*!< Specifies the card Type */
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 */
EMMC_EXT_CSD EmmcExtCsd;
}HAL_MMC_CardInfoTypeDef;
static HAL_StatusTypeDef MMC_Read_ExtCsd(MMC_HandleTypeDef *hmmc)
{
uint32_t errorstate = HAL_MMC_ERROR_NONE;
SDIO_CmdInitTypeDef sdmmc_cmdinit;
SDIO_DataInitTypeDef config;
uint32_t count = 0;
uint32_t cnt2;
uint32_t *ExtCsdBuf;
ExtCsdBuf = (uint32_t *)(&(hmmc-> MmcCard.EmmcExtCsd.CsdBuf[0]));
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = (uint32_t)512;
config.DataBlockSize = (uint32_t) 9 << 4;
config.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO;
config.TransferMode = SDIO_TRANSFER_MODE_BLOCK;
config.DPSM = SDIO_DPSM_ENABLE;
SDIO_ConfigData(hmmc->Instance, &config);
/* Send CMD8 to verify SD card interface operating condition */
/* Argument: - [31:12]: Reserved (shall be set to '0')
- [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
- [7:0]: Check Pattern (recommended 0xAA) */
/* CMD Response: R7 */
sdmmc_cmdinit.Argument = 0;
sdmmc_cmdinit.CmdIndex = SDMMC_CMD_HS_SEND_EXT_CSD;
sdmmc_cmdinit.Response = SDIO_RESPONSE_SHORT;
sdmmc_cmdinit.WaitForInterrupt = SDIO_WAIT_NO;
sdmmc_cmdinit.CPSM = SDIO_CPSM_ENABLE;
SDIO_SendCommand(hmmc->Instance, &sdmmc_cmdinit);
/* Check for error conditions */
errorstate = SDMMC_GetCmdResp1(hmmc->Instance, SDMMC_CMD_HS_SEND_EXT_CSD, 0xffff);
while(!__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_STA_STBITERR))
{
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXFIFOHF))
{
for (count = 0; count < 8; count++)
{
*(ExtCsdBuf + count) = SDIO_ReadFIFO(hmmc->Instance);
}
ExtCsdBuf += 8;
}
}
/* Get error state */
if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DTIMEOUT))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDMMC_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_TIMEOUT;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_DCRCFAIL))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDMMC_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_DATA_CRC_FAIL;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
else if(__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXOVERR))
{
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDMMC_STATIC_FLAGS);
hmmc->ErrorCode |= HAL_MMC_ERROR_RX_OVERRUN;
hmmc->State = HAL_MMC_STATE_READY;
return HAL_ERROR;
}
count = 100;
/* Empty FIFO if there is still any data */
while ((__HAL_MMC_GET_FLAG(hmmc, SDIO_FLAG_RXDAVL)) && (count >0))
{
SDIO_ReadFIFO(hmmc->Instance);
count --;
}
/* Clear all the static flags */
__HAL_MMC_CLEAR_FLAG(hmmc, SDMMC_STATIC_FLAGS);
hmmc->State = HAL_MMC_STATE_READY;
return HAL_OK;
}
/*off:ext_csd寄存器偏移地址,可利用宏 #define EXT_CSD_OFFSET(member) (size_t)&( ((EMMC_EXT_CSD*)0)->EXT_CSD.member )计算
val: 写入值*/
static HAL_StatusTypeDef MMC_Write_ExtCsd(MMC_HandleTypeDef *hmmc, uint8_t off, uint8_t val)
{
uint32_t errorstate = HAL_ERROR;
if(off>191) return errorstate;
uint32_t arg = (0x03 << 24) | ((off)<<16) | ((val) << 8) ;
errorstate = SDMMC_CmdSwitch(hmmc->Instance,arg);
return errorstate;
}