simotin13's message

simotin13といいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

ESP32でのLittleFSの使い方について

ESP32を使っていて外部のサーバと通信するような場合、サーバのAPIを呼び出して、JSON形式のデータを取得するようなことがあります。
一時的に利用するデータであればメモリ上の変数に保持しておけばよいですが、永続的に保存したい場合に、ファイルに保存しておきたいという場合があると思います。
ファイルに保存する場合、ESP32ではLittleFSというファイルシステムを使ってファイルにするのが推奨されているので、タイトルの通りESP32でLittleFSを利用してファイルに保存する方法について書いておきたいと思います。

ESP32での不揮発性ストレージへの保存について

上記のように不揮発性の領域にデータを永続的に保存したい場合、
ESP32では、小規模な設定値やセンサーなどの補正値といったデータであれば、NVS(Non-Volatile Storage)というキーバリュー型のストレージを利用するのが簡単で便利です。
例えば、 device_name: "ESP32", boot_count: 5 といったように、キーと値のペアで数値や文字列、任意のバイナリデータを保存することができます。

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_flash.html

ただし、NVSでは大規模なデータを保存するのには適していません。
https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_flash.html

文字列型は最大 4000 バイト、可変長のBlob型(バイナリ)で508,000バイトまで保存可能です。
大規模なデータを保存する場合は、WindowsやMac、Linuxと同様にファイルに保存することができます。
ESP32ではFATファイルシステム、SPIFFS、LittleFSの3種類のファイルシステムが利用可能です。
それぞれの特徴をまとめると以下の表のようになります。

ファイルシステム 特徴 電断耐性 ディレクトリのサポート* 持ち運び可能性*
FAT WindowsやMac、Linuxでサポートされている あり
SPIFFS SPIFlash向けのファイルシステム なし
LittleFS 電源障害やフラッシュ書き込みを考慮した組み込み向けファイルシステム あり

ESP32ではFATファイルシステムがサポートされているので、SDカードなどの記憶メディアを利用する場合は、FATファイルシステムを利用することでデータの持ち運びが可能になります。
ただし電源断耐性はLittleFSと比べると高くありません。電源障害が発生する可能性がある場合は、SPIFFSやLittleFSを利用することが推奨されます。
SPIFFSはSPIFlash向けのファイルシステムで、ESP32の内蔵フラッシュメモリに保存することができます。
ただし、電源障害に対する耐性はLittleFSと比べて弱く、またディレクトリのサポートもないため、ESP32の内蔵フラッシュメモリに保存する場合は、最近ではLittleFSを利用することが推奨されているようです。

LittleFSを利用する準備

LittleFSはESP-IDFの外部コンポーネントとして提供されているため、明示的にプロジェクトに追加する必要があります。
プロジェクトへの外部コンポーネントの追加は、idf.py add-dependencyコマンドを使うと簡単に行うことができます。

idf.py add-dependency joltwallet/littlefs==1.20.4

プロジェクトで使用するコンポーネントの情報はidf_component.yml に記載されます。
add-dependencyコマンドを使わずに直接このファイルを編集する形で外部コンポーネントを追加することも可能です。

ちなみに、一度 idf.py build を実行した後に add-dependencyコマンドを実行してコンポーネントを追加した場合は、
ビルドキャッシュが残っているため、追加したコンポーネントのヘッダーファイルが見つからずにビルドエラーになってしまいます。
この場合は、

idf.py clean

を実行して、ビルドキャッシュを削除する必要があります。

パーティションテーブルの設定

LittleFSを利用するためには、パーティションテーブルにLittleFS用のパーティションを追加する必要があります。
ESP-IDFのプロジェクトでは、CSV形式でパーティションテーブルを定義することができます。
プロジェクトのルートディレクトリに、partitions.csv というファイルを作成して、以下のようにLittleFS用のパーティションを追加します。

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  24K,
phy_init, data, phy,     0xf000,  4K,
factory,  app,  factory, 0x10000, 1M,
littlefs, data,littlefs, ,        1M,

この例では、littlefs という名前のパーティションを追加しています。

partitions.csvを作成しただけでは、LittleFSが利用できるわけではありません。
パーティションテーブルを定義した後は、プロジェクトのコンフィギュレーションで、Partition Tableの項目をCustom partition table CSV に変更して、先ほど作成した partitions.csv を指定します。
これで、ビルド時にESP32のフラッシュメモリにLittleFS用のパーティションが作成されるようになります。

LittleFSを利用するコードの例

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_system.h"

#include "nvs_flash.h"
#include "nvs.h"

#include "esp_littlefs.h"

static const char *TAG = "storage-sample";

void app_main(void)
{
    esp_vfs_littlefs_conf_t conf = {
        .base_path = "/littlefs",
        .partition_label = NULL,
        .format_if_mount_failed = true,
        .dont_mount = false
    };

    esp_err_t ret = esp_vfs_littlefs_register(&conf);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to mount LittleFS (%s)", esp_err_to_name(ret));
        return;
    }
    ESP_LOGI(TAG, "LittleFS mounted");

    // logsフォルダの存在チェック
    struct stat st;
    if (stat("/littlefs/logs", &st) != 0) {
        ESP_LOGI(TAG, "logs folder does not exist. Creating...");
        ret = mkdir("/littlefs/logs", 0777);
        if (ret != 0) {
            ESP_LOGE(TAG, "Failed to create logs folder");
            return;
        }
    } else {
        ESP_LOGI(TAG, "logs folder exists");
    }

    // hoge.txtへの書き込み
    const char *write_buf = "Hello, LittleFS!";
    FILE *fp = fopen("/littlefs/hoge.txt", "a");
    if (fp == NULL) {
        ESP_LOGE(TAG, "Failed to open hoge.txt for appending");
        return;
    }

    fwrite(write_buf, 1, strlen(write_buf), fp);
    fwrite("\n", 1, 1, fp);
    fclose(fp);

    esp_vfs_littlefs_unregister(conf.partition_label);
    ESP_LOGI(TAG, "LittleFS unmounted");
}

LittleFSを利用するためには、まずLittleFSをマウントする必要があります。

ファイルやディレクトリ操作に対応する関数

LittleFSをマウントした後は、ファイルやディレクトリの操作に対応する関数を利用して、ファイルの読み書きやディレクトリの作成などを行うことができます。
操作はC言語の標準ライブラリの関数で利用することができます。

主な操作で使用する関数は以下の通りです。

操作 関数
ファイルの作成 fopen
ファイルの読み書き fread, fwrite
ファイルのクローズ fclose
ディレクトリの作成 mkdir
ディレクトリの削除 rmdir
ディレクトリ情報へのアクセス opendir,readdir,closedir
ファイルの削除 unlink
ファイル・ディレクトリの存在確認 stat

ESP-IDFでの開発について

LittleFSのようなストレージ管理は、ESP-IDFのメモリ構造やパーティションテーブルの理解があると、より安全に設計できます。

  • パーティションテーブルについて
  • NVSとファイルシステムの使い分け
  • PSRAMと内部RAMの違い

といった、ESP-IDF開発で必要になる基礎を体系的に解説しています。

FreeRTOSやWiFi・BLE通信、周辺機能(GPIO,UART,I2C)の使い方など幅広くまとめたコースになっておりますのでこれから本格的にESP32・ESP-IDFを使って開発される方はぜひご覧ください。

www.udemy.com

自宅に太陽光発電を設置した結果~4年目~

太陽光発電・蓄電池のシステムを自宅に設置して4年目の結果が出たので簡単に振り返ってみたいと思います。

1年目の結果は以下の記事を参照。
mcommit.hatenadiary.com

2年目の結果は以下の記事を参照。
mcommit.hatenadiary.com

3年目の結果は以下の記事を参照。
mcommit.hatenadiary.com

2025年のデータ

発電データとグラフは以下のような結果です。

2025年発電データ
2025年発電量グラフ

4年間の推移

発電量(kWh) 消費量(kWh) 売電量(kWh) 買電量(kWh) 蓄電池放電量(kWh) 自給率(%)
2022 2,378 4,306 386 2,397 1,047 55
2023 2,441 4,344 435 2,423 1,030 56
2024 2,384 4,441 355 2,501 1,041 54
2025 2,471 4,758 360 2,737 1,050 52

2025年は2024年と比べると87kWh発電量が増えました。発電量では設置した2022年以降過去最高です。
一方で消費量・買電量も過去最高になっています。これは新しくエアコンを設置したためかと思います。
ここ数年の夏場の暑さが尋常じゃないのも理由の1つかもしれません。

このブログを書いているのは太陽光のパネルの劣化や故障がないかに気づくためという意図もあるのですが今のところしっかりと発電しているので故障はし
ていないようです。

シミュレーション結果との比較

導入時に営業の人が持ってきたシミュレーション結果との比較を見てみましょう。
年間推定発電量は2,921kWhなので2025年の結果と比較すると500kWhの差異があり、相変わらずこのシミュレーション結果には遠く及ばない結果になっています。

https://cdn-ak.f.st-hatena.com/images/fotolife/s/simotin13/20230129/20230129011749.png

電気料金と再エネ賦課金の推移について

2025年の再エネ賦課金は3.98円だったようです。
この記事を書いている2026年2月時点では2026年4月以降のの再エネ賦課金は未確定ですが、4円を上回るとの予想が出ているようです。

感想

再エネ賦課金が値上がりしていくのは気分がいいものではありません。
自然エネルギーをより効率よく利用できるような技術の進歩に期待したいです。

ESP32でのPSRAMへのstatic変数の配置について

ESP-IDFでアプリケーションを実装していると、メモリの問題に直面することがあります。
例えばESP32S3では、内蔵RAMが512KB搭載されていますが、これには命令キャッシュ専用のメモリ領域が含まれており、またブートローダやFreeRTOSのカーネルも内蔵RAMを使用するため、実際に開発者が利用できるのはおおむね400KB未満になります。
ESP32ではライブラリが充実していることもあり調子に乗って高機能なアプリケーションを実装しようとすると、内蔵RAMだけではすぐにメモリ不足になってしまいます。

この問題を解決するために、ESP32ではPSRAM(Pseudo Static RAM)を利用することができます。PSRAMは外部RAMとして接続され、大容量のメモリを提供します。これにより、内蔵RAMの制約を克服し、より複雑なアプリケーションを実装することが可能になります。
PSRAMはチップ外部のSPIで接続されている、MBオーダーの大容量RAMで、ESP32S3では最大16MBのPSRAMを利用することができます。

ただし、PSRAMはデフォルトでは無効になっているため、PSRAMを利用するためには、 menuconfigでPSRAMの設定を有効にする必要があります。
具体的には、CONFIG_SPIRAM_SUPPORT を有効にすることで、PSRAMを利用できるようになります。
これにより、malloc関数で確保する領域をPSRAMから確保できるようになります。また、タスクのスタックもPSRAMから確保できるようになります。
ちなみにPSRAMに関わらず、malloc/freeを使ってメモリの確保・解放を繰り返していると、メモリが断片化により最終的に、メモリを確保できなくなってしまう可能性があります。
利用頻度が高いは場合はあらかじめ必要なメモリを確保しておいた上で、確保したメモリを使いまわすことをお勧めします。

このように、PSRAMを利用することでメモリ不足の問題は解決できて、万事うまくいきそうですが、実際にはそうはいきません。

実は、AESなどの暗号化処理やTLS通信などでは、計算にDMAが利用されますが、内蔵メモリにデータが配置されていることが前提になっているため、
スタックをPSRAMから確保すると実行時にエラーが発生します。
このため暗号化計算を利用するタスクのスタックをPSRAMから確保することはできません。
また、PSRAMから確保した変数も暗号化計算などの処理で利用すると、実行時にエラーが発生する可能性があります。
最近ではHTTPもMQTTもTLS通信が前提になっているため、このような通信プロトコルを扱うタスクではPSRAMから確保した変数を暗号化計算などの処理で利用することはできません。
内蔵RAMから確保した変数を利用する必要があります。

内蔵RAMの使用量を節約するとなると、各タスクのスタックサイズを節約したいところですが、実は static変数(グローバル変数)もPSRAMから確保することができます。
ESP-IDFでは EXT_RAM_BSS_ATTR という属性を使用して、static変数をPSRAMに配置することができます。
具体的には以下のような宣言になります。

EXT_RAM_BSS_ATTR static uint8_t my_buffer[1024];

これにより、my_bufferはPSRAMに配置されます。
バッファなどの大きな変数はstatic変数として確保することが多いと思いますが、PSRAMに配置することで、内蔵RAMの使用量を節約することができます。
ちなみに static変数をPSRAMに配置するには menuconfigで CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY を有効にする必要があります。
注意点として、初期値のないstatic変数はBSSセクションに配置され、PSRAMから確保できますが、初期値のあるstatic変数はデータセクションに配置されるため、PSRAMから確保できません。
したがって、初期値のないstatic変数を使用する場合にのみ、EXT_RAM_BSS_ATTR を使用してPSRAMに配置することができます。

参考サイト

docs.espressif.com

体系的にESP-IDFを学びたい方へ

PSRAMの扱いはESP-IDF開発の中でも特につまずきやすいポイントの1つです。
本記事ではstatic変数をPSRAMに配置する方法を紹介しましたが、実際の開発では

  • FreeRTOSタスク設計
  • WiFi/BLE通信
  • NVSやLittleFSなどFlash管理
  • デバッグ方法(gdb)

なども含めて、全体像を理解しておくと開発中の遠回りが減ります。

ESP32・ESP-IDFについてUdemyで「実践で学ぶESP32・ESP-IDF入門講座」というコースを公開しています。
www.udemy.com

ESP-IDF開発を基礎から実機で学べる構成にしていますので興味ある方はぜひご視聴ください。

UdemyでESP32・ESP-IDFのコースの提供を始めました。

久しぶりにこのブログを更新します。
このたびUdemyで「実践で学ぶESP32・ESP-IDF入門講座」を公開しました。

新規に販売を始めたばかりですので、期間限定の割引価格で公開しています。
www.udemy.com

コースを作った背景

文字通り、ESP32・ESP-IDFについて学習するコースです。
この数年ESP32シリーズを使った、スマートホームの規格であるMatterの製品開発に携わっているのですが、私自身、数年前にプロジェクトに参加するまではESP32に関する経験が全くありませんでした。
ESP32の開発環境であるESP-IDFは、ESP32が持つ機能を非常にうまく抽象化していて、サンプルコードも充実しているので、他のマイコンと比べて初心者にもやさしい開発環境になっています。

ただ、基本はやさしい一方で、開発を進めていると

  • PSRAMの正しい使い方がわからない
  • mallocはどのメモリから確保されているか?
  • 不揮発のデータを扱う作法が知りたい

といった不明点や疑問がたくさん出てきます。私も最初はこのあたりで何度も手が止まりました。

また、ESP-IDFには便利な機能が数多く用意されていますが、知らないまま開発を進めると遠回りになってしまうことがあります。

開発中は公式サイトのマニュアルやChatGPTなどを使って調べながら理解を深めていましたが、

「ESP-IDFで知っておくべき機能を体系的に速習できる教材が欲しい」

と感じることがときどきありました。

私自身、何か新しい技術を扱うときはUdemyでコースを探してみることが多いのですが、日本語でESP-IDFについて学べるようなコースがありませんでした。日本語で体系的に学べるコースがないのであれば、自分で作ってみようと思ったのがきっかけです。

ESP32・ESP-IDFの豊富な機能について全てを網羅しているわけではありませんが、

  • ESP32での本格的な開発に着手される方
  • ESP-IDFを初めて触る方

が知っておくと、開発の序盤でありがちな遠回りを回避でき、学習コストを下げることができるようなコースにすることを意識しています。

コースの内容について

コースでは、ESP32-S3の基板をご用意頂いて、実際にお手元でコースで学習するプロジェクトを動かして頂く構成になっています。

セクションは以下の通りです。

セクション|*タイトル|*内容|

1 ESP32・ESP-IDFについて知ろう ESP32・ESP-IDFの基本的な説明
2 ESP-IDFの開発環境を構築しよう ESP-IDFの環境構築
3 ESP-IDFの基本的な操作を覚えよう idf.pyコマンドの使い方、プロジェクト作成、エラーハンドリング、gdbデバッグ
4 ESP32の周辺機能を使ってみよう LEDチカチカ、RGB LEDの利用、UART通信、I2C通信
5 ESP-IDFで採用されているFreeRTOS・リアルタイムOSについて理解しよう FreeRTOS、リアルタイムOS、タスク間通信API
6 WiFi・BLEの機能を使ってみよう WiFiステーションモードの利用、BLEのGATT通信
7 メモリとFlashROMの使い方を理解しよう PSRAMの利用方法、NVS,LittleFS、パーティションテーブルについて

コースの前半ではESP-IDFの基本的な知識について説明になり、後半はやや応用的な内容になります。
www.udemy.com

コースの前提知識・経験

ような方をイメージしています。
シェルの操作についてはコース内でも説明しているので多少不慣れでも問題ないかもしれませんが、C/C++言語を全く触ったことがない方は少し難しいかと思います。
ジャンルとしては組み込みソフトウェアの開発になりますが、ESP32・ESP-IDFは基板への書き込みやデバッグなど開発者がCPUの仕様について細かく把握しなくても利用できるよう開発環境全体でいい感じに抽象化されています。このため、組み込みソフトウェアの開発経験はなくても学習を進められます。

コースの環境について

コースでの説明は、Ubuntu環境にESP-IDFをインストールして、WindowsPCからSSHでログインして説明しています。
ESP-IDFはWindows,MacOS,LinuxをサポートしているのでUbuntu以外の環境でもコマンドの内容を読み替えて頂くことコースの内容を試してみて頂けます。
※ESP-IDFの環境構築についてはUbuntuWindowsについて説明しています。

コースで使用する基板について

コース内では、Freenove社のESP32-S3 WROOM-1の基板を使って説明しています。
Freenove ESP32-S3 ESP32 S3 Wi-Fi Bluetooth Board Lite, Dual-core 32-bit 240 MHz Microcontroller, Python C Code, Example Projects Tutorialstore.freenove.com

こちらはAmazonで入手可能です。
コースでは赤色のFlashROM16MBの基板を使用していますが、黒色の8MBの基板で問題ありません。また、少し値段が高くなりますがカメラ付きのタイプの基板でも問題ありません。

また、Freenoveの基板が入手できない場合はEspressif公式の ESP32-S3 DevkitC-1の基板でも試してみて頂けます。
ただし、こちらはFreenoveの基板と異なりIO2にLEDがありませんので、LEDに関する説明を確認していただく際は別途LEDや抵抗をご用意頂く必要があります。
www.marutsu.co.jp

ESP32の他のシリーズの製品でもコースの内容を参考にして頂けますが、FlashROM・PSRAMのサイズなどが異なりますのでmenuconfig設定内容などを読み替えて頂く必要があります。
なので、コースを受講頂く場合はESP32-S3 WROOM-1が搭載されている基板をご用意頂くことをお勧めします。

今後について

本コースで身につけた基礎を土台として、将来的にはより実践的なIoT機能の応用編や、esp-matterを使ったMatter開発などの発展的な内容についてもコースとして提供していきたいと考えています。

最後に

ESP32・ESP-IDFは非常に強力で、うまく使いこなせると開発効率が大きく上がります。
例えば、PWM制御やI2Cの通信の機能を実装しようとすると他のマイコンであればそれなりの規模になったりデバッグに時間がかかったり、オシロをつないで様子を見たりと苦労することがありますが、ESP32ではPWM制御もI2C通信も数十行のコードで実装でき、開発中にソフトウェアのデバッグのために波形を見ることもありませんでした。

うまく使いこなすと生産性が高いマイコンだと思いますので、ESP32・ESP-IDF開発について効率よく体系的に学びたい方は、ぜひご覧ください。
www.udemy.com

自宅に太陽光発電を設置した結果~3年目~

太陽光発電・蓄電池のシステムを自宅に設置して3年目の結果が出たので簡単に振り返ってみたいと思います。(厳密には2年と半年ほどになります)

1年目の結果は以下の記事を参照。
mcommit.hatenadiary.com

2年目の結果は以下の記事を参照。
mcommit.hatenadiary.com

2024年のデータ

発電データとグラフは以下のような結果でした。

2024年発電データ
2024年発電グラフ

3年間の推移

発電量(kWh) 消費量(kWh) 売電量(kWh) 買電量(kWh) 蓄電池放電量(kWh) 自給率(%)
2022 2,378 4,306 386 2,397 1,047 55
2023 2,441 4,344 435 2,423 1,030 56
2024 2,384 4,441 355 2,501 1,041 54

2024年は2023年と比べると60kWh程度発電量が少し減っています。
雨の日や曇りの日が多かった印象はあまりありませんが、発電量を一日当たり6~7kWhとすると約10日前後雨や曇りの日が多かった計算になります。年間で10日なので誤差の範囲なのかもしれません。

シミュレーション結果との比較

導入時に営業の人が持ってきたシミュレーション結果との比較を見てみましょう。
年間推定発電量は2,921kWhなので2024年の結果と比較すると537kWhの差異があり、相変わらずこのシミュレーション結果には遠く及ばない結果になっています。

https://cdn-ak.f.st-hatena.com/images/fotolife/s/simotin13/20230129/20230129011749.png

電気料金と再エネ賦課金の推移について

2023年の再エネ賦課金は1.4円/kWhでしたが2024年は3.49円だったようです。
再エネ賦課金は2022年度は3.45円/kWhでしたが、2023年は1.4円/kWhになっています。

2025年の再エネ賦課金は3.98円/kWhになったそうです。

感想

予想されていたとはいえ、再エネ賦課金が実際にこうして値上がりしていくのを見ると再生エネルギーの割合を高くする方針というのが正しいことなのか疑問は強くなります。
自然エネルギーをより効率よく利用できるような技術の進歩に期待したいです。