GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - createskyblue/flashstore-ab-partition: A/B dual-page flash storage for small MCUs. Zero dependencies. Stateless. | A/B 双页 Flash 存储,面向小型 MCU。零依赖,无状态。

BranchesTags
Open more actions menu

Latest commit

 

History

19 Commits
19 Commits

Folders and files

NameName
Last commit message
Last commit date
include
include
 
 
src
src
 
 
tests
tests
 
 
.gitignore
.gitignore
 
 
CMakeLists.txt
CMakeLists.txt
 
 
LICENSE
LICENSE
 
 
README.md
README.md
 
 
README_CN.md
README_CN.md
 
 

Repository files navigation

中文

FlashStore A/B Partition

A/B dual-page flash storage for small MCUs. Zero dependencies. Stateless.

https://github.com/createskyblue/flashstore-ab-partition

Which to choose?

FlashStore FlashDB LittleFS
Purpose Single-blob reliable storage Embedded key-value DB Embedded file system
Data model Binary blob Key-value pairs Files
I/O Save/Load whole blob Set/Get by key Open/Read/Write
Wear leveling ❌ ✅ ✅
Power-loss safe ✅ Dual-page ✅ Transaction log ✅
Best for Config data, infrequent writes Multiple KVs, independent updates Files, logs, large data

Resource usage (Cortex-M0 -Os measured)

Module Flash Static RAM Stack
flash_store 500 bytes 0 ~20 bytes
chacha20 (optional) 700 bytes 0 ~200 bytes
xxtea (optional) 737 bytes 0 ~0

flash_store breakdown: Load 158B / load_page 108B / save_page 100B / Save 66B / CRC32 52B / MaxDataSize 16B. Link what you use.

Quick start

  1. Copy include/flash_store.h and src/flash_store.c into your project. Add chacha20 or xxtea if you need encryption.
  2. Implement 3 callbacks:
bool my_read(void *ctx, uint32_t addr, uint8_t *out, size_t len) {
    memcpy(out, (void *)(uintptr_t)addr, len);  // or HAL read
    return true;
}
bool my_erase(void *ctx, uint32_t addr, size_t len) {
    HAL_FLASH_ErasePage(addr);                  // full page erase
    return true;
}
bool my_program(void *ctx, uint32_t addr, const uint8_t *data, size_t len) {
    // word-by-word program, or memcpy if byte-addressable flash
    return true;
}
  1. Init and go:
FlashStore_IO io = {
    .read = my_read, .erase = my_erase, .program = my_program,
};
FlashStore_Config cfg = {
    .io = &io, .page_a_address = 0x0800FE00, .page_b_address = 0x0800FE80,
    .page_size = 128,
};
FlashStore_Save(&cfg, data, len);   // write
FlashStore_Load(&cfg, data, len);   // read

Need encryption? Use ChaCha20 — RFC 8439, stream cipher, no alignment requirements. Cortex-M0 -Os: 700B Flash + ~200B stack, 0 static RAM. For extreme resource savings, XXTEA — obfuscation only, requires 4-byte alignment and ≥8 bytes. Encrypt externally: encrypt → FlashStore_Save / FlashStore_Load → decrypt.

Why data won't get lost

A is written before B. At any power-loss moment, at least one valid copy exists in flash.

Save:  A first → B second     Load: read both → CRC check → return good → repair bad
Power loss at… A B Load result
Idle v2 v2 Returns v2
Writing A bad v1 Returns v1, repairs A
A done, before B v2 (CRC=c2) v1 (CRC=c1) CRC differ → A is newer → returns v2, repairs B
Writing B v2 bad Returns v2, repairs B next time
Both pages bad bad bad ERROR_NO_VALID_DATA

WARN_REPAIR_FAILED? Means erase/program failed during repair. Should not happen in normal operation — check your hardware or IO.

Header layout

12-byte header + payload per page:

Offset Field Description
0 magic (4B) 0x46534142
4 length (4B) Payload size
8 crc32 (4B) Payload CRC32

Bigger logical pages (span several erase sectors)

page_size is a logical size — a page may span several physical erase sectors, so a single blob can be larger than one sector without changing the library at all. Your erase/program callbacks just handle the whole region:

#define FLASH_BASE   0x08000000u
#define SECTOR_SIZE  0x800u   /* 2KB erase sector */
#define A_SECTOR     8        /* A = sectors 8..11 */
#define SECTORS      4        /* logical page = 4 sectors */

FlashStore_Config cfg = {
    .io              = &io,
    .page_a_address  = FLASH_STORE_SECTOR_ADDR(FLASH_BASE, SECTOR_SIZE, A_SECTOR),
    .page_b_address  = FLASH_STORE_SECTOR_ADDR(FLASH_BASE, SECTOR_SIZE, A_SECTOR + SECTORS),
    .page_size       = FLASH_STORE_PAGE_SIZE(SECTORS, SECTOR_SIZE),
};

The helpers FLASH_STORE_SECTOR_ADDR / FLASH_STORE_PAGE_SIZE / FLASH_STORE_PAGE_B (see flash_store.h) are constant expressions, so they work in static initializers and _Static_assert.

Three rules:

  1. A and B must not share a physical erase sector. Erasing A wipes every sector it covers; if B overlaps any of them, the redundancy is destroyed. ConfigCheck verifies the logical pages don't overlap, but it cannot know the physical sector map — that part is on you.
  2. Erase the whole region. Your erase callback receives page_size bytes; if that spans N physical sectors, erase all N (or use a multi-sector erase).
  3. Wear scales with page size. Every commit erases and rewrites both pages in full, so a 4KB page wears ~4x faster than a 1KB page — keep commits infrequent.

Status codes

Return Meaning
OK Success
ERROR_ARGUMENT Bad parameter
ERROR_WRITE Erase or program failed
ERROR_NO_VALID_DATA Both pages are corrupt
WARN_REPAIR_FAILED Data OK but redundancy not restored

Tests

cmake -S . -B build && cmake --build build && ./build/flash_store_tests.exe

10 tests: round-trip, A corrupt→B, B corrupt→repair, A-write-fail, CRC-staleness, both corrupt, MaxDataSize, Save/Load arg check, ConfigCheck, repair-failed.

License

MIT

About

A/B dual-page flash storage for small MCUs. Zero dependencies. Stateless. | A/B 双页 Flash 存储,面向小型 MCU。零依赖,无状态。

Topics

ab-partitionembeddedflash-storageiotlightweightmicrocontroller

Resources

Readme
MIT license
Activity

Stars

14 stars

Watchers

0 watching

Forks

5 forks
Report repository

Releases

Packages

Contributors

Languages

You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.