espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.5k stars 7.39k forks source link

Update Class does not work with FFAT / FATFS partition (see also #7267) #7878

Open congoblue opened 1 year ago

congoblue commented 1 year ago

Board

ESP32-WROOM32 (8MB flash)

Device Description

Custom hardware

Hardware Configuration

There are some other IO connections but not relevant to this issue

Version

v2.0.6

IDE Name

VSCode/PlatformIO

Operating System

W10

Flash frequency

40MHz

PSRAM enabled

yes

Upload speed

115200

Description

When Update class is used to upload a new filesystem to a FATFS partition, the partition is not written correctly and the filesystem will not mount.

This issue has already been raised and closed in #7267 but it does not work in my code.

In Updater.cpp line 140, an offset variable _paroffset is set to 0x1000 for a FATFS partition which appears to be necessary due to a wear levelling table at the bottom of the partition. (e.g. If the partition file is set to start at 0x680000, then the esptool will upload a fatfs partition at 0x681000).

However this variable _paroffset does not appear to be actually used anywhere in the update code.

if the filesystem is uploaded serially using PlatformIO then the filesystem loads correctly.

If 0x1000 bytes of zero data are written to the flash using update.write before the head of the OTA file is written, then the filesystem also loads correctly. I have adopted this as a workaround for the time being.

Sketch

in platformio set the filesystem to fatfs:
board_build.filesystem = fatfs
board_build.partitions = default_ffat.csv

use any OTA update example which uses the Update class, for example:
https://github.com/G6EJD/ESP32-OTA-Example/blob/master/ESP32_Basic_OTA.ino

then attempt to open the filesystem
#include <FFat.h>
void setup() {
FFat.begin() };

will give the error message
[   339][E][FFat.cpp:60] begin(): Mounting FFat partition failed! Error: -1

Debug Message

[   339][E][FFat.cpp:60] begin(): Mounting FFat partition failed! Error: -1

Other Steps to Reproduce

The Update class works correctly with a SPIFFS partition or a LittleFS partition.

I have checked existing issues, online documentation and the Troubleshooting Guide

SinglWolf commented 11 months ago

Faced the same problem. I decided by adding 1 line to the code of the function

bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn, const char *label) {
    if(_size > 0){
        log_w("already running");
        return false;
    }

    _ledPin = ledPin;
    _ledOn = !!ledOn; // 0(LOW) or 1(HIGH)

    _reset();
    _error = 0;
    _target_md5 = emptyString;
    _md5 = MD5Builder();

    if(size == 0) {
        _error = UPDATE_ERROR_SIZE;
        return false;
    }

    if (command == U_FLASH) {
        _partition = esp_ota_get_next_update_partition(NULL);
        if(!_partition){
            _error = UPDATE_ERROR_NO_PARTITION;
            return false;
        }
        log_d("OTA Partition: %s", _partition->label);
    }
    else if (command == U_SPIFFS) {
        _partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, label);
        _paroffset = 0;
        if(!_partition){
            _partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, NULL);
            _paroffset = 0x1000;  //Offset for ffat, assuming size is already corrected
            if(!_partition){
               _error = UPDATE_ERROR_NO_PARTITION;
               return false;
            }
        }
        _progress = _paroffset; // <- this
    }
    else {
        _error = UPDATE_ERROR_BAD_ARGUMENT;
        log_e("bad command %u", command);
        return false;
    }

    if(size == UPDATE_SIZE_UNKNOWN){
        size = _partition->size;
    } else if(size > _partition->size){
        _error = UPDATE_ERROR_SIZE;
        log_e("too large %u > %u", size, _partition->size);
        return false;
    }

    //initialize
    _buffer = (uint8_t*)malloc(SPI_FLASH_SEC_SIZE);
    if(!_buffer){
        log_e("malloc failed");
        return false;
    }
    _size = size;
    _command = command;
    _md5.begin();
    return true;
}