CustomLFS¶
LITTLEFS · SECOND FILE SYSTEM · EXTRAFS · QSPI
On nRF52, MeshCore has two file systems. The internal one from the Adafruit core holds the settings and keys; alongside it, CustomLFS creates a second LittleFS volume on another piece of flash, or on an external QSPI chip. Only nRF52 does this.
[!NOTE] Source. This page was verified against the firmware itself:
MeshCorev1.16.0, commit03b6ef4, 28 July 2026 — filesplatformio.iniandexamples/companion_radio/main.cpp.
What it does¶
CustomLFS by oltaco extends the LittleFS support in the Adafruit nRF52 core.
Where that core knows one fixed internal volume, CustomLFS lets you define one
yourself: you give a start address, a size and a block size, and you get a
LittleFS on it. The CustomLFS_QSPIFlash variant does the same on an external
flash chip on the QSPI bus. The repository is at
github.com/oltaco/CustomLFS.
How MeshCore pulls it in¶
platformio.ini r.95
https://github.com/oltaco/CustomLFS#0.2.2
Not a registry package but a git URL, with the tag 0.2.2 after #. The line
sits in [nrf52_base], so only nRF52 variants get it.
Two build flags in the same section belong with it:
platformio.ini r.91-92
-D LFS_NO_ASSERT=1
-D EXTRAFS=1
EXTRAFS switches on the second volume. LFS_NO_ASSERT strips the asserts
out of LittleFS: an inconsistency in the file system then lets the node carry
on rather than halting it.
That second flag does not touch CustomLFS itself — it contains no littlefs but
wraps Adafruit_LittleFS (CustomLFS.h r.30). It touches the littlefs copy
inside the nRF52 framework. The second copy in the build tree,
arch/stm32/Adafruit_LittleFS_stm32/src/littlefs/, keeps its asserts, because
[stm32_base] does not set the flag. See
../library-configuration.md for that
mechanism.
How MeshCore uses it¶
The choice between internal, extra and QSPI falls at compile time:
examples/companion_radio/main.cpp r.15-26
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#include <InternalFileSystem.h>
#if defined(QSPIFLASH)
#include <CustomLFS_QSPIFlash.h>
DataStore store(InternalFS, QSPIFlash, rtc_clock);
#else
#if defined(EXTRAFS)
#include <CustomLFS.h>
CustomLFS ExtraFS(0xD4000, 0x19000, 128);
DataStore store(InternalFS, ExtraFS, rtc_clock);
#else
DataStore store(InternalFS, rtc_clock);
The three numbers on CustomLFS ExtraFS are the start address in flash
(0xD4000), the size (0x19000, 102,400 bytes) and the block size.
DataStore then receives one or two volumes. If there is a second, contacts
and channels go there and the rest stays on the internal volume:
examples/companion_radio/DataStore.h r.54
FILESYSTEM* _getContactsChannelsFS() const { if (_fsExtra) return _fsExtra; return _fs;};
The text CustomLFS occurs in two source files; the accompanying InternalFS
in twelve.
What it means for a node¶
The second volume provides space that does not count against the internal file system. On a companion node the contacts and channels end up there, separated from the settings and keys on the internal volume.
That this exists only on nRF52 comes down to the flash layout there being known and stable: the nRF52 core reserves a fixed region, and what follows is free. On ESP32 the layout is set by a partition table, on RP2040 by the core itself. On STM32WL there is simply too little flash.
Sources¶
platformio.iniexamples/companion_radio/DataStore.hexamples/companion_radio/main.cpp- oltaco/CustomLFS
Translated from Dutch by Anthropic Claude