STM32H743驱动eMMC挂载FATFS系统读写文件

前面两篇文章分别介绍了 STM32H743 对 eMMC 的读写和 eMMC 虚拟 U 盘的操作,接下来就介绍一下 STM32H743 驱动 eMMC 挂载 FatFs 系统读写文件。FatFs 是一个用于小型嵌入式系统的通用 FAT/exFAT 文件系统模块。FatFs 模块是按照 ANSI C(C89)编写的,与磁盘 I/O 层完全分离。因此,它独立于平台。它可以集成到资源有限的小型微控制器中,如 8051、PIC、AVR、ARM、Z80、RX 等。此外,还提供了用于微型微控制器的 Petit Fatfs 模块。

参考资料:

一、开发平台

  • 开发环境:MDK5.30
  • 移植驱动:STM32Cube_FW_H7_V1.9.0
  • 硬件平台:STM32H743VITX + eMMC(型号:MTFC4GACAJCN-1M WT)

二、STM32CubeMX 配置

这部分可以参考下面的文章:

STM32H743使用SDMMC接口读写eMMC存储器

STM32H743使用SDMMC接口读写eMMC存储器

STM32H743 使用 SDMMC 接口读写 eMMC 存储器,与 STM32 驱动 SD 类似。通过官方 HAL 库中 stm32h7xx_hal_mmc.h 文件驱动,采用 …

三、FatFs 项目框架解读及操作流程分析

生成工程文件后,可以看出来如图 1 所示的项目文件框架。

STM32H743驱动eMMC挂载FATFS系统读写文件
图 1 STM32H743 驱动 MMC 挂载 FATFS 系统读写文件的工程文件结构
  • main.c 文件中包含了 FatFs 的应用程序;
  • user_diskio.c 文件中是磁盘 I/O 驱动文件;
  • sdmmc.c 文件是对 eMMC HAL 文件中对 eMMC 读写等功能的封装,供 user_diskio.c 调用;
  • eMMC HAL 文件是 STM32H743 的 HAL 库文件;
  • FatFs 文件夹是 FatFs 源码相关文件,这里的文件不需要改动。

以上即是实现 eMMC 挂载 FatFs 文件系统所需要的主要文件,这么多文件具体的调用关系如何呢?可以先来看一下 FatFs 的介绍。

FatFs 各个文件的依赖关系:

STM32H743驱动eMMC挂载FATFS系统读写文件
图 2 FatFs 各个文件的依赖关系

驱动一个磁盘或者多个磁盘的框图:

STM32H743驱动eMMC挂载FATFS系统读写文件
图 3 驱动一个磁盘或者多个磁盘的框图

上面两张图清晰的描绘了 FatFs 文件系统各个文件的依赖关系和调用关系,结合工程文件用一张图来说明 STM32H743 驱动 eMMC 挂载 FatFs 系统读写文件的工程文件调用关系:

STM32H743驱动eMMC挂载FATFS系统读写文件
图 4 STM32H743 驱动 MMC 挂载 FATFS 系统读写文件的工程文件调用

具体就是:

(1)main.c 文件是 FatFs 文件系统的 Application,也就是应用程序;通过 f_open()、f_read()等函数操作 FatFs 文件系统。

(2)FatFs 文件系统为应用程序提供函数接口,也就是 f_open()、f_read()等函数;对底层驱动使用 disk_read()、disk_write()、get_fattime()等函数来操作,这些函数与磁盘 I/O 完全分离。

(3)user_diskio.c 文件是承接 FatFs 系统和底层驱动的文件,或者说其也是底层驱动的一部分,该文件定义了操作磁盘 I/O 的数据结构,并结合 sdmmc.c 和 emmc HAL 库共同完成底层驱动。

以一个初始化的例子来说明操作流程,例如在 main 函数中创建文件系统:

res = f_mkfs(MMCPath, FM_FAT32, 0, workBuffer, sizeof(workBuffer));

f_mkfs 函数的定义是在 FatFs 文件系统的 ff.c 文件中,在函数 f_mkfs 中会初始化并检查磁盘:

	/* Check physical drive status */
	stat = disk_initialize(pdrv);

这里又调用了 disk_initialize()函数,该函数的定义则是 FatFs 文件系统中的 diskio.c 中:

/**
  * @brief  Initializes a Drive
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
  DSTATUS stat = RES_OK;

  if(disk.is_initialized[pdrv] == 0)
  {
    disk.is_initialized[pdrv] = 1;
    stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);
  }
  return stat;
}

其中,

stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);

会实例化到底层驱动,具体就是 user_diskio.c 中的 DSTATUS USER_initialize();

该函数里面则是具体操作磁盘 I/O 的工作(由于在 STM32CubeMX 配置 FatFs 的时候,这里选择了 User-defined,所以默认这里是空函数),会涉及到 sdmmc.c 文件和 emmc HAL 库文件。至此,完成创建文件系统的工作。

同样,f_open()、f_read()、f_write()、f_close()等函数的操作流程也是这么个过程。

根据上面的分析,弄懂了 FatFs 的工作流程,就可以修改 user_diskio.c 文件,实现相应的磁盘 I/O 操作功能。再在 main 函数中增加应用程序,就可以实现 STM32H743 驱动 eMMC 挂载 FatFs 系统读写文件。main 函数中的应用程序如下:

  /*-1- Link the micro SD disk I/O driver*/
  if(FATFS_LinkDriver(&USER_Driver, MMCPath) == 0)
  {
    /* Create FAT volume */
    usb_printf("[CM7]:\tCreating FileSystem...\n");
    res = f_mkfs(MMCPath, FM_FAT32, 0, workBuffer, sizeof(workBuffer));

    if (res != FR_OK)
    {
      usb_printf("[CM7]:\tCreating FileSystem Failed!...\n");
      Error_Handler();
    }
    usb_printf("[CM7]:\tFileSystem Created successfully!\n");

    /* start the FatFs operations simulaneously with the Core CM4 */
    FS_FileOperations();
  }

注意:f_mkfs()函数每次程序运行时都会重新创建一次系统,相当于格式化。所以,如果 eMMC 已经创建好 FatFs 文件系统,此语句可屏蔽掉。

FS_FileOperations()函数代码如下:

uint32_t file_size;
static void FS_FileOperations(void)
{
  FRESULT res;
  uint32_t byteswritten, bytesread;

  /* Register the file system object to the FatFs module */
  if(f_mount(&MMCFatFs, (TCHAR const*)MMCPath, 0) != FR_OK)
  {
    goto error;
  }
  /* open the file "CM7.TXT" in write mode */
  res = f_open(&MyFile, CM7_FILE, FA_CREATE_ALWAYS | FA_WRITE);
  if(res != FR_OK)
  {
    goto error;
  }

//  LOCK_HSEM(UART_HSEM_ID);
  usb_printf("[CM7]:\topening '%s' for writting...\r\n", CM7_FILE);
//  UNLOCK_HSEM(UART_HSEM_ID);

  /* Write data to the text file */
  res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&byteswritten);

  if((byteswritten == 0) || (res != FR_OK))
  {
    f_close(&MyFile);
    goto error;
  }

//  LOCK_HSEM(UART_HSEM_ID);
  usb_printf("[CM7]:\t'%s' '%lu' bytes written...\r\n", CM7_FILE, byteswritten);
//  UNLOCK_HSEM(UART_HSEM_ID);

  /* Close the open text file */
  f_close(&MyFile);

  /* Open the text file object with read access */
  if(f_open(&MyFile, CM7_FILE, FA_READ) != FR_OK)
  {
    goto error;
  }

//  LOCK_HSEM(UART_HSEM_ID);
  usb_printf("[CM7]:\treading '%s' content...\r\n", CM7_FILE);
//  UNLOCK_HSEM(UART_HSEM_ID);

  /* Read data from the text file */
  res = f_read(&MyFile, rtext, sizeof(rtext), (void *)&bytesread);
  if((bytesread == 0) || (res != FR_OK))
  {
    f_close(&MyFile);
    goto error;
  }
  /* Close the open text file */
  f_close(&MyFile);

 /* Compare read data with the expected data */
  if(FatfsBuffercmp(rtext,  (uint8_t *)wtext,  byteswritten) != 0)
  {
    goto error;
  }
  else
  {
//    LOCK_HSEM(UART_HSEM_ID);
    usb_printf("[CM7]:\t%s ==> '>  %s <'\r\n", CM7_FILE, rtext);
//    UNLOCK_HSEM(UART_HSEM_ID);
    while(1)
    {
//      BSP_LED_Toggle(LED_RED);
      HAL_Delay(250);
    }
  }


error:
  Error_Handler();
}

代码执行流程为:

在主函数中为 eMMC 创建 FAT32 文件系统,挂载 eMMC,创建 CM7.LOG 文件,往里写数据,写完成之后关闭文件,读文件,关闭文件,比对读写数据是否正确。

编译下载,通过串口查看程序执行过程中打印的信息,如图 5 所示。

STM32H743驱动eMMC挂载FATFS系统读写文件
图 5 STM32H743 驱动 eMMC 挂载 FATFS 系统读写文件测试结果

另外,也可以运行“STM32H743 实现 eMMC 虚拟 U 盘功能”程序,更直观的查看 STM32H743 在 eMMC 虚拟 U 盘里创建的 log 文件以及内容,如图 6 所示。

STM32H743驱动eMMC挂载FATFS系统读写文件
图 6 STM32H743 驱动 eMMC 挂载 FATFS 系统读写文件测试结果
附件仅博主测试所用,暂不提供下载

扫码关注尚为网微信公众号

尚为网微信公众号
每天学习电路设计嵌入式系统的专业知识,关注一波,没准就用上了。

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/939.html

(1)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2021年3月29日 17:10
下一篇 2021年4月2日 21:31

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注