
简介面向Windows 64位环境下ESP32开发的LittleFS文件系统工具包用于在电脑端创建、查看与整理LittleFS磁盘镜像。LittleFS是一种专为资源受限微控制器设计的轻量级文件系统具有掉电保护和坏块管理能力该工具包内含可直接运行的mklittlefs.exe命令行程序及记录参数信息的package.json文件工具基于i686-w64-mingw32工具链构建在64位Windows上即可调用免去手动编译的繁琐。压缩包共2个文件整体大小仅325KB结构极为精简。实际开发中可将网页、静态资源或配置文件按指定块大小与页大小封装为LittleFS映像再结合ESP-IDF烧录命令烧入ESP32内置Flash有效简化Web配网、固件更新和文件部署流程适合正在使用ESP32做嵌入式联网产品的开发者。目前已有312人学习下载。1. 这串字符不是乱码i686-w64-mingw32.mklittlefs 到底是什么把i686-w64-mingw32.mklittlefs-c41e51a.200706拆开看它其实由三段信息拼成i686-w64-mingw32是交叉编译目标意思是这份工具跑在 32 位 Windows 上mklittlefs是本体一个像 mkfs 一样把目录打包成 littlefs 文件系统镜像的命令行程序c41e51a.200706是源码提交号加构建日期。也就是说这是一份由开源工具链提前编译好的 Windows 版 littlefs 镜像生成器拿到手就能用不用在自己机器上折腾交叉编译环境。它解决的是嵌入式交付里一个很具体的痛点设备首次上电时文件系统里最好已经躺着网页、配置、证书这些静态资源而不是等代码运行时慢慢建目录、写文件。littlefs 这类掉电安全文件系统的镜像布局强依赖 Flash 的擦除块和页大小运行时初始化的速度和一致性都不可控。离线生成一份完整镜像烧录时一次性写入 Flash才能真正做到「上电即用」。这篇笔记就沿着「原理—命令—参数—踩坑—验证」这条线把这份工具用透。2. 先把原理立住为什么 littlefs 镜像要按 Flash 几何结构离线生成2.1 littlefs 的元数据对与 CTZ 跳表镜像为什么不是文件顺序拼接很多人第一次接触 mklittlefs 会把它当成 zip 或 tar 那种打包工具这是最容易踩的思维误区。zip 的产物是「文件头压缩数据」的线性拼接解压时照着文件头一个个解就行littlefs 的镜像则是一套完整的文件系统布局内部有超级块、目录元数据、块分配表、文件数据块而且这些结构在 Flash 上是分散排布的不是「文件 A 后面跟着文件 B」。littlefs 最核心的两个设计是元数据对metadata pair和 CTZ 跳表。元数据对的意思是每个目录或文件的关键描述信息都存在一对连续区域内更新时先写备用区域再通过一个递增计数器切换生效区域。这样即使写入过程中突然掉电启动时也能靠计数器挑出最新且完整的一份。CTZ 跳表则是文件数据块的索引方式——每个文件有一组指针链按块地址向前跳跃文件多大、数据块在哪全部靠这套链表推导出来。这意味着 mklittlefs 在 PC 上做的工作本质上是把 littlefs 的分配算法完整跑了一遍先建超级块再建根目录然后逐个文件分配块、写目录项、维护跳表指针最后把剩余区域标记为空闲块。这个过程对 Flash 的几何参数极其敏感参数填错生成的镜像在设备端挂载时就会被判定为损坏。你可以用一条命令快速感受一下镜像开头的特征od -A x -t x1z -v littlefs.bin | head -20正常生成的镜像开头几个字节是 littlefs 超级块固定的魔法数如果这里全是0xFF说明文件系统区域没有被写入任何有效结构。设备挂载时第一件事就是读这个位置读到空数据会直接返回损坏错误。所以镜像不是「内容对就行」而是「布局必须和设备端配置严丝合缝」。2.2 块大小、页大小和块数littlefs 与 Flash 几何的对应关系Flah 的物理约束决定了 littlefs 的三个核心参数块大小block size、页大小page size、块数block count。块大小通常对应 Flash 的最小擦除单位常见 SPI NOR Flash 是 4096 字节页大小对应一次编程的最小单位常见是 256 字节块数则等于文件系统分区容量除以块大小。三者关系可以写成一个简单的公式块数 分区容量 ÷ 块大小。设备端挂载时lfs_mount会用代码里配置的block_size去读取超级块并和镜像里记录的几何字段做比对。两边任何一个数字对不上返回的错误码就是LFS_ERR_CORRUPT。我见过最典型的一次现场PC 端工具按 4096 生成镜像设备端驱动把擦除粒度误配成了 64KB结果超级块读到一半就被判定损坏整块 Flash 看起来像报废一样。页大小同样不能拍脑袋。page_size决定 littlefs 每次编程的最小单位如果填得比 Flash 实际页大小还大一次写入就可能跨页硬件层面直接失败填小了又会浪费 cache 和写入次数。所以这三个数字不是「推荐参数」而是必须从 Flash 数据手册里精确抄录的物理参数差一个字节都不行。常见组合大致如下Flash 容量页大小扇区大小常见文件系统分区块数4MB256B4KB1MB / 2MB256 / 5128MB256B4KB2MB / 4MB512 / 102416MB256B4KB4MB / 8MB1024 / 20482.3 为什么镜像必须离线生成在线 mkfs 的产线难题有人会问设备上电后自己格式化文件系统再写文件不也一样吗原理上可行工程上不建议。在线初始化的时间不可控一颗 4MB Flash 做整片擦除、建超级块、逐文件写入几百台设备在产线上跑起来每台多花几十秒产能就被拖住了。而且每台设备写出来的布局可能因为写入顺序、block 回收状态不同而有细微差异出了问题很难复盘。离线镜像让一切都可复现PC 上同一份源目录永远生成同一份二进制镜像哈希值固定产线烧录后抽检只需比对哈希。这就是为什么 mklittlefs 这类工具在嵌入式交付里几乎是刚需——它不是「把文件塞进 bin」而是「把一套完整文件系统状态预制成二进制」。这里还有一个容易忽略的版本匹配问题。littlefs 有大版本区分v1 和 v2 的磁盘布局完全不兼容镜像工具和设备端 lfs 库必须属于同一个大版本。标题里200706这个构建日期通常对应 littlefs v2 时代的工具如果你手头设备跑的是历史遗留的 v1 库哪怕参数一字不差挂载也会失败。我一般会在镜像文件命名里额外加一个lfs2-前缀从名字上杜绝混用。3. 在 Windows 命令行跑通 mklittlefs先验证再生成后回读3.1 第一步验证 mklittlefs 是可用的DLL 与版本拿到 exe 之后别急着写烧录脚本先把它放到一个固定目录比如C:\tools\mklittlefs\mklittlefs.exe然后用绝对路径调用。这样做是为了避免 PATH 里有同名工具干扰产线脚本里也建议统一用绝对路径少一些玄学问题。第一步永远是执行帮助命令C:\tools\mklittlefs\mklittlefs.exe -h正常输出会列出-c、-b、-p、-s、-l这些开关的含义。如果一闪而过或者弹窗提示找不到某个 DLL说明这份预编译产物依赖 MinGW 运行时库但 DLL 没有一起分发。把缺失的libgcc_s_dw2-1.dll、libwinpthread-1.dll之类文件拷到 exe 同目录即可或者干脆换一个静态编译版本。64 位 Windows 跑 32 位 exe 没有兼容性问题系统会自动用 WoW64 机制处理。验证完帮助输出我还会用 Git Bash 里自带的file命令看一眼产物格式file C:\tools\mklittlefs\mklittlefs.exe输出里出现PE32 executable (console) Intel 80386就说明这确实是 i686 目标和文件名对得上。这一步看起来多余但能挡住「文件名写的是 i686实际下载了个 x86_64 版本」这类低级错误。命令行环境也有讲究cmd 里直接写相对路径PowerShell 里要加.\前缀Git Bash 里路径分隔符统一用/。我建议全程用 cmd 窗口操作最省事。3.2 第二步生成一个最小 littlefs 镜像假设你有一个data目录里面放了index.html、config.ini和一个assets子目录想打包成 1MB 的 littlefs 镜像命令是C:\tools\mklittlefs\mklittlefs.exe -c data -b 4096 -p 256 -s 1048576 littlefs.bin拆开说明-c data把 data 目录递归打包进镜像-b 4096指定块大小对应 Flash 最小擦除单位-p 256指定页大小对应 Flash 页编程粒度-s 1048576指定镜像总大小必须是分区容量的准确值最后的littlefs.bin是输出文件。执行完当前目录会出现一个正好 1048576 字节的镜像文件。这里要特别提醒mklittlefs 不同构建版本的参数命名确实有过混乱有的版本用-d表示块大小、-b表示块数有的则反过来。所以你在别处抄到一条命令参数含义可能和本版完全相反。最稳妥的做法是先跑-h看本版本输出再按「块大小、页大小、块数、镜像总大小」四个语义一一对应填进去。块数通常不需要手填因为块数 镜像大小 ÷ 块大小工具会自动算。常见错误集中在三个地方一是-c后面填了文件而不是目录二是-s填成整颗 Flash 容量而不是文件系统分区容量三是命令行路径里混用了中文或空格导致解析错位。前两个错误生成时不一定报错烧进设备才暴露所以生成完必须做下一步回读。3.3 第三步用 -l 回读镜像内容生成镜像后马上用列表参数回读C:\tools\mklittlefs\mklittlefs.exe -l littlefs.bin输出会打印镜像内部的目录树大致长这样/ index.html config.ini /assets logo.png看到这个列表和源目录一对比就能确认文件有没有被完整装进去。用dir /s /b data可以拿到源目录的完整文件清单把分隔符统一成/后再和-l输出对比。一个立刻能发现的典型差异是空目录在-l结果里可能根本不出现原因后面避坑章会说。我自己的习惯是把-l输出重定向保存成manifest.txt连同镜像一起提交到发布目录。以后任何人拿到这个镜像第一件事就是看 manifest不用重新生成也能知道里面装了什么。这一步花不了十秒钟但能让你少信很多「我明明放了那个文件」的邪门说法。4. 把参数对齐 Flash 规格一次烧录成功的前提是数据手册没抄错4.1 littlefs 参数从哪来数据手册上三个必抄数字到了这一章默认你已经成功生成过一个镜像。接下来要解决的是「怎么保证这个镜像在设备上一定能挂载」。答案只有一个参数必须来自 Flash 数据手册而不是来自网上抄来的命令模板。以一颗常见的 8MB SPI NOR Flash 为例数据手册的 Memory Architecture 章节会明确写出三行关键信息扇区擦除大小 4KB、页编程大小 256B、芯片总容量 8MB。你要抄的正是这三个数字。block_size 取扇区擦除大小绝大多数情况是 4096page_size 取页编程大小绝大多数情况是 256如果文件系统只分到 4MB 空间块数就是4MB ÷ 4KB 1024。有些 Flash 数据手册还会写支持 32KB 或 64KB 的区块擦除指令那是硬件擦除指令的粒度不代表 littlefs 的 block_size 也要跟着放大。用 4096 作为逻辑块能兼顾小文件写入效率和磨损均衡的精细度。设备端的lfs_config结构体里也有block_size和page_size两个字段它们必须和 mklittlefs 命令行参数保持一致。这个一致不是「大概对齐」而是字节级一致。我踩过一次工具按 4096 生成镜像设备端代码里block_size写成了 8192开发板上蒙混过了关因为硬件擦除时 8KB 对齐也没报错换了一批 Flash 后部分芯片挂载失败率直线上升最后定位到就是参数不一致。从那以后我把这些参数单独抽到一个配置文件里PC 端工具脚本和设备端头文件共用同一份数字谁都不许手改。4.2 不同容量场景下 littlefs 参数组合可直接抄表格根据文件系统分区容量我常用的组合就下面几种不同项目直接套用场景分区容量block_size块数page_size适用内容小型 Web 配置页1MB4096256256网页、配置文件、证书配置 日志2MB4096512256需要保留运行日志大资源包4MB40961024256固件备份、语音资源为什么 block_size 不选 8192 或 16384因为小文件多的时候块越大每个文件最少占用一块的浪费就越大。一个 100 字节的配置文件配 16KB 块名义上用了 16KB 空间磨损均衡和小文件碎片都会变差。反过来block_size 小于擦除单位也不行那会逼着底层驱动做读改写掉电安全等于没做。4096 是多数 SPI NOR Flash 的物理扇区大小也是最不容易出错的默认值。page_size 如果拿不准优先抄数据手册的 Page Program 字段。曾经有人把-p 4096填进去镜像生成毫不报错烧录后小文件读不出来——因为每次写入被当成整个 4KB 页而 Flash 实际页编程只能按 256B 推进数据覆盖逻辑整个错位。这类问题在日志里只会显示成偶发读错误排查起来非常费时。4.3 littlefs 镜像的分区偏移与烧录校验镜像生成只是中间产物烧到 Flash 的哪个地址决定了它能不能被正确挂载。常见做法是用分区表把一颗 Flash 切成几段bootloader、应用固件、文件系统各占一段。一个典型布局如下分区名类型起始偏移大小boot引导程序0x00000064KBapp应用固件0x0100001MBfs文件系统0x1D00001MBmklittlefs 的-s 1048576对应表中 fs 分区的大小而烧录工具的写入偏移必须填0x1D0000。有人习惯把镜像烧到0x000000结果 bootloader 被覆盖设备直接变砖。烧录完成后我建议立刻做一次回读校验flashwriter --read --offset 0x1D0000 --size 16读回来的前几个字节应该能看到 littlefs 超级块的魔法数而不是清一色的0xFF。这个动作相当于给烧录结果打了一个「确实写进去了」的标记比看烧录软件提示「成功」可靠得多。另外手工指定偏移时要确认它是 4KB 的整数倍否则后续任何按块擦除的操作都可能越界。5. 避坑mklittlefs 在 Windows 上最容易翻车的五个现场5.1 闪退运行时 DLL 缺失现象双击或命令行执行mklittlefs -h窗口一闪而过系统弹窗提示找不到libgcc_s_dw2-1.dll或libwinpthread-1.dll。原因这份产物是 MinGW 动态编译的GCC 运行时库没有打进 exe拷贝时只带了工具本体。解决把缺失的 DLL 拷到 exe 同目录或者换一份静态编译版本。验证方法是在 cmd 里手动执行并保留窗口弹窗信息会直接告诉你缺哪个文件。产线部署时我习惯在批处理开头加一段存在性检查工具或 DLL 缺失就中止流程避免烧到一半才发现环境不对。5.2 挂载报 LFS_ERR_CORRUPT几何参数不一致现象镜像生成正常、烧录正常但设备端lfs_mount返回LFS_ERR_CORRUPT。原因有三个方向block_size 与设备端配置不一致烧录偏移错误导致 mount 读到别的分区数据工具和设备端 littlefs 大版本不兼容。解决先把设备端lfs_config里的block_size和page_size打印出来和-h输出逐项对比再回读 Flash 前 16 字节确认超级块位置正确最后确认两端都是 littlefs v2。绝大多数「镜像坏了」最后都落在第一个原因上。5.3 中文文件名乱码代码页与 UTF-8 冲突现象Windows 上用中文目录名或文件名生成镜像-l看起来正常设备端读文件名却是乱码甚至打不开文件。原因Windows 命令行默认代码页是 GBKmklittlefs 按 UTF-8 字节流写入文件名两边编码对不上。解决静态资源统一用 ASCII 文件名必须用中文时先执行chcp 65001切到 UTF-8 代码页再运行工具。这里有一条血泪经验不要在 Git Bash 和 cmd 之间混用中文路径两个环境的转码行为不一致生成的镜像可能是同一个版本的两种结果。5.4 空目录从镜像里消失现象源目录里有logs/和cache/两个空目录生成镜像后用-l查看只剩下根目录。原因空目录在 littlefs 里没有实际数据块只有一条目录项记录某些构建版本的 mklittlefs 为了节省元数据空间会直接跳过。解决在空目录里放一个.keep占位文件或者让设备端代码在首次启动时负责mkdir。更稳妥的做法是不依赖镜像里是否存在空目录所有目录都由代码显式创建文件系统只是兜底。5.5 镜像越界覆盖其它分区现象烧录完成后设备无法启动或 bootloader 区数据被清空。原因-s填了整颗 Flash 大小而烧录偏移又恰好是0x000000镜像容量远超文件系统分区直接覆盖了后面的固件区也可能是分区表改过但镜像没有重新生成。解决在烧录脚本里加一行数值检查确认「分区起始偏移 镜像大小 ≤ 分区结束地址」不满足就退出。同时养成习惯每次修改分区表后必须重新生成镜像旧的 littlefs.bin 一律作废。这个检查代码量不大但能挡住产线上最贵的返工。6. 落一个验证习惯镜像内容与设备实际读取的 CRC 对照生成镜像、烧录成功只是一个良好开端真正能让你站稳脚跟的是对「生成内容」和「设备读出内容」做一致性校验。我在发布流程里放了一个 Python 小脚本先递归遍历源目录计算每个文件的 SHA256再调用 mklittlefs 的-l拿到镜像内的相对路径清单最后通过串口或者网络从设备端把每个文件读回来同样计算哈希。三边一致这个镜像才允许进入产线。import hashlib, os, subprocess, sys def dir_manifest(root): result {} for dirpath, _, filenames in os.walk(root): for f in filenames: path os.path.join(dirpath, f) rel os.path.relpath(path, root).replace(os.sep, /) h hashlib.sha256() with open(path, rb) as fh: for chunk in iter(lambda: fh.read(65536), b): h.update(chunk) result[rel] h.hexdigest() return result if __name__ __main__: source dir_manifest(sys.argv[1]) listing subprocess.check_output( [C:/tools/mklittlefs/mklittlefs.exe, -l, littlefs.bin], textTrue ) print(listing) # 设备端回读逻辑可复用 dir_manifest # 将设备端 /fs 目录下载到本地后用同一函数计算哈希再比对这段脚本的逻辑很直白dir_manifest递归遍历目录并计算哈希-l的输出用来核实路径清单设备端读回的文件目录用同一个函数算一遍。任何一层不一致都能立刻定位到是打包漏文件、还是烧录读回异常。需要注意Windows 下os.walk拿到的路径分隔符是反斜杠比对前统一转成/否则清单对比会全是假告警。这个习惯是一次教训换来的。有一回我把-s从 1MB 调到 2MB镜像生成顺利产线烧录也一路绿灯结果设备上电后配置文件读取被截断。查到最后发现文件系统元数据里记录的块范围越过了分区边界但工具和烧录器都没有明确报错。从那以后没有哈希对照的镜像一律不发版。希望这个习惯也能帮你少走一段弯路祝你的 littlefs 镜像一次过。本文还有配套的精品资源点击获取