# 磨损均衡 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 部分扇区存储内部数据，因此计算所得内存大小有少许偏差。

## 另请参阅

- FAT 文件系统

- 分区表

## 应用示例

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

## 高级 API 参考

### 头文件

- fatfs/vfs/esp_vfs_fat.h

有关高级磨损均衡函数 `esp_vfs_fat_spiflash_mount_rw_wl()`、 `esp_vfs_fat_spiflash_unmount_rw_wl()` 和结构体 `esp_vfs_fat_mount_config_t` 的详细内容，请参见 FAT 文件系统。

## 中层 API 参考

### Header File

- components/wear_levelling/include/wear_levelling.h

- This header file can be included with:

  >     #include "wear_levelling.h"

- This header file is a part of the API provided by the `wear_levelling` component. To declare that your component depends on `wear_levelling`, add the following to your CMakeLists.txt:

  >     REQUIRES wear_levelling

  > or

  >     PRIV_REQUIRES wear_levelling

### 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 WL allocation is successful;

    - ESP_ERR_INVALID_ARG, if the arguments for WL configuration are not valid;

    - ESP_ERR_NO_MEM, if the WL allocation fails because of insufficient memory;

esp_err_t wl_unmount(wl_handle_t handle)

  Unmount WL for defined partition.

  参数:

    handle -- WL partition handle

  返回:

    - ESP_OK, if the operation is successful;

    - 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 from 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 the result of function wl_sector_size(...)..

  返回:

    - ESP_OK, if the given 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 corresponding to the WL 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. The Pointer must be non-NULL and the 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 the actual flash size in use for the WL storage partition.

  参数:

    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

提供有关此文档的反馈