Panel For Example Panel For Example Panel For Example

JesFS Flash File System for Small Controllers

Author : Adrian September 09, 2025

JesFS Flash File System

Introduction

Files are an important part of modern electronic devices. Processors access different types of files via the operating system, but in embedded and low-power custom Linux solutions, file-system options are relatively limited. Many embedded developers store data in firmware, which requires a firmware update for every configuration change. JesFS is an embedded file system designed to address this issue for very small, low-power devices.

Files vs. Code

Files are basic containers used to organize and transport information. From servers to microcontrollers, systems understand and handle information through operating-system interfaces. In many embedded projects, code and data are not separated, which can lead to maintenance and update problems. For example, storing system parameters directly in firmware is convenient, but any later modification necessitates a firmware upgrade. JesFS was developed to provide a straightforward file-based alternative for microcontroller-scale systems and ultra-low-power applications.

JesFS Overview

JesFS was designed with reliability and small footprint as primary goals, together with data integrity and support for remote firmware updates. JesFS is independent of any bootloader; a separate bootloader can be used to support AES-encrypted firmware images. The project is available under the GPL v3 license.

Reference Example

JesFS is written in standard C and can be compiled with a standard C compiler. Example usage is demonstrated on TI's CC1310 development board. The CC1310 is a 32-bit ARM Cortex-M3-based device with 868/915 MHz radio capability. The CC13xx/26xx LaunchPad development platform is low-cost, supports source-level debugging with TI's IDE, and typically includes a 1 MB serial Flash device in a very small package (around a few square millimeters). JesFS can be compiled for the LaunchPad platform or for Windows/Linux hosts, but embedded usage requires a driver for the serial Flash device.

Small Flash Memory Devices

Embedded systems typically need modest storage capacity; 1–16 MB is usually sufficient. Flash devices can be extremely small: a 1 MB device may measure about 1.24 mm × 1.29 mm. JesFS itself has a tiny RAM footprint: about 200 bytes of RAM are sufficient for basic operation. Many larger file systems use RAM for caching, which increases complexity and power consumption and can delay mode transitions (for example, entering sleep). JesFS is optimized for low power and can enter and exit sleep in a few milliseconds. Serial Flash devices typically draw less than 1 μA in sleep mode, making them suitable for battery-powered devices.

IoT-Oriented Functionality

JesFS supports mirroring of embedded device files to a remote server, so the server maintains a near-real-time copy of the device file system. This can be used to collect data at minute-level intervals, although to conserve power updates to the server are typically less frequent (for example, every few hours). JesFS uses metadata such as timestamps and CRC32 hashes to identify and retrieve files from the server when needed. These mechanisms enable many remote-update and data-retrieval workflows. The project includes tested scripts and tools for these use cases; detailed descriptions are available in the project documentation.

Handling of Open Files

Many file systems restrict write access to files that are explicitly opened for writing, and unexpected events can leave files in an unclosed state, risking data loss. JesFS is designed so that files can be opened for reading and writing at any time without causing data corruption. This behavior is useful for log files and other diagnostic data where the device may be writing while a remote system reads or syncs data.

Limitations

JesFS is a simple file system targeted at resource-constrained embedded systems. Some design trade-offs include a limit on file name length (up to 21 characters) and the absence of an indexed directory structure to reduce CPU and memory overhead. The file system is intentionally flat and minimal to match the constraints and typical use cases of small embedded devices.

Serial NOR Flash Basics

Before describing software details, a few key serial NOR Flash characteristics are relevant. Most serial NOR Flash devices share a similar behavior: 1) erased cells default to bit '1'; 2) programming changes bits from '1' to '0'; 3) erase operations reset bits from '0' to '1'; 4) write operations typically program between 1 and 256 bytes and take on the order of 1 ms; 5) erase operations are performed per block/sector (typically 4 KB) or for the entire chip and can take 20–200 ms; 6) erase cycles are limited (often to around 100,000 cycles).

Accessing a serial Flash device usually involves these four steps: 1) pull the chip select line low to activate the device; 2) clock commands and data in via the clock and data-in pins; 3) read data or status via the clock and data-out pins; 4) release chip select to end the operation.

Serial Flash devices

Serial Flash devices often support high clock rates (>50 MHz), but many microcontroller hardware drivers cannot fully utilize these speeds. On the CC1310 platform, a 12 MHz SPI clock can achieve roughly 1 MB/s throughput. Suitable common Flash chips for small systems include MX25R8035F (1 MB) up to MX25R1635F (16 MB), W25Q80DL (1 MB) up to W25Q128JV (16 MB), and GD25Q16 (2 MB). Some compatible alternatives exist but may have higher power consumption.

Black-Box Demo: On-Device Flight Recorder

Some embedded devices run for years without issues but occasional failures occur and debugging requires historical logs. A compact “black-box” logger can capture internal parameters (temperature, voltage, humidity, etc.) to aid post-failure analysis. JesFS supports robust logging that avoids data loss even across resets or power interruptions by using two files to maintain a fixed-length history.

  • Primary file: Data.pri — writable up to a HISTORY-defined length.
  • Secondary file: Data.sec — a backup copy used during rotation.

The scheme constrains stored history to a fixed number of records (at most twice the HISTORY size) and allows reconstructing the correct chronological order by reading Data.sec followed by Data.pri.

Example Code Excerpt

log_blackbox(char *logtext, uint16_t len) /* This function logs one line to the history */ int16_t log_blackbox(char* logtext, uint16_t len){ FS_DESC fs_desc, fs_desc_sec; /* two JesFS file descriptors */ int16_t res; res = fs_start(FS_START_RESTART); /* (fast) wake JesFS (may be sleeping) */ if(res) return res; /* OPEN: create file if not exists and open in RAW mode (RAW mode prevents truncation if file exists) */ res = fs_open(&fs_desc, "Data.pri", SF_OPEN_CREATE | SF_OPEN_RAW); if(res) return res; /* Move internal file pointer to end to append */ fs_read(&fs_desc, NULL, 0xFFFFFFFF); /* dummy read as much as possible */ /* Write new data (ASCII from function arguments) */ res = fs_write(&fs_desc, logtext, len); if(res) return res; /* Optionally print what was written */ uart_printf("Pos:%u Log: %s", fs_desc.file_len, logtext); /* Rotate files if larger than HISTORY */ if(fs_desc.file_len >= HISTORY){ uart_printf("Shift 'Data.pri' -> 'Data.sec'"); /* Open or create secondary file */ res = fs_open(&fs_desc_sec, "Data.sec", SF_OPEN_CREATE); if(res) return res; /* Rename full primary file to secondary file */ res = fs_rename(&fs_desc, &fs_desc_sec); if(res) return res; } fs_deepsleep(); /* set filesystem to ultra-low-power mode */ return 0; /* OK */ }