feat(storage/fatfs): add minimal FatFS example

pull/11534/merge
Tomáš Rohlínek 2024-05-29 10:10:38 +02:00 zatwierdzone przez Tomas Rohlinek
rodzic 84ba1a323c
commit b9a54fb1f3
9 zmienionych plików z 174 dodań i 0 usunięć

Wyświetl plik

@ -34,6 +34,14 @@ examples/storage/ext_flash_fatfs:
temporary: true
reason: lack of runners
examples/storage/fatfs_basic:
depends_components:
- fatfs
- vfs
disable_test:
- if: IDF_TARGET != "esp32"
reason: only one target needed
examples/storage/nvs_rw_blob:
depends_components:
- nvs_flash

Wyświetl plik

@ -7,6 +7,7 @@ This directory contains a range of examples ESP-IDF projects. These are intended
The examples are grouped into sub-directories by category. Each category directory contains one or more example projects:
* `fatfs_basic` minimal example of FatFS usage on SPI FLASH
* `custom_flash_driver` example demonstrates how to implement your own flash chip driver by overriding the default driver.
* `emmc` example demonstrates how to use an eMMC chip with an ESP device.
* `ext_flash_fatfs` example demonstrates how to use FATFS partition with external SPI FLASH chip.

Wyświetl plik

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(fatfsgen)

Wyświetl plik

@ -0,0 +1,43 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
# FATFS minimal example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates the minimal setup required to store persistent data on SPI Flash using the FAT filesystem.
Beware that the minimal required size of the flash is 4 MB.
## How to use example
### Build and flash
To run the example, type the following command:
```CMake
# CMake
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is the example's console output:
```
...
I (339) example: Mounting FAT filesystem
I (339) example: Filesystem mounted
I (339) example: Opening file
I (729) example: File written
I (729) example: Reading file
I (739) example: Read from file: 'This is written by the device'
I (739) example: Unmounting FAT filesystem
I (849) example: Done
```
The logic of the example is contained in a [single source file](./main/fat_example_main.c),
and it should be relatively simple to match points in its execution with the log outputs above.

Wyświetl plik

@ -0,0 +1,2 @@
idf_component_register(SRCS "fat_example_main.c"
INCLUDE_DIRS ".")

Wyświetl plik

@ -0,0 +1,87 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "sdkconfig.h"
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");
// 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 formatted before
const esp_vfs_fat_mount_config_t mount_config = {
.max_files = 4, // Number of files that can be open at a time
.format_if_mount_failed = true, // If true, try to format the partition if mount fails
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE, // Size of allocation unit, cluster size.
.use_one_fat = false, // Use only one FAT table (reduce memory usage), but decrease reliability of file system in case of power failure.
};
esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(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;
}
ESP_LOGI(TAG, "Filesystem mounted");
ESP_LOGI(TAG, "Opening file");
const char *filename = "/spiflash/example.txt";
FILE *f = fopen(filename, "wb");
if (f == NULL) {
perror("fopen");
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(filename, "r");
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');
if (pos) {
*pos = '\0';
}
ESP_LOGI(TAG, "Read from file: '%s'", line);
// Unmount FATFS
ESP_LOGI(TAG, "Unmounting FAT filesystem");
ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, s_wl_handle));
ESP_LOGI(TAG, "Done");
}

Wyświetl plik

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 1M,

Wyświetl plik

@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.generic
def test_examples_fatfs_basic(dut: Dut) -> None:
dut.expect('example: Mounting FAT filesystem', timeout=90)
dut.expect('example: Filesystem mounted', timeout=90)
dut.expect('example: Opening file', timeout=90)
dut.expect('example: File written', timeout=90)
dut.expect('example: Reading file', timeout=90)
dut.expect('example: Read from file: \'This is written by the device\'', timeout=90)
dut.expect('example: Unmounting FAT filesystem', timeout=90)
dut.expect('example: Done', timeout=90)

Wyświetl plik

@ -0,0 +1,4 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y