重置與開機程序

執行 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()

  • 使用者按下開發板上的實體 Reset 按鈕(在適用的情況下)。

  • 從深度睡眠中喚醒(在大多數移植版本上)。

  • MCU 硬體看門狗重置。

  • MCU 硬體電壓不足偵測器。

硬體特定重置觸發條件的細節取決於移植版本及相關硬體。可使用 machine.reset_cause() 函式進一步判斷重置的原因。

軟重置

當 MicroPython 已在執行時,可透過 在 REPL 中輸入 Ctrl-D 或執行 machine.soft_reset() 來觸發軟重置。

軟重置會清除 Python 直譯器、釋放所有 Python 記憶體,並重新啟動 MicroPython 環境。

軟重置所清除的狀態包括:

  • 所有 Python 變數、物件、已匯入的模組等。

  • 大多數使用 machine 模組 設定的周邊裝置。但有極少數例外,例如 machine.Pin 模式(亦即接腳是輸入或輸出、高電位或低電位)在大多數移植版本上不會被重置。更進階的設定(例如 Pin.irq())則一定會被重置。

  • Bluetooth。

  • 網路 socket。已開啟的 TCP socket 會相對於另一方乾淨地關閉。

  • 已開啟的檔案。檔案系統會保持在有效狀態。

軟重置後某些系統狀態會維持不變,包括:

  • 任何現有的網路連線(Ethernet、Wi-Fi 等)在 IP 網路層仍保持作用中。從程式碼查詢 網路介面 可能會顯示該網路介面仍處於作用中狀態,並具有已設定的 IP 位址等。

  • 作用中的 REPL 在軟重置前後看起來是連續的,除了某些特殊情況:

    • 序列 UART REPL 會還原其預設的硬體設定(鮑率等)。

  • CPU 時脈速度通常不會因軟重置而改變。

  • RTC 設定(亦即目前時間的設定)不會因軟重置而改變。

開機程序

當 MicroPython 在硬重置或軟重置後開機時,它會依序遵循以下開機程序:

_boot.py

這是一個 凍結在 MicroPython 韌體中 的內部指令碼。MicroPython 在許多移植版本上都提供它,用來執行必要的初始化。

舉例來說,在大多數移植版本上,_boot.py 會偵測新裝置的首次開機,並格式化 內部 flash 檔案系統 以供使用。

除非你正在建立自訂的 MicroPython 組建或新增移植版本,否則你大概不需要在意 _boot.py。除非你真的清楚自己在做什麼,否則最好不要更改其內容。

boot.py

名為 boot.py 的檔案可使用 mpremote 複製到開發板的內部 檔案系統

如果找到 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.pymain.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 的全域環境中仍會保持設定狀態。

  • 為了充分最佳化 flash 用量與記憶體消耗,你可以將 預先編譯的 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 並接管。如果相機完全無法連線,請使用下方的原廠重置。接下來描述的 Ctrl-C 方法適用於直接的序列終端機工作階段,它依賴裝置上的 REPL,而 OpenMV IDE 並不使用該 REPL。

KeyboardInterrupt

在許多情況下,開啟 REPL 序列埠並輸入 Ctrl-C 會注入 KeyboardInterrupt,這可能會使正在執行的指令碼退出並啟動 REPL。在 REPL 中,你可以使用 os.remove() 移除行為異常的 Python 檔案::

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

若要確認內部檔案系統中還存在哪些檔案::

import os
os.listdir()

原廠重置

如果你無法使用上述方法進入 REPL,剩下的選項就是原廠重置:抹除內部 flash 檔案系統的全部內容。如果內部檔案系統已損毀,這也是修復的方法。

OpenMV IDE 有數種內建方式可以做到這一點。首先將相機切換到其復原/bootloader 模式,由於各開發板的方法不同,請參閱你開發板 快速參考 中的 Recovery and debug pins 一節,以了解如何進入該模式。然後在 OpenMV IDE 中點選連線按鈕,並依照提示抹除檔案系統並重新燒錄韌體。

警告

抹除檔案系統的情況下重新燒錄韌體,通常無法從軟變磚中復原,因為一般的韌體更新會保留檔案系統的內容。請務必在 OpenMV IDE 提示時選擇抹除選項。

如果你卡住了,請至 OpenMV 論壇 提問。