We continue to explore the rp2040 devices, very interesting microcontrollers. All prototype boards come with integrated SPI Flash. Raspberry Pi selected the LittleFS filesystem to manage this storage, a good compromise between functionality and performance.
Here my selection of rp2040 boards Official Pi Pico - Official Pi Pico W - Waveshare rp2040-zero - WeAct Studio rp2040
LittleFS File System
LittleFS is focuses on higher performance and directory support and has reasonable filesystem and per-file overhead (4K minimum file allocation unit).
The LittleFS implementation for the ESP8266 supports filenames of up to 31 characters + terminating zero (i.e. char filename[32]
) and as many subdirectories as space permits.
Add files from IDE to LittleFS
This operation without an extension for the Arduino IDE is not so simple, but here we will explain the most straightforward way.
First, you must download the plugin for Arduino IDE here.
Then you must find your Shetckbook folder, so you must go to file –> Preferences; in that screen, you can find at the top of the window the Sketchbook location
.
Now you must create (if not exist) the folder tools/PicoLittleFS/tool
and add the jar file picolittlefs.jar
there.
Now restart the IDE and on Tools
menu you can find new menu-line Pico LittleFS Data Upload
.
Create data
folder
On Arduino IDE, do Ctrl+K to open a file browser on the sketch’s directory.
Create a directory data to put the data you want to upload.
Set the size of LittleFS on Tools --> Flash size
this is the size of your Microcontroller filesystem.
Upload your sketch, and then click on Pico LittleFS Data Upload
.
Now go to the example sketch to check if all is OK.
Commands
There are some standard commands that you can use with this filesystem
LittreFS.begin()
This method mounts the LittreFS file system and must be called before any other FS APIs are used. Returns true if the file system was mounted successfully; false otherwise.
LittreFS.format()
Formats the file system. Returns true if the formatting was successful.
LittreFS.open(path, mode)
Opens a file. The path should be absolute, starting with a slash (e.g.,/dir/filename.txt). Mode is a string specifying access mode. It can be one of “r,” “w”, and “a”. Meaning of these modes is the same as for fopen C function.
Returns File object. To check whether the file was opened successfully, use the boolean operator.
LittreFS.exists(path)
Returns true if a file with a given path exists; false otherwise.
LittreFS.remove(path): Deletes the file given its absolute path. Returns true if the file was deleted successfully.
LittleFS.rename(pathFrom, pathTo)
Renames file from pathFrom to pathTo. Returns true if the file was renamed successfully. Paths must be absolute.
LittreFS.mkdir(path):
Create a new folder. Returns true if the directory creation succeeded, false otherwise.
LittreFS.rmdir(path):
Remove directory. Returns true if the directory was successfully removed; false otherwise.
LittreFS.info()
Fill all information about the filesystem, and you must pass a structure FSInfo. Returns true if It’s all ok.
struct FSInfo {
size_t totalBytes;
size_t usedBytes;
size_t blockSize;
size_t pageSize;
size_t maxOpenFiles;
size_t maxPathLength;
};
file.seek(offset, mode)
This function behaves like fseek C function. Depending on the value of mode, it moves the current position in a file as follows:
- if the mode is SeekSet, the position is set to offset bytes from the beginning.
- if the mode is SeekCur, the current position is moved by offset bytes.
- if the mode is SeekEnd, the position is set to offset bytes from the end of the file.
- Returns true if the position was set successfully.
file.position()
Returns the current position inside the file in bytes.
file.size()
Returns file size in bytes.
file.name()
Returns file name as const char*.
file.close()
Close the file.
file.getLastWrite()
time_t time of last write (use the internal time to manage date).
file.getCreationTime()
time_t of creation.
file.isDirectory()
Return if It’s a directory
file.isFile()
Return if It’s a file
file.openNextFile()
Set the next file pointer in the directory.
file.rewindDirectory()
Restart the pointer to the first file of the directory.
dir.isFile()
Returns true if the current file pointed to by the internal iterator is a File.
dir.isDirectory()
Returns true if the current file pointed to by the internal iterator is a Directory.
dir.openFile()
This method takes mode argument, which has the same meaning as for LittleFS.open()
function.
dir.fileName()
Return the name of the file currently pointed.
dir.filetime()
Return the last write time of the file currently pointed.
dir.fileCreationTime()
Return the creation time of the file currently pointed.
dir.fileSize()
Return the size of the file currently pointed.
dir.rewind()
Resets the internal pointer to the start of the directory.
dir.next()
Put the internal pointer to the next element of the directory.
Practical examples
Here is a sketch to get info and check all files in your LittleFS.
/*
* Raspberry Pi Pico (or generic rp2040)
* LittleFS get info, read dir and show all file uploaded
* add a data folder to use with Pico LittleFS Data Upload
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org
*
*/
#include "Arduino.h"
#include "LittleFS.h"
void printDirectory(File dir, int numTabs = 3);
void setup()
{
Serial.begin(115200);
while (!Serial) {delay(100);}
Serial.println(F("Inizializing FS..."));
if (LittleFS.begin()){
Serial.println(F("done."));
}else{
Serial.println(F("fail."));
}
// To format all space in LittleFS
// LittleFS.format()
// Get all information of your LittleFS
FSInfo *info;
LittleFS.info(*info);
unsigned int totalBytes = info->totalBytes;
unsigned int usedBytes = info->usedBytes;
unsigned int freeBytes = totalBytes-usedBytes;
unsigned int maxPath = info->maxPathLength;
Serial.println("File sistem info.");
Serial.print("Total space: ");
Serial.print(totalBytes);
Serial.println("byte");
Serial.print("Total space used: ");
Serial.print(usedBytes);
Serial.println("byte");
Serial.print("Total space free: ");
Serial.print(freeBytes);
Serial.println("byte");
Serial.print("Max path lenght: ");
Serial.print(maxPath);
Serial.println("");
Serial.println();
// Open dir folder
File dir = LittleFS.open("/", "r");
// Cycle all the content
printDirectory(dir);
}
void loop()
{
}
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.print(entry.size(), DEC);
Serial.print("\t");
Serial.println("byte");
}
entry.close();
}
}
The result is:
Inizializing FS...
done.
File sistem info.
Total space: 537140992byte
Total space used: 239byte
Total space free: 537140753byte
Max path lenght: 13107322
file1.txt 62 byte
folderTest/
file2.txt 62 byte
file3.txt 62 byte
Here is a sketch with more valuable commands, write a string in a file, read all file content, position on the 9 bytes of the file, and read from there the data.
/*
* Raspberry Pi Pico (or generic rp2040)
* LittleFS write, read and seek file
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org/
*
*/
#include "Arduino.h"
#include "LittleFS.h"
void setup()
{
Serial.begin(115200);
while (!Serial) {delay(100);}
Serial.println(F("Inizializing FS..."));
if (LittleFS.begin()){
Serial.println(F("done."));
}else{
Serial.println(F("fail."));
}
// To remove previous test
// LittleFS.remove(F("/testCreate.txt"));
File testFile = LittleFS.open(F("/testCreate.txt"), "w");
if (testFile){
Serial.println("Write file content!");
testFile.print("Here the test text www.mischianti.org!!");
testFile.close();
}else{
Serial.println("Problem on create file!");
}
testFile = LittleFS.open(F("/testCreate.txt"), "r");
if (testFile){
Serial.println("Read file content!");
/**
* File derivate from Stream so you can use all Stream method
* readBytes, findUntil, parseInt, println etc
*/
Serial.println(testFile.readString());
testFile.close();
}else{
Serial.println("Problem on read file!");
}
testFile = LittleFS.open(F("/testCreate.txt"), "r");
if (testFile){
/**
* mode is SeekSet, position is set to offset bytes from the beginning.
* mode is SeekCur, current position is moved by offset bytes.
* mode is SeekEnd, position is set to offset bytes from the end of the file.
* Returns true if position was set successfully.
*/
Serial.println("Position inside the file at 19 byte!");
testFile.seek(19, SeekSet);
Serial.println("Read file content!");
Serial.println(testFile.readString());
testFile.close();
}else{
Serial.println("Problem on read file!");
}
}
void loop()
{
}
Here is the result of the sketch.
Inizializing FS...
done.
Write file content!
Read file content!
Here the test text www.mischianti.org!!
Position inside the file at 19 byte!
Read file content!
www.mischianti.org!!
Thanks
- Raspberry Pi Pico and rp2040 boards: pinout, specs, and Arduino IDE configuration
- Raspberry Pi Pico and rp2040 boards: integrated LittleFS filesystem
- Raspberry Pi Pico and rp2040 board: ethernet w5500 with plain (HTTP) and SSL (HTTPS) requests
- Raspberry Pi Pico and rp2040 boards: WiFiNINA with ESP32 WiFi Co-Processor
- Raspberry Pi Pico and rp2040 boards: how to use SD card
- Dallas ds18b20
- Connecting the EByte E70 to Raspberry Pi Pico (rp2040) devices and a simple sketch example