摘要:以 ESP Mini App Platform 0.4.9 Beta 为例,记录我如何把自己电脑上的固件构建结果整理成给别人首次安装的 Windows 发布包。重点不是写一个"双击即可"的批处理按钮,而是把完整镜像、校验、串口选择、烧录、可选存储初始化和硬件说明组成一条可复现的交付路径。
1. 背景:能烧录,不等于能交付
开发阶段,我知道当前工程的分区表、固件位置、串口号和烧录命令,在自己的电脑上运行成功并不难。但把项目交给第一次接触它的人时,对方通常只拿到一个 .bin 和一块开发板:这个文件是首次安装镜像还是 OTA 镜像?应该写到哪个地址?是否需要先擦除?哪个 COM 口是目标设备?失败后怎么判断?
因此,这次发布的目标不只是"固件可以启动",而是让一台未配置 ESP-IDF 的 Windows 10/11 64 位电脑,按照包内说明也能走完首次安装。这里的"一键"是统一入口和减少重复操作,不是取消硬件核对和破坏性操作确认。
本文所述包面向 ESP-Mosaico 开发板/ESP32-S31。它不是可直接烧录到所有 ESP32 型号的通用固件。
2. 先定义交付物,而不是先写 BAT
我最终整理出的发布包,关键内容如下:
text
ESP-Mini-App-Platform-0.4.9-Windows/
├─ 一键安装.bat # 首次安装入口
├─ 检查烧录包.bat # 只校验,不写设备
├─ 初始化外置NAND.bat # 按需单独初始化存储
├─ 开始使用.md
├─ 新手安装说明.md
├─ 硬件支持说明.md
├─ SHA256SUMS.txt
├─ release-manifest.json
├─ firmware/
│ ├─ merged-binary.bin # 首次安装使用的完整镜像
│ └─ esp_mini_platform.bin # 后续 OTA 使用的应用镜像
└─ tools/
├─ install.ps1
└─ esptool.exe # 随包携带的便携版工具
这是结构摘录,不是发布包中的全部文件。完整解压后再运行安装入口,不要只把 BAT 和某个 BIN 单独拷出来。
merged-binary.bin 把 Bootloader、分区表、初始 OTA 数据和平台固件组合到一个从 0x0 写入的镜像中。这样首次安装时不需要让新用户逐个理解地址、文件对应关系和分区版本。便携版 esptool 5.3.1 也一并提供,用户不必为这一步另外安装 Python 或 ESP-IDF。
设计发布包时,我把文件校验和硬件说明视为组成部分,而不是"有空再补"的附录。否则一个按钮能启动,却无法回答"刷错板子会怎样""原有设置会不会丢"这些真正影响使用的事。
3. 完整镜像、OTA 镜像、应用包:三种分发层级
这个项目是小应用平台,因此发布物不止一种。三者需要在说明里明确区分:
| 文件类型 | 面向的设备状态 | 作用 | 能否替代首次安装镜像 |
|---|---|---|---|
完整镜像 merged-binary.bin |
尚未安装平台的目标板 | 写入启动、分区与平台固件 | 可以,它就是首次安装入口 |
OTA 镜像 esp_mini_platform.bin |
已运行平台的设备 | 后续系统升级 | 不可以 |
.app 应用包 |
已运行平台且应用存储可用 | 单独安装或更新应用 | 不可以 |
第一次写入完整镜像后,设备通常先安装内置的 Hello WASM 示例。Touch Paint、Snake、Pocket Garden 等应用则在连接 Wi-Fi 后,通过在线目录获取。把多个应用放进首次烧录镜像并不是这套平台的目标;系统更新和应用发布应保持两条独立路径。
4. 安装脚本的核心流程
Windows 入口由 BAT 启动 PowerShell 脚本,实际流程可以概括为:
text
检查发布包文件和 SHA-256
↓
列出当前 COM 口,选择目标串口
↓
用户核对 ESP-Mosaico/ESP32-S31 和数据范围
↓
输入 INSTALL 后调用 esptool 写入完整镜像
↓
显示结果、保留运行记录
↓
询问是否检查并按需初始化外置 NAND
脚本先确认 firmware/merged-binary.bin、其校验文件和 tools/esptool.exe 均存在,再计算完整镜像的 SHA-256。校验失败应直接停止,不应让错误文件进入烧录阶段。
串口选择也要可理解:只检测到一个 COM 口时可以自动使用,多个串口时让用户选序号。选中串口后,脚本显示目标型号和数据影响范围,只有准确输入 INSTALL 才继续。连接设备后,esptool 会输出识别到的芯片信息。窗口错误提示和临时目录下的运行记录,便于在首次安装失败时定位问题。
目前的写入参数核心如下,路径和 COM 口由工具填入;这段用于说明结构,不建议新用户绕过安装脚本直接复制执行:
powershell
.\tools\esptool.exe --chip esp32s31 -p COM19 -b 115200 --before default-reset --after hard-reset --no-stub write-flash --flash-mode dio --flash-size 16MB --flash-freq 80m 0x0 .\firmware\merged-binary.bin
上面的 COM19 只是示例,实际串口应以安装工具检测结果为准;命令需在完整解压后的发布包根目录运行。
脚本固定使用 115200 波特率,写入前不会执行 erase-flash 整片擦除。早期脚本曾在 ESP32-S31 ROM 下载模式下调用不支持的整片擦除操作;修正版改为让写入命令处理镜像覆盖的扇区。这个问题在文章里一笔带过,关键结论是:烧录工具的行为必须与目标芯片实际支持的模式一致。
5. 数据边界:内部 Flash 与外置 NAND 分开看
"不整片擦除 16 MB"不等于"旧数据完全不受影响"。完整镜像从 0x0 写入,镜像覆盖范围内的内部 Flash 扇区会被擦写,原固件和位于该范围的 NVS 设置会被覆盖。镜像范围外的数据可保留,但不能保证新固件一定能识别或继续使用。因此对已有设备,仍应先备份重要配置。
外置 SPI NAND 是另一块存储。平台用它保存在线应用包、应用文件和缓存。首次烧录内部 Flash 时,不会自动清除外置 NAND。安装脚本会询问是否检查并按需初始化;若设备检测到 NAND 已挂载,不会再次格式化。只有确认尚未挂载、且用户输入 INIT 后,才会发送格式化命令。全新设备可以选择这一步;有历史数据的设备应该先判断是否需要保留。
把这两种存储写成两个独立动作,是为了避免一句"烧录会清空数据"过于笼统,也避免一句"不会整片擦除"给人错误的安全感。
6. 新用户的完整路径
面对当前直接支持的 ESP-Mosaico/ESP32-S31,包内《新手安装说明》给出的路径是:
- 用支持数据传输的 USB 线连接开发板,完整解压 Windows 压缩包。
- 按住
BOOT、短按RESET、松开BOOT,进入 ROM 下载模式。 - 双击
一键安装.bat,选择串口,核对硬件与数据范围,输入INSTALL。 - 成功重启后,按需初始化外置 NAND;有需保留的数据时先跳过。
- 在设备设置中连接 2.4 GHz Wi-Fi,打开应用库的在线应用页面并刷新。
- 选择 Touch Paint、Snake 或 Pocket Garden 等应用安装。
在线目录地址已经写进 0.4.9 固件,普通用户不用手动输入 JSON 目录 URL。但这一步仍依赖可用 Wi-Fi、HTTPS 访问和就绪的应用存储;因此"固件烧录成功"与"可以在线安装应用"是两个不同的检查点。
7. 硬件支持范围写在显眼处
当前公开完整镜像直接支持的组合是:ESP-Mosaico、ESP32-S31、16 MB 内部 Flash、当前配置的 PSRAM、480 × 480 CO5300 QSPI 显示、CST9217 触摸和板载 SPI NAND。
ESP32-S3 与 ESP32-S31 不是同一个固件目标。即使接上相似外设,也不能直接写入本包。其他 ESP32-S31 开发板也要先适配 BSP、屏幕、触摸、存储、引脚和分区,再生成自己的完整镜像。把这句话放在安装前,比烧录失败后再解释更有效。
8. 对交付流程的复盘
这次真正改变的,不是把命令包成 BAT,而是把"构建者脑子里的隐含前提"逐一变成发布包中的显式信息:
- 哪个二进制文件用于第一次安装;
- 哪些文件要一起保留;
- 写入前怎样检查内容是否完整;
- 用户要核对哪个芯片和串口;
- 内部 Flash 与外置 NAND 分别会怎样变化;
- 失败后到哪里看提示;
- 固件成功启动后怎样安装第一个应用。
对我而言,能在自己的开发机上烧录,只是项目运行的起点;别人能在没有开发环境的电脑上,按说明走到"打开第一个应用",才算完成一次真正的交付。
ESP32-S31、ESP32、esptool、嵌入式开发、固件烧录、OTA、Windows、项目交付