Merge branch 'feat/fatfs_support_sector_less_than_128' into 'master'

feat(fatfs): enable partition handling for sectors less than 128

Closes IDF-8538

See merge request espressif/esp-idf!33569
This commit is contained in:
Martin Vychodil 2024-10-16 13:34:12 +08:00
commit 2c5dcc977e
11 changed files with 199 additions and 30 deletions

View File

@ -1,10 +1,11 @@
#!/usr/bin/env python
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import os
from datetime import datetime
from typing import Any, List, Optional
from typing import Any
from typing import List
from typing import Optional
from fatfs_utils.boot_sector import BootSector
from fatfs_utils.exceptions import NoFreeClusterException
@ -12,10 +13,16 @@ from fatfs_utils.fat import FAT
from fatfs_utils.fatfs_state import FATFSState
from fatfs_utils.fs_object import Directory
from fatfs_utils.long_filename_utils import get_required_lfn_entries_count
from fatfs_utils.utils import (BYTES_PER_DIRECTORY_ENTRY, FATFS_INCEPTION, FATFS_MIN_ALLOC_UNIT,
RESERVED_CLUSTERS_COUNT, FATDefaults, get_args_for_partition_generator,
get_fat_sectors_count, get_non_data_sectors_cnt, read_filesystem,
required_clusters_count)
from fatfs_utils.utils import BYTES_PER_DIRECTORY_ENTRY
from fatfs_utils.utils import FATDefaults
from fatfs_utils.utils import FATFS_INCEPTION
from fatfs_utils.utils import FATFS_MIN_ALLOC_UNIT
from fatfs_utils.utils import get_args_for_partition_generator
from fatfs_utils.utils import get_fat_sectors_count
from fatfs_utils.utils import get_non_data_sectors_cnt
from fatfs_utils.utils import read_filesystem
from fatfs_utils.utils import required_clusters_count
from fatfs_utils.utils import RESERVED_CLUSTERS_COUNT
def duplicate_fat_decorator(func): # type: ignore
@ -48,14 +55,15 @@ class FATFS:
volume_label: str = FATDefaults.VOLUME_LABEL,
file_sys_type: str = FATDefaults.FILE_SYS_TYPE,
root_entry_count: int = FATDefaults.ROOT_ENTRIES_COUNT,
explicit_fat_type: int = None,
explicit_fat_type: Optional[int] = None,
media_type: int = FATDefaults.MEDIA_TYPE) -> None:
# root directory bytes should be aligned by sector size
assert (root_entry_count * BYTES_PER_DIRECTORY_ENTRY) % sector_size == 0
assert (int(root_entry_count) * BYTES_PER_DIRECTORY_ENTRY) % sector_size == 0
# number of bytes in the root dir must be even multiple of BPB_BytsPerSec
assert ((root_entry_count * BYTES_PER_DIRECTORY_ENTRY) // sector_size) % 2 == 0
if (int(root_entry_count) > 128):
assert ((int(root_entry_count) * BYTES_PER_DIRECTORY_ENTRY) // sector_size) % 2 == 0
root_dir_sectors_cnt: int = (root_entry_count * BYTES_PER_DIRECTORY_ENTRY) // sector_size
root_dir_sectors_cnt: int = (int(root_entry_count) * BYTES_PER_DIRECTORY_ENTRY) // sector_size
self.state: FATFSState = FATFSState(sector_size=sector_size,
explicit_fat_type=explicit_fat_type,

View File

@ -44,7 +44,10 @@ TEST_CASE("Create volume, open file, write and read back data", "[fatfs]")
fr_result = f_fdisk(pdrv, part_list, work_area);
REQUIRE(fr_result == FR_OK);
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, 0};
// For host tests, include FM_SFD flag when formatting partitions smaller than 128KB.
// if n_root field of MKFS_PARM is set to 128 => 1 root directory sec and if set to 0(default 512) => 4 root directory sectors.
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 128, 0};
fr_result = f_mkfs("", &opt, work_area, sizeof(work_area)); // Use default volume
// Mount the volume
@ -56,7 +59,7 @@ TEST_CASE("Create volume, open file, write and read back data", "[fatfs]")
REQUIRE(fr_result == FR_OK);
// Generate data
uint32_t data_size = 100000;
uint32_t data_size = 1000;
char *data = (char*) malloc(data_size);
char *read = (char*) malloc(data_size);
@ -130,7 +133,7 @@ static void prepare_fatfs(const char* partition_label, const esp_partition_t** p
fr_result = f_fdisk(_pdrv, part_list, work_area);
REQUIRE(fr_result == FR_OK);
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, 0};
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 128, 0};
fr_result = f_mkfs(drv, &opt, work_area, sizeof(work_area)); // Use default volume
REQUIRE(fr_result == FR_OK);
}
@ -222,7 +225,7 @@ TEST_CASE("Test mounting 2 volumes, writing data and formatting the 2nd one, rea
const size_t workbuf_size = 4096;
void *workbuf = ff_memalloc(workbuf_size);
REQUIRE(workbuf != NULL);
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 0, CONFIG_WL_SECTOR_SIZE};
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 128, CONFIG_WL_SECTOR_SIZE};
fr_result = f_mkfs(drv1, &opt, workbuf, workbuf_size);
free(workbuf);
workbuf = NULL;

View File

@ -3,5 +3,5 @@
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 1M,
storage2, data, fat, , 1M,
storage, data, fat, , 32k,
storage2, data, fat, , 32k,

1 # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 1M, storage, data, fat, , 32k,
7 storage2, data, fat, , 1M, storage2, data, fat, , 32k,

View File

@ -34,7 +34,6 @@
#error Wrong include file (ff.h).
#endif
/* Limits and boundaries */
#define MAX_DIR 0x200000 /* Max size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */
@ -43,6 +42,10 @@
#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */
#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */
#define MIN_FAT12_SEC_VOL 4 /* Min size of the FAT sector volume
1 FAT, 1 root dir, 1 reserved, 1 data sector */
#define MIN_FAT12_DATA_SEC 1 /* Min FAT data sectors */
/* Character code support macros */
#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z')
@ -3318,7 +3321,7 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS,
&& ld_word(fs->win + BPB_RsvdSecCnt) != 0 /* Properness of reserved sectors (MNBZ) */
&& (UINT)fs->win[BPB_NumFATs] - 1 <= 1 /* Properness of FATs (1 or 2) */
&& ld_word(fs->win + BPB_RootEntCnt) != 0 /* Properness of root dir entries (MNBZ) */
&& (ld_word(fs->win + BPB_TotSec16) >= 128 || ld_dword(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume sectors (>=128) */
&& (ld_word(fs->win + BPB_TotSec16) >= MIN_FAT12_SEC_VOL || ld_dword(fs->win + BPB_TotSec32) >= 0x10000) /* Properness of volume sectors (>=MIN_FAT12_SEC_VOL) */
&& ld_word(fs->win + BPB_FATSz16) != 0) { /* Properness of FAT size (MNBZ) */
return 0; /* It can be presumed an FAT VBR */
}
@ -6034,7 +6037,11 @@ FRESULT f_mkfs (
}
}
}
if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */
if (n_fat == 1) {
if (sz_vol < MIN_FAT12_SEC_VOL) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >= MIN_FAT12_SEC_VOLs */
} else {
if (sz_vol < (MIN_FAT12_SEC_VOL + 1)) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >= (MIN_FAT12_SEC_VOL+1)s */
}
/* Now start to create an FAT volume at b_vol and sz_vol */
@ -6265,7 +6272,7 @@ FRESULT f_mkfs (
}
/* Determine number of clusters and final check of validity of the FAT sub-type */
if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
if (sz_vol < b_data + pau * MIN_FAT12_DATA_SEC - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
n_clst = ((DWORD)sz_vol - sz_rsv - sz_fat * n_fat - sz_dir) / pau;
if (fsty == FS_FAT32) {
if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32? */

View File

@ -1,4 +1,4 @@
idf_component_register(SRCS "test_fatfs_flash_wl.c"
idf_component_register(SRCS "test_fatfs_flash_wl.c" "test_fatfs_small_partition.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity spi_flash fatfs vfs test_fatfs_common
WHOLE_ARCHIVE)

View File

@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/unistd.h>
#include "unity.h"
#include "esp_vfs_fat.h"
static wl_handle_t s_test_wl_handle;
static void test_setup(void)
{
// With this configuration, for 32k partition size,
// 4 sectors will be used for WL and 4 sectors for FATFS
// (1 FAT, 1 root directory, 1 reserved and 1 data sector)
esp_vfs_fat_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5,
.use_one_fat = true,
};
TEST_ESP_OK(esp_vfs_fat_spiflash_format_cfg_rw_wl("/spiflash", "storage1", &mount_config));
TEST_ESP_OK(esp_vfs_fat_spiflash_mount_rw_wl("/spiflash", "storage1", &mount_config, &s_test_wl_handle));
}
static void test_teardown(void)
{
TEST_ESP_OK(esp_vfs_fat_spiflash_unmount_rw_wl("/spiflash", s_test_wl_handle));
}
static void test_write_data_sec(int num_data_sec)
{
int fd = open("/spiflash/test.txt", O_CREAT | O_WRONLY);
TEST_ASSERT_NOT_EQUAL(-1, fd);
// Generate data
uint32_t data_size = 4096*num_data_sec;
char *data = (char*) malloc(data_size);
char *read_data = (char*) malloc(data_size);
for(uint32_t i = 0; i < (data_size); i += sizeof(i))
{
*((uint32_t*)(data + i)) = i;
}
ssize_t wr = write(fd, data, data_size);
if (num_data_sec == 1) {
TEST_ASSERT_EQUAL(data_size, wr);
} else {
TEST_ASSERT_NOT_EQUAL(data_size, wr);
}
TEST_ASSERT_EQUAL(0, close(fd));
fd = open("/spiflash/test.txt", O_RDONLY);
int r = read(fd, read_data, data_size);
if (num_data_sec == 1) {
TEST_ASSERT_EQUAL(data_size, r);
} else {
TEST_ASSERT_NOT_EQUAL(data_size, r);
}
TEST_ASSERT_EQUAL(0, strcmp(data, read_data));
TEST_ASSERT_EQUAL(0, close(fd));
}
TEST_CASE("(WL) can format small partition and read-write data", "[fatfs][wear_levelling][timeout=120]")
{
test_setup();
test_write_data_sec(1); //for 1 data sectors, write and read func should work
test_write_data_sec(2); //for 2 data sectors, write and read func should fail
test_teardown();
}

View File

@ -2,3 +2,4 @@
factory, app, factory, 0x10000, 768k,
storage, data, fat, , 528k,
storage2, data, fat, , 528k,
storage1, data, fat, , 32k,

1 # Name Type SubType Offset Size Flags
2 factory app factory 0x10000 768k
3 storage data fat 528k
4 storage2 data fat 528k
5 storage1 data fat 32k

View File

@ -15,6 +15,10 @@
#include "wear_levelling.h"
#include "diskio_wl.h"
// If the available sectors based on partition size are less than 128,
// the root directory sector should be set to 1.
#define MIN_REQ_SEC 128
static const char* TAG = "vfs_fat_spiflash";
static vfs_fat_spiflash_ctx_t *s_ctx[FF_VOLUMES] = {};
@ -74,7 +78,7 @@ vfs_fat_spiflash_ctx_t* get_vfs_fat_spiflash_ctx(wl_handle_t wlhandle)
return NULL;
}
static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags)
static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags, size_t sec_num)
{
FRESULT fresult = f_mount(fs, drv, 1);
if (fresult != FR_OK) {
@ -93,7 +97,13 @@ static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_moun
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(CONFIG_WL_SECTOR_SIZE, mount_config->allocation_unit_size);
ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), (mount_config->use_one_fat ? 1 : 2), 0, 0, alloc_unit_size};
UINT root_dir_entries;
if (CONFIG_WL_SECTOR_SIZE == 512) {
root_dir_entries = 16;
} else {
root_dir_entries = 128;
}
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), (mount_config->use_one_fat ? 1 : 2), 0, (sec_num <= MIN_REQ_SEC ? root_dir_entries : 0), alloc_unit_size};
fresult = f_mkfs(drv, &opt, workbuf, workbuf_size);
free(workbuf);
workbuf = NULL;
@ -157,8 +167,9 @@ esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char* base_path,
vfs_fat_x_ctx_flags_t flags = 0;
size_t sec_num = wl_size(*wl_handle) / wl_sector_size(*wl_handle);
// Try to mount partition
ret = s_f_mount_rw(fs, drv, mount_config, &flags);
ret = s_f_mount_rw(fs, drv, mount_config, &flags, sec_num);
if (ret != ESP_OK) {
goto fail;
}
@ -224,6 +235,7 @@ esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const cha
wl_handle_t temp_handle = WL_INVALID_HANDLE;
uint32_t id = FF_VOLUMES;
size_t sec_num = 0;
bool found = s_get_context_id_by_label(partition_label, &id);
if (!found) {
@ -239,6 +251,7 @@ esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const cha
}
ESP_RETURN_ON_ERROR(esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, mount_cfg, &temp_handle), TAG, "Failed to mount");
found = s_get_context_id_by_label(partition_label, &id);
sec_num = wl_size(temp_handle) / wl_sector_size(temp_handle);
assert(found);
if (s_ctx[id]->flags & FORMATTED_DURING_LAST_MOUNT) {
ESP_LOGD(TAG, "partition was formatted during mounting, skipping another format");
@ -250,6 +263,8 @@ esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const cha
if (cfg) {
s_ctx[id]->mount_config = *cfg;
}
temp_handle = s_ctx[id]->wlhandle;
sec_num = wl_size(temp_handle) / wl_sector_size(temp_handle);
}
//unmount
@ -266,7 +281,13 @@ esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const cha
}
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(CONFIG_WL_SECTOR_SIZE, s_ctx[id]->mount_config.allocation_unit_size);
ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), (s_ctx[id]->mount_config.use_one_fat ? 1 : 2), 0, 0, alloc_unit_size};
UINT root_dir_entries;
if (CONFIG_WL_SECTOR_SIZE == 512) {
root_dir_entries = 16;
} else {
root_dir_entries = 128;
}
const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), (s_ctx[id]->mount_config.use_one_fat ? 1 : 2), 0, (sec_num <= MIN_REQ_SEC ? root_dir_entries : 0), alloc_unit_size};
fresult = f_mkfs(drv, &opt, workbuf, workbuf_size);
free(workbuf);
workbuf = NULL;
@ -274,7 +295,7 @@ esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const cha
mount_back:
if (partition_was_mounted) {
esp_err_t err = s_f_mount_rw(s_ctx[id]->fs, drv, &s_ctx[id]->mount_config, NULL);
esp_err_t err = s_f_mount_rw(s_ctx[id]->fs, drv, &s_ctx[id]->mount_config, NULL, sec_num);
if (err != ESP_OK) {
ESP_LOGE(TAG, "failed to mount back, go to recycle");
goto recycle;

View File

@ -50,7 +50,7 @@ The most significant properties and features of above-mentioned file systems are
- Integrated
- Integrated
* - Minimum partition size
- * 128 sectors With wear levelling on (WL sector=4096B):
- * 8 sectors with wear levelling on (4 FATFS sectors + 4 WL sectors with WL sector size = 4096B)
* plus 4 sectors at least
* real number given by WL configuration (Safe, Perf)
- * 6 logical blocks

View File

@ -157,6 +157,32 @@ Usage::
Parameter --verbose prints detailed information from boot sector of the FatFs image to the terminal before folder structure is generated.
FATFS Minimum Partition Size and Limits
---------------------------------------
The FATFS component supports FAT12, FAT16, and FAT32 file system types. The file system type is determined by the number of clusters (calculated as data sectors divided by sectors per cluster) on the volume. The minimum partition size is defined by the number of sectors allocated to FAT tables, root directories and data clusters.
* The minimum supported size for a FAT partition with wear leveling enabled is 32 KB for a sector size of 4096 bytes. For a sector size of 512 bytes, the minimum partition size varies based on the WL configuration: 20 KB for Performance mode and 28 KB for Safety mode (requiring 2 extra sectors).
* For a partition with wear leveling enabled, 4 sectors will be reserved for wear-leveling operations, and 4 sectors will be used by the FATFS (1 reserved sector, 1 FAT sector, 1 root directory sector and 1 data sector).
* Increasing the partition size will allocate additional data sectors, allowing for more storage space.
* For partition sizes less than 528 KB, 1 root directory sector will be allocated; for larger partitions, 4 root directory sectors will be used.
* By default, two FAT sectors are created, increasing the partition size by one sector to accommodate the extra FAT sector. To enable a single FAT sector, configure the `use_one_fat` option in `struct esp_vfs_fat_mount_config_t` (see :component_file:`fatfs/vfs/esp_vfs_fat.h`). Enabling this option allows the minimum partition size to be reduced to 32 KB.
* The general formula for calculating the partition size for a wear-leveled partition is::
partition_size = Wear-levelling sectors * FLASH_SEC_SIZE + FATFS partition sectors * FAT_SEC_SIZE
Where:
- Wear-leveling sectors are fixed at 4
- FLASH_SEC_SIZE is 4096 bytes
- FATFS partition sectors include: 1 reserved sector + FAT sectors + root directory sectors + data sectors
- FAT_SEC_SIZE can be either 512 bytes or 4096 bytes, depending on the configuration
* For read-only partitions without wear leveling enabled and a sector size of 512 bytes, the minimum partition size can be reduced to as low as 2 KB.
Please refer :doc:`File System Considerations <../../api-guides/file-system-considerations>` for further details.
High-level API Reference
------------------------

View File

@ -99,7 +99,7 @@ FatFs 分区生成器
该生成器可以在主机上创建文件系统镜像,并用指定的主机文件夹内容对其进行填充。
该脚本是建立在分区生成器的基础上 (:component_file:`fatfsgen.py<fatfs/fatfsgen.py>`),目前除了可以生成分区外,也可以初始化损均衡。
该脚本是建立在分区生成器的基础上 (:component_file:`fatfsgen.py<fatfs/fatfsgen.py>`),目前除了可以生成分区外,也可以初始化损均衡。
目前的最新版本支持短文件名、长文件名、FAT12 和 FAT16。长文件名的上限是 255 个字符,文件名中可以包含多个 ``.`` 字符以及其他字符,如 ``+````,````;````=````[`` and ``]`` 等。
@ -112,13 +112,13 @@ FatFs 分区生成器
fatfs_create_spiflash_image(<partition> <base_dir> [FLASH_IN_PROJECT])
如果不希望在生成分区时使用损均衡,可以使用 ``fatfs_create_rawflash_image``::
如果不希望在生成分区时使用损均衡,可以使用 ``fatfs_create_rawflash_image``::
fatfs_create_rawflash_image(<partition> <base_dir> [FLASH_IN_PROJECT])
``fatfs_create_spiflash_image`` 以及 ``fatfs_create_rawflash_image`` 必须从项目的 CMakeLists.txt 中调用。
如果决定使用 ``fatfs_create_rawflash_image`` (不支持损均衡),请注意它仅支持在设备中以只读模式安装。
如果决定使用 ``fatfs_create_rawflash_image`` (不支持损均衡),请注意它仅支持在设备中以只读模式安装。
该函数的参数如下:
@ -157,6 +157,33 @@ FatFs 分区分析器
生成文件夹结构之前,参数 --verbose 将根据 FatFs 镜像的引导扇区在终端打印详细信息。
FATFS 最小分区大小及限制
------------------------
FATFS 组件支持 FAT12、FAT16 和 FAT32 文件系统类型。文件系统类型取决于卷上簇的数量(簇数通过数据扇区数量除以每簇包含的扇区数计算得出)。最小分区大小由分配给 FAT 表、根目录和数据簇的扇区数量决定。
* 对于 4096 字节的扇区,启用损耗均衡的 FAT 分区大小最小支持 32 KB。对于 512 字节的扇区,最小分区大小取决于损耗均衡的配置:性能模式下,最小支持 20 KB安全模式下最小支持 28 KB需要额外的 2 个扇区)。
* 启用了损耗均衡的分区会预留 4 个扇区用于损耗均衡操作。此外FATFS 本身也会使用 4 个扇区,分别为 1 个保留扇区、1 个 FAT 扇区、1 个根目录扇区和 1 个数据扇区。
* 增加分区大小将分配更多的数据扇区,提供更大的存储空间。
* 对小于 528 KB 的分区,将分配 1 个根目录扇区;对于更大的分区,将分配 4 个根目录扇区。
* 默认会创建两个 FAT 扇区,因此分区大小会增加一个扇区来容纳这个额外的 FAT 扇区。如要启用单个 FAT 扇区,可以在 `struct esp_vfs_fat_mount_config_t` 中(参见 :component_file:`fatfs/vfs/esp_vfs_fat.h`)设置 `use_one_fat` 选项。启用此选项后,最小分区大小可减少至 32 KB。
* 计算损耗均衡分区大小的一般公式为::
partition_size = 损耗均衡扇区数 * FLASH_SEC_SIZE + FATFS 分区扇区数量 * FAT_SEC_SIZE
其中:
- 损耗均衡扇区数固定为 4 个
- FLASH_SEC_SIZE 为 4096 字节
- FATFS 分区扇区包括1 个保留扇区 + FAT 扇区 + 根目录扇区 + 数据扇区
- FAT_SEC_SIZE 根据不同的配置,可以是 512 字节或 4096 字节
* 对于未启用损耗均衡、扇区大小为 512 字节的只读分区,最小分区大小可减少至 2 KB。
更多详情请参考 :doc:`文件系统注意事项 <../../api-guides/file-system-considerations>`
高级 API 参考
------------------------