From a07d018409194632fb9d18ebc4ed4eabc571e60f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Wed, 4 Mar 2026 10:42:23 +0100 Subject: [PATCH 1/4] docs(storage/fatfs): Update LFN default and dynamic buffers docs --- docs/en/api-reference/storage/fatfs.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index d4e95ab665..ff117acc04 100644 --- a/docs/en/api-reference/storage/fatfs.rst +++ b/docs/en/api-reference/storage/fatfs.rst @@ -31,7 +31,7 @@ Most applications use the following workflow when working with ``esp_vfs_fat_`` #. To mount the filesystem using the same drive number which was passed to :cpp:func:`esp_vfs_fat_register`, call the FatFs function :cpp:func:`f_mount`. If the filesystem is not present on the target logical drive, :cpp:func:`f_mount` will fail with the ``FR_NO_FILESYSTEM`` error. In such case, call :cpp:func:`f_mkfs` to create a fresh FatFS structure on the drive first, and then call :cpp:func:`f_mount` again. Note that SD cards need to be partitioned with :cpp:func:`f_fdisk` prior to previously described steps. For more information, see `FatFs documentation `_. -#. Call the C standard library and POSIX API functions to perform such actions on files as open, read, write, erase, copy, etc. Use paths starting with the path prefix passed to :cpp:func:`esp_vfs_register` (for example, ``"/sdcard/hello.txt"``). The filesystem uses `8.3 filenames `_ format (SFN) by default. If you need to use long filenames (LFN), enable the :ref:`CONFIG_FATFS_LONG_FILENAMES` option. Please refer to `FatFs filenames `_ for more details. +#. Call the C standard library and POSIX API functions to perform such actions on files as open, read, write, erase, copy, etc. Use paths starting with the path prefix passed to :cpp:func:`esp_vfs_register` (for example, ``"/sdcard/hello.txt"``). The filesystem supports long filenames (LFN) by default. If you want to reduce memory usage and avoid LFN working buffers, set :ref:`CONFIG_FATFS_LFN_NONE` (this limits names to the `8.3 format `_, SFN only). Please refer to `FatFs filenames `_ for more details. #. Optionally, call the FatFs library functions directly. In this case, use paths without a VFS prefix, for example, ``"/hello.txt"``. @@ -72,6 +72,7 @@ Configuration options The following configuration options are available for the FatFs component: * :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` - If enabled, FatFs tries to allocate its heap work buffers in DMA-capable, cache-aligned memory first so SDMMC transfers can avoid extra copies. This is useful on targets using PSRAM with SDMMC DMA (for example ESP32-P4). If enabled together with :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`, FatFs will try DMA-capable RAM first, then external RAM, then internal RAM. +* :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` - If enabled, FatFs allocates instance buffers separately, sized according to each mounted volume's sector size. This is useful when multiple FatFs instances use different sector sizes and can reduce memory usage. If disabled, all instances use buffers sized for the largest configured sector size. * :ref:`CONFIG_FATFS_USE_FASTSEEK` - If enabled, the POSIX :cpp:func:`lseek` function will be performed faster. The fast seek does not work for files in write mode, so to take advantage of fast seek, you should open (or close and then reopen) the file in read-only mode. * :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC` - If enabled, the FatFs will automatically call :cpp:func:`f_sync` to flush recent file changes after each call of :cpp:func:`write`, :cpp:func:`pwrite`, :cpp:func:`link`, :cpp:func:`truncate` and :cpp:func:`ftruncate` functions. This feature improves file-consistency and size reporting accuracy for the FatFs, at a price of decreased performance due to frequent disk operations. * :ref:`CONFIG_FATFS_LINK_LOCK` - If enabled, this option guarantees the API thread safety, while disabling this option might be necessary for applications that require fast frequent small file operations (e.g., logging to a file). Note that if this option is disabled, the copying performed by :cpp:func:`link` will be non-atomic. In such case, using :cpp:func:`link` on a large file on the same volume in a different task is not guaranteed to be thread safe. From 4af8f201b93406ae039ab612ffd6b40d55fa893b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Wed, 4 Mar 2026 14:05:30 +0100 Subject: [PATCH 2/4] docs(storage/fatfs): Refactor FatFs documentation --- .../api-guides/file-system-considerations.rst | 3 +- docs/en/api-reference/storage/fatfs.rst | 512 ++++++++++++------ 2 files changed, 342 insertions(+), 173 deletions(-) diff --git a/docs/en/api-guides/file-system-considerations.rst b/docs/en/api-guides/file-system-considerations.rst index fbd8bcee4a..e6acd9a876 100644 --- a/docs/en/api-guides/file-system-considerations.rst +++ b/docs/en/api-guides/file-system-considerations.rst @@ -101,8 +101,7 @@ The most supported file system, recommended for common applications - file/direc - `FatFS source site `_ - More about `FAT table size limits `_ -- :ref:`Using FatFS with VFS ` -- :ref:`Using FatFS with VFS and SD cards ` +- :ref:`Using FatFS in ESP-IDF ` - ESP-IDF FatFS tools: :ref:`Partition generator ` and :ref:`Partition analyzer ` **Examples:** diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index ff117acc04..b45d90218e 100644 --- a/docs/en/api-reference/storage/fatfs.rst +++ b/docs/en/api-reference/storage/fatfs.rst @@ -3,98 +3,375 @@ FAT Filesystem Support :link_to_translation:`zh_CN:[中文]` -ESP-IDF uses the `FatFs `_ library to work with FAT filesystems. FatFs resides in the ``fatfs`` component. Although the library can be used directly, many of its features can be accessed via VFS using the C standard library and POSIX API functions. +ESP-IDF uses the `FatFs `_ library to work with FAT filesystems. ESP-IDF integrates the FatFs library in the FatFs component. After mounting a FAT filesystem volume, the VFS layer exposes standard C library and POSIX file APIs. -Additionally, FatFs has been modified to support the runtime pluggable disk I/O layer. This allows mapping of FatFs drives to physical disks at runtime. +.. note:: -.. _using-fatfs-with-vfs: + FatFs is an ambiguous term, as it refers to the filesystem itself, the upstream library, as well as the component in ESP-IDF. For clarity, this documentation uses the following terms: -Using FatFs with VFS --------------------- + - **FAT filesystem**: the on-disk FAT format (FAT12/FAT16/FAT32). + - **FatFs library**: the upstream `FatFs library `_ used by ESP-IDF. + - **FatFs component**: the ESP-IDF integration layer around the FatFs library (mount helpers, wrappers, and related APIs) in :component:`fatfs`. -The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` defines the functions for connecting FatFs and VFS. + Other terms relevant to this documentation are explained in the :ref:`Glossary ` section. -The function :cpp:func:`esp_vfs_fat_register` allocates a ``FATFS`` structure and registers a given path prefix in VFS. Subsequent operations on files starting with this prefix are forwarded to FatFs APIs. +.. _fatfs-mount-and-use: -The function :cpp:func:`esp_vfs_fat_unregister_path` deletes the registration with VFS, and frees the ``FATFS`` structure. +Mount and Use FatFs +------------------- -Most applications use the following workflow when working with ``esp_vfs_fat_`` functions: +The FatFs component provides convenience wrappers for mounting the filesystem for use with the VFS layer. Use these wrappers for most use cases instead of mounting the filesystem manually. For manual setup instructions, refer to :ref:`Manually mounting a FAT filesystem partition `. -#. - Call :cpp:func:`esp_vfs_fat_register` to specify: +The following is the general workflow for mounting: - - Path prefix where to mount the filesystem (e.g., ``"/sdcard"``, ``"/spiflash"``) - - FatFs drive number - - A variable which receives the pointer to the ``FATFS`` structure +#. Select a mount path (for example, ``"/spiflash"`` or ``"/sdcard"``) and set ``esp_vfs_fat_mount_config_t``. + Set ``max_files`` to the smallest value that fits your workload. Higher values allow more simultaneously open files, but increase RAM usage. +#. Mount the volume with a convenience helper from :component_file:`fatfs/vfs/esp_vfs_fat.h`: -#. Call :cpp:func:`ff_diskio_register` to register the disk I/O driver for the drive number used in Step 1. + - :cpp:func:`esp_vfs_fat_spiflash_mount_rw_wl` for SPI flash partitions with wear leveling + - :cpp:func:`esp_vfs_fat_spiflash_mount_ro` for read-only SPI flash partitions **without** wear leveling + - :cpp:func:`esp_vfs_fat_sdmmc_mount` or :cpp:func:`esp_vfs_fat_sdspi_mount` for SD cards -#. To mount the filesystem using the same drive number which was passed to :cpp:func:`esp_vfs_fat_register`, call the FatFs function :cpp:func:`f_mount`. If the filesystem is not present on the target logical drive, :cpp:func:`f_mount` will fail with the ``FR_NO_FILESYSTEM`` error. In such case, call :cpp:func:`f_mkfs` to create a fresh FatFS structure on the drive first, and then call :cpp:func:`f_mount` again. Note that SD cards need to be partitioned with :cpp:func:`f_fdisk` prior to previously described steps. For more information, see `FatFs documentation `_. +#. Use standard file APIs (``stdio.h`` or POSIX) on paths under the mount path (for example, ``"/spiflash/example.txt"`` or ``"/sdcard/data.bin"``). +#. Close open files and call the matching unmount helper. -#. Call the C standard library and POSIX API functions to perform such actions on files as open, read, write, erase, copy, etc. Use paths starting with the path prefix passed to :cpp:func:`esp_vfs_register` (for example, ``"/sdcard/hello.txt"``). The filesystem supports long filenames (LFN) by default. If you want to reduce memory usage and avoid LFN working buffers, set :ref:`CONFIG_FATFS_LFN_NONE` (this limits names to the `8.3 format `_, SFN only). Please refer to `FatFs filenames `_ for more details. +.. _fatfs-configuration-options: -#. Optionally, call the FatFs library functions directly. In this case, use paths without a VFS prefix, for example, ``"/hello.txt"``. - -#. Close all open files. - -#. Call the FatFs function :cpp:func:`f_mount` for the same drive number with NULL ``FATFS*`` argument to unmount the filesystem. - -#. Call the FatFs function :cpp:func:`ff_diskio_register` with NULL ``ff_diskio_impl_t*`` argument and the same drive number to unregister the disk I/O driver. - -#. Call :cpp:func:`esp_vfs_fat_unregister_path` with the path where the file system is mounted to remove FatFs from VFS, and free the ``FATFS`` structure allocated in Step 1. - -The convenience functions :cpp:func:`esp_vfs_fat_sdmmc_mount`, :cpp:func:`esp_vfs_fat_sdspi_mount`, and :cpp:func:`esp_vfs_fat_sdcard_unmount` wrap the steps described above and also handle SD card initialization. These functions are described in the next section. - -Differences from the POSIX Standard ------------------------------------ - -#. :cpp:func:`link`: Because FAT filesystem does not support hardlinks, :cpp:func:`link` copies contents of the file instead. (This only applies to files on FatFs volumes.) -#. :cpp:func:`unlink`: Attempting to remove an open file will fail with ``EBUSY`` when ``CONFIG_FATFS_FS_LOCK`` is enabled. Otherwise, the behavior is undefined and may cause file system corruption. - -.. _using-fatfs-with-vfs-and-sdcards: - -Using FatFs with VFS and SD Cards ---------------------------------- - -The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` defines convenience functions :cpp:func:`esp_vfs_fat_sdmmc_mount`, :cpp:func:`esp_vfs_fat_sdspi_mount`, and :cpp:func:`esp_vfs_fat_sdcard_unmount`. These functions perform Steps 1–3 and 7–9 respectively and handle SD card initialization, but provide only limited error handling. Developers are encouraged to check its source code and incorporate more advanced features into production applications. - -The convenience function :cpp:func:`esp_vfs_fat_sdmmc_unmount` unmounts the filesystem and releases the resources acquired by :cpp:func:`esp_vfs_fat_sdmmc_mount`. - - -Using FatFs with VFS in Read-Only Mode --------------------------------------- - -The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` also defines the convenience functions :cpp:func:`esp_vfs_fat_spiflash_mount_ro` and :cpp:func:`esp_vfs_fat_spiflash_unmount_ro`. These functions perform Steps 1-3 and 7-9 respectively for read-only FAT partitions. These are particularly helpful for data partitions written only once during factory provisioning, which will not be changed by production application throughout the lifetime of the hardware. - -Configuration options +Configuration Options --------------------- The following configuration options are available for the FatFs component: -* :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` - If enabled, FatFs tries to allocate its heap work buffers in DMA-capable, cache-aligned memory first so SDMMC transfers can avoid extra copies. This is useful on targets using PSRAM with SDMMC DMA (for example ESP32-P4). If enabled together with :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`, FatFs will try DMA-capable RAM first, then external RAM, then internal RAM. -* :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` - If enabled, FatFs allocates instance buffers separately, sized according to each mounted volume's sector size. This is useful when multiple FatFs instances use different sector sizes and can reduce memory usage. If disabled, all instances use buffers sized for the largest configured sector size. -* :ref:`CONFIG_FATFS_USE_FASTSEEK` - If enabled, the POSIX :cpp:func:`lseek` function will be performed faster. The fast seek does not work for files in write mode, so to take advantage of fast seek, you should open (or close and then reopen) the file in read-only mode. -* :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC` - If enabled, the FatFs will automatically call :cpp:func:`f_sync` to flush recent file changes after each call of :cpp:func:`write`, :cpp:func:`pwrite`, :cpp:func:`link`, :cpp:func:`truncate` and :cpp:func:`ftruncate` functions. This feature improves file-consistency and size reporting accuracy for the FatFs, at a price of decreased performance due to frequent disk operations. -* :ref:`CONFIG_FATFS_LINK_LOCK` - If enabled, this option guarantees the API thread safety, while disabling this option might be necessary for applications that require fast frequent small file operations (e.g., logging to a file). Note that if this option is disabled, the copying performed by :cpp:func:`link` will be non-atomic. In such case, using :cpp:func:`link` on a large file on the same volume in a different task is not guaranteed to be thread safe. +* ``CONFIG_FATFS_LONG_FILENAMES`` - Selects how the FatFs library handles long filename (LFN) support. The available options are :ref:`CONFIG_FATFS_LFN_NONE ` to disable LFN support and limit names to the `8.3 format `_ (SFN only), :ref:`CONFIG_FATFS_LFN_HEAP ` to enable LFN support with the LFN working buffer stored on the heap (default), and :ref:`CONFIG_FATFS_LFN_STACK ` to enable LFN support with the LFN working buffer stored on the stack. For details, see `FatFs filenames `_. +* :ref:`CONFIG_FATFS_VOLUME_COUNT` - Sets the number of logical FatFs volumes. Increasing this value can increase baseline memory usage. +* :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` - If enabled, the FatFs library prefers external RAM when allocating internal buffers. If external RAM allocation fails, it falls back to internal RAM. This can have a noticeable performance cost on hot I/O paths. Disable this option to prioritize performance; enable it to reduce internal RAM usage. +* :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` - If enabled, the FatFs library tries to allocate heap work buffers in DMA-capable, cache-aligned memory first so SDMMC transfers avoid extra copies. This option is useful on targets that use PSRAM with SDMMC DMA (for example ESP32-P4). If this option and :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` are both enabled, the FatFs library tries DMA-capable RAM first, then external RAM, then internal RAM. +* :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` - If enabled, the FatFs library allocates instance buffers separately and sizes them according to each mounted volume's sector size. This option is useful when multiple FatFs instances use different sector sizes, as it can reduce memory usage. If disabled, all instances use buffers sized for the largest configured sector size. +* :ref:`CONFIG_FATFS_PER_FILE_CACHE` - If enabled, each open file uses a separate cache buffer. This improves I/O performance but increases RAM usage when multiple files are open. If disabled, a single shared cache is used, which reduces RAM usage but can increase storage read/write operations. +* :ref:`CONFIG_FATFS_USE_FASTSEEK` - If enabled, POSIX :cpp:func:`lseek` runs faster. Fast seek does not work for files opened in write mode. To use fast seek, open the file in read-only mode, or close and reopen it in read-only mode. +* :ref:`CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE` - Sets the CLMT buffer size used by fast seek when :ref:`CONFIG_FATFS_USE_FASTSEEK` is enabled. Larger buffers can improve seek behavior on larger files, but use more RAM. +* :ref:`CONFIG_FATFS_VFS_FSTAT_BLKSIZE` - Sets the default stdio file buffer block size used through VFS. This option is mainly relevant for stdio-based I/O (for example ``fread``/``fgets``) and is not the primary tuning knob for direct POSIX ``read``/``write`` paths. Larger values can improve buffered read throughput, but increase heap usage. +* :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC` - If enabled, the FatFs library calls :cpp:func:`f_sync` automatically after each call to :cpp:func:`write`, :cpp:func:`pwrite`, :cpp:func:`link`, :cpp:func:`truncate`, and :cpp:func:`ftruncate`. This option improves file consistency and size-reporting accuracy, but decreases performance because it triggers frequent disk operations. +* :ref:`CONFIG_FATFS_LINK_LOCK` - If enabled, this option guarantees API thread safety for the :cpp:func:`link` function. Disabling this option can help applications that perform frequent small file operations (for example, file logging). When disabled, the copy performed by :cpp:func:`link` is non-atomic. In that case, using :cpp:func:`link` on a large file on the same volume from another task is not guaranteed to be thread-safe. +* Of note may also be: :ref:`CONFIG_FATFS_FS_LOCK`, :ref:`CONFIG_FATFS_TIMEOUT_MS`, and ``CONFIG_FATFS_CHOOSE_CODEPAGE`` (especially ``CONFIG_FATFS_CODEPAGE_DYNAMIC`` for code-size impact). Additional options include ``CONFIG_FATFS_SECTOR_SIZE``, ``CONFIG_FATFS_MAX_LFN``, ``CONFIG_FATFS_API_ENCODING``, and ``CONFIG_FATFS_USE_STRFUNC_CHOICE``. -These options set a behavior of how the FatFs filesystem calculates and reports free space: +These options control how the FatFs library calculates and reports free space: -* :ref:`CONFIG_FATFS_DONT_TRUST_FREE_CLUSTER_CNT` - If 1, free cluster count will be ignored. Default value is 0. -* :ref:`CONFIG_FATFS_DONT_TRUST_LAST_ALLOC` - If 1, last allocation number will be ignored. Default value is 0. +* :ref:`CONFIG_FATFS_DONT_TRUST_FREE_CLUSTER_CNT` - If set to 1, the FatFs library ignores the free cluster count. The default value is 0. +* :ref:`CONFIG_FATFS_DONT_TRUST_LAST_ALLOC` - If set to 1, the FatFs library ignores the last allocation number. The default value is 0. .. note:: - Setting these options to 1 may increase the accuracy of :cpp:func:`f_getfree` output at a price of decreased performance, e.g., due to performing full FAT scan. + Setting these options to 1 can improve :cpp:func:`f_getfree` accuracy, but it reduces performance, for example by forcing a full FAT scan. +Differences from the POSIX Standard +----------------------------------- + +#. :cpp:func:`link`: FAT filesystems do not support hard links, therefore :cpp:func:`link` copies file contents instead. (This applies only to files on FAT filesystem volumes.) +#. :cpp:func:`unlink`: If ``CONFIG_FATFS_FS_LOCK`` is enabled, removing an open file fails with ``EBUSY``. Otherwise, behavior is undefined and can corrupt the filesystem. + +.. _fatfs-formatting: + +Formatting a FAT Filesystem +--------------------------- + +Formatting creates a new FAT filesystem on the target volume and erases the existing directory structure and file data on that volume. Use it for first-time provisioning, or to recover from ``FR_NO_FILESYSTEM``. + +For mount-time auto-formatting, set ``esp_vfs_fat_mount_config_t.format_if_mount_failed`` to ``true`` before calling a mount helper. This is useful when the volume is expected to be blank during first boot. When formatting is triggered this way, the mount configuration also controls the new filesystem layout: + +* ``allocation_unit_size`` sets the cluster size used by :cpp:func:`f_mkfs`. Larger values can improve throughput, but waste more space for many small files. +* ``use_one_fat`` creates one FAT instead of two. This saves some space, but reduces redundancy. + +For explicit formatting after initialization, use the helper that matches the storage type: + +* :cpp:func:`esp_vfs_fat_spiflash_format_rw_wl` or :cpp:func:`esp_vfs_fat_spiflash_format_cfg_rw_wl` for SPI flash partitions with wear leveling +* :cpp:func:`esp_vfs_fat_sdcard_format` or :cpp:func:`esp_vfs_fat_sdcard_format_cfg` for SD cards + +The SPI flash formatting helpers can be called whether the filesystem is currently mounted or not. The SD card formatting helpers require the card (but not the filesystem) to be mounted first. + +Read-only SPI flash partitions mounted with :cpp:func:`esp_vfs_fat_spiflash_mount_ro` cannot be reformatted on the target. To populate a read-only partition, generate the image on the host with :ref:`FatFs Partition Generator `. + +.. _fatfs-partition-generator: + +FatFs Partition Generator +------------------------- + +ESP-IDF provides a FatFs partition generator (:component_file:`wl_fatfsgen.py `) integrated into the build system for direct use in user projects. + +Use this tool to create filesystem images on a host and populate them with content from a specified host folder. + +The script is based on the partition generator (:component_file:`fatfsgen.py `). In addition to generating a FatFs partition, ``wl_fatfsgen.py`` initializes wear leveling, so it is typically used for writable SPI flash filesystems. Use ``fatfsgen.py`` instead for read-only SPI flash images and SD card images. + +The latest version supports short and long file names, FAT12, and FAT16. Long file names are limited to 255 characters and can contain multiple periods (``.``) in the file name, but, crucially, not in the path, as well as the following additional characters: ``+``, ``,``, ``;``, ``=``, ``[`` and ``]``. + +An in-depth description of the FatFs partition generator and analyzer can be found at :doc:`Generating and parsing FAT partition on host `. + +Build System Integration with FatFs Partition Generator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Invoke the FatFs generator directly from the CMake build system by calling ``fatfs_create_spiflash_image``:: + + fatfs_create_spiflash_image( [FLASH_IN_PROJECT]) + +To generate a **read-only** partition without wear leveling support, use ``fatfs_create_rawflash_image``:: + + fatfs_create_rawflash_image( [FLASH_IN_PROJECT]) + +Call ``fatfs_create_spiflash_image`` or ``fatfs_create_rawflash_image`` from the project's CMakeLists.txt. + + +The function arguments are: + +#. partition - Name of the partition as defined in the partition table (e.g., :example_file:`storage/fatfs/fatfsgen/partitions_example.csv`). + +#. base_dir - Directory encoded into the FAT filesystem partition and optionally flashed to the target. Make sure the partition table defines an appropriate partition size. + +#. flag ``FLASH_IN_PROJECT`` - Optionally flash the image automatically with app binaries, partition tables, and other outputs when you run ``idf.py flash -p ``. + +#. flag ``PRESERVE_TIME`` - Optionally preserve timestamps from the source folder in the target image. Without this flag, the tool sets every timestamp to the FatFs library default initial time (1 January 1980). + +#. flag ``ONE_FAT`` - Optionally generate a FAT filesystem volume with one FAT (FAT Table) instead of two. This increases free space in the FAT filesystem volume by ``number of sectors used by FAT * sector size``, but it also increases corruption risk. + +For example:: + + fatfs_create_spiflash_image(my_fatfs_partition my_folder FLASH_IN_PROJECT) + +If ``FLASH_IN_PROJECT`` is not specified, the image is still generated, but you must flash it manually by using ``esptool`` or a custom build system target. + +For an example project, see :example:`storage/fatfs/fatfsgen`. + + +.. _fatfs-partition-analyzer: + +FatFs Partition Parser +---------------------- + +The :component_file:`fatfsparse.py ` tool is the reverse of :component_file:`fatfsgen.py `. It generates the host folder structure from a FAT filesystem image. + +Usage:: + + ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] [--verbose] fatfs_image.img + +The ``--verbose`` option prints detailed information from the FAT filesystem image boot sector before the tool generates the folder structure. + +.. _fatfs-minimum-partition-size: + +FatFs Minimum Partition Size and Limits +--------------------------------------- + +The FatFs component supports FAT12, FAT16, and FAT32 filesystem types. The number of clusters on the volume determines the filesystem type (clusters = data sectors / sectors per cluster). A cluster is a logical FAT allocation unit made of one or more sectors. The minimum partition size depends on 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 with a 4096-byte sector size. With a 512-byte sector size, the minimum partition size depends on the WL configuration: 20 KB for Performance mode and 28 KB for Safety mode (which requires 2 extra sectors). +* For a partition with wear leveling enabled, 4 sectors are reserved for wear leveling operations, and the FAT filesystem uses 4 sectors (1 reserved sector, 1 FAT sector, 1 root directory sector, and 1 data sector). +* Increasing the partition size allocates additional data sectors and increases storage space. +* For partition sizes smaller than 528 KB, the FAT filesystem allocates 1 root directory sector. For larger partitions, the FAT filesystem allocates 4 root directory sectors. +* By default, the FAT filesystem creates two FAT sectors, which increases partition size by one sector. To use one FAT sector, configure the `use_one_fat` option in ``esp_vfs_fat_mount_config_t`` (see :component_file:`fatfs/vfs/esp_vfs_fat.h`). This option reduces the minimum partition size to 32 KB. +* The general formula for calculating the partition size for a wear-leveled partition is:: + + partition_size = wear_leveling_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 and with a 512-byte sector size, the minimum partition size is as low as 2 KB. + +For more details, see :doc:`File System Considerations <../../api-guides/file-system-considerations>`. + +.. note:: + The wear leveling layer protects the underlying flash by distributing write and erase cycles across the managed storage region. Its effectiveness therefore scales with the size of that region. Small partitions restrict wear distribution and can significantly reduce protection, so their use is strongly discouraged. For more information, refer to :doc:`wear leveling `. + +Optimizing +---------- + +FatFs setup can be optimized for multiple variables by choosing specific configuration options, with different tradeoffs. + +The main variables that affect behavior are: + +* Buffer placement and sizing (:ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS`, :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`, :ref:`CONFIG_FATFS_USE_DYN_BUFFERS`, :ref:`CONFIG_FATFS_PER_FILE_CACHE`, and application I/O buffer sizes) +* Wear leveling sector size and mode (``CONFIG_WL_SECTOR_SIZE_*`` and ``CONFIG_WL_SECTOR_MODE_*``) +* Sync strategy (:ref:`CONFIG_FATFS_IMMEDIATE_FSYNC`) +* Workload pattern (transaction sizes, sequential vs random access, read vs write ratio) + +Optimizing for I/O Performance +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For throughput-oriented workloads: + +* Keep :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC` disabled unless your consistency requirements need it. +* If peak speed is the top priority, disable :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` so buffers stay in internal RAM. +* Prefer larger read/write transaction sizes over many small operations. +* Align transaction sizes to the active sector size when possible (for example 512 B or 4096 B), and pad writes if needed to reduce partial-sector overhead. +* For SPI flash with wear leveling, prefer ``CONFIG_WL_SECTOR_SIZE_4096`` when RAM budget allows, as it is generally more efficient. +* If using 512-byte WL sectors, use ``CONFIG_WL_SECTOR_MODE_PERF`` when your application can accept the higher power-loss risk during sector erase. +* Prefer POSIX ``read``/``write`` over ``fread``/``fwrite`` on hot paths when possible. For broader speed guidance, see :doc:`Maximizing Execution Speed <../../api-guides/performance/speed>`. +* On SDMMC DMA targets (for example ESP32-P4 with PSRAM), enable :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` to reduce extra buffer copies. +* Enable :ref:`CONFIG_FATFS_USE_FASTSEEK` for read-heavy workloads with long backward seeks. + +.. note:: + For a baseline of what to expect in a performance-optimized scenario, see :example:`storage/perf_benchmark`. + +Optimizing for memory usage +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Disable :ref:`CONFIG_FATFS_PER_FILE_CACHE` to use a single shared cache when reducing RAM usage is the priority. +* Tune ``esp_vfs_fat_mount_config_t.max_files`` (see :ref:`Mount and Use FatFs `) as low as practical; each simultaneously open file increases RAM usage. +* If :ref:`CONFIG_FATFS_PER_FILE_CACHE` is enabled, prefer ``CONFIG_WL_SECTOR_SIZE_512`` to reduce per-file cache size. +* If :ref:`CONFIG_FATFS_PER_FILE_CACHE` is disabled, ``CONFIG_WL_SECTOR_SIZE_4096`` can be a better tradeoff. +* Enable :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` on targets with external RAM support to reduce internal RAM pressure, but expect lower I/O performance. +* Consider ``CONFIG_FATFS_LONG_FILENAMES = CONFIG_FATFS_LFN_NONE`` when SFN (8.3) filenames are acceptable. +* If long filenames are required, reduce ``CONFIG_FATFS_MAX_LFN`` to the smallest value that meets your needs. +* Enable :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` so each mounted volume uses buffers sized to its actual sector size. + +Optimizing for storage efficiency +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For maximizing usable filesystem capacity: + +* For generated read-only images, consider the ``ONE_FAT`` option in ``fatfs_create_spiflash_image`` (see :ref:`FatFs Partition Generator `) to use one FAT instead of two. +* Consider ``CONFIG_WL_SECTOR_SIZE_512`` when minimizing overhead is a priority, as smaller sectors can improve usable storage efficiency in some layouts. +* Size partitions with margin. Very small partitions have proportionally higher metadata and wear leveling overhead. +* Keep long filenames short where possible; long names consume additional directory entries. +* For read-only data, consider raw FAT partitions without wear leveling where appropriate. + +Advanced operations +------------------- + +Manual mounting may be required when you use storage media that ESP-IDF does not directly support or when you need access to low-level FatFs library functions. + +Architecture Overview +^^^^^^^^^^^^^^^^^^^^^ + +The following diagram illustrates the layered architecture of FatFs and its relationship with other ESP-IDF components: + +:: + + +---------------------------------------------------------------+ + | Newlib/Picolib (C Standard Library) | + | fopen, fread, fwrite, fclose, fseek, etc. | + +---------------------------------------------------------------+ + | VFS (Virtual File System) | + | POSIX API: open, read, write, close, lseek, stat, etc. | + +---------------------------------------------------------------+ + | FatFs Library | + | f_mount, f_open, f_read, f_write, f_close, f_mkfs | + +---------------------------------------------------------------+ + | Disk I/O Layer | + | ff_diskio_register, disk_read, disk_write, disk_ioctl, etc. | + +-------------------------------+-------------------------------+ + | Wear Leveling (optional) | | + | wl_mount, wl_read, wl_write | SD/MMC Driver | + +-------------------------------+ | + | esp_partition | sdmmc_read/write_sectors | + | esp_partition_read/write | | + +-------------------------------+-------------------------------+ + | SPI Flash | SD Card | + +-------------------------------+-------------------------------+ + + + +.. _fatfs-manual-mount: + +Manually Mounting a FAT Filesystem Partition +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When mounting a FAT filesystem partition manually, follow the same general steps performed by the convenience wrappers from :ref:`Mount and Use FatFs ` to register the filesystem with the FatFs library and then mount it in the VFS. + +#. + Register the filesystem with the VFS by calling :cpp:func:`esp_vfs_fat_register`. This allocates the ``FATFS`` structure and sets up the interface between the VFS and the FatFs library. Specify: + + - The path prefix where the filesystem will be mounted (for example, ``"/sdcard"`` or ``"/spiflash"``) + - The FatFs drive number + - A variable that receives a pointer to the ``FATFS`` structure + +#. Register the disk I/O driver for the drive number used in Step 1 by calling :cpp:func:`ff_diskio_register`. + +#. Mount the filesystem for the drive number passed to :cpp:func:`esp_vfs_fat_register` by calling :cpp:func:`f_mount`. + + If no filesystem is present on the target logical drive, :cpp:func:`f_mount` fails with ``FR_NO_FILESYSTEM``. In that case, create a new FAT filesystem on the drive with :cpp:func:`f_mkfs`, and then call :cpp:func:`f_mount` again. + + For SD cards, create a partition table first with :cpp:func:`f_fdisk`. For details, see the `FatFs documentation `_. + +To unmount, follow these general steps: + +#. Unmount the filesystem by calling :cpp:func:`f_mount` with the same drive number and a NULL ``FATFS*`` argument. + +#. Unregister the disk I/O driver by calling :cpp:func:`ff_diskio_register` with the same drive number and a NULL ``ff_diskio_impl_t*`` argument. + +#. Remove the VFS registration and free the ``FATFS`` structure allocated in Step 1 of the mounting procedure by calling :cpp:func:`esp_vfs_fat_unregister_path` with the mount path. + +When calling low-level functions provided by the FatFs library, use paths without the mount-point prefix. For example, use ``"/hello.txt"``. .. _fatfs-diskio-layer: -FatFS Disk IO Layer -------------------- +FatFs Disk I/O Layer +^^^^^^^^^^^^^^^^^^^^ -FatFs has been extended with API functions that register the disk I/O driver at runtime. +FatFs provides APIs to register disk I/O drivers at runtime. These APIs provide a generic interface between medium-specific access functions and the FatFs library. -These APIs provide implementation of disk I/O functions for SD/MMC cards and can be registered for the given FatFs drive number using the function :cpp:func:`ff_diskio_register_sdmmc`. +The disk I/O layer uses :cpp:struct:`ff_diskio_impl_t` to provide medium access functions. Pass this structure to :cpp:func:`ff_diskio_register`. + +ESP-IDF provides a set of convenience wrappers that simplify mounting a set of supported storage media. These include: + + - :cpp:func:`ff_diskio_register_wl_partition` for SPI flash partitions with wear leveling + - :cpp:func:`ff_diskio_register_raw_partition` for read-only SPI flash partitions **without** wear leveling + - :cpp:func:`ff_diskio_register_sdmmc` for both SDMMC and SPI connected SD cards + +For API reference, see :ref:`Disk I/O API Reference `. + +.. _fatfs-glossary: + +Glossary +-------- + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Term + - Description + * - VFS + - Virtual File System, an abstraction layer provided by ESP-IDF that allows accessing different underlying filesystems through unified POSIX and stdio.h interfaces. + * - Sector + - The minimum physical unit for read/write operations on a storage device, typically 512 bytes or 4096 bytes. + * - Cluster + - The minimum logical unit for filesystem storage allocation, consisting of one or more contiguous sectors. + * - FAT Table + - File Allocation Table, which records the usage status of each cluster and the linkage relationships between file data blocks. + * - Wear Leveling + - A technique to extend the lifespan of flash memory by distributing write operations evenly across storage cells, preventing specific blocks from wearing out prematurely due to frequent erasing. + * - Drive Number + - A number (0-9) used by FatFs to identify different logical drives, each corresponding to an independent filesystem instance. + * - Mount + - The process of associating a filesystem with a specified path, enabling applications to access the filesystem contents through that path. + * - SFN/LFN + - Short File Name (8.3 format) and Long File Name (up to 255 characters). + +.. _fatfs-application-examples: + +Application Examples +-------------------- + +- :example:`storage/fatfs/getting_started` demonstrates the minimal setup required to store persistent data on SPI flash with FatFs, including mounting the filesystem, opening a file, performing basic read and write operations, and unmounting the filesystem. + +- :example:`storage/fatfs/fs_operations` demonstrates advanced FatFs operations, including reading and writing files, creating, moving, and deleting files and directories, and inspecting file details. + +- :example:`storage/fatfs/ext_flash` demonstrates how to operate an external SPI flash formatted with FatFs, including initializing the SPI bus, configuring the flash chip, registering it as a partition, and performing read and write operations. + +.. _fatfs-high-level-api-reference: + +High-level API Reference +------------------------ + +.. include-build-file:: inc/esp_vfs_fat.inc + +.. _fatfs-diskio-api-reference: + +Disk I/O API Reference +^^^^^^^^^^^^^^^^^^^^^^ .. doxygenfunction:: ff_diskio_register .. doxygenstruct:: ff_diskio_impl_t @@ -102,110 +379,3 @@ These APIs provide implementation of disk I/O functions for SD/MMC cards and can .. doxygenfunction:: ff_diskio_register_sdmmc .. doxygenfunction:: ff_diskio_register_wl_partition .. doxygenfunction:: ff_diskio_register_raw_partition - - -.. _fatfs-partition-generator: - -FatFs Partition Generator -------------------------- - -We provide a partition generator for FatFs (:component_file:`wl_fatfsgen.py `) which is integrated into the build system and could be easily used in the user project. - -The tool is used to create filesystem images on a host and populate it with content of the specified host folder. - -The script is based on the partition generator (:component_file:`fatfsgen.py `). Apart from generating partition, it can also initialize wear levelling. - -The latest version supports both short and long file names, FAT12 and FAT16. The long file names are limited to 255 characters and can contain multiple periods (``.``) characters within the filename and additional characters ``+``, ``,``, ``;``, ``=``, ``[`` and ``]``. - -An in-depth description of the FatFs partition generator and analyzer can be found at :doc:`Generating and parsing FAT partition on host `. - -Build System Integration with FatFs Partition Generator -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It is possible to invoke FatFs generator directly from the CMake build system by calling ``fatfs_create_spiflash_image``:: - - fatfs_create_spiflash_image( [FLASH_IN_PROJECT]) - -If you prefer generating partition without wear levelling support, you can use ``fatfs_create_rawflash_image``:: - - fatfs_create_rawflash_image( [FLASH_IN_PROJECT]) - -``fatfs_create_spiflash_image`` respectively ``fatfs_create_rawflash_image`` must be called from project's CMakeLists.txt. - -If you decide for any reason to use ``fatfs_create_rawflash_image`` (without wear levelling support), beware that it supports mounting only in read-only mode in the device. - - -The arguments of the function are as follows: - -#. partition - the name of the partition as defined in the partition table (e.g., :example_file:`storage/fatfs/fatfsgen/partitions_example.csv`). - -#. base_dir - the directory that will be encoded to FatFs partition and optionally flashed into the device. Beware that you have to specify the suitable size of the partition in the partition table. - -#. flag ``FLASH_IN_PROJECT`` - optionally, users can have the image automatically flashed together with the app binaries, partition tables, etc. on ``idf.py flash -p `` by specifying ``FLASH_IN_PROJECT``. - -#. flag ``PRESERVE_TIME`` - optionally, users can force preserving the timestamps from the source folder to the target image. Without preserving the time, every timestamp will be set to the FATFS default initial time (1st January 1980). - -#. flag ``ONE_FAT`` - optionally, users can still choose to generate a FATFS volume with a single FAT (file allocation table) instead of two. This makes the free space in the FATFS volume a bit larger (by ``number of sectors used by FAT * sector size``) but also more prone to corruption. - -For example:: - - fatfs_create_spiflash_image(my_fatfs_partition my_folder FLASH_IN_PROJECT) - -If FLASH_IN_PROJECT is not specified, the image will still be generated, but you will have to flash it manually using ``esptool`` or a custom build system target. - -For an example, see :example:`storage/fatfs/fatfsgen`. - - -.. _fatfs-partition-analyzer: - -FatFs Partition Analyzer ------------------------- - -(:component_file:`fatfsparse.py `) is a partition analyzing tool for FatFs. - -It is a reverse tool of (:component_file:`fatfsgen.py `), i.e., it can generate the folder structure on the host based on the FatFs image. - -Usage:: - - ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] [--verbose] fatfs_image.img - -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. - -Application Examples --------------------- - -- :example:`storage/fatfs/getting_started` demonstrates the minimal setup required to store persistent data on SPI flash using the FatFS, including mounting the file system, opening a file, performing basic read and write operations, and unmounting the file system. - -- :example:`storage/fatfs/fs_operations` demonstrates more advanced FatFS operations, including reading and writing files, creating, moving, and deleting files and directories, and inspecting file details. - -- :example:`storage/fatfs/ext_flash` demonstrates how to operate an external SPI flash formatted with FatFS, including initializing the SPI bus, configuring the flash chip, registering it as a partition, and performing read and write operations. - -High-level API Reference ------------------------- - -.. include-build-file:: inc/esp_vfs_fat.inc From 917e0fd2555481fe2f9559d2772306ceb49cead0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Tue, 17 Mar 2026 17:41:02 +0100 Subject: [PATCH 3/4] docs(storage/fatfs): Fix problem with FatFs refactor --- docs/en/api-reference/storage/fatfs.rst | 206 +++++++++++++++++------- 1 file changed, 151 insertions(+), 55 deletions(-) diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index b45d90218e..301e78c5eb 100644 --- a/docs/en/api-reference/storage/fatfs.rst +++ b/docs/en/api-reference/storage/fatfs.rst @@ -3,13 +3,13 @@ FAT Filesystem Support :link_to_translation:`zh_CN:[中文]` -ESP-IDF uses the `FatFs `_ library to work with FAT filesystems. ESP-IDF integrates the FatFs library in the FatFs component. After mounting a FAT filesystem volume, the VFS layer exposes standard C library and POSIX file APIs. +ESP-IDF uses the `FatFs `_ library to work with FAT filesystems through the FatFs component. After a FAT filesystem volume is mounted, the VFS layer exposes standard C library and POSIX file APIs. .. note:: FatFs is an ambiguous term, as it refers to the filesystem itself, the upstream library, as well as the component in ESP-IDF. For clarity, this documentation uses the following terms: - - **FAT filesystem**: the on-disk FAT format (FAT12/FAT16/FAT32). + - **FAT filesystem**: the on-disk FAT format (FAT12/FAT16/FAT32); exFAT (see :ref:`Optional exFAT Support `). - **FatFs library**: the upstream `FatFs library `_ used by ESP-IDF. - **FatFs component**: the ESP-IDF integration layer around the FatFs library (mount helpers, wrappers, and related APIs) in :component:`fatfs`. @@ -20,19 +20,18 @@ ESP-IDF uses the `FatFs `_ library to Mount and Use FatFs ------------------- -The FatFs component provides convenience wrappers for mounting the filesystem for use with the VFS layer. Use these wrappers for most use cases instead of mounting the filesystem manually. For manual setup instructions, refer to :ref:`Manually mounting a FAT filesystem partition `. +The FatFs component provides convenience wrappers for mounting filesystems through the VFS layer. Use these wrappers for most use cases instead of mounting the filesystem manually. For manual setup instructions, refer to :ref:`Manually mounting a FAT filesystem partition `. -The following is the general workflow for mounting: +The general mounting workflow is: #. Select a mount path (for example, ``"/spiflash"`` or ``"/sdcard"``) and set ``esp_vfs_fat_mount_config_t``. - Set ``max_files`` to the smallest value that fits your workload. Higher values allow more simultaneously open files, but increase RAM usage. #. Mount the volume with a convenience helper from :component_file:`fatfs/vfs/esp_vfs_fat.h`: - :cpp:func:`esp_vfs_fat_spiflash_mount_rw_wl` for SPI flash partitions with wear leveling - :cpp:func:`esp_vfs_fat_spiflash_mount_ro` for read-only SPI flash partitions **without** wear leveling - :cpp:func:`esp_vfs_fat_sdmmc_mount` or :cpp:func:`esp_vfs_fat_sdspi_mount` for SD cards -#. Use standard file APIs (``stdio.h`` or POSIX) on paths under the mount path (for example, ``"/spiflash/example.txt"`` or ``"/sdcard/data.bin"``). +#. Use standard file APIs (``stdio.h`` or POSIX) on paths under the mount path. #. Close open files and call the matching unmount helper. .. _fatfs-configuration-options: @@ -46,14 +45,14 @@ The following configuration options are available for the FatFs component: * :ref:`CONFIG_FATFS_VOLUME_COUNT` - Sets the number of logical FatFs volumes. Increasing this value can increase baseline memory usage. * :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` - If enabled, the FatFs library prefers external RAM when allocating internal buffers. If external RAM allocation fails, it falls back to internal RAM. This can have a noticeable performance cost on hot I/O paths. Disable this option to prioritize performance; enable it to reduce internal RAM usage. * :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` - If enabled, the FatFs library tries to allocate heap work buffers in DMA-capable, cache-aligned memory first so SDMMC transfers avoid extra copies. This option is useful on targets that use PSRAM with SDMMC DMA (for example ESP32-P4). If this option and :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` are both enabled, the FatFs library tries DMA-capable RAM first, then external RAM, then internal RAM. -* :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` - If enabled, the FatFs library allocates instance buffers separately and sizes them according to each mounted volume's sector size. This option is useful when multiple FatFs instances use different sector sizes, as it can reduce memory usage. If disabled, all instances use buffers sized for the largest configured sector size. +* :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` - If enabled, the FatFs library allocates instance buffers separately and sizes them according to each mounted volume's logical sector size. This option is useful when multiple FatFs instances use different logical sector sizes, as it can reduce memory usage. If disabled, all instances use buffers sized for the largest configured logical sector size. * :ref:`CONFIG_FATFS_PER_FILE_CACHE` - If enabled, each open file uses a separate cache buffer. This improves I/O performance but increases RAM usage when multiple files are open. If disabled, a single shared cache is used, which reduces RAM usage but can increase storage read/write operations. * :ref:`CONFIG_FATFS_USE_FASTSEEK` - If enabled, POSIX :cpp:func:`lseek` runs faster. Fast seek does not work for files opened in write mode. To use fast seek, open the file in read-only mode, or close and reopen it in read-only mode. -* :ref:`CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE` - Sets the CLMT buffer size used by fast seek when :ref:`CONFIG_FATFS_USE_FASTSEEK` is enabled. Larger buffers can improve seek behavior on larger files, but use more RAM. +* :ref:`CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE` - Sets the CLMT (Cluster Link Map Table) buffer size used by fast seek when :ref:`CONFIG_FATFS_USE_FASTSEEK` is enabled. Larger buffers can improve seek behavior on larger files, but use more RAM. * :ref:`CONFIG_FATFS_VFS_FSTAT_BLKSIZE` - Sets the default stdio file buffer block size used through VFS. This option is mainly relevant for stdio-based I/O (for example ``fread``/``fgets``) and is not the primary tuning knob for direct POSIX ``read``/``write`` paths. Larger values can improve buffered read throughput, but increase heap usage. * :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC` - If enabled, the FatFs library calls :cpp:func:`f_sync` automatically after each call to :cpp:func:`write`, :cpp:func:`pwrite`, :cpp:func:`link`, :cpp:func:`truncate`, and :cpp:func:`ftruncate`. This option improves file consistency and size-reporting accuracy, but decreases performance because it triggers frequent disk operations. * :ref:`CONFIG_FATFS_LINK_LOCK` - If enabled, this option guarantees API thread safety for the :cpp:func:`link` function. Disabling this option can help applications that perform frequent small file operations (for example, file logging). When disabled, the copy performed by :cpp:func:`link` is non-atomic. In that case, using :cpp:func:`link` on a large file on the same volume from another task is not guaranteed to be thread-safe. -* Of note may also be: :ref:`CONFIG_FATFS_FS_LOCK`, :ref:`CONFIG_FATFS_TIMEOUT_MS`, and ``CONFIG_FATFS_CHOOSE_CODEPAGE`` (especially ``CONFIG_FATFS_CODEPAGE_DYNAMIC`` for code-size impact). Additional options include ``CONFIG_FATFS_SECTOR_SIZE``, ``CONFIG_FATFS_MAX_LFN``, ``CONFIG_FATFS_API_ENCODING``, and ``CONFIG_FATFS_USE_STRFUNC_CHOICE``. +* Other relevant options include :ref:`CONFIG_FATFS_FS_LOCK`, :ref:`CONFIG_FATFS_TIMEOUT_MS`, and ``CONFIG_FATFS_CHOOSE_CODEPAGE`` (especially ``CONFIG_FATFS_CODEPAGE_DYNAMIC`` for code-size impact). Additional options include ``CONFIG_FATFS_SECTOR_SIZE``, ``CONFIG_FATFS_MAX_LFN``, ``CONFIG_FATFS_API_ENCODING``, and ``CONFIG_FATFS_USE_STRFUNC_CHOICE``. These options control how the FatFs library calculates and reports free space: @@ -69,6 +68,7 @@ Differences from the POSIX Standard #. :cpp:func:`link`: FAT filesystems do not support hard links, therefore :cpp:func:`link` copies file contents instead. (This applies only to files on FAT filesystem volumes.) #. :cpp:func:`unlink`: If ``CONFIG_FATFS_FS_LOCK`` is enabled, removing an open file fails with ``EBUSY``. Otherwise, behavior is undefined and can corrupt the filesystem. +#. ``.`` and ``..`` are not supported as references to the current and parent directory. .. _fatfs-formatting: @@ -77,7 +77,7 @@ Formatting a FAT Filesystem Formatting creates a new FAT filesystem on the target volume and erases the existing directory structure and file data on that volume. Use it for first-time provisioning, or to recover from ``FR_NO_FILESYSTEM``. -For mount-time auto-formatting, set ``esp_vfs_fat_mount_config_t.format_if_mount_failed`` to ``true`` before calling a mount helper. This is useful when the volume is expected to be blank during first boot. When formatting is triggered this way, the mount configuration also controls the new filesystem layout: +For mount-time auto-formatting, set ``esp_vfs_fat_mount_config_t.format_if_mount_failed`` to ``true`` before calling a mount helper. This is useful when the volume is expected to be blank on first boot. When formatting is triggered this way, the mount configuration also controls the new filesystem layout: * ``allocation_unit_size`` sets the cluster size used by :cpp:func:`f_mkfs`. Larger values can improve throughput, but waste more space for many small files. * ``use_one_fat`` creates one FAT instead of two. This saves some space, but reduces redundancy. @@ -96,13 +96,13 @@ Read-only SPI flash partitions mounted with :cpp:func:`esp_vfs_fat_spiflash_moun FatFs Partition Generator ------------------------- -ESP-IDF provides a FatFs partition generator (:component_file:`wl_fatfsgen.py `) integrated into the build system for direct use in user projects. +ESP-IDF provides a FatFs partition generator, :component_file:`wl_fatfsgen.py `, which is integrated into the build system. -Use this tool to create filesystem images on a host and populate them with content from a specified host folder. +Use this tool to create filesystem images on a host and populate them from a specified host folder. -The script is based on the partition generator (:component_file:`fatfsgen.py `). In addition to generating a FatFs partition, ``wl_fatfsgen.py`` initializes wear leveling, so it is typically used for writable SPI flash filesystems. Use ``fatfsgen.py`` instead for read-only SPI flash images and SD card images. +The script is based on the partition generator (:component_file:`fatfsgen.py `). In addition to generating a FatFs partition, ``wl_fatfsgen.py`` initializes wear leveling, so it is typically used for writable SPI flash filesystems. Use ``fatfsgen.py`` instead for SD card images and read-only SPI flash images. -The latest version supports short and long file names, FAT12, and FAT16. Long file names are limited to 255 characters and can contain multiple periods (``.``) in the file name, but, crucially, not in the path, as well as the following additional characters: ``+``, ``,``, ``;``, ``=``, ``[`` and ``]``. +This tool supports short and long file names, FAT12, and FAT16. Long file names are limited to 255 characters and can contain multiple periods (``.``) in the file name, but not in the path. They can also contain the following additional characters: ``+``, ``,``, ``;``, ``=``, ``[`` and ``]``. An in-depth description of the FatFs partition generator and analyzer can be found at :doc:`Generating and parsing FAT partition on host `. @@ -111,14 +111,13 @@ Build System Integration with FatFs Partition Generator Invoke the FatFs generator directly from the CMake build system by calling ``fatfs_create_spiflash_image``:: - fatfs_create_spiflash_image( [FLASH_IN_PROJECT]) + fatfs_create_spiflash_image( [optional arguments]) To generate a **read-only** partition without wear leveling support, use ``fatfs_create_rawflash_image``:: - fatfs_create_rawflash_image( [FLASH_IN_PROJECT]) - -Call ``fatfs_create_spiflash_image`` or ``fatfs_create_rawflash_image`` from the project's CMakeLists.txt. + fatfs_create_rawflash_image( [optional arguments]) +Call ``fatfs_create_spiflash_image`` or ``fatfs_create_rawflash_image`` from the project's ``CMakeLists.txt``. The function arguments are: @@ -126,27 +125,25 @@ The function arguments are: #. base_dir - Directory encoded into the FAT filesystem partition and optionally flashed to the target. Make sure the partition table defines an appropriate partition size. -#. flag ``FLASH_IN_PROJECT`` - Optionally flash the image automatically with app binaries, partition tables, and other outputs when you run ``idf.py flash -p ``. - +#. flag ``FLASH_IN_PROJECT`` - Optionally flash the image automatically with app binaries, partition tables, and other outputs when you run ``idf.py flash -p ``. If ``FLASH_IN_PROJECT`` is not specified, the image is still generated, but you must flash it manually by using ``esptool`` or a custom build-system target. #. flag ``PRESERVE_TIME`` - Optionally preserve timestamps from the source folder in the target image. Without this flag, the tool sets every timestamp to the FatFs library default initial time (1 January 1980). -#. flag ``ONE_FAT`` - Optionally generate a FAT filesystem volume with one FAT (FAT Table) instead of two. This increases free space in the FAT filesystem volume by ``number of sectors used by FAT * sector size``, but it also increases corruption risk. +#. flag ``ONE_FAT`` - Optionally generate a FAT filesystem volume with one FAT (File Allocation Table) instead of two. This increases free space in the FAT filesystem volume by ``number of logical sectors used by one FAT * logical sector size``, but it also increases corruption risk. For example:: fatfs_create_spiflash_image(my_fatfs_partition my_folder FLASH_IN_PROJECT) -If ``FLASH_IN_PROJECT`` is not specified, the image is still generated, but you must flash it manually by using ``esptool`` or a custom build system target. +If you generate an image for an SD card, ESP-IDF does not currently provide a host-side flashing step to write that image directly to the card. Use other host tooling, such as ``dd``, to deploy the image. For an example project, see :example:`storage/fatfs/fatfsgen`. - .. _fatfs-partition-analyzer: FatFs Partition Parser ---------------------- -The :component_file:`fatfsparse.py ` tool is the reverse of :component_file:`fatfsgen.py `. It generates the host folder structure from a FAT filesystem image. +The :component_file:`fatfsparse.py ` tool performs the reverse operation of :component_file:`fatfsgen.py `. It reconstructs a host folder structure from a FAT filesystem image. Usage:: @@ -156,28 +153,114 @@ The ``--verbose`` option prints detailed information from the FAT filesystem ima .. _fatfs-minimum-partition-size: -FatFs Minimum Partition Size and Limits ---------------------------------------- +Size Requirements and Limits +---------------------------- -The FatFs component supports FAT12, FAT16, and FAT32 filesystem types. The number of clusters on the volume determines the filesystem type (clusters = data sectors / sectors per cluster). A cluster is a logical FAT allocation unit made of one or more sectors. The minimum partition size depends on the number of sectors allocated to FAT tables, root directories, and data clusters. +The FatFs component supports FAT12, FAT16, and FAT32 filesystem types, and can optionally support exFAT (see :ref:`Optional exFAT Support `). +The filesystem type depends on the number of clusters on the volume: -* The minimum supported size for a FAT partition with wear leveling enabled is 32 KB with a 4096-byte sector size. With a 512-byte sector size, the minimum partition size depends on the WL configuration: 20 KB for Performance mode and 28 KB for Safety mode (which requires 2 extra sectors). -* For a partition with wear leveling enabled, 4 sectors are reserved for wear leveling operations, and the FAT filesystem uses 4 sectors (1 reserved sector, 1 FAT sector, 1 root directory sector, and 1 data sector). -* Increasing the partition size allocates additional data sectors and increases storage space. -* For partition sizes smaller than 528 KB, the FAT filesystem allocates 1 root directory sector. For larger partitions, the FAT filesystem allocates 4 root directory sectors. -* By default, the FAT filesystem creates two FAT sectors, which increases partition size by one sector. To use one FAT sector, configure the `use_one_fat` option in ``esp_vfs_fat_mount_config_t`` (see :component_file:`fatfs/vfs/esp_vfs_fat.h`). This option reduces the minimum partition size to 32 KB. -* The general formula for calculating the partition size for a wear-leveled partition is:: +.. math:: - partition_size = wear_leveling_sectors * FLASH_SEC_SIZE + fatfs_partition_sectors * FAT_SEC_SIZE + cluster\_count = data\_logical\_sectors / logical\_sectors\_per\_cluster - Where: +The minimum partition size therefore depends on the number of logical sectors required by FAT metadata and by at least one data cluster. For the terminology used below, see :ref:`Glossary `. - - 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 +.. _fatfs-minimum-partition-size-raw: -* For read-only partitions without wear leveling and with a 512-byte sector size, the minimum partition size is as low as 2 KB. +Raw FAT Filesystem Size +^^^^^^^^^^^^^^^^^^^^^^^ + +The required size of a raw FAT filesystem consists of the FAT filesystem metadata plus the data area: + +.. math:: + + fatfs_size = (reserved + fats + root\_dir + data) * logical\_sector\_size + +Where: + +* ``reserved`` is the number of reserved logical sectors +* ``fats`` is the total number of logical sectors occupied by all FAT copies +* ``root_dir`` is the number of logical sectors occupied by the root directory on FAT12/FAT16 +* ``data`` is the number of logical sectors in the data area + +The FAT area depends on the selected FAT type and the number of clusters: + +.. list-table:: + :widths: 18 25 57 + :header-rows: 1 + + * - FAT Type + - Cluster Count + - FAT Sizing + * - FAT12 + - ``<= 4085`` + - Each FAT entry uses 12 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 3 / 2) / logical_sector_size)`` logical sectors. + * - FAT16 + - ``4085 < cluster_count < 65526`` + - Each FAT entry uses 16 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 2) / logical_sector_size)`` logical sectors. + * - FAT32 + - ``>= 65526`` + - Each FAT entry uses 32 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 4) / logical_sector_size)`` logical sectors. + * - exFAT + - ``16 .. 0x7FFFFFFD`` + - Each FAT entry uses 32 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 4) / logical_sector_size)`` logical sectors. + +For FAT12 and FAT16, the root directory is outside the data area, so: + +.. math:: + + root\_dir = ceil((root\_dir\_entries * 32) / logical\_sector\_size) + +For FAT32, the root directory is stored in the data area, so ``root_dir = 0`` in the formula above. + +exFAT uses a different metadata layout. In addition to the FAT area, it requires an allocation bitmap and an up-case table, and its root directory is stored in the data area. As a result, the FAT12/FAT16 root-directory formula above does not apply to exFAT. + +When exFAT support is enabled, the minimum exFAT volume size is 4096 logical sectors and the maximum cluster count is ``0x7FFFFFFD``. + +In practice: + +* Increasing the partition size adds data logical sectors and therefore increases usable storage space. +* On small FAT12/FAT16 volumes, the root directory can occupy 1 logical sector. On larger ones, it can occupy 4 logical sectors. +* For FAT12, FAT16, and FAT32, the default layout uses two FATs. Compared with ``use_one_fat = true``, this adds the logical sectors required by one extra FAT copy. exFAT uses a single FAT. +* For read-only partitions without wear leveling and with a 512-byte logical sector size, the practical minimum partition size is 2 KB. This minimum layout uses 4 logical sectors: 1 reserved sector, 1 FAT sector, 1 root-directory sector, and 1 data sector. + +This minimum raw layout is relevant for media such as SD cards and read-only raw flash partitions. + +.. _fatfs-minimum-partition-size-wl: + +FAT Filesystem with Wear Leveling +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For a flash partition with wear leveling, the total size is the raw FAT filesystem size from :ref:`Raw FAT Filesystem Size ` plus the wear-leveling metadata area: + +.. math:: + + partition_size = wl_metadata_flash_sectors * flash_sector_size + fatfs_size + +Where: + +* ``wl_metadata_flash_sectors`` is the number of flash sectors reserved for wear-leveling metadata +* ``flash_sector_size`` is the SPI flash erase-sector size. On almost all ESP boards it is 4096 bytes +* ``fatfs_size`` is the raw FAT filesystem size, as defined in :ref:`Raw FAT Filesystem Size ` + +The minimum supported partition size depends on the WL configuration: + +.. list-table:: + :widths: 28 18 54 + :header-rows: 1 + + * - Condition + - Minimum Size + - Notes + * - ``CONFIG_WL_SECTOR_SIZE = 4096`` + - 32 KB + - The minimum layout consists of 4 flash sectors reserved by the wear leveling layer plus the minimum raw FAT filesystem layout of 4 logical sectors. In this configuration, the logical sector size and the flash-sector size are both 4096 bytes. + * - ``CONFIG_WL_SECTOR_SIZE = 512`` and WL Performance mode + - 20 KB + - The raw FAT filesystem still needs the same minimum layout of 4 logical sectors, but the wear leveling layer keeps its metadata in 4096-byte flash sectors. + * - ``CONFIG_WL_SECTOR_SIZE = 512`` and WL Safety mode + - 28 KB + - Same raw FAT minimum as above, plus 2 additional flash sectors reserved by the wear leveling layer. For more details, see :doc:`File System Considerations <../../api-guides/file-system-considerations>`. @@ -187,12 +270,12 @@ For more details, see :doc:`File System Considerations <../../api-guides/file-sy Optimizing ---------- -FatFs setup can be optimized for multiple variables by choosing specific configuration options, with different tradeoffs. +FatFs behavior can be tuned for different priorities by choosing the right configuration options and filesystem layout. The main variables that affect behavior are: * Buffer placement and sizing (:ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS`, :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`, :ref:`CONFIG_FATFS_USE_DYN_BUFFERS`, :ref:`CONFIG_FATFS_PER_FILE_CACHE`, and application I/O buffer sizes) -* Wear leveling sector size and mode (``CONFIG_WL_SECTOR_SIZE_*`` and ``CONFIG_WL_SECTOR_MODE_*``) +* Wear leveling logical sector size and mode (``CONFIG_WL_SECTOR_SIZE_*`` and ``CONFIG_WL_SECTOR_MODE_*``) * Sync strategy (:ref:`CONFIG_FATFS_IMMEDIATE_FSYNC`) * Workload pattern (transaction sizes, sequential vs random access, read vs write ratio) @@ -206,7 +289,7 @@ For throughput-oriented workloads: * Prefer larger read/write transaction sizes over many small operations. * Align transaction sizes to the active sector size when possible (for example 512 B or 4096 B), and pad writes if needed to reduce partial-sector overhead. * For SPI flash with wear leveling, prefer ``CONFIG_WL_SECTOR_SIZE_4096`` when RAM budget allows, as it is generally more efficient. -* If using 512-byte WL sectors, use ``CONFIG_WL_SECTOR_MODE_PERF`` when your application can accept the higher power-loss risk during sector erase. +* If using 512-byte WL sectors, use ``CONFIG_WL_SECTOR_MODE_PERF`` when your application can accept the higher power-loss risk during flash-sector erase. * Prefer POSIX ``read``/``write`` over ``fread``/``fwrite`` on hot paths when possible. For broader speed guidance, see :doc:`Maximizing Execution Speed <../../api-guides/performance/speed>`. * On SDMMC DMA targets (for example ESP32-P4 with PSRAM), enable :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` to reduce extra buffer copies. * Enable :ref:`CONFIG_FATFS_USE_FASTSEEK` for read-heavy workloads with long backward seeks. @@ -220,7 +303,7 @@ Optimizing for memory usage * Disable :ref:`CONFIG_FATFS_PER_FILE_CACHE` to use a single shared cache when reducing RAM usage is the priority. * Tune ``esp_vfs_fat_mount_config_t.max_files`` (see :ref:`Mount and Use FatFs `) as low as practical; each simultaneously open file increases RAM usage. * If :ref:`CONFIG_FATFS_PER_FILE_CACHE` is enabled, prefer ``CONFIG_WL_SECTOR_SIZE_512`` to reduce per-file cache size. -* If :ref:`CONFIG_FATFS_PER_FILE_CACHE` is disabled, ``CONFIG_WL_SECTOR_SIZE_4096`` can be a better tradeoff. +* If :ref:`CONFIG_FATFS_PER_FILE_CACHE` is disabled, ``CONFIG_WL_SECTOR_SIZE_4096`` may be a better tradeoff. * Enable :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` on targets with external RAM support to reduce internal RAM pressure, but expect lower I/O performance. * Consider ``CONFIG_FATFS_LONG_FILENAMES = CONFIG_FATFS_LFN_NONE`` when SFN (8.3) filenames are acceptable. * If long filenames are required, reduce ``CONFIG_FATFS_MAX_LFN`` to the smallest value that meets your needs. @@ -240,7 +323,18 @@ For maximizing usable filesystem capacity: Advanced operations ------------------- -Manual mounting may be required when you use storage media that ESP-IDF does not directly support or when you need access to low-level FatFs library functions. +Manual mounting may be required when you use storage media that ESP-IDF does not support directly or when you need access to low-level FatFs library functions. + +.. _fatfs-optional-exfat-support: + +Optional exFAT Support +^^^^^^^^^^^^^^^^^^^^^^ + +The upstream FatFs library includes optional exFAT support, but ESP-IDF does not enable it by default. + +If your project requires exFAT, you must modify the FatFs configuration in the :component:`fatfs` component manually and integrate the resulting configuration into your build and validation flow. ESP-IDF does not provide a dedicated menuconfig option or a standard high-level enablement path for exFAT. + +Before enabling exFAT, review any licensing or other intellectual-property considerations that may apply to your product, distribution model, and target markets. Architecture Overview ^^^^^^^^^^^^^^^^^^^^^ @@ -271,14 +365,12 @@ The following diagram illustrates the layered architecture of FatFs and its rela | SPI Flash | SD Card | +-------------------------------+-------------------------------+ - - .. _fatfs-manual-mount: Manually Mounting a FAT Filesystem Partition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -When mounting a FAT filesystem partition manually, follow the same general steps performed by the convenience wrappers from :ref:`Mount and Use FatFs ` to register the filesystem with the FatFs library and then mount it in the VFS. +When mounting a FAT filesystem partition manually, follow the same general flow used by the convenience wrappers described in :ref:`Mount and Use FatFs `: register the filesystem with the FatFs library, then mount it through the VFS. #. Register the filesystem with the VFS by calling :cpp:func:`esp_vfs_fat_register`. This allocates the ``FATFS`` structure and sets up the interface between the VFS and the FatFs library. Specify: @@ -310,11 +402,11 @@ When calling low-level functions provided by the FatFs library, use paths withou FatFs Disk I/O Layer ^^^^^^^^^^^^^^^^^^^^ -FatFs provides APIs to register disk I/O drivers at runtime. These APIs provide a generic interface between medium-specific access functions and the FatFs library. +FatFs provides APIs to register disk I/O drivers at runtime. These APIs form the interface between medium-specific access functions and the FatFs library. The disk I/O layer uses :cpp:struct:`ff_diskio_impl_t` to provide medium access functions. Pass this structure to :cpp:func:`ff_diskio_register`. -ESP-IDF provides a set of convenience wrappers that simplify mounting a set of supported storage media. These include: +ESP-IDF provides convenience wrappers for the supported storage media. These include: - :cpp:func:`ff_diskio_register_wl_partition` for SPI flash partitions with wear leveling - :cpp:func:`ff_diskio_register_raw_partition` for read-only SPI flash partitions **without** wear leveling @@ -334,12 +426,16 @@ Glossary * - Term - Description * - VFS - - Virtual File System, an abstraction layer provided by ESP-IDF that allows accessing different underlying filesystems through unified POSIX and stdio.h interfaces. - * - Sector - - The minimum physical unit for read/write operations on a storage device, typically 512 bytes or 4096 bytes. + - Virtual File System, an abstraction layer provided by ESP-IDF that allows applications to access different underlying filesystems through unified POSIX and ``stdio.h`` interfaces. + * - Logical Sector + - The logical block size presented to FatFs and the disk I/O layer. For wear-leveled SPI flash, this is the WL sector size. For read-only raw SPI flash partitions, this is the flash-sector size. For SD cards, it is typically 512 bytes. + * - WL Sector + - The logical sector size exposed by the wear leveling layer to FatFs. Depending on ``CONFIG_WL_SECTOR_SIZE``, it is either 512 bytes or 4096 bytes. + * - Flash Sector + - The underlying SPI flash erase unit used by the flash chip. On nearly all ESP boards, this is 4096 bytes. It can differ from the WL sector size presented to FatFs when wear leveling is configured for 512-byte sectors. * - Cluster - - The minimum logical unit for filesystem storage allocation, consisting of one or more contiguous sectors. - * - FAT Table + - The minimum logical FAT allocation unit, consisting of one or more contiguous logical sectors. + * - FAT - File Allocation Table, which records the usage status of each cluster and the linkage relationships between file data blocks. * - Wear Leveling - A technique to extend the lifespan of flash memory by distributing write operations evenly across storage cells, preventing specific blocks from wearing out prematurely due to frequent erasing. From 0dd5d8f726d10cd455fa84aea43897f5339969ca Mon Sep 17 00:00:00 2001 From: Zhang Shuxian Date: Thu, 26 Mar 2026 12:01:47 +0800 Subject: [PATCH 4/4] docs: Provide translation for fatfs docs --- docs/en/api-reference/storage/fatfs.rst | 90 +-- .../api-guides/file-system-considerations.rst | 3 +- docs/zh_CN/api-reference/storage/fatfs.rst | 652 +++++++++++++----- 3 files changed, 516 insertions(+), 229 deletions(-) diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index 301e78c5eb..a6fa1f2739 100644 --- a/docs/en/api-reference/storage/fatfs.rst +++ b/docs/en/api-reference/storage/fatfs.rst @@ -9,7 +9,7 @@ ESP-IDF uses the `FatFs `_ library to FatFs is an ambiguous term, as it refers to the filesystem itself, the upstream library, as well as the component in ESP-IDF. For clarity, this documentation uses the following terms: - - **FAT filesystem**: the on-disk FAT format (FAT12/FAT16/FAT32); exFAT (see :ref:`Optional exFAT Support `). + - **FAT filesystem**: the on-disk FAT format (FAT12/FAT16/FAT32), exFAT (see :ref:`Optional exFAT Support `). - **FatFs library**: the upstream `FatFs library `_ used by ESP-IDF. - **FatFs component**: the ESP-IDF integration layer around the FatFs library (mount helpers, wrappers, and related APIs) in :component:`fatfs`. @@ -27,9 +27,9 @@ The general mounting workflow is: #. Select a mount path (for example, ``"/spiflash"`` or ``"/sdcard"``) and set ``esp_vfs_fat_mount_config_t``. #. Mount the volume with a convenience helper from :component_file:`fatfs/vfs/esp_vfs_fat.h`: - - :cpp:func:`esp_vfs_fat_spiflash_mount_rw_wl` for SPI flash partitions with wear leveling - - :cpp:func:`esp_vfs_fat_spiflash_mount_ro` for read-only SPI flash partitions **without** wear leveling - - :cpp:func:`esp_vfs_fat_sdmmc_mount` or :cpp:func:`esp_vfs_fat_sdspi_mount` for SD cards + - :cpp:func:`esp_vfs_fat_spiflash_mount_rw_wl` for SPI flash partitions with wear leveling. + - :cpp:func:`esp_vfs_fat_spiflash_mount_ro` for read-only SPI flash partitions **without** wear leveling. + - :cpp:func:`esp_vfs_fat_sdmmc_mount` or :cpp:func:`esp_vfs_fat_sdspi_mount` for SD cards. #. Use standard file APIs (``stdio.h`` or POSIX) on paths under the mount path. #. Close open files and call the matching unmount helper. @@ -66,13 +66,13 @@ These options control how the FatFs library calculates and reports free space: Differences from the POSIX Standard ----------------------------------- -#. :cpp:func:`link`: FAT filesystems do not support hard links, therefore :cpp:func:`link` copies file contents instead. (This applies only to files on FAT filesystem volumes.) +#. :cpp:func:`link`: FAT filesystems do not support hard links, therefore :cpp:func:`link` copies file contents instead, which applies only to files on FAT filesystem volumes. #. :cpp:func:`unlink`: If ``CONFIG_FATFS_FS_LOCK`` is enabled, removing an open file fails with ``EBUSY``. Otherwise, behavior is undefined and can corrupt the filesystem. #. ``.`` and ``..`` are not supported as references to the current and parent directory. .. _fatfs-formatting: -Formatting a FAT Filesystem +Format a FAT Filesystem --------------------------- Formatting creates a new FAT filesystem on the target volume and erases the existing directory structure and file data on that volume. Use it for first-time provisioning, or to recover from ``FR_NO_FILESYSTEM``. @@ -84,8 +84,8 @@ For mount-time auto-formatting, set ``esp_vfs_fat_mount_config_t.format_if_mount For explicit formatting after initialization, use the helper that matches the storage type: -* :cpp:func:`esp_vfs_fat_spiflash_format_rw_wl` or :cpp:func:`esp_vfs_fat_spiflash_format_cfg_rw_wl` for SPI flash partitions with wear leveling -* :cpp:func:`esp_vfs_fat_sdcard_format` or :cpp:func:`esp_vfs_fat_sdcard_format_cfg` for SD cards +* :cpp:func:`esp_vfs_fat_spiflash_format_rw_wl` or :cpp:func:`esp_vfs_fat_spiflash_format_cfg_rw_wl` for SPI flash partitions with wear leveling. +* :cpp:func:`esp_vfs_fat_sdcard_format` or :cpp:func:`esp_vfs_fat_sdcard_format_cfg` for SD cards. The SPI flash formatting helpers can be called whether the filesystem is currently mounted or not. The SD card formatting helpers require the card (but not the filesystem) to be mounted first. @@ -109,11 +109,15 @@ An in-depth description of the FatFs partition generator and analyzer can be fou Build System Integration with FatFs Partition Generator ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Invoke the FatFs generator directly from the CMake build system by calling ``fatfs_create_spiflash_image``:: +Invoke the FatFs generator directly from the CMake build system by calling ``fatfs_create_spiflash_image``: + +.. code-block:: none fatfs_create_spiflash_image( [optional arguments]) -To generate a **read-only** partition without wear leveling support, use ``fatfs_create_rawflash_image``:: +To generate a **read-only** partition without wear leveling support, use ``fatfs_create_rawflash_image``: + +.. code-block:: none fatfs_create_rawflash_image( [optional arguments]) @@ -130,7 +134,9 @@ The function arguments are: #. flag ``ONE_FAT`` - Optionally generate a FAT filesystem volume with one FAT (File Allocation Table) instead of two. This increases free space in the FAT filesystem volume by ``number of logical sectors used by one FAT * logical sector size``, but it also increases corruption risk. -For example:: +For example: + +.. code-block:: none fatfs_create_spiflash_image(my_fatfs_partition my_folder FLASH_IN_PROJECT) @@ -145,7 +151,9 @@ FatFs Partition Parser The :component_file:`fatfsparse.py ` tool performs the reverse operation of :component_file:`fatfsgen.py `. It reconstructs a host folder structure from a FAT filesystem image. -Usage:: +Usage + +.. code-block:: none ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] [--verbose] fatfs_image.img @@ -157,6 +165,7 @@ Size Requirements and Limits ---------------------------- The FatFs component supports FAT12, FAT16, and FAT32 filesystem types, and can optionally support exFAT (see :ref:`Optional exFAT Support `). + The filesystem type depends on the number of clusters on the volume: .. math:: @@ -174,7 +183,7 @@ The required size of a raw FAT filesystem consists of the FAT filesystem metadat .. math:: - fatfs_size = (reserved + fats + root\_dir + data) * logical\_sector\_size + fatfs\_size = (reserved + fats + root\_dir + data) × logical\_sector\_size Where: @@ -194,22 +203,22 @@ The FAT area depends on the selected FAT type and the number of clusters: - FAT Sizing * - FAT12 - ``<= 4085`` - - Each FAT entry uses 12 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 3 / 2) / logical_sector_size)`` logical sectors. + - Each FAT entry uses 12 bits, so one FAT copy requires ``ceil(((cluster_count + 2) × 3 / 2) / logical_sector_size)`` logical sectors. * - FAT16 - ``4085 < cluster_count < 65526`` - - Each FAT entry uses 16 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 2) / logical_sector_size)`` logical sectors. + - Each FAT entry uses 16 bits, so one FAT copy requires ``ceil(((cluster_count + 2) × 2) / logical_sector_size)`` logical sectors. * - FAT32 - ``>= 65526`` - - Each FAT entry uses 32 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 4) / logical_sector_size)`` logical sectors. + - Each FAT entry uses 32 bits, so one FAT copy requires ``ceil(((cluster_count + 2) × 4) / logical_sector_size)`` logical sectors. * - exFAT - ``16 .. 0x7FFFFFFD`` - - Each FAT entry uses 32 bits, so one FAT copy requires ``ceil(((cluster_count + 2) * 4) / logical_sector_size)`` logical sectors. + - Each FAT entry uses 32 bits, so one FAT copy requires ``ceil(((cluster_count + 2) × 4) / logical_sector_size)`` logical sectors. For FAT12 and FAT16, the root directory is outside the data area, so: .. math:: - root\_dir = ceil((root\_dir\_entries * 32) / logical\_sector\_size) + root\_dir = ceil((root\_dir\_entries × 32) / logical\_sector\_size) For FAT32, the root directory is stored in the data area, so ``root_dir = 0`` in the formula above. @@ -235,7 +244,7 @@ For a flash partition with wear leveling, the total size is the raw FAT filesyst .. math:: - partition_size = wl_metadata_flash_sectors * flash_sector_size + fatfs_size + partition\_size = wl\_metadata\_flash\_sectors × flash\_sector\_size + fatfs\_size Where: @@ -265,21 +274,22 @@ The minimum supported partition size depends on the WL configuration: For more details, see :doc:`File System Considerations <../../api-guides/file-system-considerations>`. .. note:: + The wear leveling layer protects the underlying flash by distributing write and erase cycles across the managed storage region. Its effectiveness therefore scales with the size of that region. Small partitions restrict wear distribution and can significantly reduce protection, so their use is strongly discouraged. For more information, refer to :doc:`wear leveling `. -Optimizing ----------- +Optimization +------------ FatFs behavior can be tuned for different priorities by choosing the right configuration options and filesystem layout. The main variables that affect behavior are: -* Buffer placement and sizing (:ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS`, :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`, :ref:`CONFIG_FATFS_USE_DYN_BUFFERS`, :ref:`CONFIG_FATFS_PER_FILE_CACHE`, and application I/O buffer sizes) -* Wear leveling logical sector size and mode (``CONFIG_WL_SECTOR_SIZE_*`` and ``CONFIG_WL_SECTOR_MODE_*``) -* Sync strategy (:ref:`CONFIG_FATFS_IMMEDIATE_FSYNC`) -* Workload pattern (transaction sizes, sequential vs random access, read vs write ratio) +* Buffer placement and sizing (:ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS`, :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`, :ref:`CONFIG_FATFS_USE_DYN_BUFFERS`, :ref:`CONFIG_FATFS_PER_FILE_CACHE`, and application I/O buffer sizes). +* Wear leveling logical sector size and mode (``CONFIG_WL_SECTOR_SIZE_*`` and ``CONFIG_WL_SECTOR_MODE_*``). +* Sync strategy (:ref:`CONFIG_FATFS_IMMEDIATE_FSYNC`). +* Workload pattern (transaction sizes, sequential vs random access, read vs write ratio). -Optimizing for I/O Performance +Optimize I/O Performance ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For throughput-oriented workloads: @@ -295,9 +305,10 @@ For throughput-oriented workloads: * Enable :ref:`CONFIG_FATFS_USE_FASTSEEK` for read-heavy workloads with long backward seeks. .. note:: + For a baseline of what to expect in a performance-optimized scenario, see :example:`storage/perf_benchmark`. -Optimizing for memory usage +Optimize Memory Usage ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Disable :ref:`CONFIG_FATFS_PER_FILE_CACHE` to use a single shared cache when reducing RAM usage is the priority. @@ -309,8 +320,8 @@ Optimizing for memory usage * If long filenames are required, reduce ``CONFIG_FATFS_MAX_LFN`` to the smallest value that meets your needs. * Enable :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` so each mounted volume uses buffers sized to its actual sector size. -Optimizing for storage efficiency -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Optimize Storage Efficiency +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For maximizing usable filesystem capacity: @@ -320,7 +331,7 @@ For maximizing usable filesystem capacity: * Keep long filenames short where possible; long names consume additional directory entries. * For read-only data, consider raw FAT partitions without wear leveling where appropriate. -Advanced operations +Advanced Operations ------------------- Manual mounting may be required when you use storage media that ESP-IDF does not support directly or when you need access to low-level FatFs library functions. @@ -341,7 +352,7 @@ Architecture Overview The following diagram illustrates the layered architecture of FatFs and its relationship with other ESP-IDF components: -:: +.. code-block:: none +---------------------------------------------------------------+ | Newlib/Picolib (C Standard Library) | @@ -367,17 +378,16 @@ The following diagram illustrates the layered architecture of FatFs and its rela .. _fatfs-manual-mount: -Manually Mounting a FAT Filesystem Partition +Manually Mount a FAT Filesystem Partition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When mounting a FAT filesystem partition manually, follow the same general flow used by the convenience wrappers described in :ref:`Mount and Use FatFs `: register the filesystem with the FatFs library, then mount it through the VFS. -#. - Register the filesystem with the VFS by calling :cpp:func:`esp_vfs_fat_register`. This allocates the ``FATFS`` structure and sets up the interface between the VFS and the FatFs library. Specify: +#. Register the filesystem with the VFS by calling :cpp:func:`esp_vfs_fat_register`. This allocates the ``FATFS`` structure and sets up the interface between the VFS and the FatFs library. Specify: - - The path prefix where the filesystem will be mounted (for example, ``"/sdcard"`` or ``"/spiflash"``) - - The FatFs drive number - - A variable that receives a pointer to the ``FATFS`` structure + - The path prefix where the filesystem will be mounted (for example, ``"/sdcard"`` or ``"/spiflash"``). + - The FatFs drive number. + - A variable that receives a pointer to the ``FATFS`` structure. #. Register the disk I/O driver for the drive number used in Step 1 by calling :cpp:func:`ff_diskio_register`. @@ -408,9 +418,9 @@ The disk I/O layer uses :cpp:struct:`ff_diskio_impl_t` to provide medium access ESP-IDF provides convenience wrappers for the supported storage media. These include: - - :cpp:func:`ff_diskio_register_wl_partition` for SPI flash partitions with wear leveling - - :cpp:func:`ff_diskio_register_raw_partition` for read-only SPI flash partitions **without** wear leveling - - :cpp:func:`ff_diskio_register_sdmmc` for both SDMMC and SPI connected SD cards + - :cpp:func:`ff_diskio_register_wl_partition` for SPI flash partitions with wear leveling. + - :cpp:func:`ff_diskio_register_raw_partition` for read-only SPI flash partitions **without** wear leveling. + - :cpp:func:`ff_diskio_register_sdmmc` for both SDMMC and SPI connected SD cards. For API reference, see :ref:`Disk I/O API Reference `. diff --git a/docs/zh_CN/api-guides/file-system-considerations.rst b/docs/zh_CN/api-guides/file-system-considerations.rst index 529b34efc7..9ec5880113 100644 --- a/docs/zh_CN/api-guides/file-system-considerations.rst +++ b/docs/zh_CN/api-guides/file-system-considerations.rst @@ -101,8 +101,7 @@ FatFS 是最适用于常见应用的文件系统,如文件/目录访问、数 - `FatFS 源站点 `_ - 更多关于 `FAT 表大小限制 `_ -- :ref:`using-fatfs-with-vfs` -- :ref:`using-fatfs-with-vfs-and-sdcards` +- :ref:`fatfs-mount-and-use` - ESP-IDF FatFS 工具: :ref:`FatFS 分区生成器 ` 和 :ref:`FatFS 分区分析器 ` **示例:** diff --git a/docs/zh_CN/api-reference/storage/fatfs.rst b/docs/zh_CN/api-reference/storage/fatfs.rst index 6df8f9cedc..72b762ebb4 100644 --- a/docs/zh_CN/api-reference/storage/fatfs.rst +++ b/docs/zh_CN/api-reference/storage/fatfs.rst @@ -3,96 +3,481 @@ FAT 文件系统 :link_to_translation:`en:[English]` -ESP-IDF 使用 `FatFs `_ 库来实现 FAT 文件系统。FatFs 库位于 ``fatfs`` 组件中,支持直接使用,也可以借助 C 标准库和 POSIX API 通过 VFS(虚拟文件系统)使用 FatFs 库的大多数功能。 - -此外,我们对 FatFs 库进行了扩展,新增了支持可插拔磁盘 I/O 调度层,从而允许在运行时将 FatFs 驱动映射到物理磁盘。 - -.. _using-fatfs-with-vfs: - -FatFs 与 VFS 配合使用 ----------------------------- - -头文件 :component_file:`fatfs/vfs/esp_vfs_fat.h` 定义了连接 FatFs 和 VFS 的函数。 - -函数 :cpp:func:`esp_vfs_fat_register` 分配一个 ``FATFS`` 结构,并在 VFS 中注册特定路径前缀。如果文件路径以此前缀开头,则对此文件的后续操作将转至 FatFs API。 - -函数 :cpp:func:`esp_vfs_fat_unregister_path` 删除在 VFS 中的注册,并释放 ``FATFS`` 结构。 - -多数应用程序在使用 ``esp_vfs_fat_`` 函数时,采用如下步骤: - -#. - 调用 :cpp:func:`esp_vfs_fat_register`,指定: - - - 挂载文件系统的路径前缀(例如,``"/sdcard"`` 或 ``"/spiflash"``) - - FatFs 驱动编号 - - 一个用于接收指向 ``FATFS`` 结构指针的变量 - -#. 调用 :cpp:func:`ff_diskio_register`,为步骤 1 中的驱动编号注册磁盘 I/O 驱动; - -#. 如需使用与传递到 :cpp:func:`esp_vfs_fat_register` 相同的驱动编号挂载文件系统,可调用 FatFs 函数 :cpp:func:`f_mount`。如果目标逻辑驱动上不存在该文件系统,:cpp:func:`f_mount` 将调用失败并报告 ``FR_NO_FILESYSTEM`` 错误。此时,应首先调用 :cpp:func:`f_mkfs`,在驱动上创建新的 FatFS 结构体,然后重新调用 :cpp:func:`f_mount`。注意,应在上述步骤之前调用 :cpp:func:`f_fdisk` 对 SD 卡进行分区。请参考 `FatFs 文档 `_,查看更多信息; - -#. 调用 C 标准库和 POSIX API 对路径中带有步骤 1 中所述前缀的文件(例如,``"/sdcard/hello.txt"``)执行打开、读取、写入、擦除、复制等操作。文件系统默认使用 `8.3 文件名 `_ 格式 (SFN)。如需使用长文件名 (LFN),启用 :ref:`CONFIG_FATFS_LONG_FILENAMES` 选项。请参考 `FatFs 文件系统 `_,查看更多信息; - -#. 可以直接调用 FatFs 库函数,但需要使用没有 VFS 前缀的路径,如 ``"/hello.txt"``; - -#. 关闭所有打开的文件; - -#. 调用 FatFs 函数 :cpp:func:`f_mount` 并使用 NULL ``FATFS*`` 参数,为与上述编号相同的驱动卸载文件系统; - -#. 调用 FatFs 函数 :cpp:func:`ff_diskio_register` 并使用 NULL ``ff_diskio_impl_t*`` 参数和相同的驱动编号,来释放注册的磁盘 I/O 驱动; - -#. 调用 :cpp:func:`esp_vfs_fat_unregister_path` 并使用文件系统挂载的路径将 FatFs 从 VFS 中移除,并释放步骤 1 中分配的 ``FATFS`` 结构。 - -便捷函数 :cpp:func:`esp_vfs_fat_sdmmc_mount`、:cpp:func:`esp_vfs_fat_sdspi_mount` 和 :cpp:func:`esp_vfs_fat_sdcard_unmount` 对上述步骤进行了封装,并加入了对 SD 卡初始化的处理。我们将在下一章节详细介绍以上函数。 - -与 POSIX 标准的差异 ---------------------- - -#. :cpp:func:`link`:由于 FAT 文件系统不支持硬链接,调用 :cpp:func:`link` 后会复制文件内容(仅适用于 FatFs 卷上的文件)。 -#. :cpp:func:`unlink`:当尝试删除已打开的文件时,如果启用了 ``CONFIG_FATFS_FS_LOCK``,操作将失败并返回 ``EBUSY``。如果未启用,则行为未定义(可能导致文件系统损坏)。 - -.. _using-fatfs-with-vfs-and-sdcards: - -FatFs 与 VFS 和 SD 卡配合使用 ---------------------------------- - -头文件 :component_file:`fatfs/vfs/esp_vfs_fat.h` 定义了便捷函数 :cpp:func:`esp_vfs_fat_sdmmc_mount`、 :cpp:func:`esp_vfs_fat_sdspi_mount` 和 :cpp:func:`esp_vfs_fat_sdcard_unmount`。这些函数分别执行上一章节的步骤 1-3 和步骤 7-9,并初始化 SD 卡,但仅提供有限的错误处理功能。我们鼓励开发人员查看源代码,将更多高级功能集成到产品应用中。 - -便捷函数 :cpp:func:`esp_vfs_fat_sdmmc_unmount` 用于卸载文件系统并释放从 :cpp:func:`esp_vfs_fat_sdmmc_mount` 函数获取的资源。 - - -FatFs 与 VFS 配合使用(只读模式下) --------------------------------------- - -头文件 :component_file:`fatfs/vfs/esp_vfs_fat.h` 也定义了两个便捷函数 :cpp:func:`esp_vfs_fat_spiflash_mount_ro` 和 :cpp:func:`esp_vfs_fat_spiflash_unmount_ro`。上述两个函数分别对 FAT 只读分区执行步骤 1-3 和步骤 7-9。有些数据分区仅在工厂配置时写入一次,之后在整个硬件生命周期内都不会再有任何改动。利用上述两个函数处理这种数据分区非常方便。 - -配置选项 --------- - -FatFs 组件有以下配置选项: - -* :ref:`CONFIG_FATFS_USE_FASTSEEK` - 如果启用该选项,POSIX :cpp:func:`lseek` 函数将以更快的速度执行。快速查找不适用于编辑模式下的文件,所以,使用快速查找时,应在只读模式下打开(或者关闭然后重新打开)文件。 -* :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC` - 如果启用该选项,FatFs 将在每次调用 :cpp:func:`write`、:cpp:func:`pwrite`、:cpp:func:`link`、:cpp:func:`truncate` 和 :cpp:func:`ftruncate` 函数后,自动调用 :cpp:func:`f_sync` 以同步最近的文件改动。该功能提升了 FatFs 的文件一致性和文件大小报告的准确性,但频繁的磁盘操作会降低性能。 -* :ref:`CONFIG_FATFS_LINK_LOCK` - 如果启用该选项,可保证 API 的线程安全,但如果应用程序需要快速频繁地进行小文件操作(例如将日志记录到文件),则可能有必要禁用该选项。请注意,如果禁用该选项,调用 :cpp:func:`link` 后的复制操作将是非原子的,此时如果在不同任务中对同一卷上的大文件调用 :cpp:func:`link`,则无法确保线程安全。 - -以下选项用于设置 FatFs 文件系统计算和报告空闲空间的策略: - -* :ref:`CONFIG_FATFS_DONT_TRUST_FREE_CLUSTER_CNT` – 如果设置为 1,将忽略空闲簇计数。默认值为 0。 -* :ref:`CONFIG_FATFS_DONT_TRUST_LAST_ALLOC` – 如果设置为 1,将忽略上次分配的簇号。默认值为 0。 +ESP-IDF 通过 FatFs 组件使用 `FatFs `_ 库来实现 FAT 文件系统。挂载 FAT 文件系统卷后,VFS 层会暴露标准 C 库和 POSIX API。 .. note:: - 将这两个选项设为 1 可能会提高 :cpp:func:`f_getfree` 输出的准确性,但性能会下降,例如,可能需要执行完整的 FAT 扫描。 + FatFs 可用于指代多个概念,如文件系统本身、上游库,或 ESP-IDF 组件。为清晰起见,本文档使用以下术语: + - **FAT 文件系统**:磁盘上的 FAT 格式 (FAT12/FAT16/FAT32),exFAT(参见 :ref:`可选的 exFAT 支持 `)。 + - **FatFs 库**:ESP-IDF 使用的上游 `FatFs 库 `_。 + - **FatFs 组件**:ESP-IDF 中围绕 FatFs 库的集成层(挂载辅助函数、封装器和相关 API),位于 :component:`fatfs`。 + + 本文档相关的其他术语在 :ref:`术语表 ` 中进行了解释。 + +.. _fatfs-mount-and-use: + +挂载和使用 FatFs +---------------- + +FatFs 组件提供了便利的封装函数,用于通过 VFS 层挂载文件系统。在大多数用例中,应使用这些封装函数,而不是手动挂载文件系统。有关手动设置的说明,请参考 :ref:`手动挂载 FAT 文件系统分区 `。 + +一般的挂载流程是: + +#. 选择挂载路径(例如 ``"/spiflash"`` 或 ``"/sdcard"``),并设置 ``esp_vfs_fat_mount_config_t``。 +#. 使用 :component_file:`fatfs/vfs/esp_vfs_fat.h` 中的便利辅助函数挂载卷: + + - :cpp:func:`esp_vfs_fat_spiflash_mount_rw_wl` 用于带磨损均衡的 SPI flash 分区。 + - :cpp:func:`esp_vfs_fat_spiflash_mount_ro` 用于 **不带** 磨损均衡的只读 SPI flash 分区。 + - :cpp:func:`esp_vfs_fat_sdmmc_mount` 或 :cpp:func:`esp_vfs_fat_sdspi_mount` 用于 SD 卡。 + +#. 在挂载路径下的路径上使用标准文件 API(``stdio.h`` 或 POSIX)。 +#. 关闭打开的文件,并调用相应的卸载辅助函数。 + +.. _fatfs-configuration-options: + +配置选项 +-------------------- + +FatFs 组件提供以下配置选项: + +* ``CONFIG_FATFS_LONG_FILENAMES`` - 选择 FatFs 库如何处理长文件名 (LFN) 支持。可用选项包括 :ref:`CONFIG_FATFS_LFN_NONE ` 以禁用 LFN 支持并将名称限制为 `8.3 格式 `_ (仅 SFN), :ref:`CONFIG_FATFS_LFN_HEAP ` 以启用 LFN 支持并将 LFN 工作缓冲区存储在堆上(默认),以及 :ref:`CONFIG_FATFS_LFN_STACK ` 以启用 LFN 支持并将 LFN 工作缓冲区存储在栈上。详细信息请参阅 `FatFs 文件名 `_。 +* :ref:`CONFIG_FATFS_VOLUME_COUNT` - 设置逻辑 FatFs 卷的数量。增加此值可能会增加基础内存使用量。 +* :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` - 如果启用,FatFs 库在分配内部缓冲区时优先使用外部 RAM。如果外部 RAM 分配失败,则回退到内部 RAM。这可能会对热 I/O 路径产生明显的性能开销。禁用此选项可优先考虑性能;启用可减少内部 RAM 使用量。 +* :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` - 如果启用,FatFs 库首先尝试在支持 DMA、缓存对齐的内存中分配堆工作缓冲区,以便 SDMMC 传输避免额外的拷贝。此选项在使用 PSRAM 和 SDMMC DMA 的目标芯片上(例如 ESP32-P4)非常有用。如果同时启用此选项和 :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`,FatFs 库会先尝试支持 DMA 的 RAM,然后是外部 RAM,最后是内部 RAM。 +* :ref:`CONFIG_FATFS_USE_DYN_BUFFERS` - 如果启用,FatFs 库会单独分配实例缓冲区,并根据每个已挂载卷的逻辑扇区大小调整其大小。当多个 FatFs 实例使用不同的逻辑扇区大小时,此选项非常有用,因为它可以减少内存使用量。如果禁用,所有实例都使用为最大配置逻辑扇区大小调整大小的缓冲区。 +* :ref:`CONFIG_FATFS_PER_FILE_CACHE` - 如果启用,每个打开的文件使用单独的缓存缓冲区。这提高了 I/O 性能,但当多个文件打开时会增加 RAM 使用量。如果禁用,则使用单个共享缓存,这减少了 RAM 使用量,但可能会增加存储读写操作。 +* :ref:`CONFIG_FATFS_USE_FASTSEEK` - 如果启用,POSIX :cpp:func:`lseek` 运行更快。快速定位不适用于以写入模式打开的文件。要使用快速查找,请以只读模式打开文件,或关闭后以只读模式重新打开。 +* :ref:`CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE` - 设置当 :ref:`CONFIG_FATFS_USE_FASTSEEK` 启用时快速查找使用的 CLMT(簇链接映射表)缓冲区大小。较大的缓冲区可以改善较大文件上的查找行为,但会使用更多 RAM。 +* :ref:`CONFIG_FATFS_VFS_FSTAT_BLKSIZE` - 设置通过 VFS 使用的默认 stdio 文件缓冲区块大小。此选项主要与基于 stdio 的 I/O(例如 ``fread``/``fgets``)相关,不是直接 POSIX ``read``/``write`` 路径的主要调整参数。较大的值可以提高缓冲读取吞吐量,但会增加堆使用量。 +* :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC` - 如果启用,FatFs 库会在每次调用 :cpp:func:`write`、:cpp:func:`pwrite`、:cpp:func:`link`、:cpp:func:`truncate` 和 :cpp:func:`ftruncate` 后自动调用 :cpp:func:`f_sync`。此选项提高了文件一致性和大小报告的准确性,但由于会触发频繁的磁盘操作而降低了性能。 +* :ref:`CONFIG_FATFS_LINK_LOCK` - 如果启用,此选项保证 :cpp:func:`link` 函数的 API 线程安全。禁用此选项可以帮助执行频繁小文件操作(例如文件日志记录)的应用程序。禁用时,:cpp:func:`link` 执行的拷贝是非原子的。在这种情况下,从另一个任务在同一卷上对大文件使用 :cpp:func:`link` 不保证线程安全。 +* 其他相关选项包括 :ref:`CONFIG_FATFS_FS_LOCK`、:ref:`CONFIG_FATFS_TIMEOUT_MS` 和 ``CONFIG_FATFS_CHOOSE_CODEPAGE`` (特别是 ``CONFIG_FATFS_CODEPAGE_DYNAMIC`` 对代码大小的影响)。其他选项包括 ``CONFIG_FATFS_SECTOR_SIZE``、``CONFIG_FATFS_MAX_LFN``、``CONFIG_FATFS_API_ENCODING`` 和 ``CONFIG_FATFS_USE_STRFUNC_CHOICE``。 + +这些选项控制 FatFs 库如何计算和报告可用空间: + +* :ref:`CONFIG_FATFS_DONT_TRUST_FREE_CLUSTER_CNT` - 如果设置为 1,FatFs 库忽略空闲簇计数。默认值为 0。 +* :ref:`CONFIG_FATFS_DONT_TRUST_LAST_ALLOC` - 如果设置为 1,FatFs 库忽略上次分配编号。默认值为 0。 + +.. note:: + + 将这些选项设置为 1 可以提高 :cpp:func:`f_getfree` 的准确性,但会降低性能,例如强制进行完整的 FAT 扫描。 + +与 POSIX 标准的差异 +----------------------------------- + +#. :cpp:func:`link`:FAT 文件系统不支持硬链接,因此 :cpp:func:`link` 会复制文件内容(这仅适用于 FAT 文件系统卷上的文件)。 +#. :cpp:func:`unlink`:如果启用 ``CONFIG_FATFS_FS_LOCK``,删除打开的文件会失败并返回 ``EBUSY``。否则,行为未定义,可能会损坏文件系统。 +#. 不支持将 ``.`` 和 ``..`` 作为当前目录和上级目录的引用。 + +.. _fatfs-formatting: + +格式化 FAT 文件系统 +--------------------------- + +格式化会在目标卷上创建一个新的 FAT 文件系统,并擦除该卷上现有的目录结构和文件数据。用于首次配置,或从 ``FR_NO_FILESYSTEM`` 中恢复。 + +对于挂载时自动格式化,请在调用挂载辅助函数之前将 ``esp_vfs_fat_mount_config_t.format_if_mount_failed`` 设置为 ``true``。当卷在首次启动时预期为空白时,这非常有用。当以这种方式触发格式化时,挂载配置还控制新文件系统的布局: + +* ``allocation_unit_size`` 设置 :cpp:func:`f_mkfs` 使用的簇大小。较大的值可以提高吞吐量,但对于许多小文件会浪费更多空间。 +* ``use_one_fat`` 创建一个 FAT 而不是两个。这节省了一些空间,但降低了冗余性。 + +对于初始化后的显式格式化,请使用与存储类型匹配的辅助函数: + +* :cpp:func:`esp_vfs_fat_spiflash_format_rw_wl` 或 :cpp:func:`esp_vfs_fat_spiflash_format_cfg_rw_wl` 用于带磨损均衡的 SPI flash 分区。 +* :cpp:func:`esp_vfs_fat_sdcard_format` 或 :cpp:func:`esp_vfs_fat_sdcard_format_cfg` 用于 SD 卡。 + +无论当前是否已挂载文件系统,都可以调用 SPI flash 格式化辅助函数。SD 卡格式化辅助函数要求先挂载卡(但不是文件系统)。 + +使用 :cpp:func:`esp_vfs_fat_spiflash_mount_ro` 挂载的只读 SPI flash 分区不能在目标上重新格式化。要填充只读分区,请在主机上使用 :ref:`FatFs 分区生成器 ` 生成镜像。 + +.. _fatfs-partition-generator: + +FatFs 分区生成器 +------------------------- + +ESP-IDF 提供了一个 FatFs 分区生成器 :component_file:`wl_fatfsgen.py `,该工具已集成到构建系统中。 + +使用此工具在主机上创建文件系统镜像,并从指定的主机文件夹填充它们。 + +该脚本基于分区生成器 (:component_file:`fatfsgen.py `)。除了生成 FatFs 分区外,``wl_fatfsgen.py`` 还初始化磨损均衡,因此通常用于可写的 SPI flash 文件系统。对于 SD 卡镜像和只读 SPI flash 镜像,请改用 ``fatfsgen.py``。 + +此工具支持短文件名和长文件名、FAT12 和 FAT16。长文件名最多 255 个字符,文件名中可以包含多个点(``.``),但路径中不能包含。它们还可以包含以下附加字符:``+``、``,``、``;``、``=``、``[`` 和 ``]``。 + +有关 FatFs 分区生成器和分析器的详细说明,请参阅 :doc:`在主机上生成和解析 FAT 分区 `。 + +与 FatFs 分区生成器的构建系统集成 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +通过调用 ``fatfs_create_spiflash_image`` 直接从 CMake 构建系统调用 FatFs 生成器: + +.. code-block:: none + + fatfs_create_spiflash_image( [optional arguments]) + +要生成不带磨损均衡支持的 **只读** 分区,请使用 ``fatfs_create_rawflash_image``: + +.. code-block:: none + + fatfs_create_rawflash_image( [optional arguments]) + +在项目的 ``CMakeLists.txt`` 中调用 ``fatfs_create_spiflash_image`` 或 ``fatfs_create_rawflash_image``。 + +函数参数为: + +#. partition - 分区表中定义的分区名称(例如,:example_file:`storage/fatfs/fatfsgen/partitions_example.csv`)。 + +#. base_dir - 编码到 FAT 文件系统分区中并可选择烧录到目标的目录。确保分区表定义了适当的分区大小。 + +#. 标志 ``FLASH_IN_PROJECT`` - 可选择在运行 ``idf.py flash -p `` 时自动将镜像与应用程序二进制文件、分区表和其他输出一起烧录。如果未指定 ``FLASH_IN_PROJECT``,镜像仍然会生成,但你必须使用 ``esptool`` 或自定义构建系统目标手动烧录。 +#. 标志 ``PRESERVE_TIME`` - 可选择保留目标镜像中源文件夹的时间戳。如果没有此标志,该工具将所有时间戳设置为 FatFs 库默认初始时间(1980 年 1 月 1 日)。 + +#. 标志 ``ONE_FAT`` - 可选择生成具有一个 FAT(文件分配表)而不是两个的 FAT 文件系统卷。这通过 ``一个 FAT 使用的逻辑扇区数 * 逻辑扇区大小`` 增加了 FAT 文件系统卷中的可用空间,但也增加了损坏风险。 + +例如: + +.. code-block:: none + + fatfs_create_spiflash_image(my_fatfs_partition my_folder FLASH_IN_PROJECT) + +如果你为 SD 卡生成镜像,ESP-IDF 目前不提供主机端烧录步骤来将镜像直接写入卡。请使用其他主机工具(例如 ``dd``)来部署镜像。 + +有关示例项目,请参阅 :example:`storage/fatfs/fatfsgen`。 + +.. _fatfs-partition-analyzer: + +FatFs 分区解析器 +---------------------- + +:component_file:`fatfsparse.py ` 工具执行 :component_file:`fatfsgen.py ` 的逆向操作。它从 FAT 文件系统镜像重建主机文件夹结构。 + +用法: + +.. code-block:: none + + ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] [--verbose] fatfs_image.img + +``--verbose`` 选项在工具生成文件夹结构之前打印 FAT 文件系统镜像引导扇区的详细信息。 + +.. _fatfs-minimum-partition-size: + +大小要求和限制 +---------------------------- + +FatFs 组件支持 FAT12、FAT16 和 FAT32 文件系统类型,并且可以选择支持 exFAT(参见 :ref:`可选的 exFAT 支持 `)。 + +文件系统类型取决于卷上的簇数: + +.. math:: + + cluster\_count = data\_logical\_sectors / logical\_sectors\_per\_cluster + +因此,最小分区大小取决于 FAT 元数据和至少一个数据簇所需的逻辑扇区数。对于下面使用的术语,请参见 :ref:`术语表 `。 + +.. _fatfs-minimum-partition-size-raw: + +原始 FAT 文件系统大小 +^^^^^^^^^^^^^^^^^^^^^^^ + +原始 FAT 文件系统的所需大小包括 FAT 文件系统元数据加上数据区: + +.. math:: + + fatfs\_size = (reserved + fats + root\_dir + data) × logical\_sector\_size + +其中: + +* ``reserved`` 是保留的逻辑扇区数 +* ``fats`` 是所有 FAT 副本占用的逻辑扇区总数 +* ``root_dir`` 是 FAT12/FAT16 上根目录占用的逻辑扇区数 +* ``data`` 是数据区中的逻辑扇区数 + +FAT 区域取决于所选的 FAT 类型和簇数: + +.. list-table:: + :widths: 18 25 57 + :header-rows: 1 + + * - FAT 类型 + - 簇数 + - FAT 大小计算 + * - FAT12 + - ``<= 4085`` + - 每个 FAT 条目使用 12 位,因此一个 FAT 副本需要 ``ceil(((cluster_count + 2) × 3 / 2) / logical_sector_size)`` 个逻辑扇区。 + * - FAT16 + - ``4085 < cluster_count < 65526`` + - 每个 FAT 条目使用 16 位,因此一个 FAT 副本需要 ``ceil(((cluster_count + 2) × 2) / logical_sector_size)`` 个逻辑扇区。 + * - FAT32 + - ``>= 65526`` + - 每个 FAT 条目使用 32 位,因此一个 FAT 副本需要 ``ceil(((cluster_count + 2) × 4) / logical_sector_size)`` 个逻辑扇区。 + * - exFAT + - ``16 .. 0x7FFFFFFD`` + - 每个 FAT 条目使用 32 位,因此一个 FAT 副本需要 ``ceil(((cluster_count + 2) × 4) / logical_sector_size)`` 个逻辑扇区。 + +对于 FAT12 和 FAT16,根目录在数据区之外,因此: + +.. math:: + + root\_dir = ceil((root\_dir\_entries × 32) / logical\_sector\_size) + +对于 FAT32,根目录存储在数据区中,因此上述公式中 ``root_dir = 0``。 + +exFAT 使用不同的元数据布局。除了 FAT 区域外,它还需要一个分配位图和一个大小写转换表,其根目录存储在数据区中。因此,上述 FAT12/FAT16 根目录公式不适用于 exFAT。 + +当启用 exFAT 支持时,最小 exFAT 卷大小为 4096 个逻辑扇区,最大簇数为 ``0x7FFFFFFD``。 + +在实践中: + +* 增加分区大小会添加数据逻辑扇区,从而增加可用存储空间。 +* 在小的 FAT12/FAT16 卷上,根目录可以占用 1 个逻辑扇区。在较大的卷上,它可以占用 4 个逻辑扇区。 +* 对于 FAT12、FAT16 和 FAT32,默认布局使用两个 FAT。与 ``use_one_fat = true`` 相比,这增加了一个额外 FAT 副本所需的逻辑扇区。exFAT 使用单个 FAT。 +* 对于不带磨损均衡且逻辑扇区大小为 512 字节的只读分区,实际最小分区大小为 2 KB。此最小布局使用 4 个逻辑扇区:1 个保留扇区、1 个 FAT 扇区、1 个根目录扇区和 1 个数据扇区。 + +此最小原始布局适用于 SD 卡和只读原始 flash 分区等介质。 + +.. _fatfs-minimum-partition-size-wl: + +带磨损均衡的 FAT 文件系统 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +对于带磨损均衡的 flash 分区,总大小为 :ref:`原始 FAT 文件系统大小 ` 加上磨损均衡元数据区: + +.. math:: + + partition\_size = wl\_metadata\_flash\_sectors × flash\_sector\_size + fatfs\_size + +其中: + +* ``wl_metadata_flash_sectors`` 是为磨损均衡元数据保留的 flash 扇区数 +* ``flash_sector_size`` 是 SPI flash 擦除扇区大小。在几乎所有 ESP 开发板上,它是 4096 字节 +* ``fatfs_size`` 是原始 FAT 文件系统大小,如 :ref:`原始 FAT 文件系统大小 ` 中所定义 + +最小支持的分区大小取决于 WL 配置: + +.. list-table:: + :widths: 28 18 54 + :header-rows: 1 + + * - 条件 + - 最小大小 + - 说明 + * - ``CONFIG_WL_SECTOR_SIZE = 4096`` + - 32 KB + - 最小布局由磨损均衡层保留的 4 个 flash 扇区加上最小原始 FAT 文件系统布局的 4 个逻辑扇区组成。在此配置中,逻辑扇区大小和 flash 扇区大小均为 4096 字节。 + * - ``CONFIG_WL_SECTOR_SIZE = 512`` 且 WL 性能模式 + - 20 KB + - 原始 FAT 文件系统仍然需要相同的最小布局的 4 个逻辑扇区,但磨损均衡层将其元数据保留在 4096 字节的 flash 扇区中。 + * - ``CONFIG_WL_SECTOR_SIZE = 512`` 且 WL 安全模式 + - 28 KB + - 与上述原始 FAT 最小值相同,加上磨损均衡层保留的 2 个额外 flash 扇区。 + +有关更多详细信息,请参阅 :doc:`文件系统注意事项 <../../api-guides/file-system-considerations>`。 + +.. note:: + + 磨损均衡层通过在受管存储区域中均匀分布写入和擦除周期来保护底层 flash。因此,其有效性随该区域的大小而缩放。小分区会限制磨损分布,并可能显著降低保护效果,因此强烈不建议使用。有关更多信息,请参阅 :doc:`磨损均衡 `。 + +优化 +---------- + +通过选择正确的配置选项和文件系统布局,可以针对不同的优先级调整 FatFs 行为。 + +影响行为的主要变量是: + +* 缓冲区位置和大小(:ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS`、:ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`、:ref:`CONFIG_FATFS_USE_DYN_BUFFERS`、:ref:`CONFIG_FATFS_PER_FILE_CACHE` 和应用程序 I/O 缓冲区大小)。 +* 磨损均衡逻辑扇区大小和模式(``CONFIG_WL_SECTOR_SIZE_*`` 和 ``CONFIG_WL_SECTOR_MODE_*``)。 +* 同步策略(:ref:`CONFIG_FATFS_IMMEDIATE_FSYNC`)。 +* 工作负载模式(事务大小、顺序访问与随机访问、读取与写入比率)。 + +优化 I/O 性能 +^^^^^^^^^^^^^^^^^^^^^^ + +对于面向吞吐量的工作负载: + +* 除非一致性要求需要,否则保持禁用 :ref:`CONFIG_FATFS_IMMEDIATE_FSYNC`。 +* 如果峰值速度是最高优先级,请禁用 :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM`,以便缓冲区保留在内部 RAM 中。 +* 优先选择较大的读写事务大小,而不是许多小操作。 +* 尽可能将事务大小与活动扇区大小(例如 512 B 或 4096 B)对齐,并在需要时填充写入以减少部分扇区开销。 +* 对于带磨损均衡的 SPI flash,当 RAM 预算允许时,优先选择 ``CONFIG_WL_SECTOR_SIZE_4096``,因为它通常更高效。 +* 如果使用 512 字节的 WL 扇区,当应用程序可以接受 flash 扇区擦除期间更高的断电风险时,请使用 ``CONFIG_WL_SECTOR_MODE_PERF``。 +* 在热路径上尽可能优先选择 POSIX ``read``/``write`` 而不是 ``fread``/``fwrite``。有关更广泛的速度指导,请参阅 :doc:`最大化执行速度 <../../api-guides/performance/speed>`。 +* 在 SDMMC DMA 目标(例如带有 PSRAM 的 ESP32-P4)上,启用 :ref:`CONFIG_FATFS_ALLOC_PREFER_ALIGNED_WORK_BUFFERS` 以减少额外的缓冲区拷贝。 +* 对于具有长反向查找的读取密集型工作负载,启用 :ref:`CONFIG_FATFS_USE_FASTSEEK`。 + +.. note:: + + 有关性能优化场景下预期基准的参考,请参阅 :example:`storage/perf_benchmark`。 + +优化内存使用 +^^^^^^^^^^^^^^^^^^^ + +* 当减少 RAM 使用是优先事项时,禁用 :ref:`CONFIG_FATFS_PER_FILE_CACHE` 以使用单个共享缓存。 +* 尽可能低地调整 ``esp_vfs_fat_mount_config_t.max_files`` (参见 :ref:`挂载和使用 FatFs `);每个同时打开的文件都会增加 RAM 使用量。 +* 如果启用了 :ref:`CONFIG_FATFS_PER_FILE_CACHE`,优先选择 ``CONFIG_WL_SECTOR_SIZE_512`` 以减少每文件缓存大小。 +* 如果禁用了 :ref:`CONFIG_FATFS_PER_FILE_CACHE`,``CONFIG_WL_SECTOR_SIZE_4096`` 可能是更好的权衡。 +* 在支持外部 RAM 的目标上启用 :ref:`CONFIG_FATFS_ALLOC_PREFER_EXTRAM` 以减少内部 RAM 压力,但预计 I/O 性能会降低。 +* 当 SFN (8.3) 文件名可接受时,考虑使用 ``CONFIG_FATFS_LONG_FILENAMES = CONFIG_FATFS_LFN_NONE``。 +* 如果需要长文件名,将 ``CONFIG_FATFS_MAX_LFN`` 减小到满足需求的最小值。 +* 启用 :ref:`CONFIG_FATFS_USE_DYN_BUFFERS`,以便每个挂载的卷使用根据其实际扇区大小调整大小的缓冲区。 + +优化存储效率 +^^^^^^^^^^^^^^^^^^^^^^^^^ + +为了最大化可用文件系统容量: + +* 对于生成的只读镜像,考虑在 ``fatfs_create_spiflash_image`` 中使用 ``ONE_FAT`` 选项(参见 :ref:`FatFs 分区生成器 `)以使用一个 FAT 而不是两个。 +* 当最小化开销是优先事项时,考虑使用 ``CONFIG_WL_SECTOR_SIZE_512``,因为在某些布局中,较小的扇区可以提高可用存储效率。 +* 为分区留有余量。非常小的分区具有不成比例的高元数据和磨损均衡开销。 +* 尽可能保持长文件名简短;长名称会消耗额外的目录条目。 +* 对于只读数据,在适当的情况下考虑不带磨损均衡的原始 FAT 分区。 + +高级操作 +------------------- + +当你使用 ESP-IDF 不直接支持的存储介质,或者当你需要访问底层 FatFs 库函数时,可能需要手动挂载。 + +.. _fatfs-optional-exfat-support: + +可选的 exFAT 支持 +^^^^^^^^^^^^^^^^^^^^^^ + +上游 FatFs 库包括可选的 exFAT 支持,但 ESP-IDF 默认不启用它。 + +如果你的项目需要 exFAT,你必须在 :component:`fatfs` 组件中手动修改 FatFs 配置,并将生成的配置集成到你的构建和验证流程中。ESP-IDF 不提供专门的 menuconfig 选项或标准的 exFAT 高级启用路径。 + +在启用 exFAT 之前,请审查可能适用于你的产品、分销模式和目标市场的任何许可或其他知识产权考虑因素。 + +架构概述 +^^^^^^^^^^^^^^^^^^^^^ + +下图说明了 FatFs 的分层架构及其与 ESP-IDF 其他组件的关系: + +.. code-block:: none + + +---------------------------------------------------------------+ + | Newlib/Picolib (C 标准库) | + | fopen, fread, fwrite, fclose, fseek 等 | + +---------------------------------------------------------------+ + | VFS (虚拟文件系统) | + | POSIX API: open, read, write, close, lseek, stat 等 | + +---------------------------------------------------------------+ + | FatFs 库 | + | f_mount, f_open, f_read, f_write, f_close, f_mkfs | + +---------------------------------------------------------------+ + | 磁盘 I/O 层 | + | ff_diskio_register, disk_read, disk_write, disk_ioctl 等 | + +-------------------------------+-------------------------------+ + | 磨损均衡(可选) | | + | wl_mount, wl_read, wl_write | SD/MMC 驱动 | + +-------------------------------+ | + | esp_partition | sdmmc_read/write_sectors | + | esp_partition_read/write | | + +-------------------------------+-------------------------------+ + | SPI flash | SD 卡 | + +-------------------------------+-------------------------------+ + +.. _fatfs-manual-mount: + +手动挂载 FAT 文件系统分区 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +手动挂载 FAT 文件系统分区时,请遵循 :ref:`挂载和使用 FatFs ` 中描述的便利封装函数使用的相同一般流程:向 FatFs 库注册文件系统,然后通过 VFS 挂载它。 + +#. 通过调用 :cpp:func:`esp_vfs_fat_register` 向 VFS 注册文件系统。这会分配 ``FATFS`` 结构,并设置 VFS 和 FatFs 库之间的接口。指定: + + - 文件系统将挂载的路径前缀(例如 ``"/sdcard"`` 或 ``"/spiflash"``)。 + - FatFs 驱动器号。 + - 一个接收指向 ``FATFS`` 结构的指针的变量。 + +#. 通过调用 :cpp:func:`ff_diskio_register` 为步骤 1 中使用的驱动器号注册磁盘 I/O 驱动程序。 + +#. 通过调用 :cpp:func:`f_mount` 为传递给 :cpp:func:`esp_vfs_fat_register` 的驱动器号挂载文件系统。 + + 如果目标逻辑驱动器上不存在文件系统,:cpp:func:`f_mount` 将失败并返回 ``FR_NO_FILESYSTEM``。在这种情况下,使用 :cpp:func:`f_mkfs` 在驱动器上创建一个新的 FAT 文件系统,然后再次调用 :cpp:func:`f_mount`。 + + 对于 SD 卡,首先使用 :cpp:func:`f_fdisk` 创建分区表。有关详细信息,请参阅 `FatFs 文档 `_。 + +要卸载,请遵循以下一般步骤: + +#. 通过使用相同的驱动器号和 NULL ``FATFS*`` 参数调用 :cpp:func:`f_mount` 来卸载文件系统。 + +#. 通过使用相同的驱动器号和 NULL ``ff_diskio_impl_t*`` 参数调用 :cpp:func:`ff_diskio_register` 来注销磁盘 I/O 驱动程序。 + +#. 通过使用挂载路径调用 :cpp:func:`esp_vfs_fat_unregister_path` 来删除 VFS 注册并释放在挂载过程的步骤 1 中分配的 ``FATFS`` 结构。 + +调用 FatFs 库提供的底层函数时,使用不带挂载点前缀的路径。例如,使用 ``"/hello.txt"``。 .. _fatfs-diskio-layer: FatFs 磁盘 I/O 层 -------------------- +^^^^^^^^^^^^^^^^^^^^ -我们对 FatFs API 函数进行了扩展,实现了运行期间注册磁盘 I/O 驱动。 +FatFs 提供 API 以在运行时注册磁盘 I/O 驱动程序。这些 API 构成了介质特定访问函数和 FatFs 库之间的接口。 -上述 API 为 SD/MMC 卡提供了磁盘 I/O 函数实现方式,可使用 :cpp:func:`ff_diskio_register_sdmmc` 函数注册指定的 FatFs 驱动编号。 +磁盘 I/O 层使用 :cpp:struct:`ff_diskio_impl_t` 来提供介质访问函数。将此结构传递给 :cpp:func:`ff_diskio_register`。 + +ESP-IDF 为支持的存储介质提供便利封装函数。这些包括: + + - :cpp:func:`ff_diskio_register_wl_partition` 用于带磨损均衡的 SPI flash 分区。 + - :cpp:func:`ff_diskio_register_raw_partition` 用于 **不带** 磨损均衡的只读 SPI flash 分区。 + - :cpp:func:`ff_diskio_register_sdmmc` 用于 SDMMC 和 SPI 连接的 SD 卡。 + +有关 API 参考,请参见 :ref:`磁盘 I/O API 参考 `。 + +.. _fatfs-glossary: + +术语表 +-------- + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - 术语 + - 描述 + * - VFS + - 虚拟文件系统,ESP-IDF 提供的抽象层,允许应用程序通过统一的 POSIX 和 ``stdio.h`` 接口访问不同的底层文件系统。 + * - 逻辑扇区 + - 呈现给 FatFs 和磁盘 I/O 层的逻辑块大小。对于带磨损均衡的 SPI flash,这是 WL 扇区大小。对于只读原始 SPI flash 分区,这是 flash 扇区大小。对于 SD 卡,通常为 512 字节。 + * - WL 扇区 + - 磨损均衡层暴露给 FatFs 的逻辑扇区大小。根据 ``CONFIG_WL_SECTOR_SIZE``,可以是 512 字节或 4096 字节。 + * - flash 扇区 + - flash 芯片使用的底层 SPI flash 擦除单元。在几乎所有 ESP 开发板上,这是 4096 字节。当磨损均衡配置为 512 字节扇区时,它可以不同于呈现给 FatFs 的 WL 扇区大小。 + * - 簇 + - 最小的逻辑 FAT 分配单元,由一个或多个连续的逻辑扇区组成。 + * - FAT + - 文件分配表,记录每个簇的使用状态以及文件数据块之间的链接关系。 + * - 磨损均衡 + - 一种通过均匀分布写入操作来延长 flash 存储器寿命的技术,防止特定块因频繁擦除而过早磨损。 + * - 驱动器号 + - FatFs 用于标识不同逻辑驱动器的数字 (0-9),每个驱动器对应一个独立的文件系统实例。 + * - 挂载 + - 将文件系统与指定路径关联的过程,使应用程序能够通过该路径访问文件系统内容。 + * - SFN/LFN + - 短文件名(8.3 格式)和长文件名(最多 255 个字符)。 + +.. _fatfs-application-examples: + +应用程序示例 +-------------------- + +- :example:`storage/fatfs/getting_started` 演示了使用 FatFs 在 SPI flash 上存储持久数据所需的最小设置,包括挂载文件系统、打开文件、执行基本的读写操作和卸载文件系统。 + +- :example:`storage/fatfs/fs_operations` 演示了高级 FatFs 操作,包括读写文件、创建、移动和删除文件和目录,以及检查文件详细信息。 + +- :example:`storage/fatfs/ext_flash` 演示了如何操作格式化为 FatFs 的外部 SPI flash,包括初始化 SPI 总线、配置 flash 芯片、将其注册为分区以及执行读写操作。 + +.. _fatfs-high-level-api-reference: + +高级 API 参考 +------------------------ + +.. include-build-file:: inc/esp_vfs_fat.inc + +.. _fatfs-diskio-api-reference: + +磁盘 I/O API 参考 +^^^^^^^^^^^^^^^^^^^^^^ .. doxygenfunction:: ff_diskio_register .. doxygenstruct:: ff_diskio_impl_t @@ -100,110 +485,3 @@ FatFs 磁盘 I/O 层 .. doxygenfunction:: ff_diskio_register_sdmmc .. doxygenfunction:: ff_diskio_register_wl_partition .. doxygenfunction:: ff_diskio_register_raw_partition - - -.. _fatfs-partition-generator: - -FatFs 分区生成器 -------------------------- - -我们为 FatFs (:component_file:`wl_fatfsgen.py`) 提供了分区生成器,该生成器集成在构建系统中,方便用户在自己的项目中使用。 - -该生成器可以在主机上创建文件系统镜像,并用指定的主机文件夹内容对其进行填充。 - -该脚本是建立在分区生成器的基础上 (:component_file:`fatfsgen.py`),目前除了可以生成分区外,也可以初始化损耗均衡。 - -目前的最新版本支持短文件名、长文件名、FAT12 和 FAT16。长文件名的上限是 255 个字符,文件名中可以包含多个 ``.`` 字符以及其他字符,如 ``+``、``,``、``;``、``=``、``[`` and ``]`` 等。 - -如需进一步了解 FatFs 分区生成器或分区分析器,请查看 :doc:`Generating and parsing FAT partition on host <./fatfsgen>`。 - -构建系统中使用 FatFs 分区生成器 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -通过调用 ``fatfs_create_partition_image`` 可以直接从 CMake 构建系统中调用 FatFs 分区生成器:: - - fatfs_create_spiflash_image( [FLASH_IN_PROJECT]) - -如果不希望在生成分区时使用损耗均衡,可以使用 ``fatfs_create_rawflash_image``:: - - fatfs_create_rawflash_image( [FLASH_IN_PROJECT]) - -``fatfs_create_spiflash_image`` 以及 ``fatfs_create_rawflash_image`` 必须从项目的 CMakeLists.txt 中调用。 - -如果决定使用 ``fatfs_create_rawflash_image`` (不支持损耗均衡),请注意它仅支持在设备中以只读模式安装。 - - -该函数的参数如下: - -#. partition - 分区的名称,需要在分区表中定义(如 :example_file:`storage/fatfs/fatfsgen/partitions_example.csv`)。 - -#. base_dir - 目录名称,该目录会被编码为 FatFs 分区,也可以选择将其被烧录进设备。但注意必须在分区表中指定合适的分区大小。 - -#. ``FLASH_IN_PROJECT`` 标志 - 可选参数,用户可以通过指定 ``FLASH_IN_PROJECT``,选择在执行 ``idf.py flash -p `` 时让分区镜像自动与应用程序二进制文件、分区表等一同烧录进设备。 - -#. ``PRESERVE_TIME`` 标志 - 可选参数,用户可强制让目标镜像保留源文件夹的时间戳。如果不保留,每个目标镜像的时间戳都将设置为 FATFS 默认初始时间(1980 年 1 月 1 日)。 - -#. ``ONE_FAT`` 标志 - 可选参数,支持生成仅包含单个 FAT(文件分配表)的 FATFS 卷。与包含两个 FAT 的 FATFS 卷相比,这样做可以拥有相对较大的可用空间(通过 ``FAT 使用的扇区数 * 扇区大小`` 计算),但会增加 FATFS 卷损坏的风险。 - -例如:: - - fatfs_create_partition_image(my_fatfs_partition my_folder FLASH_IN_PROJECT) - -没有指定 FLASH_IN_PROJECT 时也可以生成分区镜像,但是用户需要使用 ``esptool`` 或自定义的构建系统目标对其手动烧录。 - -相关示例请查看 :example:`storage/fatfs/fatfsgen`。 - - -.. _fatfs-partition-analyzer: - -FatFs 分区分析器 ------------------- - -我们为 FatFs 提供分区分析器 (:component_file:`fatfsparse.py`)。 - -该分析器为 FatFs 分区生成器 (:component_file:`fatfsgen.py`) 的逆向工具,可以根据 FatFs 镜像在主机上生成文件夹结构。 - -可以使用:: - - ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] [--verbose] fatfs_image.img - -生成文件夹结构之前,参数 --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>`。 - -应用示例 ------------------ - -- :example:`storage/fatfs/getting_started` 演示了如何使用 FatFS 在 SPI flash 上存储永久数据的基本设置,包括挂载文件系统、打开文件、执行基本的读写操作以及卸载文件系统。 - -- :example:`storage/fatfs/fs_operations` 演示了更全面的 FatFS 操作,包括读取和写入文件、创建、移动和删除文件及目录,以及检查文件详细信息。 - -- :example:`storage/fatfs/ext_flash` 演示了如何操作使用 FatFS 格式化的外部 SPI flash,包括初始化 SPI 总线、配置 flash、将其注册为分区以及执行读写操作。 - -高级 API 参考 ------------------------- - -.. include-build-file:: inc/esp_vfs_fat.inc