iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
📖

Easy Data Storage on M5Stack with LittleFS

に公開

Hi everyone! Don't you sometimes want to save and load small data on microcontrollers like M5Stack? And there are microcontrollers like the M5Stick series that don't have a microSD card slot, so you might wonder how to store data on them. For all of you, the ESP microcontroller (ESP32/ESP8266, hereafter ESP) used in most M5Stack microcontroller modules has a mechanism to easily handle files on flash memory. It's called LittleFS, and by using LittleFS, you can easily save and load data to and from the microcontroller's flash. This time, I'm summarizing how to use "LittleFS," a filesystem available for ESP.

While other articles also explain how to use LittleFS, I'm compiling it again here as it's information I'll likely refer to repeatedly.
https://zenn.dev/nananauno/articles/62d95c3ccad989#littlefs

What to Do

This time, I'll use an M5Stick series without a microSD card slot to load and display/play text, image, and audio data saved on LittleFS. I used M5StickS3, but feel free to use any microcontroller you like.

Here's how the sample I created works:
・Place appropriate image (png), audio (wav), and text on LittleFS.
・When M5StickS3 starts, load and display the image and text from LittleFS on the screen.
・Press button A to play the audio from LittleFS.

https://x.com/nananauno/status/2023008904947564657?s=20

Environment

The environment I used this time is as follows:

Microcontroller Module

  • M5StickS3

Arduino

  • Arduino IDE 2.x
  • arduino-littlefs-upload 1.6.3
  • Board: M5Stack 3.2.5

PlatformIO

  • pioarduino (platform-espressif32) Arduino v3.3.7 / ESP-IDF v5.5.2.260206

Target Audience

  • Those who want to easily save and load data on M5Stack
  • Those who want to review how to use LittleFS

What is LittleFS?

LittleFS is a mechanism that allows you to easily save data to flash memory on ESP. The capacity depends on the flash size and partition settings, but about 1.5MB is available by default on an 8MB flash. While not a huge size, it's enough to store small texts, images, and audio, isn't it?

For example, it can be used for:

  • Logging sensor readings
  • Storing HTML files for a web server
  • Holding images to display on the screen

The area available for LittleFS changes depending on the partition table being used. There are several commonly used partition tables defined that you can use, or you can define your own. I'll omit the details about partition tables here, so if you're interested, refer to the following resources to configure them.

Commonly used tables are pre-defined:
https://github.com/espressif/arduino-esp32/tree/master/tools/partitions

See here for how to set up partition tables:
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/partition-tables.html

What's the difference from SPIFFS?

SPIFFS was a mechanism used before LittleFS. It could do almost the same things, but LittleFS is more robust, so SPIFFS is now deprecated. When you try to build code using SPIFFS, you'll see a warning like this, won't you? Although old samples on the internet might still use SPIFFS, it's better to use LittleFS from now on.

> SPIFFS has been deprecated. Please consider moving to LittleFS or other filesystems.

What's the difference from NVS?

Have you heard of NVS? There's also a mechanism called NVS for storing values in flash. The difference between NVS and LittleFS is that NVS uses a key-value format and the storage capacity is only a few KB. Key-value means storing and retrieving values based on a specified key, which is not suitable for holding long texts, images, or audio. Its primary purpose is to hold short values like configuration settings, Wi-Fi SSIDs, or passwords.

I won't explain how to use NVS this time, but hopefully, I can explain it on another occasion.

Let's Put Data in the LittleFS Area

To place data in the LittleFS area, you need to first create a data folder and put all the files you want to upload to the microcontroller's flash memory into it. The location of the data folder and the upload method differ between Arduino and PlatformIO, so I'll explain each method.

Execute the created application and data writing to the LittleFS area in the following order. If the partition table used by the already written application is exactly the same, there should be no problems, but if a different partition table is used, it may cause writing to fail.

  1. Write to the application area
  2. Write to the LittleFS area

From Arduino

Preparation
To write to the LittleFS area from the Arduino IDE, you need to install a plugin. Please refer to the following repository to install it.

https://github.com/earlephilhower/arduino-littlefs-upload

Once the plugin is installed, open your sketch folder and create a data folder in the same location as your .ino file. Then, place the data you want to write into the data folder.

Upload
Press Cmd+Shift+P on Mac or Ctrl+Shift+P on Windows, and then run Upload LittleFS to Pico/ESP8266/ESP32 from the command palette to upload data to the flash.

From PlatformIO

Preparation
To write to the LittleFS area with PlatformIO, create a data folder in the project root (at the same level as src). Then, place the data you want to write into the data folder.

Upload
From the left sidebar of VS Code, select the PlatformIO icon, and then select Upload Filesystem Image under PROJECT TASKS to upload to the microcontroller's flash. For M5StickS3, writing was possible while it was in boot mode.

Let's Create It

Now, let's explain how to actually use the data written to LittleFS. In the sample code, the following three types of data are read from the LittleFS area and displayed or played:

  • Images
  • Text
  • Audio

Since M5Stack is used, M5Unified is utilized for screen display and audio playback.

Initializing LittleFS

To use LittleFS, you need to include LittleFS.h. The key is to include it before M5Unified.h if you are using M5Unified. If the order is reversed, a build error will occur.

LittleFS.begin()
This initializes LittleFS. If you pass true as an argument, LittleFS will automatically format the area if it's not already formatted. When uploading data from the data folder, you should be fine without true (default is false), but if mounting fails, try setting it to true.

Reading and Displaying Images (PNG)

If you use M5Unified, reading and displaying images from LittleFS is very easy! Just call drawPngFile.

M5.Display.drawPngFile(LittleFS, "/xxx.png", 0, 0)
This reads /xxx.png from LittleFS and displays it on the screen. 0,0 are the x,y coordinates to draw the image. BMP and JPEG files can also be read and displayed using drawBmpFile and drawJpgFile. The path on LittleFS specified here must start with a / (slash).

Please refer to this for image drawing functions available with M5Unified:
https://docs.m5stack.com/ja/arduino/m5gfx/m5gfx_image

Reading and Displaying Text

Reading text files is almost the same as general file reading. Here's an example of reading a file from LittleFS at the specified path and returning the read text. By calling readString(), you can read the entire text from the file.

String readTextFile(const char* path) {
  File f = LittleFS.open(path);
  if (!f) return "Not found";
  String s = f.readString();
  f.close();
  return s;
}

Reading and Playing Audio (WAV)

Using M5Unified makes playing audio files very simple! Just read the WAV file data from LittleFS and pass it to M5Unified's playWav. Here's an example of reading a WAV file from LittleFS. It reads all the binary data of the file using readBytes.

size_t loadWavFromFS(const char* path) {
  File wavFile = LittleFS.open(path, "r");
  if (!wavFile) {
    log_e("Failed to open WAV file: %s", path);
    return 0;
  }

  size_t fileSize = wavFile.size();
  wavdata = new uint8_t[fileSize];
  wavFile.readBytes((char*)wavdata, fileSize);
  wavFile.close();
  return fileSize;
}

To play an audio file with M5Unified, you just need to pass the read WAV data and its size.

M5.Speaker.playWav(wavdata, wavdata_size);

Sample Code

Here is the complete code for reading, displaying, and playing images, text, and audio.

#include <LittleFS.h>   // Always include before M5Unified
#include <M5Unified.h>
#include <Preferences.h>

// Holds Wav data
const uint8_t *wavdata;
size_t wavdata_size=0;

// Reads a WAV file with the specified filename from LittleFS
size_t loadWavFromFS(const char* path) {
  File wavFile = LittleFS.open(path, "r");
  if (!wavFile) {
    log_e("Failed to open WAV file: %s", path);
    return 0;
  }

  size_t fileSize = wavFile.size();
  wavdata = new uint8_t[fileSize];
  wavFile.readBytes((char*)wavdata, fileSize);
  wavFile.close();
  return fileSize;
}

// Reads a text file with the specified filename from LittleFS
String readTextFile(const char* path) {
  File f = LittleFS.open(path);
  if (!f) return "Not found";
  String s = f.readString();
  f.close();
  return s;
}

void setup() {
  M5.begin();

  M5.Power.setExtOutput(false);
  M5.Speaker.setVolume(178); // Speaker volume setting
  
  // Initialize LittleFS
  if (!LittleFS.begin()) {
    log_e("LittleFS mount failed");
    return;
  }

  // Screen display settings
  M5.Display.setRotation(1);  // Set screen to landscape orientation
  M5.Display.fillScreen(BLACK);
  M5.Display.setTextColor(WHITE, BLACK);
  M5.Display.setCursor(0, 0);
  M5.Display.setTextSize(2);

  // Read PNG file from LittleFS and display on screen
  M5.Display.drawPngFile(LittleFS, "/teto.png", 0, 0);

  // Read text file from LittleFS and display on screen
  String text = readTextFile("/teto.txt");
  M5.Display.println(text);

  // Read WAV file from LittleFS
  wavdata_size = loadWavFromFS("/teto1.wav");
  if(wavdata_size == 0) {
    log_e("Failed to load WAV file");
  }else{
    log_i("Loaded WAV file: %u bytes", wavdata_size);
  }  
}

void loop() {
  M5.update();
  
  if (M5.BtnA.wasPressed()) { 
    // Play audio when Button A is pressed
    bool result = M5.Speaker.playWav(wavdata, wavdata_size);
    if(!result){
      log_e("playWav failed");
    }else{
      log_i("playWav started");
    }
  }
}

Arduino Board Settings
For reference, here are the Arduino board settings I used for M5StickS3. I haven't changed much from the default, but if it's not working correctly, please check these settings.

USB CDC On Boot: "Enabled"
CPU Frequency: "240MHz (WiFi)"
Core Debug Level: "None"
USB DFU On Boot: "Disabled"
Erase All Flash Before Sketch Upload: "Disabled"
Events Run On: "Core 1"
Flash Mode: "QIO 80MHz"
Flash Size: "8MB (64Mb)"
JAG Adapter: "Disabled"
Arduino Runs On: "Core 1"
USB Firmware MSC On Boot: "Disabled"
Partition Scheme: "8M with spiffs (3MB APP/1.5MB SPIFFS)"
PSRAM: "OPI PSRAM"
Upload Mode: "UART0 / Hardware CDC"
Upload Speed: "921600"
USB Mode: "Hardware CDC and JTAG"

Even though the Partition Scheme says "spiffs", LittleFS can still be used with these settings.

Platformio.ini
For reference, here are the platformio.ini settings I used for M5StickS3. The most important setting is board_build.filesystem = littlefs. Don't forget this.

[env]
;platform = espressif32
platform = https://github.com/pioarduino/platform-espressif32.git
framework = arduino
lib_deps =
    M5Unified=https://github.com/m5stack/M5Unified

[env:esp32-s3-devkitc-1]
board = esp32-s3-devkitc-1
board_build.arduino.partitions = default_8MB.csv
board_build.arduino.memory_type = qio_opi
board_build.filesystem = littlefs
build_flags =
    -DESP32S3
    -DBOARD_HAS_PSRAM
    -mfix-esp32-psram-cache-issue
    -DCORE_DEBUG_LEVEL=5
    -DARDUINO_USB_CDC_ON_BOOT=1
    -DARDUINO_USB_MODE=1
lib_deps =
    ${env.lib_deps}
    M5PM1=https://github.com/m5stack/M5PM1

Summary

This time, I've summarized LittleFS, which allows easy data retention on flash memory with ESP. With M5Stack, using it with M5Unified made it very easy to read data from LittleFS and display it on the screen or play audio. It's a very convenient mechanism for microcontrollers without an microSD card slot or when you want to handle small amounts of data. Writing data is also simple: just create a data folder and upload the files, so it seems easy to carry data around as long as you pay attention to the size! Please make use of LittleFS to easily store data on flash and create various things!

See you next time!

GitHubで編集を提案

Discussion