Przeglądaj źródła

Merge branch 'feature/fatfs_allocation_unit_size' into 'master'

fatfs: add option to set allocation unit size

See merge request idf/esp-idf!1760
Ivan Grokhotkov 8 lat temu
rodzic
commit
56843281c7

+ 19 - 1
components/fatfs/src/esp_vfs_fat.h

@@ -88,8 +88,26 @@ esp_err_t esp_vfs_fat_unregister_path(const char* base_path);
  * @brief Configuration arguments for esp_vfs_fat_sdmmc_mount and esp_vfs_fat_spiflash_mount functions
  */
 typedef struct {
-    bool format_if_mount_failed;    ///< If FAT partition can not be mounted, and this parameter is true, create partition table and format the filesystem
+    /**
+     * If FAT partition can not be mounted, and this parameter is true,
+     * create partition table and format the filesystem.
+     */
+    bool format_if_mount_failed;
     int max_files;                  ///< Max number of open files
+    /**
+     * 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.
+     */
+    size_t allocation_unit_size;
 } esp_vfs_fat_mount_config_t;
 
 // Compatibility definition

+ 30 - 0
components/fatfs/src/vfs_fat_internal.h

@@ -0,0 +1,30 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "esp_vfs_fat.h"
+#include <sys/param.h>
+#include <stddef.h>
+
+static inline size_t esp_vfs_fat_get_allocation_unit_size(
+        size_t sector_size, size_t requested_size)
+{
+    size_t alloc_unit_size = requested_size;
+    const size_t max_sectors_per_cylinder = 128;
+    const size_t max_size = sector_size * max_sectors_per_cylinder;
+    alloc_unit_size = MAX(alloc_unit_size, sector_size);
+    alloc_unit_size = MIN(alloc_unit_size, max_size);
+    return alloc_unit_size;
+}

+ 11 - 3
components/fatfs/src/vfs_fat_sdmmc.c

@@ -17,6 +17,7 @@
 #include "esp_log.h"
 #include "esp_vfs.h"
 #include "esp_vfs_fat.h"
+#include "vfs_fat_internal.h"
 #include "driver/sdmmc_host.h"
 #include "driver/sdspi_host.h"
 #include "sdmmc_cmd.h"
@@ -112,16 +113,23 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
             goto fail;
         }
         ESP_LOGW(TAG, "partitioning card");
-        DWORD plist[] = {100, 0, 0, 0};
         workbuf = malloc(workbuf_size);
+        if (workbuf == NULL) {
+            err = ESP_ERR_NO_MEM;
+            goto fail;
+        }
+        DWORD plist[] = {100, 0, 0, 0};
         res = f_fdisk(s_pdrv, plist, workbuf);
         if (res != FR_OK) {
             err = ESP_FAIL;
             ESP_LOGD(TAG, "f_fdisk failed (%d)", res);
             goto fail;
         }
-        ESP_LOGW(TAG, "formatting card");
-        res = f_mkfs(drv, FM_ANY, s_card->csd.sector_size, workbuf, workbuf_size);
+        size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(
+                s_card->csd.sector_size,
+                mount_config->allocation_unit_size);
+        ESP_LOGW(TAG, "formatting card, allocation unit size=%d", alloc_unit_size);
+        res = f_mkfs(drv, FM_ANY, alloc_unit_size, workbuf, workbuf_size);
         if (res != FR_OK) {
             err = ESP_FAIL;
             ESP_LOGD(TAG, "f_mkfs failed (%d)", res);

+ 10 - 2
components/fatfs/src/vfs_fat_spiflash.c

@@ -17,6 +17,7 @@
 #include "esp_log.h"
 #include "esp_vfs.h"
 #include "esp_vfs_fat.h"
+#include "vfs_fat_internal.h"
 #include "diskio.h"
 
 #include "wear_levelling.h"
@@ -78,8 +79,15 @@ esp_err_t esp_vfs_fat_spiflash_mount(const char* base_path,
             goto fail;
         }
         workbuf = malloc(workbuf_size);
-        ESP_LOGI(TAG, "Formatting FATFS partition");
-        fresult = f_mkfs(drv, FM_ANY | FM_SFD, workbuf_size, workbuf, workbuf_size);
+        if (workbuf == NULL) {
+            result = ESP_ERR_NO_MEM;
+            goto fail;
+        }
+        size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(
+                CONFIG_WL_SECTOR_SIZE,
+                mount_config->allocation_unit_size);
+        ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
+        fresult = f_mkfs(drv, FM_ANY | FM_SFD, alloc_unit_size, workbuf, workbuf_size);
         if (fresult != FR_OK) {
             result = ESP_FAIL;
             ESP_LOGE(TAG, "f_mkfs failed (%d)", fresult);

+ 2 - 1
components/fatfs/test/test_fatfs_sdmmc.c

@@ -185,7 +185,8 @@ static void speed_test(void* buf, size_t buf_size, size_t file_size, bool write)
     sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
     esp_vfs_fat_sdmmc_mount_config_t mount_config = {
         .format_if_mount_failed = write,
-        .max_files = 5
+        .max_files = 5,
+        .allocation_unit_size = 64 * 1024
     };
     TEST_ESP_OK(esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, NULL));
 

+ 2 - 1
examples/storage/sd_card/main/sd_card_example_main.c

@@ -81,7 +81,8 @@ void app_main(void)
     // formatted in case when mounting fails.
     esp_vfs_fat_sdmmc_mount_config_t mount_config = {
         .format_if_mount_failed = false,
-        .max_files = 5
+        .max_files = 5,
+        .allocation_unit_size = 16 * 1024
     };
 
     // Use settings defined above to initialize SD card and mount FAT filesystem.

+ 11 - 6
examples/storage/wear_levelling/README.md

@@ -1,4 +1,4 @@
-# SD Card example
+# Wear levelling example
 
 This example demonstrates how to use wear levelling library and FATFS library to store files in a partition inside SPI flash. Example does the following steps:
 
@@ -15,9 +15,14 @@ This example demonstrates how to use wear levelling library and FATFS library to
 Here is an typical example console output. 
 
 ```
-Try to open file ...
-I (239) wear_level: Reading file
-Read from file: 'Hello User! I'm happy to see you!1'
-W (239) wear_levelling: wl_unmount Delete driver
+I (280) example: Mounting FAT filesystem
+W (440) vfs_fat_spiflash: f_mount failed (13)
+I (440) vfs_fat_spiflash: Formatting FATFS partition, allocation unit size=4096
+I (660) vfs_fat_spiflash: Mounting again
+I (660) example: Opening file
+I (910) example: File written
+I (910) example: Reading file
+I (920) example: Read from file: 'written using ESP-IDF v3.1-dev-171-gf9ad17eee-dirty'
+I (920) example: Unmounting FAT filesystem
+I (1000) example: Done
 ```
-

+ 2 - 1
examples/storage/wear_levelling/main/wear_levelling_example_main.c

@@ -32,7 +32,8 @@ void app_main(void)
     // and allow format partition in case if it is new one and was not formated before
     const esp_vfs_fat_mount_config_t mount_config = {
             .max_files = 4,
-            .format_if_mount_failed = true
+            .format_if_mount_failed = true,
+            .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
     };
     esp_err_t err = esp_vfs_fat_spiflash_mount(base_path, "storage", &mount_config, &s_wl_handle);
     if (err != ESP_OK) {