In this ESP32 tutorial, we will learn to use ESP32 SPIFFS (SPI flash file system) and how to create, write and read files. Furthermore, we will also see how to upload files to SPIFFS such as text, HTML, CSS and JavaScript files. etc. Additionally, we will see how to create SPIFFS partition in flash of ESP32. At the end, we will use the SPIFFS APIs available in ESP-IDF required to initialize and mount the SPIFFS partition and then create, write and read data from the files.
SPIFFS Introduction
The ESP32 development board contains a Serial Peripheral Interface Flash File System commonly referred to as SPIFFS. It is a lightweight file system which is formed by partitioning the SPI NOR flash of ESP32 into binary file region and file system region. Just like the ESP32 flash memory, this file system is connected by the SPI bus. It helps to store files in SPI flash without having to use any external memory with ESP32.
Using SPIFFS with ESP32, users can easily create, read and write files to/from the flash memory of the board. Due to limited number of write cycles of flash memory, it is not recommended to use the write functionality but it is still present. In short we can read, write, delete and close files saved on SPIFFS in a very handy manner. Let us learn how to accomplish this using ESP-IDF.
ESP32 SPIFFS Upload and Read File Content using ESP-IDF
In this section, let us build and create a project with ESP-IDF where we will read from a file saved on ESP32 SPIFFS.
Create Project
Open your VS Code and head over to View > Command Palette. Type ESP-IDF: New Project in the search bar and press enter.
Specify the project name and directory. We have named our project ‘ESP32_SPIFFS_READ_FILE.’ For the ESP-IDF board, we have chosen the custom board option. For ESP-IDF target, we have chosen ESP32 module. Click ‘Choose Template’ button to proceed forward.
In the Extension, select ESP-IDF option:
We will click the ‘sample_project’ under the get-started tab. Now click ‘Create project using template sample_project.’
You will get a notification that the project has been created. To open the project in a new window, click ‘Yes.’
This opens our ESP32_SPIFFS_READ_FILE project that we created inside the EXPLORER tab. There are several folders inside our project folder. This is the same for every project which you will create through ESP-IDF Explorer.
Let us first create show you how to create some additional files which are required for this project.
Create a new file and name it as ‘partitions.csv.’ Copy the data given below in that file and save it. We want to add our own custom partition table hence we will be using this file.
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, , 0x6000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 1M,
storage, data, spiffs, , 1M
After creating the partitions.csv file now let us create a folder named ‘spiffs_data‘ and inside that folder create a text file named ‘data.txt.’ This is the file that we will read from the SPI flash memory. You can add any text in this file. For example purposes, we will add the following text to our data.txt file and save it.
This is a getting started guide to read, save and write to SPIFFS from ESP32 using ESP-IDF.
Head over to the folder named ‘main’ and open CMakeLists.txt file. Include the following line at the end of this file and save it.
spiffs_create_partition_image(storage ../spiffs_data FLASH_IN_PROJECT)
Project Configuration
Lets first head over to the menuconfig. Click the icon shown below. It opens the ESP-IDF SDK Configuration Editor.
Scroll down and open the Serial Flasher config. Here you can set the flash SPI mode, flash sampling mode, flash SPI speed, flash size etc. Set the parameters as shown below and save it. Note that we have set the flash size as 4 MB.
Next scroll down and click Partition Table. Here we will select ‘custom partition table CSV’ option from Partition Table, give the name of the CSV file that we created and the offset of the partition table.
ESP-IDF SPIFFS Read File Code
The main folder contains the source code meaning the main.c file will be found here. Now go to main > main.c and open it. Copy the code given below and save it.
#include <stdio.h>
#include "esp_spiffs.h"
#include "esp_log.h"
#define TAG "spiffs"
void app_main(void)
{
esp_vfs_spiffs_conf_t config = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 5,
.format_if_mount_failed = true,
};
esp_vfs_spiffs_register(&config);
FILE *file = fopen("/spiffs/data.txt", "r");
if(file ==NULL)
{
ESP_LOGE(TAG,"File does not exist!");
}
else
{
char line[256];
while(fgets(line, sizeof(line), file) != NULL)
{
printf(line);
}
fclose(file);
}
esp_vfs_spiffs_unregister(NULL);
}
How the Code Works?
We start off by including the necessary libraries for this project that includes esp_spiffs.h for the ESP32 SPIFFS functionality and esp_log.h as the logging library to display informational logs.
#include <stdio.h>
#include "esp_spiffs.h"
#include "esp_log.h"
This code uses Informational Logging. The log function takes in two arguments. The first argument is the tag and the second argument is a formatted string. Therefore this global variable will be useful while calling the ESP_LOGI() functions. Here, “spiffs” is the tag that will be used while logging.
#define TAG "spiffs"
First, we have the configuration structure for for esp_vfs_spiffs_register. It holds the following memebers:
- base_path which is the file path prefix linked with the file system. In our case it is “/spiffs.”
- partition_label which is the label of SPIFFS partition for usage. It is optional. We have set it to NULL hence first partition with subtype=spiffs will be used.
- max_files is the maximum number of files that can be opened at a time. In our case, we have set it as 5.
- format_if_mount_failed is set to true. Therefore it will format the file system incase of failure during mount.
To register and mount SPIFFS to VFS with given path prefix, we call the function, esp_vfs_spiffs_register(). This function takes in a single parameter which is the pointer to esp_vfs_spiffs_conf_t configuration structure defined previously.
esp_vfs_spiffs_conf_t config = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 5,
.format_if_mount_failed = true,
};
esp_vfs_spiffs_register(&config);
The ESP32 SPIFFS file system follows a flat structure. Therefore it does not support directories. For example if SPIFFS is mounted under /spiffs, then creating a file with the path: /spiffs/tmp/myfile.txt will create a file called /tmp/myfile.txt in SPIFFS, instead of myfile.txt in the directory /spiffs/tmp.
To open a file, fopen() is the standard function used. Specify the file path as the first parameter and the mode as the second parameter. In this case, the file path is “/spiffs/data.txt” and it is being opened in read (r) mode. Here ‘file’ is the file pointer that is pointing to the file type.
FILE *file = fopen("/spiffs/data.txt", "r");
If the file does not exist on SPIFFS then the ESP-IDF terminal will print the message that the file does not exist. Otherwise, if the file is present, then it reads the characters from the file and prints them on the terminal. This is achieved by calling the fgets() function. We use the function fgets() to read the characters from the file that gets stored in the array of characters ‘line’. The first parameter is the buffer which is ‘line’ in our case. The second parameter is number of characters which is ‘sizeof(line)’ and the third parameter is the file pointer which is ‘file’ in our case. Afterwards, we close the file using fclose() function and pass the file pointer as a parameter inside it.
if(file ==NULL)
{
ESP_LOGE(TAG,"File does not exist!");
}
else
{
char line[256];
while(fgets(line, sizeof(line), file) != NULL)
{
printf(line);
}
fclose(file);
}
At the end we unregister and unmount SPIFFS from VFS by calling esp_vfs_spiffs_unregister() function. This function takes in a single parameter which is the partition label that we defined in the esp_vfs_spiffs_conf_t configuration structure. It was NULL in our case.
esp_vfs_spiffs_unregister(NULL);
Compiling the Sketch
To flash your chip, type the following command in the serial terminal. Remember to replace the COM port with the one through which your board is connected.
idf.py -p COMX flash monitor
After the code flashes successfully, the ESP-IDF displays the text saved on our data.txt file which is uploaded on the ESP32 SPIFFS.
ESP32 SPIFFS Create and Write Files using ESP-IDF
In this section, let us build and create a project with ESP-IDF where we will create a file and upload it t ESP32 SPIFFS and write to it.
Create Project
Open your VS Code and head over to View > Command Palette. Type ESP-IDF: New Project in the search bar and press enter.
Specify the project name and directory. We have named our project ‘ESP32_SPIFFS_CREATE_WRITE.’ For the ESP-IDF board, we have chosen the custom board option. For ESP-IDF target, we have chosen ESP32 module. Click ‘Choose Template’ button to proceed forward.
In the Extension, select ESP-IDF option:
We will click the ‘sample_project’ under the get-started tab. Now click ‘Create project using template sample_project.’
You will get a notification that the project has been created. To open the project in a new window, click ‘Yes.’
This opens our project that we created inside the EXPLORER tab. Create a new file and name it as ‘partitions.csv.’ Copy the data given below in that file and save it. We want to add our own custom partition table hence we will be using this file.
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, , 0x6000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 1M,
storage, data, spiffs, , 1M
Project Configuration
Lets first head over to the menuconfig. It opens the ESP-IDF SDK Configuration Editor.
Scroll down and open the Serial Flasher config. Here you can set the flash SPI mode, flash sampling mode, flash SPI speed, flash size etc. Set the parameters as shown below and save it. Note that we have set the flash size as 4 MB.
Next scroll down and click Partition Table. Here we will select ‘custom partition table CSV’ option from Partition Table, give the name of the CSV file that we created and the offset of the partition table.
ESP-IDF SPIFFS Create New File and Write Code
The main folder contains the source code meaning the main.c file will be found here. Now go to main > main.c and open it. Copy the code given below and save it.
#include <stdio.h>
#include "esp_spiffs.h"
#include "esp_log.h"
#define TAG "spiffs"
void app_main(void)
{
esp_vfs_spiffs_conf_t config = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 5,
.format_if_mount_failed = true,
};
esp_vfs_spiffs_register(&config);
/*Create file with name hello.txt */
ESP_LOGE(TAG, "Creating New file: hello.txt");
FILE *f = fopen("/spiffs/hello.txt", "w");
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
ESP_LOGE(TAG, "Writing data to file: hello.txt");
fprintf(f, "Welcome to ESP32Tutorials.com!\n"); // write data to hello.txt file
fclose(f);
ESP_LOGI(TAG, "File written");
/* read data from hello.txt file */
ESP_LOGE(TAG, "Reading data from file: hello.txt");
FILE *file = fopen("/spiffs/hello.txt", "r");
if (file == NULL)
{
ESP_LOGE(TAG, "File does not exist!");
}
else
{
char line[256];
while (fgets(line, sizeof(line), file) != NULL)
{
printf(line);
}
fclose(file);
}
esp_vfs_spiffs_unregister(NULL);
}
How the Code Works?
Most of the code is the same as we used previously while reading from the file saved on SPIFFS. Here, however, we will create a new file and write to it and then read its contents before closing it.
To open or create a new file, we will use fopen() function. Specify the file path as the first parameter and the mode as the second parameter. In this case, we want to create a new file called hello.txt hence the file path is “/spiffs/hello.txt” and it is being created in write (w) mode. Here ‘f’ is the file pointer that is pointing to the file type.
ESP_LOGE(TAG, "Creating New file: hello.txt");
FILE *f = fopen("/spiffs/hello.txt", "w");
In case the file does not exist on SPIFFS then the ESP-IDF terminal will print the message that the file does not exist.
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
After creating the new file, we will write a string to the file. We will use fprintf() function to write to a file. It takes in two parameters. The file pointer and the string that we want to print to the file. In our case, we are writing the string “Welcome to ESP32Tutorials.com!” on our file.
After that we will close our file to ensure that the data is written on it. In order to close the file, fclose() function is used. This takes in the file pointer as a parameter inside it which is ‘f’ in our case.
ESP_LOGE(TAG, "Writing data to file: hello.txt");
fprintf(f, "Welcome to ESP32Tutorials.com!\n"); // write data to hello.txt file
fclose(f);
ESP_LOGI(TAG, "File written");
To read the hello.txt file, we first open it in read mode using fopen() function. Specify the file path as the first parameter and the mode as the second parameter. In this case, we want to open file hello.txt in read mode, hence the file path is “/spiffs/hello.txt” and it is being opened in read (r) mode. Here ‘file’ is the file pointer that is pointing to the file type.
If the file does not exist on SPIFFS then the ESP-IDF terminal will print the message that the file does not exist. Otherwise, if the file is present, then it reads the characters from the file and prints them on the terminal. This is achieved by calling the fgets() function. We use the function fgets() to read the characters from the file that gets stored in the array of characters ‘line’. The first parameter is the buffer which is ‘line’ in our case. The second parameter is number of characters which is ‘sizeof(line)’ and the third parameter is the file pointer which is ‘file’ in our case. Afterwards, we close the file using fclose() function and pass the file pointer as a parameter inside it.
ESP_LOGE(TAG, "Reading data from file: hello.txt");
FILE *file = fopen("/spiffs/hello.txt", "r");
if (file == NULL)
{
ESP_LOGE(TAG, "File does not exist!");
}
else
{
char line[256];
while (fgets(line, sizeof(line), file) != NULL)
{
printf(line);
}
fclose(file);
}
At the end we unregister and unmount SPIFFS from VFS by calling esp_vfs_spiffs_unregister() function.
esp_vfs_spiffs_unregister(NULL);
Compiling the Sketch
To flash your chip, type the following command in the serial terminal. Remember to replace the COM port with the one through which your board is connected.
idf.py -p COMX flash monitor
After the code flashes successfully, the ESP-IDF terminal shows different messages where it first creates a new file called hello.txt, then writes on it and then reads from it.
If you are using Arduino IDE instead of ESP-IDF, you can refer to this:
- Upload Files to ESP32 SPIFFS FileSystem with VS Code and PlatformIO IDE
- Install ESP32 Filesystem Uploader in Arduino IDE – SPIFFS
You may also like to read:
- ESP-IDF ESP32 Deep Sleep Modes and Wake up Sources
- ESP32 SPI Master Slave Communication with ESP-IDF
- ESP32 Web Server with ESP-IDF
- ESP32 UART Communication using ESP-IDF
We are a team of experienced Embedded Software Developers with skills in developing Embedded Linux, RTOS, and IoT products from scratch to deployment with a demonstrated history of working in the embedded software industry. Contact us for your projects: admin@esp32tutorials.com
if the text does not appear in the first code,adding printf(“\n”);to the end of the loop solves the problem.
like
else
{
char line[256];
while(fgets(line, sizeof(line), file) != NULL)
{
printf(line);
}
fclose(file);
}
printf(“\n”); //add this
esp_vfs_spiffs_unregister(NULL);
}