磨损均衡 API

[English]

概述

ESP32 所使用的 flash,特别是 SPI flash,多数具备扇区结构,且每个扇区仅允许有限次数的擦除/修改操作。为了避免过度使用某一扇区,乐鑫提供了磨损均衡组件,无需用户介入即可帮助用户均衡各个扇区之间的磨损。

磨损均衡组件包含了通过分区组件对外部 SPI flash 进行数据读取、写入、擦除和存储器映射相关的 API 函数。磨损均衡组件还具有软件上更高级别的 API 函数,与 FAT 文件系统 协同工作。

磨损均衡组件与 FAT 文件系统组件共用 FAT 文件系统的扇区,扇区大小为 4096 字节,是标准 flash 扇区的大小。在这种模式下,磨损均衡组件性能达到最佳,但需要在 RAM 中占用更多内存。

为了节省内存,磨损均衡组件还提供了另外两种模式,均使用 512 字节大小的扇区:

  • 性能模式:先将数据保存在 RAM 中,擦除扇区,然后将数据存储回 flash。如果设备在扇区擦写过程中突然断电,则整个扇区(4096 字节)数据将全部丢失。

  • 安全模式:数据先保存在 flash 中空余扇区,擦除扇区后,数据即存储回去。如果设备断电,上电后可立即恢复数据。

设备默认设置如下:

  • 定义扇区大小为 512 字节

  • 默认使用性能模式

您可以使用配置菜单更改设置。

磨损均衡组件不会将数据缓存在 RAM 中。写入和擦除函数直接修改 flash,函数返回后,flash 即完成修改。

磨损均衡访问 API

处理 flash 数据常用的 API 如下所示:

  • wl_mount - 为指定分区挂载并初始化磨损均衡模块

  • wl_unmount - 卸载分区并释放磨损均衡模块

  • wl_erase_range - 擦除 flash 中指定的地址范围

  • wl_write - 将数据写入分区

  • wl_read - 从分区读取数据

  • wl_size - 返回可用内存的大小(以字节为单位)

  • wl_sector_size - 返回一个扇区的大小

请尽量避免直接使用原始磨损均衡函数,建议您使用文件系统特定的函数。

内存大小

内存大小是根据分区参数在磨损均衡模块中计算所得,由于模块使用 flash 部分扇区存储内部数据,因此计算所得内存大小有少许偏差。

应用示例

storage/wear_levelling 中提供了一款磨损均衡驱动与 FatFs 库结合使用的示例。该示例初始化磨损均衡驱动,挂载 FAT 文件系统分区,并使用 POSIX(可移植操作系统接口)和 C 库 API 从中写入和读取数据。如需了解更多信息,请参考 storage/wear_levelling/README.md

高级 API 参考

函数

esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char *base_path, const char *partition_label, const esp_vfs_fat_mount_config_t *mount_config, wl_handle_t *wl_handle)

Convenience function to initialize FAT filesystem in SPI flash and register it in VFS.

This is an all-in-one function which does the following:

  • finds the partition with defined partition_label. Partition label should be configured in the partition table.

  • initializes flash wear levelling library on top of the given partition

  • mounts FAT partition using FATFS library on top of flash wear levelling library

  • registers FATFS library with VFS, with prefix given by base_prefix variable

This function is intended to make example code more compact.

参数
  • base_path – path where FATFS partition should be mounted (e.g. “/spiflash”)

  • partition_label – label of the partition which should be used

  • mount_config – pointer to structure with extra parameters for mounting FATFS

  • wl_handle[out] wear levelling driver handle

返回

  • ESP_OK on success

  • ESP_ERR_NOT_FOUND if the partition table does not contain FATFS partition with given label

  • ESP_ERR_INVALID_STATE if esp_vfs_fat_spiflash_mount_rw_wl was already called

  • ESP_ERR_NO_MEM if memory can not be allocated

  • ESP_FAIL if partition can not be mounted

  • other error codes from wear levelling library, SPI flash driver, or FATFS drivers

struct esp_vfs_fat_mount_config_t

Configuration arguments for esp_vfs_fat_sdmmc_mount and esp_vfs_fat_spiflash_mount_rw_wl functions.

Public Members

bool format_if_mount_failed

If FAT partition can not be mounted, and this parameter is true, create partition table and format the filesystem.

int max_files

Max number of open files.

size_t allocation_unit_size

If format_if_mount_failed is set, and mount fails, format the card with given allocation unit size. Must be a power of 2, between sector size and 128 * sector size. For SD cards, sector size is always 512 bytes. For wear_levelling, sector size is determined by CONFIG_WL_SECTOR_SIZE option.

Using larger allocation unit size will result in higher read/write performance and higher overhead when storing small files.

Setting this field to 0 will result in allocation unit set to the sector size.

bool disk_status_check_enable

Enables real ff_disk_status function implementation for SD cards (ff_sdmmc_status). Possibly slows down IO performance.

Try to enable if you need to handle situations when SD cards are not unmounted properly before physical removal or you are experiencing issues with SD cards.

Doesn’t do anything for other memory storage media.

esp_err_t esp_vfs_fat_spiflash_unmount_rw_wl(const char *base_path, wl_handle_t wl_handle)

Unmount FAT filesystem and release resources acquired using esp_vfs_fat_spiflash_mount_rw_wl.

参数
  • base_path – path where partition should be registered (e.g. “/spiflash”)

  • wl_handle – wear levelling driver handle returned by esp_vfs_fat_spiflash_mount_rw_wl

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_STATE if esp_vfs_fat_spiflash_mount_rw_wl hasn’t been called

中层 API 参考

Functions

esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)

Mount WL for defined partition.

参数
  • partition – that will be used for access

  • out_handle – handle of the WL instance

返回

  • ESP_OK, if the allocation was successfully;

  • ESP_ERR_INVALID_ARG, if WL allocation was unsuccessful;

  • ESP_ERR_NO_MEM, if there was no memory to allocate WL components;

esp_err_t wl_unmount(wl_handle_t handle)

Unmount WL for defined partition.

参数

handle – WL partition handle

返回

  • ESP_OK, if the operation completed successfully;

  • or one of error codes from lower-level flash driver.

esp_err_t wl_erase_range(wl_handle_t handle, size_t start_addr, size_t size)

Erase part of the WL storage.

参数
  • handle – WL handle that are related to the partition

  • start_addr – Address where erase operation should start. Must be aligned to the result of function wl_sector_size(…).

  • size – Size of the range which should be erased, in bytes. Must be divisible by result of function wl_sector_size(…)..

返回

  • ESP_OK, if the range was erased successfully;

  • ESP_ERR_INVALID_ARG, if iterator or dst are NULL;

  • ESP_ERR_INVALID_SIZE, if erase would go out of bounds of the partition;

  • or one of error codes from lower-level flash driver.

esp_err_t wl_write(wl_handle_t handle, size_t dest_addr, const void *src, size_t size)

Write data to the WL storage.

Before writing data to flash, corresponding region of flash needs to be erased. This can be done using wl_erase_range function.

备注

Prior to writing to WL storage, make sure it has been erased with wl_erase_range call.

参数
  • handle – WL handle that are related to the partition

  • dest_addr – Address where the data should be written, relative to the beginning of the partition.

  • src – Pointer to the source buffer. Pointer must be non-NULL and buffer must be at least ‘size’ bytes long.

  • size – Size of data to be written, in bytes.

返回

  • ESP_OK, if data was written successfully;

  • ESP_ERR_INVALID_ARG, if dst_offset exceeds partition size;

  • ESP_ERR_INVALID_SIZE, if write would go out of bounds of the partition;

  • or one of error codes from lower-level flash driver.

esp_err_t wl_read(wl_handle_t handle, size_t src_addr, void *dest, size_t size)

Read data from the WL storage.

参数
  • handle – WL module instance that was initialized before

  • dest – Pointer to the buffer where data should be stored. Pointer must be non-NULL and buffer must be at least ‘size’ bytes long.

  • src_addr – Address of the data to be read, relative to the beginning of the partition.

  • size – Size of data to be read, in bytes.

返回

  • ESP_OK, if data was read successfully;

  • ESP_ERR_INVALID_ARG, if src_offset exceeds partition size;

  • ESP_ERR_INVALID_SIZE, if read would go out of bounds of the partition;

  • or one of error codes from lower-level flash driver.

size_t wl_size(wl_handle_t handle)

Get size of the WL storage.

参数

handle – WL module handle that was initialized before

返回

usable size, in bytes

size_t wl_sector_size(wl_handle_t handle)

Get sector size of the WL instance.

参数

handle – WL module handle that was initialized before

返回

sector size, in bytes

Macros

WL_INVALID_HANDLE

Type Definitions

typedef int32_t wl_handle_t

wear levelling handle