参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。
初始化代码清单:
HAL_StatusTypeDef SDMMC1_MMC_Init(void)
{
hmmc1.Instance = SDMMC1;
hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hmmc1.Init.ClockDiv = 1;
if (HAL_MMC_Init(&hmmc1) != HAL_OK)
{
Error_Handler();
}
return HAL_OK;
}
底层驱动代码清单:
void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hmmc->Instance==SDMMC1)
{
/* USER CODE BEGIN SDMMC1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SDMMC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**SDMMC1 GPIO Configuration
PC8 ------> SDMMC1_D0
PC9 ------> SDMMC1_D1
PC10 ------> SDMMC1_D2
PC11 ------> SDMMC1_D3
PB8 ------> SDMMC1_D4
PB9 ------> SDMMC1_D5
PC6 ------> SDMMC1_D6
PC7 ------> SDMMC1_D7
PC12 ------> SDMMC1_CK
PD2 ------> SDMMC1_CMD
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断
HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);
}
}
在DMA模式下,从MMC卡的指定地址读取数据:
/**
* @brief 在DMA模式下,从MMC卡的指定地址读取数据
* @param pData:指向将包含要传输的数据的缓冲区的指针
* @param ReadAddr:要读取数据的地址
* @param NumOfBlocks:要读取的MMC块数量
* @retval eMMC状态
*/
uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
{
HAL_StatusTypeDef Status = HAL_OK;
if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)
{
Status = HAL_ERROR;
}
return Status;
}
在DMA模式下,向MMC卡的指定地址写入数据:
/**
* @brief 在DMA模式下,向MMC卡的指定地址写入数据
* @param pData:指向将包含要传输的数据的缓冲区的指针
* @param WriteAddr:要写入数据的地址
* @param NumOfBlocks:要写的MMC块的数量
* @retval MMC状态
*/
uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
HAL_StatusTypeDef Status = HAL_OK;
/* Write block(s) in DMA transfer mode */
if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)
{
Status = HAL_ERROR;
}
return Status;
}
擦除eMMC卡数据:
/**
* @brief 擦除eMMC卡数据
* @param 无
* @retval 无
*/
void MMC_EraseTest(void)
{
HAL_StatusTypeDef Status = HAL_OK;
HAL_StatusTypeDef EraseStatus = HAL_OK;
if (Status == HAL_OK)
{
Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));
//等待擦除完成
if(Wait_SDCARD_Ready() != HAL_OK)
{
EraseStatus = HAL_ERROR;
}
}
if(EraseStatus != HAL_OK)
{
Error_Handler();
}
}
eMMC卡等待擦除完成函数:
/**
* @brief eMMC卡等待擦除完成函数
* @param 无
* @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败
*/
static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
{
uint32_t loop = MMC_TIMEOUT;
/* Wait for the Erasing process is completed */
/* Verify that SD card is ready to use after the Erase */
while(loop > 0)
{
loop--;
if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)
{
return HAL_OK;
}
}
return HAL_ERROR;
}
最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。
参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。
初始化代码清单:
HAL_StatusTypeDef SDMMC1_MMC_Init(void)
{
hmmc1.Instance = SDMMC1;
hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hmmc1.Init.ClockDiv = 1;
if (HAL_MMC_Init(&hmmc1) != HAL_OK)
{
Error_Handler();
}
return HAL_OK;
}
底层驱动代码清单:
void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hmmc->Instance==SDMMC1)
{
/* USER CODE BEGIN SDMMC1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SDMMC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**SDMMC1 GPIO Configuration
PC8 ------> SDMMC1_D0
PC9 ------> SDMMC1_D1
PC10 ------> SDMMC1_D2
PC11 ------> SDMMC1_D3
PB8 ------> SDMMC1_D4
PB9 ------> SDMMC1_D5
PC6 ------> SDMMC1_D6
PC7 ------> SDMMC1_D7
PC12 ------> SDMMC1_CK
PD2 ------> SDMMC1_CMD
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断
HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);
}
}
在DMA模式下,从MMC卡的指定地址读取数据:
/**
* @brief 在DMA模式下,从MMC卡的指定地址读取数据
* @param pData:指向将包含要传输的数据的缓冲区的指针
* @param ReadAddr:要读取数据的地址
* @param NumOfBlocks:要读取的MMC块数量
* @retval eMMC状态
*/
uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
{
HAL_StatusTypeDef Status = HAL_OK;
if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)
{
Status = HAL_ERROR;
}
return Status;
}
在DMA模式下,向MMC卡的指定地址写入数据:
/**
* @brief 在DMA模式下,向MMC卡的指定地址写入数据
* @param pData:指向将包含要传输的数据的缓冲区的指针
* @param WriteAddr:要写入数据的地址
* @param NumOfBlocks:要写的MMC块的数量
* @retval MMC状态
*/
uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
HAL_StatusTypeDef Status = HAL_OK;
/* Write block(s) in DMA transfer mode */
if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)
{
Status = HAL_ERROR;
}
return Status;
}
擦除eMMC卡数据:
/**
* @brief 擦除eMMC卡数据
* @param 无
* @retval 无
*/
void MMC_EraseTest(void)
{
HAL_StatusTypeDef Status = HAL_OK;
HAL_StatusTypeDef EraseStatus = HAL_OK;
if (Status == HAL_OK)
{
Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));
//等待擦除完成
if(Wait_SDCARD_Ready() != HAL_OK)
{
EraseStatus = HAL_ERROR;
}
}
if(EraseStatus != HAL_OK)
{
Error_Handler();
}
}
eMMC卡等待擦除完成函数:
/**
* @brief eMMC卡等待擦除完成函数
* @param 无
* @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败
*/
static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
{
uint32_t loop = MMC_TIMEOUT;
/* Wait for the Erasing process is completed */
/* Verify that SD card is ready to use after the Erase */
while(loop > 0)
{
loop--;
if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)
{
return HAL_OK;
}
}
return HAL_ERROR;
}
最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。
举报