FatFS for external Flash memory

I am using ESP32 wroom with W25q32 . i want to use the SPI flash memory as storage space to store images ,gif and mp3 audio files .Is there a way to get Filesystem like littleFs or SPIFFS for External SPI flash Memory .

After some research i found out we can use FATFS for external FLash filesystem i am trying to make it using the Example code . I modified the code little to work on Arduino Environment . I am using Arduino 2.3.4 .

/*
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */
/* Example of FAT filesystem on external Flash.
   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.

   This sample shows how to store files inside a FAT filesystem.
   FAT filesystem is stored in a partition inside SPI flash, using the
   flash wear levelling library.
*/

// SPI pin definitions for external Flash
#define PIN_MOSI 23  // Master Out Slave In (MOSI)
#define PIN_MISO 19  // Master In Slave Out (MISO)
#define PIN_CLK 18   // Serial Clock (SCK)
#define PIN_CS 5     // Chip Select (CS)
#define HOST_ID SPI3_HOST  // Use SPI3_HOST (VSPI) or SPI2_HOST (HSPI)
#define EXAMPLE_FLASH_FREQ_MHZ 133  // Replace with your chip's maximum frequency



#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "esp_flash.h"
#include "esp_flash_spi_init.h"
#include "esp_partition.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "esp_system.h"
#include "soc/spi_pins.h"

// h2 and c2 will not support external flash
#define EXAMPLE_FLASH_FREQ_MHZ 40

static const char* TAG = "example";

// Pin mapping
// ESP32 (VSPI)
#ifdef CONFIG_IDF_TARGET_ESP32
#define HOST_ID SPI3_HOST
#define PIN_MOSI SPI3_IOMUX_PIN_NUM_MOSI
#define PIN_MISO SPI3_IOMUX_PIN_NUM_MISO
#define PIN_CLK SPI3_IOMUX_PIN_NUM_CLK
#define PIN_CS SPI3_IOMUX_PIN_NUM_CS
#define PIN_WP SPI3_IOMUX_PIN_NUM_WP
#define PIN_HD SPI3_IOMUX_PIN_NUM_HD
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#else  // Other chips (SPI2/HSPI)
#define HOST_ID SPI2_HOST
#define PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
#define PIN_CLK SPI2_IOMUX_PIN_NUM_CLK
#define PIN_CS SPI2_IOMUX_PIN_NUM_CS
#define PIN_WP SPI2_IOMUX_PIN_NUM_WP
#define PIN_HD SPI2_IOMUX_PIN_NUM_HD
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#endif

// Handle of the wear levelling library instance
static wl_handle_t s_wl_handle = WL_INVALID_HANDLE;

// Mount path for the partition
const char* base_path = "/extflash";

static esp_flash_t* example_init_ext_flash(void);
static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label);
static void example_list_data_partitions(void);
static bool example_mount_fatfs(const char* partition_label);

void setup(void) {
  Serial.begin(115200);
  // Set up SPI bus and initialize the external SPI Flash chip
  esp_flash_t* flash = example_init_ext_flash();
  if (flash == NULL) {
    return;
  }

  // Add the entire external flash chip as a partition
  const char* partition_label = "storage";
  example_add_partition(flash, partition_label);

  // List the available partitions
  example_list_data_partitions();

  // Initialize FAT FS in the partition
  if (!example_mount_fatfs(partition_label)) {
    return;
  }

  // Print FAT FS size information
  uint64_t bytes_total, bytes_free;
  esp_vfs_fat_info(base_path, &bytes_total, &bytes_free);
  ESP_LOGI(TAG, "FAT FS: %" PRIu64 " kB total, %" PRIu64 " kB free", bytes_total / 1024, bytes_free / 1024);

  // Create a file in FAT FS
  ESP_LOGI(TAG, "Opening file");
  FILE* f = fopen("/extflash/hello.txt", "wb");
  if (f == NULL) {
    ESP_LOGE(TAG, "Failed to open file for writing");
    return;
  }
  fprintf(f, "Written using ESP-IDF %s\n", esp_get_idf_version());
  fclose(f);
  ESP_LOGI(TAG, "File written");

  // Open file for reading
  ESP_LOGI(TAG, "Reading file");
  f = fopen("/extflash/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');
  if (pos) {
    *pos = '\0';
  }
  ESP_LOGI(TAG, "Read from file: '%s'", line);
}

static esp_flash_t* example_init_ext_flash(void) {
    // Define the SPI bus configuration
    spi_bus_config_t bus_config;
    bus_config.mosi_io_num = PIN_MOSI;  // Assign GPIO for MOSI
    bus_config.miso_io_num = PIN_MISO;  // Assign GPIO for MISO
    bus_config.sclk_io_num = PIN_CLK;   // Assign GPIO for CLK
    bus_config.quadwp_io_num = -1;      // Set to -1 if not used
    bus_config.quadhd_io_num = -1;      // Set to -1 if not used
    bus_config.max_transfer_sz = 4096;  // Default transfer size

    ESP_LOGI(TAG, "SPI Bus Pins: MOSI=%d, MISO=%d, CLK=%d, CS=%d", 
             PIN_MOSI, PIN_MISO, PIN_CLK, PIN_CS);

    // Define the SPI flash device configuration
    esp_flash_spi_device_config_t device_config;
    device_config.host_id = HOST_ID;
    device_config.cs_io_num = PIN_CS;
    device_config.io_mode = SPI_FLASH_DIO;
    device_config.freq_mhz = EXAMPLE_FLASH_FREQ_MHZ;
    device_config.cs_id = 0;

    ESP_LOGI(TAG, "Initializing SPI bus");
    esp_err_t ret = spi_bus_initialize(HOST_ID, &bus_config, 0); // Replace SPI_DMA_CH_AUTO with 0
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "SPI bus initialization failed: %s", esp_err_to_name(ret));
        return NULL;
    }

    // Add flash device to the SPI bus
    esp_flash_t* ext_flash;
    ret = spi_bus_add_flash_device(&ext_flash, &device_config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to add flash device: %s", esp_err_to_name(ret));
        return NULL;
    }

    ESP_LOGI(TAG, "Flash device added successfully");

    // Probe the flash device to ensure it works
    ESP_LOGI(TAG, "Probing the flash device");
    ret = esp_flash_init(ext_flash);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize flash: %s", esp_err_to_name(ret));
        return NULL;
    }

    // Log successful initialization
    uint32_t id;
    ESP_ERROR_CHECK(esp_flash_read_id(ext_flash, &id));
    ESP_LOGI(TAG, "Flash ID: 0x%x, size: %u KB", id, ext_flash->size / 1024);

    return ext_flash;
}




static const esp_partition_t* example_add_partition(esp_flash_t* ext_flash, const char* partition_label) {
  ESP_LOGI(TAG, "Adding external Flash as a partition, label=\"%s\", size=%" PRIu32 " KB", partition_label, ext_flash->size / 1024);
  const esp_partition_t* fat_partition;
  const size_t offset = 0;
  ESP_ERROR_CHECK(esp_partition_register_external(ext_flash, offset, ext_flash->size, partition_label, ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, &fat_partition));

  // Erase space of partition on the external flash chip
  ESP_LOGI(TAG, "Erasing partition range, offset=%u size=%" PRIu32 " KB", offset, ext_flash->size / 1024);
  ESP_ERROR_CHECK(esp_partition_erase_range(fat_partition, offset, ext_flash->size));
  return fat_partition;
}

static void example_list_data_partitions(void) {
  ESP_LOGI(TAG, "Listing data partitions:");
  esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);

  for (; it != NULL; it = esp_partition_next(it)) {
    const esp_partition_t* part = esp_partition_get(it);
    ESP_LOGI(TAG, "- partition '%s', subtype %d, offset 0x%" PRIx32 ", size %" PRIu32 " kB",
             part->label, part->subtype, part->address, part->size / 1024);
  }

  esp_partition_iterator_release(it);
}

static bool example_mount_fatfs(const char* partition_label) {
  ESP_LOGI(TAG, "Mounting FAT filesystem");
  const esp_vfs_fat_mount_config_t mount_config = {
    .format_if_mount_failed = true,
    .max_files = 4,
    .allocation_unit_size = CONFIG_WL_SECTOR_SIZE,
  };
  esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, &mount_config, &s_wl_handle);
  if (err != ESP_OK) {
    ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
    return false;
  }
  return true;
}



void loop() {
}

Output :

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:4832
load:0x40078000,len:16460
load:0x40080400,len:4
load:0x40080404,len:3504
entry 0x400805cc
E (20) spi: spi_bus_initialize(776): intr flag not allowed

i dont know what to about this error .

E (20) spi: spi_bus_initialize(776): intr flag not allowed

Make sure SCLK is NOT an input_only pin.

HI @AresXT

Not exactly what you ask for; It's clear but why not use spare room in the W25Q32 (or bigger) that lies under the metal lid beside ESP32 chip in the WROOM32 module of your card ?

Partition scheme is here for that : some space for code, some space for file system and some space for OTA if necessary

Why do you want to use a second SPI Flash for your datas ?
More room ? mandatory separate SPI Flash chip ?

Sorry for late message.

Yes there is 4MB storage in esp32 and also 16MB in its varients .I have 4 mb module which i spared 2mb for app and 2 mb for spiff .but it cost no ota . so i want to just use external spi storage if it can / upgrade the chip to the varient

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.