启动流程

[English]

ESP-VISION 沿用 MicroPython 的复位与启动模型,并增加 Flash 文件系统、板级存储、摄像头、显示和预览服务的初始化。本章说明当前固件实际实现的启动顺序。关于上游模型和通用行为,请参阅 MicroPython v1.28.0 复位与启动流程

硬复位与软复位

硬复位会先重启 MCU 和 ESP-IDF 运行时,再创建新的 MicroPython 环境。上电、开发板复位按键、machine.reset()、看门狗或欠压复位以及从深度睡眠唤醒都会触发硬复位。应用需要区分复位来源时,可以使用 machine.reset_cause()

软复位在不重启完整 MCU 运行时的情况下重新启动 MicroPython 环境,可通过友好 REPL 中的 Ctrl-Dmachine.soft_reset() 触发。ESP-VISION 会清除 Python 对象和模块,通过 MicroPython 清理过程关闭文件和 socket,释放摄像头、显示、预览、USB、PWM、定时器、UART、线程及其他托管资源,然后重新执行 Python 启动流程。

部分系统状态可能在软复位后保留,包括 RTC、CPU 时钟配置,以及 IP 层仍处于活动状态的网络接口。应用代码不能假定表示这些资源的 Python 对象仍然存在;每次复位后都应重新创建对象并检查其状态。

ESP-VISION 启动顺序

硬复位或软复位后,ESP-VISION 执行以下启动流程:

主机自动化工具使用的原始 REPL 可以在软复位时跳过 main.py,从而使开发工具无需自动启动产品应用即可取得设备控制权。

首次启动与 Flash 文件系统

冻结的 _boot.py 仅尝试挂载内部 Flash 文件系统,ESP-VISION 专用初始化由 py_inisetup.py 完成。如果 Flash 引导扇区为空,该脚本会格式化配置的 vfsffat 分区,并将其挂载到 /。随后在对应文件不存在时创建 /boot.py/main.py/README.txt/.esp_vision_disk 标记文件。

如果挂载文件系统或写入默认文件失败,py_inisetup.py 会尝试通过格式化文件系统并重新创建默认文件进行修复。格式化会清除该文件系统中的文件,因此必须在文件系统恢复后保留的产品数据应存放在独立分区、SD 卡或设备外部。

正常固件升级或软复位不会覆盖已有启动文件。开发板包可以通过 boards/<BOARD>/board_inisetup.py 提供板级默认 main.pyREADME.txt 内容。

使用 boot.py

boot.py 适合执行必须在应用启动前完成、耗时短且结果确定的初始化,例如选择产品模式、准备配置或启动必需的网络接口:

import network

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

boot.py 必须返回,不应包含应用的永久循环。ESP-VISION 仅在 boot.py 完成后初始化 MicroPython USB 设备,因此阻塞或长时间运行的 boot.py 可能导致 USB REPL 和主机工具无法使用。

使用 main.py

main.py 应作为产品应用入口。建议将具体实现放在独立模块中,使启动策略与应用逻辑彼此独立:

import sys
import my_app

try:
    my_app.main()
except KeyboardInterrupt:
    raise
except Exception as error:
    print("Fatal application error:")
    sys.print_exception(error)

允许 KeyboardInterrupt 继续抛出,可以使用 Ctrl-C 停止应用并进入友好 REPL。产品应用需要自动恢复时,也可以记录异常后调用 machine.reset(),但无条件复位循环会增加开发和故障诊断难度。

ESP-VISION 默认 main.py 会输出开发板就绪信息并在循环中休眠,使 VSCode 扩展和其他主机工具能够取得控制权。可按 Ctrl-C 中断该脚本并进入 REPL,或使用产品入口替换 /main.py

REPL 与故障恢复

main.py 正常退出或抛出未捕获异常后,控制权会转交给友好 REPL。Ctrl-C 会向正在运行的 Python 脚本注入 KeyboardInterrupt,在友好 REPL 中按 Ctrl-D 则会启动软复位。

如果应用导致设备无法正常启动,可以连接 REPL,使用 Ctrl-C 中断应用,然后重命名或删除启动文件:

import os

print(os.listdir("/"))
os.rename("/main.py", "/main.disabled.py")
# 使用 Ctrl-D 重新启动,并避免运行之前的 main.py。

如果无法恢复 REPL,应在仓库根目录擦除并重新烧录开发板。erase-flash 会清除设备的全部 Flash,包括内部文件系统和用户数据:

idf.py --board <BOARD> -p <PORT> erase-flash
idf.py --board <BOARD> -p <PORT> flash monitor

不执行 erase-flash 的重新烧录通常会保留数据文件系统,因此也可能保留存在问题的 boot.pymain.py