ESP32 零拷贝加载 Lottie 动画:esp_mmap_assets 闪存资源映射实战

在 ESP32 这类嵌入式设备上,资源文件(图片、动画等)通常存储在 Flash 中。传统方式需要通过 SPIFFS 文件系统读取,存在以下问题:

  • 需要额外的文件系统开销
  • 读取效率较低
  • 资源与代码耦合

esp_mmap_assets 是乐鑫官方提供的一个 资源打包与内存映射组件,cmake文件中使用该组件封装好的spiffs_create_partition_assets函数,把资源文件(图片、字体、JSON 等)存到FLASH分区中;通过 内存映射 (mmap) 技术,将 Flash 中的资源文件高效地映射到内存中,让 CPU 可以直接从 Flash 地址空间读取资源,无需经过文件系统层。就是一个 "构建时打包 + 运行时零拷贝访问" 的资源管理方案,特别适合嵌入式场景下对性能和内存有严格要求的 UI 资源加载

使用方法

例如在LCD显示动态表情的项目中, Lottie 动画资源以JSON 文件放在lottie_assets文件夹内。

image

拉取esp_mmap_assets 组件

这是组件是不在ESP_IDF中的,需要使用ESP-IDF 组件管理器自动拉取第三方组件库,生成的idf_component.yml 如:

## IDF Component Manager Manifest File
dependencies:esp_mmap_assets: "1.*"

编译时自动把这个组件构建依赖注入到编译系统。

FLASH分区

partitions.csv文件:

# Name,     Type,   SubType,    Offset,     Size,   Flags
nvs,        data,   nvs,        0x10000,    0x6000,
lottie_assets,  data,   spiffs,      ,          304K,

在main文件夹内的CMakeLists.txt文件:

spiffs_create_partition_assets(lottie_assets"../lottie_assets"FLASH_IN_PROJECTMMAP_FILE_SUPPORT_FORMAT ".bmp,.json"
)
  1. animation 【分区目标名称】

  2. "../lottie_assets" 【本地资源目录路径】

电脑上存放静态资源的文件夹(相对当前 CMakeLists.txt 路径)

⚠️ 路径注意:CMake 相对路径基于当前 CMakeLists.txt 文件位置,不是工程根目录。

  1. FLASH_IN_PROJECT

关键选项含义:直接链接进项目固件(.bin)

也就是主 bin已经包含 SPIFFS 文件系统镜像;烧录主 bin 就能一并写入资源,

4. MMAP_FILE_SUPPORT_FORMAT ".bmp,.json"

开启 SPIFFS mmap 内存映射功能,并指定支持 mmap 的文件后缀列表。

编译时esp_mmap_assets 的操作

  1. 扫描 ../lottie_assets 目录下的 .bmp.json 文件
  2. 打包成 animation.bin 烧录到 Flash
  3. 在构建编译时自动生成 mmap_generate_lottie_assets.h头文件(生成的头文件名是基于分区名称)),包含文件数量、校验和等宏定义
/*** @file* @brief This file was generated by esp_mmap_assets, don't modify it*/#pragma once#include "esp_mmap_assets.h"#define MMAP_LOTTIE_ASSETS_FILES           5
#define MMAP_LOTTIE_ASSETS_CHECKSUM        0xAD4Cenum MMAP_LOTTIE_ASSETS_LISTS {MMAP_LOTTIE_ASSETS_ASK_JSON = 0,        /*!< ask.json */MMAP_LOTTIE_ASSETS_LOOK_JSON = 1,        /*!< look.json */MMAP_LOTTIE_ASSETS_RUNNING_JSON = 2,        /*!< running.json */MMAP_LOTTIE_ASSETS_SPEAK_JSON = 3,        /*!< speak.json */MMAP_LOTTIE_ASSETS_THINK_JSON = 4,        /*!< think.json */
};

程序使用方法

#include "mmap_generate_lottie_assets.h"
// Lottie动画资源句柄
mmap_assets_handle_t asset_lottie;
//====================初始化=====================//
const mmap_assets_config_t config_lottie = {.partition_label = "animation",           // 分区标签名称.max_files = MMAP_LOTTIE_ASSETS_FILES,    // 最大文件数.checksum = MMAP_LOTTIE_ASSETS_CHECKSUM,  // 资源包打包时生成的校验值.flags = {.mmap_enable = true,                  // 启用内存映射,可以直接从Flash中读取数据,节省RAM空间.app_bin_check = true,                // 启用应用二进制检查},
};
// 创建新的内存映射资源,返回资源句柄asset_lottie,后续所有文件操作都依靠这个句柄
mmap_assets_new(&config_lottie, &asset_lottie);
printf("[%s]stored_files:%d", config_lottie.partition_label, mmap_assets_get_stored_files(asset_lottie));//===========使用Lottie动画==============//
//获取指定Lottie动画资源(look.json)
void *data = mmap_assets_get_mem(asset_lottie, MMAP_LOTTIE_ASSETS_LOOK_JSON);
//获取大小只
size_t size = mmap_assets_get_size(asset_lottie, MMAP_LOTTIE_ASSETS_LOOK_JSON);
//显示look动画
lv_lottie_set_src_data(ui_face_canvas, data, size);