Unable to save file to LittleFS during normal operation after uploading Filesystem Image

I have run into a rather strange issue with LittleFS cause a ESP32 to hard crash whenever I try and post a file to a webserver hosted on the ESP32 after uploading a filesystem image via the Platform IO IDE.

I have confirmed this is something to do with the Uploaded file system as when I erase the flash and just run the code without providing the filesystem I’m able to upload the file happily without issue. I have also proven that I can still access the files on the filesystem if I do ‘Upload Filesystem Image’ and not upload any additional files, so I’m a bit lost as to why this would be the case.

I have a feeling it’s something to do with the partition table potentially but I don’t have much knowledge of that area. What I aim to do is upload the filesystem to the ESP initially but I ever need to update the CA certificate or other files I can connect to it’s network and provide the files via a POST to the webserver.

Any assistance or thoughts would be appreciated. I have attached the data I usually put in the file system, the platform.io file and code I’m currently testing with.

Screenshot 2024-06-06 203411

[env:esp32-s3-devkitm-1]
platform = espressif32
board = esp32-s3-devkitm-1
board_build.filesystem = littlefs
framework = arduino
upload_port = COM4
;monitor_port = COM5
monitor_speed = 115200
build_flags = 
	'-D ARDUINO_USB_MODE=0'
	'-D ARDUINO_USB_CDC_ON_BOOT=0'
monitor_filters = esp32_exception_decoder
lib_deps = 
	pfeerick/elapsedMillis@^1.0.6
	bblanchon/ArduinoJson@^7.0.4
	256dpi/MQTT@^2.5.2

#include "Arduino.h"
#include <ESPmDNS.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include "elapsedMillis.h"
#include "Storage.h"
#include "LittleFS.h"

WebServer configNetwork(80);
IPAddress ip(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

elapsedMillis standbyTimer;
unsigned int standbyTimeout = 60000;

Storage* _storage;
bool useConfigNetwork = false;

void handleCACertPost() { 
    if (!configNetwork.hasArg("plain")) {
        configNetwork.send(400, F("application/json"), "{\"message\": \"No file uploaded.\"}");
        return;
    }

    Serial.println("Upload filename: /AmazonRootCA1.pem");

    if (!LittleFS.begin()) {
        Serial.println("An Error has occurred while mounting LittleFS");
        configNetwork.send(500, F("application/json"), "{\"message\": \"An Error has occurred while mounting LittleFS.\"}");
        return;
    }

    File uploadFile = LittleFS.open("/AmazonRootCA1.pem", FILE_WRITE);

    if (!uploadFile) {
        Serial.println("Failed to open file for writing");
        configNetwork.send(500, F("application/json"), "{\"message\": \"Failed to open file for writing.\"}");
        return;
    }

    int contentLength = configNetwork.arg("plain").length();

    if (contentLength > 0) {
        int written = uploadFile.write((uint8_t *)configNetwork.arg("plain").c_str(), contentLength);

        if (written != contentLength) {
            Serial.println("Write failed");
            configNetwork.send(500, "text/plain", "Write failed");
            uploadFile.close();
            return;
        }

        uploadFile.close();
        Serial.println("File Uploaded Successfully");
        configNetwork.send(200, F("application/json"), "{\"message\": \"Saved CA certificate.\"}");
    } else {
        Serial.println("Content-Length was zero or invalid");
        configNetwork.send(400, F("application/json"), "{\"message\": \"Content-Length was zero or invalid.\"}");
    }
}

void handleWifiPost() {
    String body = configNetwork.arg(F("plain"));
    Serial.println(body);

    JsonDocument doc;
    deserializeJson(doc, body);

    const char* ssid = doc["ssid"].as<const char*>();
    const char* password = doc["password"].as<const char*>();

    _storage->putWifiSSID(doc["ssid"]);
    _storage->putWifiPassword(doc["password"]);

    configNetwork.send(200, F("application/json"), "{\"message\": \"Saved wifi credentials.\"}");
}

void handleRebootPost() {
    Serial.println(F("Hardware will restart in 5 seconds"));

    configNetwork.send(200, "application/json", "{ \"message\": \"Hardware will restart in 5 seconds!\"}");
    delay(5000);
    ESP.restart();
}

void beginConfigNetwork() {
    Serial.println(F("Configuring and starting config network."));

    useConfigNetwork = true;
    standbyTimer = 0;

    WiFi.disconnect();
    WiFi.mode(WIFI_OFF);
    WiFi.mode(WIFI_AP);
    WiFi.softAP(storage->getId().c_str(), NULL, 6);
    WiFi.softAPConfig(ip, ip, subnet);

    MDNS.begin("esp");

    configNetwork.on(F("/security/key"), HTTP_POST, handleDeviceKeyPost);
    configNetwork.on(F("/security/ca"), HTTP_POST, handleCACertPost);
    configNetwork.on(F("/security/wifi"), HTTP_POST, handleWifiPost);
    configNetwork.on(F("/reboot"), HTTP_POST, handleRebootPost);

    configNetwork.begin();
}

void resetConfigNetwork() {
    Serial.println(F("Resetting and restarting config network."));

    configNetwork.stop();
    delay(1000);
    configNetwork.begin();
    standbyTimer = 0;
}

void stopConfigNetwork() {
    useConfigNetwork = false;
    MDNS.end();
    configNetwork.stop();
}

void loopConfigNetwork() {
    configNetwork.handleClient();

    if (WiFi.softAPgetStationNum() < 1) {
        if (standbyTimer > standbyTimeout) {
            standbyTimer = 0;
            resetConfigNetwork();
        }
    } else {
        standbyTimer = 0;
    }
}

void setup() {
  Serial.begin(115200);
  btStop();
  delay(2000);

  beginConfigNetwork();
}

void loop() {
  loopConfigNetwork();
}

please post your used partitions.csv

1 Like

I’m not using a partitions.csv, I just assumed the default settings were correct.

After the question from Jason2866 got me thinking, I investigated the use of a partition.csv and this appears to have solved the issue, partially.

I can’t say for certain why the crash was occurring, it could have do reading/writing the wrong blocks of data in the partition table but after using the partition table from the Espressif github for littlefs for the esp32, and updating the board definition to the 16MB flash board (which matches my chip), all appears to be working.

[env:esp32-s3-devkitm-1]
platform = espressif32
board = esp32s3box
board_build.filesystem = littlefs
board_build.partitions = large_littlefs_16MB.csv
framework = arduino
upload_port = COM4
;monitor_port = COM5
monitor_speed = 115200
build_flags = 
	'-D ARDUINO_USB_MODE=0'
	'-D ARDUINO_USB_CDC_ON_BOOT=0'
monitor_filters = esp32_exception_decoder
lib_deps = 
	pfeerick/elapsedMillis@^1.0.6
	bblanchon/ArduinoJson@^7.0.4
	256dpi/MQTT@^2.5.2

large_littlefs_16MB.csv

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x480000,
app1,     app,  ota_1,   0x490000,0x480000,
spiffs,   data, spiffs,  0x910000,0x6E0000,
coredump, data, coredump,0xFF0000,0x10000,

EDIT
After more testing it appears that if the file has not been uploaded as apart of the filesystem and then is uploaded via the webserver it works. It also works if the file is apart of the filesystem and uploaded via the file system image it works. However, with the current code if you try to replace the file the ESP crashes. More investigation to follow.