STM32使用HAL库驱动EMMC挂载FATFS文件系统

STM32使用HAL库驱动EMMC挂载FATFS文件系统

  • STM32驱动EMMC
  • 使用STM32CubeMX配置SDIO
  • 编写EMMC驱动
  • 等待EMMC就绪
  • EMMC读取n(n>=1)块
  • EMMC写入n(n>=1)块
  • EMMC测试
  • 移植FATFS文件系统
  • 准备工作
  • keil工程文件结构
  • 修改底层驱动文件
  • 修改ffconf.h
  • 添加底层驱动
  • disk_status
  • disk_initialize
  • disk_read
  • disk_write
  • disk_ioctl
  • FATFS文件挂载测试
  • 工程需要使用EMMC挂载FATFS文件系统,苦苦寻找皆为SD卡挂载FATFS,虽原理一样还是写了这么一篇博客,希望对新手可以有些帮助!!!

    STM32驱动EMMC

    使用STM32CubeMX配置SDIO

    1. 选择SDIO选项
    2. 配置DMA
    3. 选择中断优先级

    编写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);
    

    ###测试结果

    作者:一个不知名的小刘

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32使用HAL库驱动EMMC挂载FATFS文件系统

    发表回复