目录

  • 简介
  • Fatfs说明
  • 驱动eMMC
  • 移植准备
  • 开始移植
  • 1、在例程路径下,复制emmc文件夹,改名为emmc_fatfs。
  • 2、emmc_fatfs下的CMakeList文件更改如下
  • 3、middleware下的CMakeList文件更改如下
  • 4、middleware\fatfs下的cmakelist文件更改如下
  • 5、middleware\fatfs\src\portable下的cmakelist文件更改如下
  • 6、将middleware\fatfs\src\portable\sdxc文件夹下的源文件与头文件复制粘贴改名为hpm_emmc_disk.c与.h。
  • 7、修改hpm_emmc_disk.h如下
  • 8、修改hpm_emmc_disk.c如下
  • 9、修改middleware\fatfs\src\portable下的diskio.c
  • 10、最后生成工程,仿照sd_fatfs修改main.c,测试
  • 总结

简介

最近用到先楫的单片机HPM6750(HPM6754),由于一些原因需要使用eMMC代替SD卡存储数据,为了方便数据管理与查看,准备使用Fatfs,而官方SDK并未提供eMMC的Fatfs读写例程,因此作者参考先楫官方提供的SD卡的Fatfs例程实现了Fatfs挂载到eMMC设备的数据读写,也就是将Fatfs“移植”到eMMC。

Fatfs说明

现在各种论坛上有很多单片机移植Fatfs的教程与分享,对于不了解Fatfs的读者可以先去了解一下。
Fatfs简单来说就是用于嵌入式的通用 FAT/exFAT文件系统模块,作为嵌入式应用的中间件使用,在对Fatfs模块配置好底层存储设备的IO驱动后,上层应用就可以方便的使用FATfs提供的各种接口对数据以文件的形式进行读写,而无需面对存储设备进行编程。

eMMC Nand Flash 读写速度 emmc读写次数_c语言


我们常说的*FAT是文件配置表(File Allocation Table)*的缩写,FATfs则是根据这样一个标准的文件配置表对数据以文件的形式,使用约定的存储方式(卷、块、扇区)在存储设备内进行读写。由于Windows“兼容”FAT文件系统,因此嵌入式设备存储在SD卡中的文件在PC中可以看到并读写。

eMMC Nand Flash 读写速度 emmc读写次数_mcu_02


驱动eMMC

在移植fatfs前,我们要确保eMMC直接初始化正确、读写正确,即底层驱动的例程应该调试通过。
对于驱动eMMC读取存储设备信息,进行数据直接读取的例程官方已经提供,只需稍加修改即可使用。
在此路径下:sdk_env\hpm_sdk\samples\drivers\sdxc
建议自行修改或者查看以下博主的论文修改:
来自博客园“求隐”:.

在此,作者使用的是江波龙的eMMC,high-speed SDR模式,读写40MB/s左右,与上述博文略有不同。

移植准备

在移植之前,我们需要知道emmc_fatfs工程应该怎么构建的,先楫是使用CMake进行管理工程与控制编译流程的,由于作者在此之前并没有接触过CMake,在移植之前我们需要知道如何添加源文件与头文件路径,以及定义条件编译等。因此我们参考sd_fatfs例程,分析构建工程、移植fatfs的流程。

需要注意的是:与MDK在IDE设置全局定义、管理工程文件与编译器设置等操作不同的是,先楫采用CMake组织管理工程文件,这些设置需要在CMakeList.txt文件中进行配置,官方推荐IDE仅做编译调试使用。


首先在sd_fatfs例程下(路径见图片左上角)的CMakeList中定义了CONFIG_SDMMC,CONFIG_FATFS,如下图。

eMMC Nand Flash 读写速度 emmc读写次数_mcu_03


middleware文件夹下的CMakeList检测到CONFIG_FATFS则在工程中添加了 middleware\fatfs这个子文件夹,下面存放fatfs的头文件与源代码。检测到CONFIG_SDMMC则在工程中添加了hpm_sdmmc这个子文件夹,下面存放先楫编写的sd/eMMC的底层驱动。如下图。

eMMC Nand Flash 读写速度 emmc读写次数_单片机_04


到此例程将两个子文件夹添加入工程,如下图。

eMMC Nand Flash 读写速度 emmc读写次数_c语言_05

进入middleware\fatfs下面的CMakeList中,检测到定义了CONFIG_SDMMC,则添加宏定义:SD_FATFS_ENABLE=1。文件开头添加了fatfs的源文件路径,另外添加了porrable子文件夹,此文件夹中包含文件系统的移植程序,也就是移植fatfs需要修改的有关底层硬件驱动的部分。如下图。

eMMC Nand Flash 读写速度 emmc读写次数_mcu_06

进入Portable文件下的CMakeList中,首先将此文件路径下的头文件与源文件添加进工程,后面判断是否定义CONFIG_XXX,如果定义了就将相应的头文件与源文件添加工程。在此,CONFIG_SDMMC已经定义,因此将sdxc作为头文件路径与源文件路径。

eMMC Nand Flash 读写速度 emmc读写次数_#include_07

移植FAT文件系统过程中,主要需要修改的是portable文件夹下的diskio头文件与源文件,portable\sdxc文件夹下的hpm_sdmmc_disk头文件与源文件。hpm_sdmmc_disk文件中写我们所要移植FAT系统设备(比如SD、flash、eMMC)的底层驱动,而diskio则是用来将我们写的底层驱动封装成FAT其他上层接口认识的底层接口,形象点说就是将函数换个名字,方便上层引用。

读者查看diskio.c文件就会豁然开朗,移植的逻辑很简单,就是根据条件编译,使能不同的函数发生作用,因此我们模仿原程序的结构对eMMC的部分进行补充就好。然后我们可以在middleware\fatfs\src\portable\sdxc下创建emmc的底层接口的驱动文件,根据sd卡的参考例程与eMMC的直接读写例程做修改即可。

开始移植

下面我们开始移植eMMC的FAT文件系统!

==在下面的移植过程中,对一些CMakeList文件的修改,作者往往只是添加了一两句,读者根据上面的分析也可能不易于理解,具体还需读者自己去查看工程文件!!!。

1、在例程路径下,复制emmc文件夹,改名为emmc_fatfs。

eMMC Nand Flash 读写速度 emmc读写次数_嵌入式硬件_08

2、emmc_fatfs下的CMakeList文件更改如下

主要是修改变量名、工程名等

# Copyright (c) 2023 HPMicro
# SPDX-License-Identifier: BSD-3-Clause

cmake_minimum_required(VERSION 3.13)

set(CONFIG_eMMC 1)
set(CONFIG_FATFS 1)

find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE})

project(emmc_fatfs)

sdk_compile_definitions(-DeMMC_FATFS_ENABLE=1)
sdk_compile_definitions(-DFF_CODE_PAGE=437)

sdk_compile_options(-Os)

sdk_inc(src)

sdk_app_src(src/emmc_fatfs.c)
generate_ses_project()

3、middleware下的CMakeList文件更改如下

# Copyright (c) 2021-2023 HPMicro
# SPDX-License-Identifier: BSD-3-Clause

add_subdirectory_ifdef(CONFIG_LVGL lvgl)
add_subdirectory_ifdef(CONFIG_TINYUSB tinyusb)
add_subdirectory_ifdef(CONFIG_TINYCRYPT tinycrypt)
add_subdirectory_ifdef(CONFIG_FATFS fatfs)
add_subdirectory_ifdef(CONFIG_FREERTOS FreeRTOS)
add_subdirectory_ifdef(CONFIG_MOTORCTRL hpm_mcl)
add_subdirectory_ifdef(CONFIG_SDMMC hpm_sdmmc)
add_subdirectory_ifdef(CONFIG_eMMC hpm_sdmmc)
add_subdirectory_ifdef(CONFIG_LIBJPEG libjpeg-turbo)
add_subdirectory_ifdef(CONFIG_LWIP lwip)
add_subdirectory_ifdef(CONFIG_COREMARK coremark)
add_subdirectory_ifdef(CONFIG_TFLM tflm)
add_subdirectory_ifdef(CONFIG_HPM_MATH hpm_math)
add_subdirectory_ifdef(CONFIG_AUDIO_CODEC audio_codec)
add_subdirectory_ifdef(CONFIG_SEGGER_RTT segger_rtt)
add_subdirectory_ifdef(CONFIG_ERPC erpc)
add_subdirectory_ifdef(CONFIG_CHERRYUSB cherryusb)
add_subdirectory_ifdef(CONFIG_MBEDTLS mbedtls)
add_subdirectory_ifdef(CONFIG_UCOS_III ucos_iii)
add_subdirectory(azure_rtos)
add_subdirectory_ifdef(CONFIG_MICROROS microros)

4、middleware\fatfs下的cmakelist文件更改如下

# Copyright (c) 2021 HPMicro
# SPDX-License-Identifier: BSD-3-Clause

sdk_inc(src/common)
sdk_src(src/common/ff.c)
sdk_src(src/common/ffunicode.c)

add_subdirectory(src/portable)

if(DEFINED CONFIG_SDMMC)
sdk_compile_definitions(-DSD_FATFS_ENABLE=1)
endif()

if(DEFINED CONFIG_eMMC)
sdk_compile_definitions(-DeMMC_FATFS_ENABLE=1)
endif()

5、middleware\fatfs\src\portable下的cmakelist文件更改如下

# Copyright (c) 2021 HPMicro
# SPDX-License-Identifier: BSD-3-Clause

sdk_inc(.)
sdk_src(diskio.c)

sdk_inc_ifdef(CONFIG_USB_FATFS usb)
sdk_src_ifdef(CONFIG_USB_FATFS_TINYUSB usb/hpm_fatfs_tinyusb.c)
sdk_src_ifdef(CONFIG_USB_FATFS_CHERRYUSB usb/hpm_fatfs_cherryusb.c)

sdk_inc_ifdef(CONFIG_eMMC sdxc)
sdk_src_ifdef(CONFIG_eMMC sdxc/hpm_emmc_disk.c)

if(NOT DEFINED CONFIG_HPM_SPI_SDCARD)
sdk_inc_ifdef(CONFIG_SDMMC sdxc)
sdk_src_ifdef(CONFIG_SDMMC sdxc/hpm_sdmmc_disk.c)
else()
sdk_inc_ifdef(CONFIG_HPM_SPI_SDCARD spi_sd)
sdk_src_ifdef(CONFIG_HPM_SPI_SDCARD spi_sd/hpm_spi_sd_disk.c)
endif()

6、将middleware\fatfs\src\portable\sdxc文件夹下的源文件与头文件复制粘贴改名为hpm_emmc_disk.c与.h。

7、修改hpm_emmc_disk.h如下

/*
 * Copyright (c) 2021-2022 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#ifndef HPM_EMMC_DISK_H
#define HPM_EMMC_DISK_H

#include "ff.h"
#include "diskio.h"
#include "hpm_sdmmc_emmc.h"

extern emmc_card_t g_emmc;


#define MAX_ALIGNED_BUF_SIZE (16384U)

#ifdef __cplusplus
extern "C" {
#endif

DSTATUS emmc_disk_initialize(BYTE pdrv);

DSTATUS emmc_disk_deinitialize(BYTE pdrv);

DSTATUS emmc_disk_status(BYTE pdrv);

DSTATUS emmc_disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count);

DSTATUS emmc_disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count);

DRESULT emmc_disk_ioctl(BYTE pdrv, BYTE cmd, void *buff);


#ifdef __cplusplus
}
#endif

#endif /* HPM_eMMC_DISK_H */

8、修改hpm_emmc_disk.c如下

/*
 * Copyright (c) 2021-2022 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include "ffconf.h"
#include "hpm_emmc_disk.h"
#include "hpm_l1c_drv.h"
#include "board.h"

#define EMMC_SECTOR_SIZE (512UL)

ATTR_PLACE_AT_NONCACHEABLE_BSS emmc_card_t g_emmc;

ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint32_t g_aligned_buf[MAX_ALIGNED_BUF_SIZE / sizeof(uint32_t)];

DSTATUS emmc_disk_initialize(BYTE pdrv)
{
    static bool has_card_initialized = false;

    if (pdrv != DEV_MMC) {
        return STA_NOINIT;
    }

    if (has_card_initialized) {
        return RES_OK;
    }

    if (emmc_init(&g_emmc) != status_success) {
        emmc_deinit(&g_emmc);
        memset(&g_emmc, 0, sizeof(g_emmc));
        return STA_NODISK;
    }
    has_card_initialized = true;

    return RES_OK;
}

DSTATUS emmc_disk_deinitialize(BYTE pdrv)
{
    emmc_deinit(&g_emmc);

    return RES_OK;
}

DSTATUS emmc_disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count)
{
    if (pdrv != DEV_MMC) {
        return RES_PARERR;
    }

    if (((uint32_t)buff % 4) != 0) {
        uint32_t sys_aligned_buf_addr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&g_aligned_buf);
        uint32_t remaining_size = EMMC_SECTOR_SIZE * count;
        while(remaining_size > 0) {
            uint32_t write_size = MIN(sizeof(g_aligned_buf), remaining_size);

            memcpy(g_aligned_buf, buff, write_size);
            l1c_dc_flush(sys_aligned_buf_addr, write_size);
            uint32_t sector_count = (uint32_t) write_size / EMMC_SECTOR_SIZE;
            if (emmc_write_blocks(&g_emmc, (const uint8_t *) sys_aligned_buf_addr, (uint32_t) sector, sector_count) != status_success) {
                return RES_ERROR;
            }
            buff += write_size;
            sector += sector_count;
            remaining_size -= write_size;
        }
    } else {
        if (emmc_write_blocks(&g_emmc, (const uint8_t *) buff, (uint32_t) sector, (uint32_t) count) != status_success) {
            return RES_ERROR;
        }
    }

    return RES_OK;
}

DSTATUS emmc_disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count)
{
    if (pdrv != DEV_MMC) {
        return RES_PARERR;
    }

    if (((uint32_t)buff % 4) != 0) {
        uint32_t sys_aligned_buf_addr = core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)&g_aligned_buf);
        uint32_t remaining_size = EMMC_SECTOR_SIZE * count;
        while(remaining_size > 0) {
            uint32_t read_size = MIN(sizeof(g_aligned_buf), remaining_size);
            uint32_t sector_count = read_size / EMMC_SECTOR_SIZE;
            if (emmc_read_blocks(&g_emmc, (uint8_t *) sys_aligned_buf_addr, sector, sector_count) != status_success) {
                return RES_ERROR;
            }
            l1c_dc_invalidate(sys_aligned_buf_addr, read_size);
            memcpy(buff, g_aligned_buf, read_size);
            buff += read_size;
            sector += sector_count;
            remaining_size -= read_size;
        }
    } else {
      if (emmc_read_blocks(&g_emmc, (uint8_t *) buff, sector, count) != status_success) {
          return RES_ERROR;
      }
    }
    return RES_OK;
}

DRESULT emmc_disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
{
    DRESULT result = RES_PARERR;
    do {
        HPM_BREAK_IF((pdrv != DEV_MMC) || ((cmd != CTRL_SYNC) && (buff == NULL)));
        result = RES_OK;
        switch (cmd) {
        case GET_SECTOR_COUNT:          
            *(uint32_t *) buff = g_emmc.device_attribute.sector_count;	
            break;
        case GET_SECTOR_SIZE:           
            *(uint32_t *) buff = g_emmc.device_attribute.sector_size;
            break;
        case GET_BLOCK_SIZE:            
            *(uint32_t *) buff = g_emmc.device_attribute.erase_group_size;
            break;
        case CTRL_SYNC:
            result = RES_OK;
            break;
        default:
            result = RES_PARERR;
            break;
        }

    } while (false);

    return result;
}

DSTATUS emmc_disk_status(BYTE pdrv)
{
    if (pdrv != DEV_MMC) {
        return STA_NOINIT;
    }

    return RES_OK;
}

9、修改middleware\fatfs\src\portable下的diskio.c

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various existing       */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

/*
 * Copyright (c) 2021-2023 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include "diskio.h"          /* Declarations of disk functions */

// usb
#if defined(USB_FATFS_ENABLE) && USB_FATFS_ENABLE
#include "./usb/hpm_fatfs_usb.h"
#endif

// sd
#if defined(SD_FATFS_ENABLE) && SD_FATFS_ENABLE

#if defined(SD_SPI_ENABLE) && (SD_SPI_ENABLE)
#include "./spi_sd/hpm_spi_sd_disk.h"
#else
#include "./sdxc/hpm_sdmmc_disk.h"
#endif

#endif

// emmc
#if defined(eMMC_FATFS_ENABLE) && eMMC_FATFS_ENABLE
#include "./sdxc/hpm_emmc_disk.h"
#endif



/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status(
        BYTE pdrv   /* Physical drive number to identify the drive */
)
{
    DSTATUS stat = STA_NOINIT;

    switch (pdrv) {
    case DEV_RAM :
        break;

    // case DEV_MMC :
    //     break;

#if defined(USB_FATFS_ENABLE) && USB_FATFS_ENABLE
    case DEV_USB :
        stat = usb_disk_status(pdrv);
        break;
#endif

#if defined(SD_FATFS_ENABLE) && SD_FATFS_ENABLE
    case DEV_SD:
#if defined(SD_SPI_ENABLE) && (SD_SPI_ENABLE)
        stat = spi_sd_disk_status(pdrv);
#else
        stat = sd_disk_status(pdrv);
#endif
        break;
#endif

// emmc
#if defined(eMMC_FATFS_ENABLE) && eMMC_FATFS_ENABLE
    case DEV_MMC:
        stat = emmc_disk_status(pdrv);
        break;
#endif

    default:
        break;
    }

    return stat;
}

/*-----------------------------------------------------------------------*/
/* Initialize a Drive                                                    */
/*-----------------------------------------------------------------------*/
void disk_deinitialize(
        BYTE pdrv   /* Physical drive number to identify the drive */
)
{
    switch (pdrv) {
    case DEV_RAM :
        break;

    // case DEV_MMC :
    //     break;

#if defined(USB_FATFS_ENABLE) && USB_FATFS_ENABLE
    case DEV_USB:
        usb_disk_deinitialize();
        break;
#endif

#if defined(SD_FATFS_ENABLE) && SD_FATFS_ENABLE
    case DEV_SD:
#if defined(SD_SPI_ENABLE) && (SD_SPI_ENABLE)
        spi_sd_disk_deinitialize(pdrv);
#else
        sd_disk_deinitialize(pdrv);
#endif
        break;
#endif

// emmc
#if defined(eMMC_FATFS_ENABLE) && eMMC_FATFS_ENABLE
    case DEV_MMC:
        emmc_disk_deinitialize(pdrv);
        break;
#endif

    default:
        break;
    }
}

DSTATUS disk_initialize(
        BYTE pdrv   /* Physical drive number to identify the drive */
)
{
    DSTATUS stat = STA_NOINIT;

    switch (pdrv) {
    case DEV_RAM :
        break;

    // case DEV_MMC :
    //     break;

#if defined(USB_FATFS_ENABLE) && USB_FATFS_ENABLE
    case DEV_USB :
        stat = usb_disk_initialize(pdrv);
        break;
#endif

#if defined(SD_FATFS_ENABLE) && SD_FATFS_ENABLE
    case DEV_SD:
#if defined(SD_SPI_ENABLE) && (SD_SPI_ENABLE)
        stat = spi_sd_disk_initialize(pdrv);
#else
        stat = sd_disk_initialize(pdrv);
#endif
        break;
#endif

// emmc
#if defined(eMMC_FATFS_ENABLE) && eMMC_FATFS_ENABLE
    case DEV_MMC:
        stat = emmc_disk_initialize(pdrv);
        break;
#endif

    default:
        break;
    }

    return stat;
}

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/
DRESULT disk_read(
        BYTE pdrv,      /* Physical drive number to identify the drive */
        BYTE *buff,     /* Data buffer to store read data */
        LBA_t sector,   /* Start sector in LBA */
        UINT count      /* Number of sectors to read */
)
{
    DRESULT res = RES_ERROR;

    switch (pdrv) {
    case DEV_RAM :
        break;

    // case DEV_MMC :
    //     break;

#if defined(USB_FATFS_ENABLE) && USB_FATFS_ENABLE
    case DEV_USB :
        res = usb_disk_read(pdrv, buff, sector, count);
        break;
#endif

#if defined(SD_FATFS_ENABLE) && SD_FATFS_ENABLE
    case DEV_SD:
#if defined(SD_SPI_ENABLE) && (SD_SPI_ENABLE)
        res = spi_sd_disk_read(pdrv, buff, sector, count);
#else
        res = sd_disk_read(pdrv, buff, sector, count);
#endif
        break;
#endif

// emmc
#if defined(eMMC_FATFS_ENABLE) && eMMC_FATFS_ENABLE
    case DEV_MMC:
        res = emmc_disk_read(pdrv, buff, sector, count);
        break;
#endif

    default:
        res = RES_PARERR;
        break;
    }

    return res;
}

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write(
        BYTE pdrv,          /* Physical drive number to identify the drive */
        const BYTE *buff,   /* Data to be written */
        LBA_t sector,       /* Start sector in LBA */
        UINT count          /* Number of sectors to write */
)
{
    DRESULT res = RES_ERROR;

    switch (pdrv) {
    case DEV_RAM :
        break;

    // case DEV_MMC :
    //     break;

#if defined(USB_FATFS_ENABLE) && USB_FATFS_ENABLE
    case DEV_USB :
        res = usb_disk_write(pdrv, buff, sector, count);
        break;
#endif

#if defined(SD_FATFS_ENABLE) && SD_FATFS_ENABLE
    case DEV_SD:
#if defined(SD_SPI_ENABLE) && (SD_SPI_ENABLE)
        res = spi_sd_disk_write(pdrv, buff, sector, count);
#else
        res = sd_disk_write(pdrv, buff, sector, count);
#endif
        break;
#endif

// emmc
#if defined(eMMC_FATFS_ENABLE) && eMMC_FATFS_ENABLE
    case DEV_MMC:
        res = emmc_disk_write(pdrv, buff, sector, count);
        break;
#endif

    default:
        res = RES_PARERR;
        break;
    }

    return res;
}

#endif

/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl(
        BYTE pdrv,      /* Physical drive number (0..) */
        BYTE cmd,       /* Control code */
        void *buff      /* Buffer to send/receive control data */
)
{
    DRESULT res = RES_ERROR;

    switch (pdrv) {
    case DEV_RAM :
        break;

    // case DEV_MMC :
    //     break;

#if defined(USB_FATFS_ENABLE) && USB_FATFS_ENABLE
    case DEV_USB :
        res = usb_disk_ioctl(pdrv, cmd ,buff);
        break;
#endif

#if defined(SD_FATFS_ENABLE) && SD_FATFS_ENABLE
    case DEV_SD:
#if defined(SD_SPI_ENABLE) && (SD_SPI_ENABLE)
        res = spi_sd_disk_ioctl(pdrv, cmd, buff);
#else
        res = sd_disk_ioctl(pdrv, cmd, buff);
#endif
        break;
#endif

// emmc
#if defined(eMMC_FATFS_ENABLE) && eMMC_FATFS_ENABLE
    case DEV_MMC:
        res = emmc_disk_ioctl(pdrv, cmd, buff);
        break;
#endif

    default:
        res = RES_ERROR;
        break;
    }

    return res;
}

10、最后生成工程,仿照sd_fatfs修改main.c,测试

/*
 * Copyright (c) 2021-2023 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include "board.h"
#include "hpm_sdmmc_emmc.h"
#include "ff.h"
#include "diskio.h"
#include "hpm_mchtmr_drv.h"
#include "hpm_clock_drv.h"

extern emmc_card_t g_emmc;

FATFS s_emmc_disk;
FIL s_file;
DIR s_dir;
FRESULT fatfs_result;
BYTE work[FF_MAX_SS];

const TCHAR driver_num_buf[3] = {DEV_MMC + '0', ':', '/'};

#define TEST_DIR_NAME "hpmicro_emmc_test_dir0"

void show_menu(void);

const char *show_error_string(FRESULT fresult);

static FRESULT emmc_mount_fs(void);

static FRESULT emmc_mkfs(void);

static FRESULT emmc_write_file(void);

static FRESULT emmc_read_file(void);

static FRESULT emmc_dir_test(void);

static FRESULT emmc_big_file_test(void);


int main(void)
{
    board_init();
    show_menu();
    fatfs_result = emmc_mount_fs();           
    if (fatfs_result == FR_NO_FILESYSTEM) {
        printf("There is no File system available, making file system...\n");
        fatfs_result = emmc_mkfs();           
    }

    while (1) {
        char option = getchar();

        switch (option) {
        case '1':
            fatfs_result = emmc_mkfs();       // Format the SD card with FATFS
            break;
        case '2':
            fatfs_result = emmc_write_file(); // Create hello.txt
            break;
        case '3':
            fatfs_result = emmc_read_file();  // Read 1st line from hello.txt
            break;
        case '4':
            fatfs_result = emmc_dir_test();   // Directory related test
            break;
        case 's':
            fatfs_result = emmc_big_file_test();    // Large file write test
            break;
        default:
            show_menu();
            break;
        }
    }
}

void show_menu(void)
{
    const char menu_str[] = "eMMC FATFS demo\n-----------------------------------\n"
                            "1 - Format the eMMC card with FATFS\n"
                            "2 - Create hello.txt\n"
                            "3 - Read 1st line from hello.txt\n"
                            "4 - Directory related test\n"
                            "s - Large file write test\n"
                            "Others - Show menu\n";

    printf(menu_str);
}




static FRESULT emmc_mount_fs(void)
{
    FRESULT fresult = f_mount(&s_emmc_disk, driver_num_buf, 1);
    if (fresult == FR_OK) {
        printf("eMMC has been mounted successfully\n");
    } else {
        printf("Failed to mount eMMC, cause: %s\n", show_error_string(fresult));
    }

    fresult = f_chdrive(driver_num_buf);
    return fresult;
}

static FRESULT emmc_mkfs(void)
{
    printf("Formatting the eMMC, depending on the eMMC capacity, the formatting process may take a long time\n");
    FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
    if (fresult != FR_OK) {
        printf("Making File system failed, cause: %s\n", show_error_string(fresult));
    } else {
        printf("Making file system is successful\n");
    }

    return fresult;
}

static FRESULT emmc_write_file(void)
{
    FRESULT fresult = f_open(&s_file, "readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
    if (fresult != FR_OK) {
        printf("Create new file failed, cause: %d\n", show_error_string(fresult));
    } else {
        printf("Create new file successfully, status=%d\n", fresult);
    }
    char hello_str[] = "Hello, this is eMMC FATFS demo\n";
    UINT byte_written;
    fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
    if (fresult != FR_OK) {
        printf("Write file failed, cause: %s\n", show_error_string(fresult));
    } else {
        printf("Write file operation is successfully\n");
    }

    f_close(&s_file);

    return fresult;
}

static FRESULT emmc_read_file(void)
{
    FRESULT fresult = f_open(&s_file, "readme.txt", FA_READ);
    if (fresult != FR_OK) {
        printf("Open file failed, cause: %s\n", show_error_string(fresult));
    } else {
        printf("Open file successfully\n");
    }

    if (fresult != FR_OK) {
        return fresult;
    }

    TCHAR str[100];
    f_gets(str, sizeof(str), &s_file);
    printf("%s\n", str);

    f_close(&s_file);

    return fresult;
}

static FRESULT emmc_big_file_test(void)
{
    FRESULT fresult = f_open(&s_file, "big_file.bin", FA_WRITE | FA_CREATE_ALWAYS);
    if (fresult != FR_OK) {
        printf("Create new file failed, cause: %s\n", show_error_string(fresult));
    } else {
        printf("Create new file successfully\n");
    }

    uint32_t write_size = 1024UL * 1024UL * 100UL;
    static uint8_t buf[32768];
    for (uint32_t i = 0; i < sizeof(buf); i++) {
        buf[i] = i & 0xFF;
    }
    while (write_size > 0) {
        UINT byte_written;
        fresult = f_write(&s_file, buf, sizeof(buf), &byte_written);
        if (fresult != FR_OK) {
            printf("Write file failed, cause: %s\n", show_error_string(fresult));
            return fresult;
        }

        write_size -= byte_written;
    }
    printf("Write file operation is successful\n");

    f_close(&s_file);

    return fresult;
}


static FRESULT emmc_dir_test(void)
{
    FRESULT fresult = f_mkdir(TEST_DIR_NAME);
    if (fresult != FR_OK) {
        printf("Creating new directory failed, cause: %s\n", show_error_string(fresult));
    } else {
        printf("Creating new directory succeeded\n");
    }

    fresult = f_rmdir(TEST_DIR_NAME);
    if (fresult != FR_OK) {
        printf("Removing new directory failed, cause: %s\n", show_error_string(fresult));
    } else {
        printf("Removing new directory succeeded\n");
    }

    return fresult;
}

const char *show_error_string(FRESULT fresult)
{
    const char *result_str;

    switch (fresult) {
    case FR_OK:
        result_str = "succeeded";
        break;
    case FR_DISK_ERR:
        result_str = "A hard error occurred in the low level disk I/O level";
        break;
    case FR_INT_ERR:
        result_str = "Assertion failed";
        break;
    case FR_NOT_READY:
        result_str = "The physical drive cannot work";
        break;
    case FR_NO_FILE:
        result_str = "Could not find the file";
        break;
    case FR_NO_PATH:
        result_str = "Could not find the path";
        break;
    case FR_INVALID_NAME:
        result_str = "Tha path name format is invalid";
        break;
    case FR_DENIED:
        result_str = "Access denied due to prohibited access or directory full";
        break;
    case FR_EXIST:
        result_str = "Access denied due to prohibited access";
        break;
    case FR_INVALID_OBJECT:
        result_str = "The file/directory object is invalid";
        break;
    case FR_WRITE_PROTECTED:
        result_str = "The physical drive is write protected";
        break;
    case FR_INVALID_DRIVE:
        result_str = "The logical driver number is invalid";
        break;
    case FR_NOT_ENABLED:
        result_str = "The volume has no work area";
        break;
    case FR_NO_FILESYSTEM:
        result_str = "There is no valid FAT volume";
        break;
    case FR_MKFS_ABORTED:
        result_str = "THe f_mkfs() aborted due to any problem";
        break;
    case FR_TIMEOUT:
        result_str = "Could not get a grant to access the volume within defined period";
        break;
    case FR_LOCKED:
        result_str = "The operation is rejected according to the file sharing policy";
        break;
    case FR_NOT_ENOUGH_CORE:
        result_str = "LFN working buffer could not be allocated";
        break;
    case FR_TOO_MANY_OPEN_FILES:
        result_str = "Number of open files > FF_FS_LOCK";
        break;
    case FR_INVALID_PARAMETER:
        result_str = "Given parameter is invalid";
        break;
    default:
        result_str = "Unknown error";
        break;
    }
    return result_str;
}

总结

在本文中,

1、我们的目标是移植fatfs实现eMMC文件系统读写。
2、我们需要通过查询了解Fatfs的结构与移植方法。
3、然后针对于先楫处理器的特点,首先通过调试确认eMMC可以直接读写,即底层驱动没问题。
4、然后了解CMake,根据例程学习工程构建与针对先楫处理器的移植。
5、更改IO文件,移植Fatfs到eMMC
理清思路,然后顺序走下去。