Merge branch 'feature/add-wl-support-fatfs' into 'master'
Add wear levelling support for fatfs partition generator Closes IDF-4043 and IDF-2053 See merge request espressif/esp-idf!15798
This commit is contained in:
@@ -1,22 +1,31 @@
|
||||
# FATFS partition generation on build example
|
||||
# FATFS partition generation example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates how to use the FATFS partition
|
||||
generation tool [fatfsgen.py](../../../components/fatfs/fatfsgen.py) to automatically create a FATFS
|
||||
filesystem image (without wear levelling support)
|
||||
from the contents of a host folder during build, with an option of
|
||||
filesystem image from the contents of a host folder during build, with an option of
|
||||
automatically flashing the created image on invocation of `idf.py -p PORT flash`.
|
||||
Beware that the minimal required size of the flash is 4 MB.
|
||||
The generated partition does not support wear levelling,
|
||||
so it can be mounted only in read-only mode.
|
||||
You can specify using menuconfig weather example will use read-only or read-write mode. The default option is read-write mode.
|
||||
To change it just use menuconfig:
|
||||
|
||||
```shell
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
Then select `Example Configuration` a chose `Mode for generated FATFS image` either `Read-Write Mode` or `Read-Only Mode`.
|
||||
`Read-Only` option indicates generating raw fatfs image without wear levelling support.
|
||||
On the other hand, for `Read-Write` the generated fatfs image will support wear levelling thus can be mounted in read-write mode.
|
||||
|
||||
|
||||
The following gives an overview of the example:
|
||||
|
||||
1. There is a directory `fatfs_image` from which the FATFS filesystem image will be created.
|
||||
|
||||
2. The function `fatfs_create_partition_image` is used to specify that a FATFS image
|
||||
should be created during build for the `storage` partition. For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt).
|
||||
2. The function `fatfs_create_rawflash_image` is used to specify that a FATFS image
|
||||
should be created during build for the `storage` partition.
|
||||
For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt).
|
||||
`FLASH_IN_PROJECT` specifies that the created image
|
||||
should be flashed on invocation of `idf.py -p PORT flash` together with app, bootloader, partition table, etc.
|
||||
The image is created on the example's build directory with the output filename `storage.bin`.
|
||||
@@ -53,4 +62,5 @@ I (332) example: Unmounting FAT filesystem
|
||||
I (342) example: Done
|
||||
```
|
||||
|
||||
The logic of the example is contained in a [single source file](./main/fatfsgen_example_main.c), and it should be relatively simple to match points in its execution with the log outputs above.
|
||||
The logic of the example is contained in a [single source file](./main/fatfsgen_example_main.c),
|
||||
and it should be relatively simple to match points in its execution with the log outputs above.
|
||||
|
||||
@@ -1 +1 @@
|
||||
this file is test as well
|
||||
This is generated on the host
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0
|
||||
from typing import Optional
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
|
||||
def test_examples_fatfsgen(env, _): # type: ignore
|
||||
def test_examples_fatfsgen(env: ttfw_idf.TinyFW.Env, _: Optional[list]) -> None:
|
||||
dut = env.get_dut('fatfsgen', 'examples/storage/fatfsgen', app_config_name='test_read_write_partition_gen')
|
||||
dut.start_app()
|
||||
dut.expect_all('example: Mounting FAT filesystem',
|
||||
'example: Opening file',
|
||||
'example: File written',
|
||||
'example: Reading file',
|
||||
'example: Read from file: \'This is written by the device\'',
|
||||
'example: Reading file',
|
||||
'example: Read from file: \'This is generated on the host\'',
|
||||
'example: Unmounting FAT filesystem',
|
||||
'example: Done',
|
||||
timeout=20)
|
||||
env.close_dut(dut.name)
|
||||
|
||||
dut = env.get_dut('fatfsgen', 'examples/storage/fatfsgen')
|
||||
dut = env.get_dut('fatfsgen', 'examples/storage/fatfsgen', app_config_name='test_read_only_partition_gen')
|
||||
dut.start_app()
|
||||
dut.expect_all('example: Mounting FAT filesystem',
|
||||
'example: Reading file',
|
||||
@@ -14,6 +29,7 @@ def test_examples_fatfsgen(env, _): # type: ignore
|
||||
'example: Unmounting FAT filesystem',
|
||||
'example: Done',
|
||||
timeout=20)
|
||||
env.close_dut(dut.name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -5,4 +5,12 @@ idf_component_register(SRCS "fatfsgen_example_main.c"
|
||||
# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that
|
||||
# the generated image should be flashed when the entire project is flashed to
|
||||
# the target with 'idf.py -p PORT flash'.
|
||||
fatfs_create_partition_image(storage ../fatfs_image FLASH_IN_PROJECT)
|
||||
# If read-only mode is set (CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY)
|
||||
# the generated image will be raw without wear levelling support.
|
||||
# Otherwise it will support wear levelling and thus enable read-write mounting of the image in the device.
|
||||
|
||||
if(CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY)
|
||||
fatfs_create_rawflash_image(storage ../fatfs_image FLASH_IN_PROJECT)
|
||||
else()
|
||||
fatfs_create_spiflash_image(storage ../fatfs_image FLASH_IN_PROJECT)
|
||||
endif()
|
||||
|
||||
10
examples/storage/fatfsgen/main/Kconfig.projbuild
Normal file
10
examples/storage/fatfsgen/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,10 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_FATFS_MODE_READ_ONLY
|
||||
bool "Read only mode for generated FATFS image"
|
||||
default n
|
||||
help
|
||||
If read-only mode is set, the generated fatfs image will be raw (without wear levelling support).
|
||||
Otherwise it will support wear levelling that enables read-write mounting.
|
||||
|
||||
endmenu
|
||||
@@ -12,12 +12,21 @@
|
||||
#include "esp_system.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY
|
||||
#define EXAMPLE_FATFS_MODE_READ_ONLY true
|
||||
#else
|
||||
#define EXAMPLE_FATFS_MODE_READ_ONLY false
|
||||
#endif
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
|
||||
// Mount path for the partition
|
||||
const char *base_path = "/spiflash";
|
||||
|
||||
// Handle of the wear levelling library instance
|
||||
static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Mounting FAT filesystem");
|
||||
@@ -28,23 +37,64 @@ void app_main(void)
|
||||
.format_if_mount_failed = false,
|
||||
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE
|
||||
};
|
||||
esp_err_t err = esp_vfs_fat_rawflash_mount(base_path, "storage", &mount_config);
|
||||
esp_err_t err;
|
||||
if (EXAMPLE_FATFS_MODE_READ_ONLY){
|
||||
err = esp_vfs_fat_rawflash_mount(base_path, "storage", &mount_config);
|
||||
} else {
|
||||
err = esp_vfs_fat_spiflash_mount(base_path, "storage", &mount_config, &s_wl_handle);
|
||||
}
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
// Open file for reading
|
||||
|
||||
char line[128];
|
||||
if (!EXAMPLE_FATFS_MODE_READ_ONLY){
|
||||
// Open file for reading
|
||||
ESP_LOGI(TAG, "Opening file");
|
||||
FILE *f = fopen("/spiflash/inner.txt", "wb");
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
fprintf(f, "This is written by the device");
|
||||
fclose(f);
|
||||
ESP_LOGI(TAG, "File written");
|
||||
|
||||
// Open file for reading
|
||||
ESP_LOGI(TAG, "Reading file");
|
||||
f = fopen("/spiflash/inner.txt", "rb");
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
fgets(line, sizeof(line), f);
|
||||
fclose(f);
|
||||
// strip newline
|
||||
char *pos = strchr(line, '\n');
|
||||
if (pos) {
|
||||
*pos = '\0';
|
||||
}
|
||||
ESP_LOGI(TAG, "Read from file: '%s'", line);
|
||||
|
||||
}
|
||||
FILE *f;
|
||||
char *pos;
|
||||
ESP_LOGI(TAG, "Reading file");
|
||||
FILE *f = fopen("/spiflash/sub/test.txt", "rb");
|
||||
if (EXAMPLE_FATFS_MODE_READ_ONLY){
|
||||
f = fopen("/spiflash/sub/test.txt", "rb");
|
||||
} else {
|
||||
f = fopen("/spiflash/hello.txt", "rb");
|
||||
}
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
char line[128];
|
||||
fgets(line, sizeof(line), f);
|
||||
fclose(f);
|
||||
// strip newline
|
||||
char *pos = strchr(line, '\n');
|
||||
pos = strchr(line, '\n');
|
||||
if (pos) {
|
||||
*pos = '\0';
|
||||
}
|
||||
@@ -52,7 +102,10 @@ void app_main(void)
|
||||
|
||||
// Unmount FATFS
|
||||
ESP_LOGI(TAG, "Unmounting FAT filesystem");
|
||||
ESP_ERROR_CHECK( esp_vfs_fat_rawflash_unmount(base_path, "storage"));
|
||||
|
||||
if (EXAMPLE_FATFS_MODE_READ_ONLY){
|
||||
ESP_ERROR_CHECK(esp_vfs_fat_rawflash_unmount(base_path, "storage"));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount(base_path, s_wl_handle));
|
||||
}
|
||||
ESP_LOGI(TAG, "Done");
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=n
|
||||
@@ -29,7 +29,7 @@ void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Mounting FAT filesystem");
|
||||
// To mount device we need name of device partition, define base_path
|
||||
// and allow format partition in case if it is new one and was not formated before
|
||||
// and allow format partition in case if it is new one and was not formatted before
|
||||
const esp_vfs_fat_mount_config_t mount_config = {
|
||||
.max_files = 4,
|
||||
.format_if_mount_failed = true,
|
||||
|
||||
Reference in New Issue
Block a user