复位与启动序列#

运行 MicroPython 的设备在复位后会遵循特定的启动序列来启动并初始化自身。

备注

下面描述的 _boot.pyboot.pymain.py → REPL 序列是固件在每次复位时都会运行的,无论你以何种方式连接——因此它始终适用。当你从 OpenMV IDE 运行脚本时,IDE 会中断当前正在运行的 main.py,并通过其自身的调试协议运行编辑器中打开的脚本来取而代之。它不使用设备上的 REPL,因此本页中特定于 REPL 的内容(交互式提示符、在串口终端按 Ctrl-D / Ctrl-C 等)适用于独立运行和直接的串口终端会话——但启动序列本身适用于所有情况。

硬复位#

硬复位启动发生在主板首次上电时,即冷启动。这是对 MCU 硬件的完全复位。

MicroPython 移植代码会初始化所有必要的硬件(包括嵌入式时钟和电源稳压器、内部串行 UART 等),然后启动 MicroPython 环境。已有的 RTC 配置在硬复位后可能会保留,但所有其他硬件状态都会被清除。

相同的硬复位启动序列可由多种事件触发,例如:

  • Python 代码执行 machine.reset()

  • 用户按下主板上的物理复位按钮(如适用)。

  • 从深度睡眠中唤醒(在大多数移植版本上)。

  • MCU 硬件看门狗复位。

  • MCU 硬件欠压检测器。

硬件相关复位触发的具体细节取决于移植版本及相关硬件。可使用 machine.reset_cause() 函数进一步确定复位的原因。

软复位#

当 MicroPython 已经在运行时,可以通过 在 REPL 中按 Ctrl-D 或执行 machine.soft_reset() 来触发软复位。

软复位会清除 Python 解释器、释放所有 Python 内存,并重新启动 MicroPython 环境。

软复位会清除的状态包括:

  • 所有 Python 变量、对象、已导入的模块等。

  • 使用 machine 模块 配置的大多数外设。也有极少数例外,例如 machine.Pin 模式(即引脚是输入还是输出、是高电平还是低电平)在大多数移植版本上不会被复位。而更高级的配置(例如 Pin.irq())则总是会被复位。

  • 蓝牙。

  • 网络套接字。已打开的 TCP 套接字会就对端而言被干净地关闭。

  • 已打开的文件。文件系统会保持在有效状态。

某些系统状态在软复位后保持不变,包括:

  • 任何已有的网络连接(以太网、Wi-Fi 等)在 IP 网络层仍然保持活动。从代码中查询 网络接口 可能会显示网络接口仍处于活动状态并配置了 IP 地址等。

  • 活动的 REPL 在软复位前后看起来是连续的,但在某些特殊情况下例外:

    • 串行 UART REPL 会恢复其默认的硬件配置(波特率等)。

  • 软复位通常不会改变 CPU 时钟速度。

  • RTC 配置(即当前时间的设置)不会被软复位改变。

启动序列#

当 MicroPython 在硬复位或软复位后启动时,会按以下顺序执行启动序列:

_boot.py#

这是一个 冻结到 MicroPython 固件中 的内部脚本。MicroPython 在许多移植版本上提供它,用于执行必要的初始化。

例如,在大多数移植版本上,_boot.py 会检测新设备的首次启动,并格式化 内部闪存文件系统 以备使用。

除非你要创建自定义的 MicroPython 构建或添加新的移植版本,否则你可能无需关心 _boot.py。除非你确实清楚自己在做什么,否则最好不要更改其内容。

boot.py#

可以使用 mpremote 将名为 boot.py 的文件复制到主板的内部 文件系统 中。

如果找到 boot.py,它就会被执行。你可以在 boot.py 中添加代码来执行自定义的一次性初始化(例如,配置主板的硬件)。

一种常见的做法是在 boot.py 中配置主板的网络连接,这样它在复位后就始终可用,可配合 REPLmpremote 等使用。

警告

boot.py 应当始终退出,而不应无限期运行。

根据主板的不同,某些硬件初始化会延迟到 boot.py 退出之后。这包括在基于 STM32 的 OpenMV Cam 上初始化 USB。在这些主板上,boot.py 打印的输出可能要等到 boot.py 运行结束后,才能在内置的 USB 串口上看到。

这种延迟初始化的目的是让你可以在 boot.py 中预先配置特定的硬件,然后让它以正确的配置启动。

备注

有时不使用 boot.py 文件,而是将任何初始化代码放在 main.py 的开头会更简单。

main.py#

boot.py 类似,可以将名为 main.py 的文件复制到主板的内部 文件系统 中。如果找到,它会在启动过程中接着被执行。

main.py 用于存放你希望在每次设备启动时运行的任何 Python 代码。

关于 main.py 用法的一些提示:

  • main.py 不一定要退出,可以随意在其中放置无限的 while True 循环。

  • 对于复杂的 Python 应用程序,你不需要把所有代码都放在 main.py 中。main.py 可以作为一个简单的入口点,导入你的应用程序并启动执行:

    import my_app
    my_app.main()
    

    这有助于保持应用程序结构的清晰。它还便于在主板上安装多个应用程序并在它们之间切换。

  • 编写健壮的应用程序时,一种良好的做法是在 main.py 中用异常处理程序包裹代码,以便在代码崩溃时采取适当的措施。例如:

    import machine, sys
    import my_app
    try:
        my_app.main()
    except Exception as e:
        print("Fatal error in main:")
        sys.print_exception(e)
    
    # Following a normal Exception or main() exiting, reset the board.
    # Following a non-Exception error such as KeyboardInterrupt (Ctrl-C),
    # this code will drop to a REPL. Place machine.reset() in a finally
    # block to always reset, instead.
    machine.reset()
    

    否则,在任何崩溃之后或当 main 退出时(见下文),MicroPython 都会进入 REPL。

  • 任何在 boot.py 中设置的全局变量在 main.py 的全局上下文中仍然有效。

  • 为了充分优化闪存使用和内存占用,你可以将 预编译的 main.mpy 和/或 boot.mpy 文件复制到文件系统中,甚至将它们 冻结 到固件构建中。

  • 当软复位从 原始 REPL 模式 发起时(例如,当 mpremote 或其他程序直接与 MicroPython 交互时),会跳过 main.py 的执行。

交互式解释器(REPL)#

如果未找到 main.py,或者 main.py 退出,那么 MicroPython 交互式解释器模式(即 REPL) 将立即启动。

备注

即使 main.py 包含一个无限循环,在 REPL 串口上按 Ctrl-C 也会注入一个 KeyboardInterrupt。如果没有异常处理程序捕获它,那么 main.py 将退出,REPL 将启动。

任何在 boot.pymain.py 中设置的全局变量在 REPL 的全局上下文中仍然有效。

REPL 会持续执行,直到 Python 代码触发硬复位或软复位。

软变砖(无法启动)#

虽然罕见,但 MicroPython 有可能在启动期间变得无响应,这种状态有时被称为“软变砖”。例如:

  • 如果 boot.py 的执行卡住,导致原生 USB 串口始终无法初始化。

  • 如果 Python 代码重新配置了 REPL 接口,使其无法访问。

请放心,是可以恢复的!

如果你使用 OpenMV IDE,通常只要连接就足够了——IDE 会停止正在运行的 main.py 并接管。如果摄像头完全无法连接,请使用下面的 Factory Reset(出厂重置)。接下来描述的 Ctrl-C 方法适用于直接的串口终端会话——它依赖于设备上的 REPL,而 OpenMV IDE 并不使用它。

KeyboardInterrupt#

在许多情况下,打开 REPL 串口并按 Ctrl-C 会注入 KeyboardInterrupt,可能会使正在运行的脚本退出并启动 REPL。从 REPL 中,你可以使用 os.remove() 来删除行为异常的 Python 文件:

import os
os.remove('main.py')

要确认内部文件系统中仍然存在哪些文件:

import os
os.listdir()

出厂重置#

如果你无法用上述方法进入 REPL,那么剩下的选择就是出厂重置:擦除内部闪存文件系统的全部内容。如果内部文件系统已损坏,这也是修复方法。

OpenMV IDE 提供了几种内置的方式来执行此操作。首先让摄像头进入其恢复/引导加载程序模式——具体方法因主板而异,请参阅你主板 快速参考 中的 Recovery and debug pins(恢复与调试引脚)一节,了解如何进入该模式。然后在 OpenMV IDE 中点击连接按钮,并按照提示擦除文件系统并重新烧录固件。

警告

擦除文件系统的情况下重新烧录固件通常无法从软变砖中恢复,因为正常的固件更新会保留文件系统的内容。请务必在 OpenMV IDE 提示时选择擦除选项。

如果你遇到困难,请在 OpenMV 论坛 上提问。