esp-idf: WL FAT FS read file error (IDFGH-1063)
Environment
- Development Kit: ESP32-Wrover-Kit
- Kit version (for WroverKit/PicoKit/DevKitC): v4.1
- Module or chip used: ESP32-WROVER-B
- IDF version (run
git describe --tagsto find it): v4.0-dev-461-g17a3bdb8c - Build System: CMake
- Compiler version (run
xtensa-esp32-elf-gcc --versionto find it): 1.22.0-80-g6c4433a - Operating System: Linux
- Power Supply: (USB|external 5V)&Battery
Problem Description
In my project i’ve creating fat fs via https://github.com/jkearins/ESP32_mkfatfs. This tool creates partition binary with WL FS v1 and after first mounting this partiton on device wl lib converts fs from v1 to v2. After it some files, that was created by mkfatfs and burned during flash procedure are read and some new files are created (config.json). Everything works well even after reset (by button or by idf_monitor.py), but if i power off my dev board and power it again I’v got the following message: ‘W (236) vfs_fat_spiflash: f_mount failed (13)’ during boot. If i set .format_if_mount_failed = true in mount_config where in esp_vfs_fat_spiflash_mount() returns ‘ESP_OK’, so in this case there is no way to determine if fs was mounted as is, or it was formated. If i set .format_if_mount_failed = false in mount_config fs mounts without any warnings but i’ve got another porblem. Files, that was created by mkfatfs and burned during flash procedure reads without any problems, but files, that was created by my programm itself is not readable. Program opens a file (config.json), fopen, ftell, fseek, fread, fclose doesn’t raise any errors but file is empty.
So, I can’t understand why esp_vfs_fat_spiflash_mount() with .format_if_mount_failed = true not mounting fs but formats it while with .format_if_mount_failed = false it successfully mount fs? but files created on device is not readable.
Also there is a problem that esp_vfs_fat_spiflash_mount() and esp_vfs_fat_sdmmc_mount() doesn’t return ‘pdrv’. It will be very useful for futher usage of ff.h functions.
Expected Behavior
- esp_vfs_fat_spiflash_mount must return a special return error if esp_vfs_fat_spiflash_mount can’t mount fs and it was formated to have an ability to process that case.
- After poweroff/poweron device all files on wl fs must be readable even they changed or not during previous device runs.
- There must be a way to determine ‘pdrv’ (ff_diskio_register_wl_partition() registration number) that esp_vfs_fat_spiflash_mount() & esp_vfs_fat_sdmmc_mount() got during execution for further usage with ff.h functions.
- If there any other more right way to create wl v2 fat fs binary from directory except ESP32_mkfatfs?
Actual Behavior
- There is no ways to determine fs was mounted or formatted if .format_if_mount_failed = true in mount_config.
- Files that was written by program running on device has no content after power off.
- No way to get ‘pdrv’ from esp_vfs_fat_spiflash_mount() & esp_vfs_fat_sdmmc_mount().
- https://github.com/jkearins/ESP32_mkfatfs generates only WL v1 FS and official documentation doesn’t contain any descriptions of procedure to create WL v2 FS binary from folder on development system.
Steps to repropduce
- make fat fs: mkfatfs -c ~/DIR_WITH_FILES_TO_PUT_INTO_FATFS_BINARY -s FS_SIZE ~/FAT_FS.bin
- burn fat fs: esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x0000000 ~/FAT_FS.bin
- Mount fat fs via esp_vfs_fat_spiflash_mount()
- Create new file, write some data to a new file and close it (do not unmount fs!!!)
- Reset device via button or idf_monitor.py and check that all files readable
- Fully poweroff the device, power on it again, wait for load and find out that file created on step 4 has zero size.
Code to reproduce this issue
esp_err_t flash_fs_mount(void) { ESP_LOGD(TAG, “Initializing SPI flash FS”); const esp_vfs_fat_mount_config_t mount_config = { .max_files = 4, .format_if_mount_failed = false, .allocation_unit_size = 512};
esp_err_t ret = esp_vfs_fat_spiflash_mount(FLASH_FS_MOUNT_PATH, "storage", &mount_config, &s_wl_handle);
if (ret != ESP_OK)
{
ESP_LOGE("SPI flash FS initialization error: %s", esp_err_to_name(ret));
return ret;
}
return ESP_OK; }
esp_err_t config_save_file(const char *filename) { FILE *fp; fp = fopen(filename, “w”); if (fp != NULL) { char *config = “{"data":"some data"}”; fprintf(fp, “%s”, config); fclose(fp); ESP_LOGI(TAG, “Config successfully saved”); if (config) { vPortFree(config); config = NULL; } return ESP_OK; } ESP_LOGE(TAG, “Config save error!”); return ESP_FAIL; }
Debug Logs
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 19 (10 by maintainers)
@dmitry1945, seems to me that I found solution. If I add setvbuf(fp, NULL, _IONBF, 0); before fprintf(fp, “%s”, config); and fflush(fp); before fclose(fp); all begins to work perfectly. Adding only fflush(fp); doesn’t helps. So seems that the problem is in buffers fflush and/or file cache logic. When file closes by fclose() driver doesn’t clean buffers/cache. In my opinion it’s not proper behaivor, in GNU/Linux fclose() fixes all unwritten data to disk.
@igrr, thanks for comments? I’ll try to. Closing issue.
Quoting the docs,
esp_vfs_fat_sdmmc_mountis a convenience function. It is mainly intended to be used in example applications to make the code less verbose. It does very limited error checking, and developers are encouraged to look at its source code and incorporate more advanced versions into production applications. The steps which the application needs to take to use FATFS with an SD card are listed here: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/fatfs.html#using-fatfs-with-vfs. This approach will also give you access to the pdrv value you are looking for.On a related note, FATFS version 0.13b has added the ability to use a Unix-style path prefix as the volume name (via the FF_STR_VOLUME_ID configuration option). Once the version of FATFS used in IDF gets updated to the latest release, getting access to the pdrv might get easier. For example,
esp_vfs_fat_sdmmc_mountmay then setpdrvequal to the VFS mount point (base_path), which would be more transparent for the application.