STM32使用HAL库驱动EMMC挂载FATFS文件系统
STM32使用HAL库驱动EMMC挂载FATFS文件系统
工程需要使用EMMC挂载FATFS文件系统,苦苦寻找皆为SD卡挂载FATFS,虽原理一样还是写了这么一篇博客,希望对新手可以有些帮助!!!
STM32驱动EMMC
使用STM32CubeMX配置SDIO
- 选择SDIO选项
- 配置DMA
- 选择中断优先级
编写EMMC驱动
等待EMMC就绪
uint8_t WaitEMMCReady(void)
{
uint8_t count = EMMC_TIMEOUT;
while(count--)
{
if(HAL_MMC_GetCardState(&hmmc)== HAL_MMC_CARD_TRANSFER)
{
return HAL_OK;
}
HAL_Delay(1);
}
return HAL_ERROR;
}
EMMC读取n(n>=1)块
HAL_StatusTypeDef EMMC_ReadBlock_DMA(uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
HAL_StatusTypeDef Status = HAL_OK;
if(WaitEMMCReady() != HAL_OK)
{
Status = HAL_BUSY;
}
HAL_DMA_DeInit(&hdma_sdio);
hdma_sdio.Instance = DMA2_Channel4;
hdma_sdio.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio.Init.Mode = DMA_NORMAL;
hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
if(HAL_DMA_Init(&hdma_sdio) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hmmc, hdmarx, hdma_sdio);
if(HAL_MMC_ReadBlocks_DMA(&hmmc, pData, BlockAdd, NumberOfBlocks) != HAL_OK)
{
Status = HAL_ERROR;
}
return Status;
}
EMMC写入n(n>=1)块
HAL_StatusTypeDef EMMC_WriteBlock_DMA(uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
HAL_StatusTypeDef Status = HAL_OK;
if(WaitEMMCReady() != HAL_OK)
{
Status = HAL_BUSY;
}
HAL_DMA_DeInit(&hdma_sdio);
hdma_sdio.Instance = DMA2_Channel4;
hdma_sdio.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio.Init.Mode = DMA_NORMAL;
hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
if(HAL_DMA_Init(&hdma_sdio) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hmmc, hdmatx, hdma_sdio);
if (HAL_MMC_WriteBlocks_DMA(&hmmc, pData, BlockAdd, NumberOfBlocks) != HAL_OK)
{
Status = HAL_ERROR;
}
return Status;
}
EMMC测试
uint8_t recvbuf[512];
uint8_t sendbuf[512] = {0xAA,0xBB,0xCC,0xDD};
printf("\r\n--------> EMMC DMA Test\r\n");
ret= EMMC_ReadBlock_DMA(recvbuf,0,1);
if(ret == HAL_OK)
{
for (uint16_t i = 0; i < BLOCKSIZE; i++)
{
printf("0x%02x ",recvbuf[i]);
if((i%16) == 0)
{
printf("\r\n");
}
}
}
ret = EMMC_WriteBlock_DMA(sendbuf,0,1);
if(ret == HAL_OK)
{
printf("\r\n--------> EMMC 写入成功\r\n");
}
ret = EMMC_ReadBlock_DMA(recvbuf,0,1);
printf("\r\n--------> ret:%d\r\n",ret);
if(ret == HAL_OK)
{
for (uint16_t i = 0; i < hmmc.MmcCard.BlockSize; i++)
{
printf("0x%02x ",recvbuf[i]);
if((i%16) == 0)
{
printf("\r\n");
}
}
}
移植FATFS文件系统
准备工作
1.FATFS官网下载地址:http://elm-chan.org/fsw/ff/00index_e.html
2.截至2024.6.1最新版本为0.15
3.本工程使用版本为0.11a
keil工程文件结构
修改底层驱动文件
底层驱动只需要修改diskio.c与ffconf.h
修改ffconf.h
#define _USE_MKFS 1 // 0–>1
#define _CODE_PAGE 936 //932–>936 日文到中文
#define _USE_LFN 1 // 0->1 支持长文件名
#define _VOLUMES 1 //根据你使用的盘符数 自行更改
#define _MAX_SS 4096 // 512–>4096 SPI 扇区大小为4096
#define _FS_LOCK 3 // 0–>3 支持同时打开文件数 3个
添加底层驱动
disk_status
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = STA_NOINIT;
if(pdrv == MMC)
{
printf("\r\n--------> disk_status EMMC\r\n");
stat &= ~STA_NOINIT;
}
return stat;
}
disk_initialize
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = STA_NOINIT;
if(pdrv == MMC)
{
printf("\r\n--------> disk_initialize EMMC\r\n");
if(HAL_MMC_Init(&hmmc)==HAL_OK)
{
printf("\r\n--------> disk_initialize EMMC Success\r\n");
stat &= ~STA_NOINIT;
}
}
return stat;
}
disk_read
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res;
if(pdrv == MMC)
{
printf("\r\n--------> disk_read EMMC\r\n");
if(EMMC_ReadBlock_DMA((uint8_t*)buff,(uint32_t)sector,count) == HAL_OK)
{
printf("\r\n--------> disk_read Success\r\n");
res = RES_OK;
}
else
{
res = RES_PARERR;
}
}
else
{
res = RES_ERROR;
}
return res;
}
disk_write
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res;
if(pdrv == MMC)
{
printf("\r\n--------> disk_write EMMC\r\n");
if(EMMC_WriteBlock_DMA((uint8_t*)buff,(uint32_t)sector,count) == HAL_OK)
{
printf("\r\n--------> disk_write Success\r\n");
res = RES_OK;
}
else
{
res = RES_WRPRT;
}
}
else
{
res = RES_ERROR;
}
return res;
}
disk_ioctl
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res = STA_NOINIT;
int result;
if(pdrv == MMC)
{
printf("\r\n--------> disk_ioctl EMMC\r\n");
switch(cmd)
{
case GET_SECTOR_COUNT:
*(DWORD * )buff = hmmc.MmcCard.BlockNbr;
break;
case GET_SECTOR_SIZE:
*(DWORD * )buff = hmmc.MmcCard.BlockSize;
break;
case GET_BLOCK_SIZE:
*(DWORD * )buff = 1;
break;
case MMC_GET_SDSTAT:
*(DWORD * )buff = HAL_MMC_GetState(&hmmc);
break;
}
res = RES_OK;
}
return RES_OK;
}
FATFS文件挂载测试
FATFS fs; /* FatFs文件系统对象 */
FIL fnew; /* 文件对象 */
FRESULT res_sd; /* 文件操作结果 */
UINT fnum; /* 文件成功读写数量 */
BYTE ReadBuffer[1024]={0}; /* 读缓冲区 */
BYTE WriteBuffer[] = "Hello World!!!"; /* 写缓冲区*/
printf("\r\n--------> EMMC 文件系统\r\n");
res_sd = f_mount(&fs,"0:",1);
/*----------------------- 格式化测试 ---------------------------*/
/* 如果没有文件系统就格式化创建创建文件系统 */
if(res_sd == FR_NO_FILESYSTEM)
{
printf("--------> EMMC还没有文件系统,即将进行格式化...\r\n");
/* 格式化 */
res_sd=f_mkfs("0:",0,0);
if(res_sd == FR_OK)
{
printf("--------> EMMC已成功格式化文件系统。\r\n");
/* 格式化后,先取消挂载 */
res_sd = f_mount(NULL,"0:",1);
/* 重新挂载 */
res_sd = f_mount(&fs,"0:",1);
}
else
{
printf("--------> EMMC格式化失败\r\n");
while(1);
}
}
else if(res_sd!=FR_OK)
{
printf("--------> EMMC挂载文件系统失败:(%d)\r\n",res_sd);
printf("--------> EMMC初始化不成功。\r\n");
while(1);
}
else
{
printf("--------> EMMC文件系统挂载成功,可以进行读写测试\r\n");
}
printf("\r\n--------> EMMC即将进行文件写入\r\n");
res_sd = f_open(&fnew, "0:FatFs1.txt",FA_CREATE_ALWAYS | FA_WRITE ); //ps:文件名不要过长,过长会导致创建失败,若过长需要在ffconf.h中开启宏定义
if ( res_sd == FR_OK )
{
printf("--------> EMMC打开/创建FatFs1.txt文件成功,向文件写入数据。\r\n");
/* 将指定存储区内容写入到文件内 */
res_sd=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
if(res_sd==FR_OK)
{
printf("--------> EMMC文件写入成功,写入字节数据:%d\n",fnum);
printf("--------> EMMC向文件写入的数据为:\r\n%s\r\n",WriteBuffer);
}
else
{
printf("-------->EMMC文件写入失败:(%d)\n",res_sd);
}
/* 不再读写,关闭文件 */
f_close(&fnew);
}
else
{
printf("--------> EMMC打开/创建文件失败\r\n");
}
printf("--------> EMMC即将进行文件读取\r\n");
res_sd = f_open(&fnew, "0:FatFs1.txt", FA_OPEN_EXISTING | FA_READ);
if(res_sd == FR_OK)
{
printf("--------> EMMC打开文件成功。\r\n");
res_sd = f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
if(res_sd==FR_OK)
{
printf("--------> EMMC文件读取成功,读到字节数据:%d\r\n",fnum);
printf("--------> EMMC读取得的文件数据为:\r\n%s \r\n", ReadBuffer);
}
else
{
printf("--------> EMMC文件读取失败:(%d)\n",res_sd);
}
}
else
{
printf("--------> EMMC打开文件失败\r\n");
}
/* 不再读写,关闭文件 */
f_close(&fnew);
/* 不再使用文件系统,取消挂载文件系统 */
f_mount(NULL,"0:",1);
###测试结果
作者:一个不知名的小刘