ESP32 Filesystems, FLASH Partitions, and OTA

I'm switching from NODEMCU to ESP32-DEVKIT, and disappointed to find it's not as straight-forward as I'd hoped. NODEMCU/ESP8266 deprecated use of SPIFFs filesystem some time ago, so I switched to LittleFS. ESP32 supports SPIFFS and FAT. It appears LittleFS can be used, but it has to be manually installed, and it's not clear to me yet how to upload files to it (it's really easy with NODEMCU, even from the command line).

Has anyone here used LittleFS on ESP32?

I'm also surprised by the odd assortment of FLASH/FS/OTA configurations on ESP32. I liked the options the NODEMCU had, and the ones on ESP32 are completely different, ,and peculiar, with odd partition sizes like 190Kb, 1.2Mb, 1.9Mb, and most options do not allow OTA, which I need. I'd really like 1Mb code + 2Mb LittleFS + OTA. Is it practical to modify boards.txt or something to allow this?

Did you try this new library ESP32's LITTLEFS Library ?

Yes, I saw that. It seems like the most promising possibility, but just hoping to find someone who's already made it work. It never seems to be as simple as it should be. For now, I'm trying to get the rest of the code working with SPIFFS. Once that's going, I'll try to switch back to LittleFS. It's odd that the interfaced have so many little differences, when they could have been made completely interchangeable.

On a similar note, I'm also using FastLED for NeoPixels, and having similar problems there. It supposedly works on ESP32, but seems there are a lot of exceptions, pinout differences, etc. that make changing boards less than trivial.

The commands for LittleFS are intentionally kept the same to those of SPIFFS as you can see in the following sketch. The example is a little complex yet efficient to read the whole struct, instead of one byte at a time.

#include <Arduino.h>

#define USE_SPIFFS      false

#if USE_SPIFFS
  #include <SPIFFS.h>
  FS* filesystem =      &SPIFFS;
  #define FileFS        SPIFFS
  #define FS_Name       "SPIFFS"
#else
  // Use LittleFS
  #include "FS.h"
  #include <LITTLEFS.h>
  
  FS* filesystem =      &LITTLEFS;
  #define FileFS        LITTLEFS
  #define FS_Name       "LittleFS"
#endif


/* You only need to format LITTLEFS the first time you run a
   test or else use the LITTLEFS plugin to create a partition
   https://github.com/lorol/arduino-esp32littlefs-plugin */

#define FORMAT_FS_IF_FAILED       true

#define SSID_MAX_LEN            32
//From v1.0.10, WPA2 passwords can be up to 63 characters long.
#define PASS_MAX_LEN            64

typedef struct
{
  char wifi_ssid[SSID_MAX_LEN];
  char wifi_pw  [PASS_MAX_LEN];
}  WiFi_Credentials;

typedef struct
{
  String wifi_ssid;
  String wifi_pw;
}  WiFi_Credentials_String;

#define NUM_WIFI_CREDENTIALS      2

typedef struct
{
  WiFi_Credentials  WiFi_Creds [NUM_WIFI_CREDENTIALS];
} WM_Config;

WM_Config WM_config =
{
  "HueNet1", "12345678",
  "HueNet2", "87654321"
};

void readStructFile(fs::FS &fs, const char * path)
{ 
  Serial.printf("Reading Struct from : %s\r\n", path);

  File file = fs.open(path);

  if (!file || file.isDirectory())
  {
    Serial.println("File open failed");
    return;
  }

  Serial.println("Reading from file ....");

  // Reading the whole struct, not just one-by-one byte
  file.readBytes((char *) &WM_config, sizeof(WM_config));
  
  Serial.printf("Read data: SSID1 = %s, PW1 = %s\n", WM_config.WiFi_Creds[0].wifi_ssid, WM_config.WiFi_Creds[0].wifi_pw);
  Serial.printf("Read data: SSID2 = %s, PW2 = %s\n", WM_config.WiFi_Creds[1].wifi_ssid, WM_config.WiFi_Creds[1].wifi_pw);
    
  file.close();
}

void writeStructFile(fs::FS &fs, const char * path)
{
  //createPath(fs, path);
  
  Serial.printf("Writing Struct to : %s\r\n", path);

  File file = fs.open(path, FILE_WRITE);

  if (!file)
  {
    Serial.println("File open failed");
    return;
  }

  // Writing the whole struct, not just one-by-one byte
  file.write((uint8_t*) &WM_config, sizeof(WM_config));

  file.close();
}

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  
  delay(100);
 
  Serial.print("\nStarting FS_StructWrite using " + String(FS_Name));
  Serial.println(" on " + String(ARDUINO_BOARD));

  if (!FileFS.begin(FORMAT_FS_IF_FAILED))
  {
    Serial.print(FS_Name);
    Serial.println(F(" failed! AutoFormatting."));
  }

  Serial.println( String(FS_Name) + " is ready" );

  writeStructFile(FileFS, "/Credentials.txt");
  readStructFile(FileFS,  "/Credentials.txt");

  Serial.println( "Done" );
}

void loop()
{

}

To use SPIFFS, You just need to change to

#define USE_SPIFFS      true

Below is the terminal output when running SPIFFS then back to LittleFS

Starting FS_StructWrite using SPIFFS on ESP32_DEV
E (135) SPIFFS: mount failed, -10025             <===== Auto Format when changing from LitteFS to SPIFFS
SPIFFS is ready
Writing Struct to : /Credentials.txt
Reading Struct from : /Credentials.txt
Reading from file ....
Read data: SSID1 = HueNet1, PW1 = 12345678
Read data: SSID2 = HueNet2, PW2 = 87654321
Done

Starting FS_StructWrite using LittleFS on ESP32_DEV
E (138) esp_littlefs: mount failed,  (-84)                          <===== Auto Format when changing from SPIFFS to LitteFS
E (142) esp_littlefs: Failed to initialize LittleFS
LittleFS is ready
Writing Struct to : /Credentials.txt
Reading Struct from : /Credentials.txt
Reading from file ....
Read data: SSID1 = HueNet1, PW1 = 12345678
Read data: SSID2 = HueNet2, PW2 = 87654321
Done

There are many more examples to use LittleFS for ESP32 in the new version v1.3.0 of

  1. ESP_WiFiManager Library
  2. ESPAsync_WiFiManager Library