I have been running into "bugs" in the FATFS implmentation of the driver. This is directly caused from the way I write to the driver using it in ways that it shouldn't be used. My project requires me to use 1MB of storage and I would prefer not to use FATFS as I have ran into issues with it on roughly 10% of all my units.
Hopefully without redirecting this thread title too much, let me identify my issues so far with the FATFS emulation. Note, this could be bug related, but is quite difficult to fix on my end I believe as there is too many layers between my code and the silicon.
I am happy to send my code directly to the esp-team if required. As this a commerical project I would prefer not to upload it to a public forum.
----
I am afraid I have a few units in field and this just happens after "sometime" (a few weeks of continuous operation) on roughly 10% of ours units. So I cannot quite identify what is the initial trigger to get the units into this state. My guess is that for some reason I have somehow corrupted a file (no idea how) then when I try to write it, I can't so the system creates a new file and continues to write on that one instead.
Specifically what happens is I have a unit that has the below partition table. I am writing to 2 files in the storage section where 1 is a configuration file that only needs to be ~40 bytes and the other is for measurement logging. I am writing to the file in a circular buffer style where it initially fills up the entire partition (with the one file) minus the configuration file. Then once full, starts to overwrite the oldest data at the top of the file. This was my psuedo wear levelling idea to maximise the storage that the esp has.
_Note: If there is an easier way to write to flash directly that would be the prefered option and would likely solve all my issues._
Code: Select all
# Espressif ESP32 Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x4000,
otadata, data, ota, 0xd000, 0x2000,
phy_init, data, phy, 0xf000, 0x1000,
ota_0, app, ota_0, 0x10000, 0x190000,
ota_1, app, ota_1, , 0x190000,
storage, data, fat, , 0xD0000,
Code: Select all
"ÿÿÿÿÿÿÿÿ.ÿÿÿ", size -2
"ÿÿÿÿÿÿÿÿ.ÿÿÿ", size -2
...repeat ÿÿÿÿÿÿÿÿ.ÿÿÿ 256 times...
"CONFIG.LOG", size 0
"PARTICLE.LOG", size 0
First looking into code, obviously built around the c standard, the readdir reads iterates through files, though I found no way to do a stat() on the file that is returned because it requires a file name, that is identical for every entry.
Code: Select all
void Hal_Storage_FatFs::Debug_ListFilesInDir(const char *dir_name) {
DIR *dir;
struct dirent *ent;
if ((dir = opendir(dir_name)) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir(dir)) != NULL) {
struct stat stat_buf;
memset(&stat_buf, 0, sizeof(stat_buf));
long len = 0;
char path[128];
strcpy(path, dir_name);
strcat(path, "/");
strcat(path, ent->d_name);
if (stat(path, &stat_buf) == 0) {
len = stat_buf.st_size;
}
else {
len = -2; //error. app would likely give 0 or -1, so just do this instead.
}
LogD("\"%s\", size %ld", ent->d_name, len);
}
closedir(dir);
}
else {
/* could not open directory */
LogE("FATFS Error couldn't open dir");
}
}
I open the file itself by doing:
Code: Select all
FILE *Hal_Storage_FatFs::OpenFile_ForModifying(const char *file_name) {
if (access(file_name, F_OK) == -1) {
//create new file
LogD("Creating new file.");
FILE *fileTmp = fopen(file_name, "wb");
if (fileTmp != NULL)
fclose(fileTmp);
}
//now actually access the file.
char write_flags[] = "rb+";
FILE *file = fopen(file_name, write_flags);
if (file == NULL) {
LogE("Couldn't open file for modifying '%s'", file_name == NULL ? "NULL" : file_name);
}
return file;
}
Code: Select all
#define FILE_NAME_DATALOG "/data/particle.log"
this->fileHandle = fatfs->OpenFile_ForModifying(FILE_NAME_DATALOG);
So at the end of the day, it would be a lot simpler to write directly to flash if possible