目录
- 简介
- 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提供的各种接口对数据以文件的形式进行读写,而无需面对存储设备进行编程。
我们常说的*FAT是文件配置表(File Allocation Table)*的缩写,FATfs则是根据这样一个标准的文件配置表对数据以文件的形式,使用约定的存储方式(卷、块、扇区)在存储设备内进行读写。由于Windows“兼容”FAT文件系统,因此嵌入式设备存储在SD卡中的文件在PC中可以看到并读写。
驱动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,如下图。
middleware文件夹下的CMakeList检测到CONFIG_FATFS则在工程中添加了 middleware\fatfs这个子文件夹,下面存放fatfs的头文件与源代码。检测到CONFIG_SDMMC则在工程中添加了hpm_sdmmc这个子文件夹,下面存放先楫编写的sd/eMMC的底层驱动。如下图。
到此例程将两个子文件夹添加入工程,如下图。
进入middleware\fatfs下面的CMakeList中,检测到定义了CONFIG_SDMMC,则添加宏定义:SD_FATFS_ENABLE=1。文件开头添加了fatfs的源文件路径,另外添加了porrable子文件夹,此文件夹中包含文件系统的移植程序,也就是移植fatfs需要修改的有关底层硬件驱动的部分。如下图。
进入Portable文件下的CMakeList中,首先将此文件路径下的头文件与源文件添加进工程,后面判断是否定义CONFIG_XXX,如果定义了就将相应的头文件与源文件添加工程。在此,CONFIG_SDMMC已经定义,因此将sdxc作为头文件路径与源文件路径。
移植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。
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
理清思路,然后顺序走下去。