1. 构建系统与工具链

本仓库包含两套并行的固件构建系统,分别对应不同硬件平台:

  • ESP32 掌控板(firmware/port/):基于 MicroPython 官方 ESP32 port,使用自维护的 Makefile 直接调用 ESP-IDF v4.0.1(通过 ESPIDF_SUPHASH_V4 = f56e8baef7fd663d590e6d3b04300066580ea7 锁定),交叉编译器为 xtensa-esp32-elf-*。构建产物经 makeimg.py 合并 bootloader/partition/application,再经 release.py 打包含 VFS、字体的完整固件镜像。

  • ESP32-S3 掌控板 3.0(esp32s3/firmware/):采用现代 ESP-IDF v5.x(默认 v5.5.4,见 eim_config.toml)+ CMake 构建,顶层 CMakeLists.txt 通过 MICROPY_BOARD 选择板型,自动拼接 SDKCONFIG_DEFAULTS 列表生成 sdkconfig.combined,最终由 IDF 的 project.cmake 驱动编译,并通过 makeimg.py 解析分区表生成 .bin 与 .uf2。

文档侧使用 Sphinx(docs/docs/conf.py、esp32s3/docs/conf.py),通过 make html / make.bat 生成中文手册,与固件源码分离。

2. 关键文件与包

  • ESP32 构建入口:firmware/port/Makefile(主构建脚本)、firmware/port/makeimg.py(bootloader/partition/app 三合一)、firmware/port/release.py(追加 vfs.bin 与字体到 0x200000/0x400000 偏移)、firmware/port/mpconfigport.h、firmware/port/qstrdefsport.h。

  • ESP32 板级配置:firmware/port/boards/<board>/mpconfigboard.mk(如 mpython/mpconfigboard.mk 叠加 sdkconfig.base、sdkconfig.240mhz、sdkconfig.ble)、各 sdkconfig.* 片段、manifest.py(冻结 Python 模块到 flash)。

  • ESP32-S3 构建入口:esp32s3/firmware/CMakeLists.txt、esp32s3/firmware/esp32_common.cmake、esp32s3/firmware/makeimg.py(解析分区表、生成 bin/uf2、注入 voice_data/srmodels)。

  • ESP32-S3 板级配置:esp32s3/firmware/boards/<board>/mpconfigboard.cmake(声明 IDF_TARGET=esp32s3、SDKCONFIG_DEFAULTS、MICROPY_SOURCE_BOARD、MICROPY_FROZEN_MANIFEST)、partitions-16MiB.csv(定义 factory/vfs/voice_data/model/fr/user_nvs 分区)、sdkconfig.board(音频/GMF AI 语音、BLE、SPIRAM 等 Kconfig 选项)。

  • 环境配置:esp32s3/firmware/eim_config.toml(指定 IDF 路径、工具链版本、镜像源)。

  • 发布脚本:firmware/port/release.py 固定偏移(bootloader=0x1000, partitions=0x8000, application=0x10000, vfs=0x200000, font=0x400000),esp32s3/firmware/makeimg.py 动态从分区表读取偏移并校验溢出。

3. 架构与约定

3.1 多板型抽象

  • ESP32:通过 BOARD ?= mpython 变量切换 boards/<board>/mpconfigboard.mk,Makefile 强制要求目录存在否则报错($(error Invalid BOARD specified))。

  • ESP32-S3:通过 MICROPY_BOARD(默认 mpython_v3)选择 boards/<board>/mpconfigboard.cmake,支持 MICROPY_BOARD_VARIANT 变体;每个板型独立 sdkconfig.board、partitions-*.csv、manifest.py。

3.2 配置分层

  • 基础配置:sdkconfig.base 提供通用 Kconfig 值。

  • 能力开关:sdkconfig.ble、sdkconfig.240mhz、sdkconfig.spiram、sdkconfig.usb 等可组合片段。

  • 板专属:sdkconfig.board 集中板级外设(如 S3 的 GMF AI Audio、SR_WN_WN9_NIHAOXIAOZHI_TTS)。

  • 构建时拼接:ESP32 在 Makefile 中 SDKCONFIG += ... 累加;ESP32-S3 在 CMake 中 foreach(SDKCONFIG_DEFAULT ${SDKCONFIG_DEFAULTS}) 写入 sdkconfig.combined.in 后复制为 sdkconfig.combined。

3.3 固件镜像组装

  • ESP32:make all → application.bin + bootloader.bin + partitions.bin → makeimg.py 合并 → release.py 追加 vfs.bin/font.bin → deploy 目标用 esptool 烧录。

  • ESP32-S3:CMake 构建出 micropython.bin + bootloader + partition-table.bin → makeimg.py 先调用 mklittlefs 打包 file_system/<board> 为 littlefs.bin,再按分区表偏移写入 vfs/voice_data/model 分区,最后对 S3/S2 芯片额外生成 .uf2。

3.4 Python 模块冻结策略

  • ESP32:boards/manifest.py 冻结 $(PORT_DIR)/modules 与 $(BOARD_DIR)/modules。

  • ESP32-S3:boards/manifest.py 额外 include asyncio、require bundle-networking、aioespnow、dht、ds18x20、onewire、upysh、collections 等标准库。

3.5 依赖与工具链管理

  • ESP32:通过 ESPIDF_SUPHASH_V3/V4 精确锁定 ESP-IDF commit,构建前检查 pyparsing==2.3.1 与 xtensa 工具链是否可用。

  • ESP32-S3:通过 eim_config.toml 声明 idf_versions=["v5.5.4"] 及所需工具集(xtensa/riscv/clang/ninja/openocd),并使用 lockfiles/dependencies.lock.${IDF_TARGET} 约束组件版本,CI 下若 lockfile 变更则失败。

4. 约定与约束

  • 板型命名:ESP32 板型位于 firmware/port/boards/<name>/,ESP32-S3 板型位于 esp32s3/firmware/boards/<name>/,两者互不混用;S3 当前支持 mpython_v3、labplus_Ledong_v2、labplus_for_xuejing、labplus_xunfei_js_middle、labplus_xunfei_js_primary 五种。

  • Kconfig 不可越权:ESP32 Makefile 显式禁止直接使用 SDKCONFIG 变量绕过 board 机制(ifneq ($(SDKCONFIG),) $(error Use the BOARD variable instead of SDKCONFIG))。

  • 分区表驱动布局:ESP32-S3 所有偏移来自 partitions-*.csv,makeimg.py 通过 gen_esp32part.PartitionTable.from_binary() 解析,任何手动修改必须同步更新 CSV;构建时会断言 offset >= cur_offset 防止重叠。

  • VFS 文件系统:ESP32 使用 LFS2(MICROPY_VFS_LFS2 = 1),通过 make_lfs.py 将 file_system/ 打包为 vfs.bin 写入 0x200000;ESP32-S3 同样使用 LittleFS,但额外包含 file_system/common/* 与 <board>/* 两个子目录内容。

  • 字体资源:ESP32 构建要求外部 Noto_Sans_CJK_SC_Light16.bin 置于根目录并写入 0x400000;ESP32-S3 的 makeimg.py 也引用同名字体文件。

  • 版本信息:ESP32 固件名取自 git describe --tags(MICROPY_GIT_TAG);ESP32-S3 的 makeimg.py 同时提取 git tag、short hash 与 build date 拼入文件名。

  • 构建产物隔离:ESP32 输出至 build/<BOARD>/,ESP32-S3 输出至 CMake BUILD 目录(默认 build/),避免多板并行冲突。

  • 文档与固件解耦:docs/ 与 esp32s3/docs/ 仅含 Sphinx 源码与示例代码,不参与固件编译;示例代码位于 docs/examples/ 与 esp32s3/firmware/examples/,供用户参考而非构建系统的一部分。