EasyFlash

repository·master·Indexed 25 days ago

https://github.com/armink/easyflash

A lightweight, open-source embedded Flash memory library providing Key-Value storage (ENV), In-Application Programming (IAP) for firmware updates, and Flash-based logging without a file system. It includes the Serial Flash Universal Driver (SFUD), an object-oriented driver for serial SPI Flash that supports SFDP (Serial Flash Device Profile) and 4-byte addressing to abstract differences between Flash brands and specifications.

Tokens
6.3K
Snippets
7
Records
29
Agent score
81%

What's inside EasyFlash

  1. Overview of EasyFlash features

    master

    EasyFlash is a lightweight embedded Flash memory library designed for MCUs in applications like smart homes, wearables, and IoT. It provides three core functionalities:

    1. ENV (Environment Variables): A small NoSQL Key-Value store for saving product parameters or running logs. It supports wear leveling (write balance) and power-fail protection.
    2. IAP (In-Application Programming): Provides interfaces for online software upgrades, supporting CRC32 checksums for both Bootloader and Application upgrades.
    3. Log: Enables direct storage of logs to Flash without requiring a file system. It integrates seamlessly with EasyLogger to allow system crash analysis on resource-constrained devices.
  2. What is SFUD (Serial Flash Universal Driver)

    master

    SFUD is an open-source universal driver library for serial SPI Flash. It is designed to abstract the differences between various Flash brands and specifications (commands, capacities, etc.), allowing software to be reusable and extensible across different hardware platforms. This helps mitigate risks associated with Flash shortages or end-of-life (EOL) components.

    Key Features

    • Object-Oriented Design: Supports multiple Flash objects simultaneously.
    • Flexible Trimming: Can be scaled down to minimize resource usage.
    • High Extensibility: Easy to add support for new Flash models.
    • 4-Byte Addressing: Supports high-capacity Flash devices.

    Resource Usage

    • Standard footprint: RAM: 0.2KB, ROM: 5.5KB
    • Minimum footprint: RAM: 0.1KB, ROM: 3.6KB

    Design Logic and SFDP Support

    SFUD relies on the SFDP (Serial Flash Device Profile) standard defined by JEDEC (JESD216). Most modern Flash devices include an SFDP table containing parameters like capacity, write granularity, erase commands, and address modes.

    1. Initialization: SFUD first attempts to read the SFDP table from the Flash device.
    2. Fallback: If the device does not support SFDP, SFUD queries the Flash parameter information table provided in the configuration file (/sfud/inc/sfud_flash_def.h).
    3. Customization: If the Flash is not found in the configuration file, you can manually add its parameters to the configuration file to enable full functionality.
  3. Use struct2json for C struct and JSON conversion

    master

    struct2json is an open-source library designed for rapid serialization and deserialization between C structures (struct) and JSON objects. It acts as a wrapper around JSON parsing libraries like cJSON to reduce code complexity and redundancy.

    Common use cases include:

    • Persistence: Serializing structs to JSON for storage in files or Flash memory.
    • Communication: Using JSON as a protocol for data exchange between C and high-level languages (e.g., JavaScript, Groovy).
    • Visualization: Converting structs to JSON for easier debugging and UI display.
  4. Explore STM32F10X Demo Implementations

    master

    The demo/env/stm32f10x directory contains several implementation examples for the STM32F10X platform, categorized by operating system environment and hardware interface:

    • Non-OS (Bare Metal): Located in non_os, this is for projects running without an operating system.
    • Non-OS with SPI Flash: Located in non_os_spi_flash, specifically designed for platforms using an external SPI Flash chip.
    • RT-Thread (OS): Located in rtt, intended for projects running on the RT-Thread operating system.
  5. Project Structure for STM32F10x Demo

    master

    The STM32F10x demo project contains the following key files and formats:

    • Porting Layer: components\easyflash\port\ef_port.c contains the hardware-specific implementation required for EasyFlash to interface with the STM32 hardware.
    • Keil Projects: Files with the .RVMDK extension are intended for use with the Keil MDK IDE.
    • IAR Projects: Files with the .EWARM extension are intended for use with the IAR Embedded Workbench IDE.
  6. Store and retrieve C structures using JSON

    master

    The most powerful feature of the Types plugin is the ability to map C structs to JSON strings for storage. This is achieved via two callback-based functions:

    1. ef_set_struct: Converts a C structure into a JSON string using a provided ef_types_set_cb callback, then stores it.
    2. ef_get_struct: Retrieves the JSON string for a key and uses an ef_types_get_cb callback to reconstruct the C structure.

    Note: The memory allocated for the structure returned by ef_get_struct must be manually freed using the free_fn provided in your S2jHook during initialization.

    /* Example: Storing and retrieving a Student struct */
    
    // 1. Define your structures
    typedef struct {
        char name[16];
    } Hometown;
    
    typedef struct {
        uint8_t id;
        double weight;
        uint8_t score[8];
        char name[16];
        Hometown hometown;
    } Student;
    
    // 2. Define the callback to convert Struct -> JSON
    static cJSON *stu_set_cb(void* struct_obj) {
        Student *struct_student = (Student *)struct_obj;
        s2j_create_json_obj(json_student);
        s2j_json_set_basic_element(json_student, struct_student, int, id);
        s2j_json_set_basic_element(json_student, struct_student, double, weight);
        s2j_json_set_array_element(json_student, struct_student, int, score, 8);
        s2j_json_set_basic_element(json_student, struct_student, string, name);
        s2j_json_set_struct_element(json_hometown, json_student, struct_hometown, struct_student, Hometown, hometown);
        s2j_json_set_basic_element(json_hometown, struct_hometown, string, name);
        return json_student;
    }
    
    // 3. Define the callback to convert JSON -> Struct
    static void *stu_get_cb(cJSON* json_obj) {
        s2j_create_struct_obj(struct_student, Student);
        s2j_struct_get_basic_element(struct_student, json_obj, int, id);
        s2j_struct_get_array_element(struct_student, json_obj, int, score);
        s2j_struct_get_basic_element(struct_student, json_obj, string, name);
        s2j_struct_get_basic_element(struct_student, json_obj, double, weight);
        s2j_struct_get_struct_element(struct_hometown, struct_student, json_hometown, json_obj, Hometown, hometown);
        s2j_struct_get_basic_element(struct_hometown, struct_student, string, name);
        return struct_student;
    }
    
    // 4. Usage
    Student orignal_student = {
            .id = 24,
            .weight = 71.2,
            .score = {1, 2, 3, 4, 5, 6, 7, 8},
            .name = "StudentName",
            .hometown.name = "HometownName",
    };
    
    // Store
    ef_set_struct("student_key", &orignal_student, stu_set_cb);
    
    // Retrieve
    Student *student = ef_get_struct("student_key", stu_get_cb);
    
    // Cleanup
    s2jHook.free_fn(student);
  7. Compare ENV modes: NG vs legacy

    master

    EasyFlash offers two modes for the ENV (Key-Value) feature. Choosing the right one depends on your hardware capabilities and resource constraints.

    NG (Next Generation) Mode

    Introduced in V4.0, this is a fully refactored mode optimized for modern requirements.

    • Resource Usage: Extremely low (RAM usage is almost 0).
    • Data Types: Supports arbitrary types and lengths (uses memcpy to Flash).
    • Efficiency: High operation efficiency; utilizes free space better and reduces erase cycles.
    • Features: Native support for wear leveling and power-fail protection; supports incremental upgrades.
    • Limitations: Some Flash chips that do not support reverse writing (e.g., STM32L4 internal Flash) cannot use NG mode.
    • Source File: ef_env.c

    legacy Mode

    Maintains compatibility with V3.0.

    • Resource Usage: Higher RAM usage as it requires extra RAM to cache each ENV before a unified save call.
    • Data Types: Best suited for string types.
    • Compatibility: More widely compatible with various Flash types, including those with restricted write patterns.
    • Source Files: ef_env_legacy.c and ef_env_legacy_wl.c

    Comparison Summary

    FeatureV4.0 NG ModeV3.0 legacy Mode
    RAM UsageLowHigh
    Flash CompatibilityLimited (e.g., no STM32L4)Comprehensive
    GC (Garbage Collection)Required (may slow writes)Not required
    Value TypeUnrestricted
    Power ProtectionSupported
    Wear LevelingSupported
    Incremental UpgradeSupported-
  8. Run the stm32f4xx RT-Thread Demo

    master

    To verify that EasyFlash is correctly integrated into an STM32F4xx system running RT-Thread, you can use the provided demo. The demo uses the test_env() function in app\src\app_task.c to demonstrate environment variable operations.

    Demo Workflow

    1. Observe Initial State: When the system starts, test_env() executes. It attempts to read a specific environment variable. If the variable does not exist, it creates it with a default value and prints a message.
    2. Verify via CLI: Use the printenv command in the serial terminal to check the value of the environment variable created by the demo.
    3. Trigger Persistence: Use the reboot command to restart the system.
    4. Verify Persistence: After rebooting, use printenv again to confirm that the environment variable value was successfully preserved across the restart.
  9. Port EasyFlash to a new hardware platform

    master

    EasyFlash is designed for high portability across different MCU platforms. To port the library to a new platform, you only need to modify one file: \easyflash`port\ef_port.c`.

    You must implement the following core functions within that file:

    • Erase: Erase Flash sectors.
    • Write: Write data to Flash.
    • Read: Read data from Flash.
    • Print: Print debug information.

    Supported platforms currently include stm32f10x and stm32f4xx internal Flash, as well as external SPI Flash (via SFUD).

  10. Run the STM32F10x Non-OS Demo

    master

    To verify that EasyFlash is working correctly on an STM32F10x platform, you can use the provided non-OS demo. The demo executes the test_env() function located in app\src\app.c, which attempts to read and write configuration data to the system. If successful, the system will output the results via a serial port.

    Steps to run the demo:

    1. Configure Serial Port: Set your serial terminal to 115200 baud, 8 data bits, 1 stop bit, and No parity.
    2. Compile and Flash: Use the provided project files to compile the code and flash it to your STM32F10x hardware.
    3. Observe Output: Monitor the serial terminal to see the results of the test_env() execution.
  11. Install the EasyFlash Types plugin

    master

    To use the Types plugin, you must integrate it into your existing EasyFlash directory structure. The plugin provides advanced data type support by leveraging the struct2json library to convert C structures to and from JSON strings.

    1. Ensure your EasyFlash directory contains \easyflash\inc, \easyflash\port, and \easyflash\src.
    2. Create a directory named plugins\types within your EasyFlash root.
    3. Copy the struct2json source files into easyflash\plugins\types\struct2json\inc and easyflash\plugins\types.