sdmmc驱动sd卡初始化流程分析
1.使用CUBEMX,配置具体的硬件接口和fatfs文件系统,会生成如下代码:
void MX_SDMMC1_SD_Init(void)
{
/* USER CODE BEGIN SDMMC1_Init 0 */
/* USER CODE END SDMMC1_Init 0 */
/* USER CODE BEGIN SDMMC1_Init 1 */
/* USER CODE END SDMMC1_Init 1 */
hsd1.Instance = SDMMC1;
hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd1.Init.ClockDiv = 5;
// if (HAL_SD_Init(&hsd1) != HAL_OK)
// {
// Error_Handler();
// }
/* USER CODE BEGIN SDMMC1_Init 2 */
/* USER CODE END SDMMC1_Init 2 */
}
建议将HAL_SD_Init部分屏蔽,否则如果上电未插SD卡会导致程序死在Error_Handler();
因为这个函数最终会在sd_diskio.c文件的 SD_Driver.SD_initialize函数中调用
const Diskio_drvTypeDef SD_Driver =
{
SD_initialize,
SD_status,
SD_read,
#if _USE_WRITE == 1
SD_write,
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
SD_ioctl,
#endif /* _USE_IOCTL == 1 */
};
SD_initialize函数原型:
DSTATUS SD_initialize(BYTE lun)
{
Stat = STA_NOINIT;
#if !defined(DISABLE_SD_INIT)
if(BSP_SD_Init() == MSD_OK)
{
Stat = SD_CheckStatus(lun);
}
#else
Stat = SD_CheckStatus(lun);
#endif
return Stat;
}
而BSP_SD_Init函数原型:
__weak uint8_t BSP_SD_Init(void)
{
uint8_t sd_state = MSD_OK;
/* Check if the SD card is plugged in the slot */
if (BSP_SD_IsDetected() != SD_PRESENT)
{
return MSD_ERROR_SD_NOT_PRESENT;
}
/* HAL SD initialization */
sd_state = HAL_SD_Init(&hsd1);
/* Configure SD Bus width (4 bits mode selected) */
if (sd_state == MSD_OK)
{
/* Enable wide operation */
if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK)
{
sd_state = MSD_ERROR;
}
}
return sd_state;
}
然而在ff.c文件中比如find_volume/f_mkfs函数都会调用 ”stat = disk_initialize(fs->drv); /* Initialize the physical drive */“
然而发i函数原型:
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = RES_OK;
if(disk.is_initialized[pdrv] == 0)
{
stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);
if(stat == RES_OK)
{
disk.is_initialized[pdrv] = 1;
}
}
return stat;
}
也就是 disk_initialize(fs->drv) ---> SD_initialize -----> BSP_SD_Init ----> HAL_SD_Init
所以最终简单分析一下HAL_SD_Init函数原型:
HAL_StatusTypeDef HAL_SD_Init(SD_HandleTypeDef *hsd)
{
HAL_SD_CardStatusTypeDef CardStatus;
uint32_t speedgrade;
uint32_t unitsize;
uint32_t tickstart;
/* Check the SD handle allocation */
if (hsd == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
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)
{
/* Allocate lock resource and initialize it */
hsd->Lock = HAL_UNLOCKED;
#if (USE_SD_TRANSCEIVER != 0U)
/* Force SDMMC_TRANSCEIVER_PRESENT for Legacy usage */
if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_UNKNOWN)
{
hsd->Init.TranceiverPresent = SDMMC_TRANSCEIVER_PRESENT;
}
#endif /*USE_SD_TRANSCEIVER */
#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
/* Reset Callback pointers in HAL_SD_STATE_RESET only */
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 /* USE_SD_TRANSCEIVER */
if (hsd->MspInitCallback == NULL)
{
hsd->MspInitCallback = HAL_SD_MspInit;
}
/* Init the low level hardware */
hsd->MspInitCallback(hsd);
#else
/* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */
HAL_SD_MspInit(hsd);
#endif /* USE_HAL_SD_REGISTER_CALLBACKS */
}
hsd->State = HAL_SD_STATE_PROGRAMMING;
/* Initialize the Card parameters */
if (HAL_SD_InitCard(hsd) != HAL_OK)
{
return HAL_ERROR;
}
if (HAL_SD_GetCardStatus(hsd, &CardStatus) != HAL_OK)
{
return HAL_ERROR;
}
/* Get Initial Card Speed from Card Status*/
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;
}
}
/* Configure the bus wide */
if (HAL_SD_ConfigWideBusOperation(hsd, hsd->Init.BusWide) != HAL_OK)
{
return HAL_ERROR;
}
/* Verify that SD card is ready to use after Initialization */
tickstart = HAL_GetTick();
while ((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER))
{
if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT)
{
hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT;
hsd->State = HAL_SD_STATE_READY;
return HAL_TIMEOUT;
}
}
/* Initialize the error code */
hsd->ErrorCode = HAL_SD_ERROR_NONE;
/* Initialize the SD operation */
hsd->Context = SD_CONTEXT_NONE;
/* Initialize the SD state */
hsd->State = HAL_SD_STATE_READY;
return HAL_OK;
}
这几个函数简单说一下:
HAL_SD_MspInit(hsd); //底层初始化
HAL_SD_InitCard
1.会将sdmmc总线配置为400k,BusWide 为1线,调用SDMMC_Init()初始化为默认配置。
2.为SDMMC控制器供电并开始输出卡时钟。
3.获取卡版本和类型<SD_PowerON> hsd->SdCard.CardVersion/hsd->SdCard.CardType
4.获取卡 <SD_InitCard> hsd->SdCard.Class。
5.设置block size <SDMMC_CmdBlockLength>。
HAL_SD_GetCardStatus
1.获取卡状态 ,主要是 HAL_SD_CardStatusTypeDef 变量的
typedef struct
{
__IO uint8_t DataBusWidth; /*!< Shows the currently defined data bus width */
__IO uint8_t SecuredMode; /*!< Card is in secured mode of operation */
__IO uint16_t CardType; /*!< Carries information about card type */
__IO uint32_t ProtectedAreaSize; /*!< Carries information about the capacity of protected area */
__IO uint8_t SpeedClass; /*!< Carries information about the speed class of the card */
__IO uint8_t PerformanceMove; /*!< Carries information about the card's performance move */
__IO uint8_t AllocationUnitSize; /*!< Carries information about the card's allocation unit size */
__IO uint16_t EraseSize; /*!< Determines the number of AUs to be erased in one operation */
__IO uint8_t EraseTimeout; /*!< Determines the timeout for any number of AU erase */
__IO uint8_t EraseOffset; /*!< Carries information about the erase offset */
__IO uint8_t UhsSpeedGrade; /*!< Carries information about the speed grade of UHS card */
__IO uint8_t UhsAllocationUnitSize; /*!< Carries information about the UHS card's allocation unit size */
__IO uint8_t VideoSpeedClass; /*!< Carries information about the Video Speed Class of UHS card */
} HAL_SD_CardStatusTypeDef;
HAL_SD_ConfigWideBusOperation
1.时钟未超过25,最终时钟就是你配置的时钟。
2.超过会根据hsd->SdCard.CardSpeed 做具体处理。
3.根据用户设置的 SDMMC参数调用SDMMC_Init(),初始化SDMMC参数。
4.再次调用SDMMC_CmdBlockLength设置block size为512bytes。
HAL_SD_GetCardState
1.初始化操作完成后获取sd卡状态。
至此简单分析完:
最后简单说一下,在SD卡拔出之后调用
f_mount(NULL, SDPath, 1);//卸载
HAL_SD_DeInit(&hsd1);// sd卡断电,解除 MSP 层的初始化状态
FATFS_UnLinkDriver(SDPath);
插入之后在调用
FATFS_LinkDriver(&SD_Driver, SDPath);

浙公网安备 33010602011771号