Skip to content

Concepts First

  • LittleFS: a lightweight file system designed for Flash with power-loss protection (no data loss on sudden power-off), wear leveling, and power-loss recovery — ideal for embedded use.
  • Difference from FATFS: FATFS targets SD cards/USB drives (interoperable with PCs); LittleFS targets on-chip or external Flash (more space-efficient and durable). The two are incompatible.
  • Partition: Flash is split into regions. This example mounts the partition named PSM with lfs_xip_init(&lfs_ctx, &lfs_cfg).
  • KV test: storing "key-value" pairs as small files and reading/writing them repeatedly, verifying reliability under frequent writes and power cycles.
  • Write amplification & wear leveling: Flash erases by block; repeatedly writing the same area ages it faster. LittleFS spreads writes across the device to extend its life.

Example Overview

This page is based on the littlefs example in the official Bouffalo SDK (examples/littlefs), which demonstrates LittleFS on on-chip Flash:

  • Initializes MTD (bflb_mtd_init) and mounts LittleFS on the PSM partition (lfs_xip_init);
  • Reads the file boot_count (created if missing), increments it, writes it back, and prints it — the counter survives restarts, proving data persistence;
  • Registers the kv_test shell command via SHELL_CMD_EXPORT_ALIAS (implementation in the kv_test/ subdirectory) for key-value read/write tests;
  • Finally starts the FreeRTOS scheduler and runs the system.

Note

The "Power-Off Saving (EasyFlash)" page in System Control also stores config into Flash; this page is lower-level and shows the LittleFS file APIs directly, suitable for managing your own files/key-values.

Operation Steps

1
Enter the Example Directory

Open a terminal and enter the SDK LittleFS example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/littlefs
2
Build the Project

Run the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:

make CHIP=bl616 BOARD=bl616dk
3
Flash the Firmware

Connect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
Run and Verify

Open a serial tool (baud rate 2000000). The example mounts LittleFS on the on-chip Flash PSM partition, reads the boot counter boot_count, increments it, and writes it back — the serial prints boot_count: N (increments on each restart). At the bouffalolab /> prompt, type kv_test to run the key-value read/write test.

Code Execution Flow

The flow from boot to running is:

APIs Used by the Example

lfs_xip_init(&lfs_ctx, &lfs_cfg)

Initializes and mounts LittleFS on a Flash partition. lfs_ctx.partition_name selects the partition (here "PSM"); lfs_cfg sets block/cache sizes.

Parameters:

  • ctx: lfs_context including the partition name
  • cfg: lfs_config (block_size, cache_size, read_size, etc.)

Returns: lfs_t * file system handle; NULL on failure (errno holds the error code)

lfs_file_open / lfs_file_read / lfs_file_write / lfs_file_close(...)

Opens, reads/writes, and closes files. The example opens boot_count with LFS_O_RDWR | LFS_O_CREAT, reads 4 bytes, rewinds with lfs_file_rewind, and writes the new value back.

Parameters:

  • lfs: file system handle
  • file: file object
  • path: file name (e.g., boot_count)
  • buff / size: data buffer and byte count

Returns: LFS_ERR_OK (0) on success; negative error codes

bflb_mtd_init()

Initializes the Flash storage device (MTD); LittleFS accesses partitions through it.

Parameters: none

Returns: 0 on success

SHELL_CMD_EXPORT_ALIAS(cmd_kv_test, kv_test, shell kv test)

Registers the kv_test command in the shell (implementation in kv_test/); typing it over serial triggers the test.

Parameters: see "Shell Command Line"

Returns: none (macro)

Complete Code

The following is the complete source of littlefs/main.c, identical to the official example, collapsed by default (the kv_test implementation lives in kv_test/):

📜 Click to expand littlefs/main.c full code
c
/****************************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include "FreeRTOS.h"
#include "task.h"
#include "shell.h"

#include "bflb_mtimer.h"
#include "bflb_flash.h"
#include "bflb_l1c.h"
#include "bflb_uart.h"
#include "board.h"
#include "bflb_mtd.h"

#include "log.h"
#include "lfs.h"
#include "lfs_port.h"

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/****************************************************************************
 * Private Data
 ****************************************************************************/

static struct bflb_device_s *uart0;
static struct lfs_context lfs_ctx = { .partition_name = "PSM" };
static struct lfs_config lfs_cfg = { .read_size = 256,
                                     .prog_size = 256,
                                     .lookahead_size = 256,
                                     .cache_size = 512,
                                     .block_size = 4096,
                                     .block_cycles = 500
                                   };
static lfs_file_t file;
lfs_t *lfs;

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

extern void shell_init_with_task(struct bflb_device_s *shell);
extern void cmd_kv_test(int argc, char **argv);
SHELL_CMD_EXPORT_ALIAS(cmd_kv_test, kv_test, shell kv test);

/****************************************************************************
 * Functions
 ****************************************************************************/

int main(void)
{
    board_init();
    bflb_mtd_init();

    uart0 = bflb_device_get_by_name("uart0");
    shell_init_with_task(uart0);

    lfs = lfs_xip_init(&lfs_ctx, &lfs_cfg);
    if (lfs == NULL) {
        LOG_F("lfs_xip_init failed. errno: %d\r\n", errno);
        while (1)
            ;
    }

    // read current count
    uint32_t boot_count = 0;
    lfs_file_open(lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
    lfs_file_read(lfs, &file, &boot_count, sizeof(boot_count));

    // update boot count
    boot_count += 1;
    lfs_file_rewind(lfs, &file);
    lfs_file_write(lfs, &file, &boot_count, sizeof(boot_count));

    // remember the storage is not updated until the file is closed successfully
    lfs_file_close(lfs, &file);

    // release any resources we were using
    // lfs_unmount(&lfs);

    // print the boot count
    printf("boot_count: %d\n", boot_count);

    vTaskStartScheduler();

    while (1) {
    }
}

FAQ

`boot_count` does not increase after restart?

Check that you really power-cycled (an EN/RST reset works) and that flashing did not overwrite the Flash region holding the firmware. Writes only land after a successful lfs_file_close; an interrupted write may roll back — that's LittleFS power-loss protection at work.

`lfs_xip_init failed`. What now?

Usually a partition mismatch: confirm a PSM partition exists in the project partition config with enough size; if the partition is occupied, point lfs_ctx.partition_name at a free one.

LittleFS or FATFS?

If data must be readable on a PC (logs, exported images), choose FATFS + SD card. If data is only used on the device and you value power-loss reliability and Flash longevity (config, parameters, OTA flags), choose LittleFS + Flash.

The `kv_test` command does nothing.

Make sure the bouffalolab /> prompt is up and the command name is correct. The kv_test implementation and registration live in the kv_test/ subdirectory; if you changed the directory structure, it must be compiled in too.

Released under the MIT License. Build Time 2026-09-11 14:52:23