Sekwencja resetu i rozruchu

Urządzenie z systemem MicroPython wykonuje określoną sekwencję rozruchu, aby uruchomić się i zainicjalizować po resecie.

Informacja

Sekwencja _boot.pyboot.pymain.py → REPL opisana poniżej jest tym, co oprogramowanie układowe wykonuje przy każdym resecie, niezależnie od sposobu połączenia — więc obowiązuje ona zawsze. Gdy uruchamiasz skrypt z OpenMV IDE, IDE przerywa aktualnie wykonywany main.py i uruchamia w jego miejsce skrypt otwarty w edytorze, korzystając z własnego protokołu debugowania. Nie używa ono REPL na urządzeniu, więc odwołania specyficzne dla REPL na tej stronie (interaktywny wiersz poleceń, Ctrl-D / Ctrl-C na terminalu szeregowym itp.) dotyczą działania samodzielnego oraz bezpośrednich sesji terminala szeregowego — ale sama sekwencja rozruchu obowiązuje we wszystkich przypadkach.

Twardy reset

Rozruch z twardego resetu następuje, gdy płytka jest włączana po raz pierwszy, czyli przy zimnym starcie. Jest to całkowity reset sprzętu MCU.

Kod portu MicroPython inicjalizuje cały niezbędny sprzęt (w tym wbudowane zegary i regulatory zasilania, wewnętrzny UART szeregowy itp.), a następnie uruchamia środowisko MicroPython. Istniejąca konfiguracja RTC może zostać zachowana po twardym resecie, ale cały pozostały stan sprzętu jest czyszczony.

Tę samą sekwencję rozruchu z twardego resetu może wywołać szereg zdarzeń, takich jak:

  • Kod Python wykonujący machine.reset().

  • Naciśnięcie przez użytkownika fizycznego przycisku Reset na płytce (jeśli dotyczy).

  • Wybudzenie z głębokiego snu (na większości portów).

  • Reset sprzętowego watchdoga MCU.

  • Sprzętowy detektor zaniku napięcia (brown out) MCU.

Szczegóły specyficznych dla sprzętu wyzwalaczy resetu zależą od portu i powiązanego sprzętu. Funkcja machine.reset_cause() może posłużyć do dokładniejszego ustalenia przyczyny resetu.

Miękki reset

Gdy MicroPython już działa, możliwe jest wywołanie miękkiego resetu poprzez wpisanie Ctrl-D w REPL lub wykonanie machine.soft_reset().

Miękki reset czyści interpreter Python, zwalnia całą pamięć Pythona i ponownie uruchamia środowisko MicroPython.

Stan czyszczony przez miękki reset obejmuje:

  • Wszystkie zmienne, obiekty, zaimportowane moduły Pythona itp.

  • Większość urządzeń peryferyjnych skonfigurowanych za pomocą modułu machine. Istnieją bardzo nieliczne wyjątki, na przykład tryby machine.Pin (tj. czy pin jest wejściem czy wyjściem, w stanie wysokim czy niskim) nie są resetowane na większości portów. Bardziej zaawansowana konfiguracja, taka jak Pin.irq(), jest zawsze resetowana.

  • Bluetooth.

  • Gniazda sieciowe. Otwarte gniazda TCP są poprawnie zamykane względem drugiej strony.

  • Otwarte pliki. System plików pozostaje w prawidłowym stanie.

Część stanu systemu pozostaje niezmieniona po miękkim resecie, w tym:

  • Wszelkie istniejące połączenia sieciowe (Ethernet, Wi-Fi itp.) pozostają aktywne na warstwie sieciowej IP. Zapytanie o interfejs sieciowy z poziomu kodu może wskazywać, że interfejs sieciowy jest nadal aktywny ze skonfigurowanym adresem IP itp.

  • Aktywny REPL wygląda na ciągły przed i po miękkim resecie, z wyjątkiem pewnych nietypowych przypadków:

    • REPL na szeregowym UART przywróci swoją domyślną konfigurację sprzętową (szybkość transmisji (baud) itp.).

  • Częstotliwość taktowania CPU zwykle nie jest zmieniana przez miękki reset.

  • Konfiguracja RTC (tj. ustawienie bieżącego czasu) nie jest zmieniana przez miękki reset.

Sekwencja rozruchu

Gdy MicroPython uruchamia się po twardym lub miękkim resecie, wykonuje tę sekwencję rozruchu w następującej kolejności:

_boot.py

Jest to wewnętrzny skrypt zamrożony w oprogramowaniu układowym MicroPython. Jest on dostarczany przez MicroPython na wielu portach w celu wykonania niezbędnej inicjalizacji.

Na przykład na większości portów _boot.py wykryje pierwszy rozruch nowego urządzenia i sformatuje wewnętrzny system plików pamięci flash, przygotowując go do użycia.

O ile nie tworzysz własnej kompilacji MicroPython ani nie dodajesz nowego portu, prawdopodobnie nie musisz przejmować się _boot.py. Najlepiej nie zmieniać jego zawartości, chyba że naprawdę wiesz, co robisz.

boot.py

Plik o nazwie boot.py można skopiować do wewnętrznego systemu plików płytki za pomocą mpremote.

Jeśli boot.py zostanie znaleziony, jest wykonywany. Możesz dodać kod do boot.py, aby przeprowadzić niestandardową, jednorazową inicjalizację (na przykład skonfigurować sprzęt płytki).

Powszechną praktyką jest konfigurowanie połączenia sieciowego płytki w boot.py, tak aby było ono zawsze dostępne po resecie do użytku z REPL, mpremote itp.

Ostrzeżenie

boot.py powinien zawsze zakończyć działanie i nie wykonywać się w nieskończoność.

W zależności od płytki część inicjalizacji sprzętu jest opóźniona aż do zakończenia działania boot.py. Obejmuje to inicjalizację USB na kamerach OpenMV Cam opartych na STM32. Na tych płytkach dane wyjściowe wypisywane z boot.py mogą nie być widoczne na wbudowanym porcie szeregowym USB aż do zakończenia wykonywania boot.py.

Celem tej opóźnionej inicjalizacji jest umożliwienie wstępnego skonfigurowania określonego sprzętu w boot.py, tak aby uruchamiał się on z prawidłową konfiguracją.

Informacja

Czasami prościej jest nie posiadać pliku boot.py i umieścić cały kod inicjalizacyjny zamiast tego na początku main.py.

main.py

Podobnie jak boot.py, plik o nazwie main.py można skopiować do wewnętrznego systemu plików płytki. Jeśli zostanie znaleziony, jest wykonywany jako następny w procesie uruchamiania.

main.py służy do umieszczania dowolnego kodu Python, który chcesz uruchamiać przy każdym starcie urządzenia.

Kilka wskazówek dotyczących używania main.py:

  • main.py nie musi kończyć działania, możesz umieścić w nim nieskończoną pętlę while True.

  • W przypadku złożonych aplikacji Python nie musisz umieszczać całego kodu w main.py. main.py może być prostym punktem wejścia, który importuje Twoją aplikację i rozpoczyna jej wykonywanie:

    import my_app
    my_app.main()
    

    Może to pomóc zachować przejrzystość struktury Twojej aplikacji. Ułatwia również zainstalowanie wielu aplikacji na płytce i przełączanie się między nimi.

  • Pisząc niezawodne aplikacje, dobrą praktyką jest opakowanie kodu w main.py procedurą obsługi wyjątków, aby podjąć odpowiednie działania w razie awarii kodu. Na przykład:

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

    W przeciwnym razie MicroPython przejdzie do REPL po każdej awarii lub gdy main zakończy działanie (patrz poniżej).

  • Wszelkie zmienne globalne ustawione w boot.py będą nadal ustawione w kontekście globalnym main.py.

  • Aby w pełni zoptymalizować wykorzystanie pamięci flash i zużycie pamięci, możesz skopiować prekompilowane pliki main.mpy i/lub boot.mpy do systemu plików, a nawet zamrozić je zamiast tego w kompilacji oprogramowania układowego.

  • Wykonanie main.py jest pomijane, gdy miękki reset jest inicjowany z trybu raw REPL (na przykład gdy mpremote lub inny program wchodzi w bezpośrednią interakcję z MicroPython).

Interaktywny interpreter (REPL)

Jeśli main.py nie zostanie znaleziony lub jeśli main.py zakończy działanie, natychmiast uruchomi się Tryb interaktywnego interpretera MicroPython (czyli REPL).

Informacja

Nawet jeśli main.py zawiera nieskończoną pętlę, wpisanie Ctrl-C na porcie szeregowym REPL spowoduje wstrzyknięcie KeyboardInterrupt. Jeśli żadna procedura obsługi wyjątków go nie przechwyci, main.py zakończy działanie i uruchomi się REPL.

Wszelkie zmienne globalne ustawione w boot.py i main.py będą nadal ustawione w kontekście globalnym REPL.

REPL kontynuuje wykonywanie, dopóki kod Python nie wywoła twardego lub miękkiego resetu.

Miękkie zablokowanie (niepowodzenie rozruchu)

Rzadko, ale jednak możliwe jest, że MicroPython przestanie reagować podczas uruchamiania, czyli wejdzie w stan czasem nazywany „soft bricked” (miękko zablokowany). Na przykład:

  • Jeśli wykonanie boot.py utknie i natywny port szeregowy USB nigdy się nie zainicjalizuje.

  • Jeśli kod Python ponownie skonfiguruje interfejs REPL, czyniąc go niedostępnym.

Bez obaw, odzyskanie jest możliwe!

Jeśli używasz OpenMV IDE, samo połączenie często wystarcza — IDE zatrzymuje działający main.py i przejmuje kontrolę. Jeśli kamera w ogóle się nie łączy, użyj opisanego poniżej przywracania ustawień fabrycznych. Opisana dalej metoda Ctrl-C jest przeznaczona do bezpośrednich sesji terminala szeregowego — opiera się na REPL na urządzeniu, którego OpenMV IDE nie używa.

KeyboardInterrupt

W wielu przypadkach otwarcie portu szeregowego REPL i wpisanie Ctrl-C spowoduje wstrzyknięcie KeyboardInterrupt i może doprowadzić do zakończenia działającego skryptu oraz uruchomienia REPL. Z poziomu REPL możesz użyć os.remove(), aby usunąć źle działający plik Python:

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

Aby potwierdzić, które pliki są nadal obecne w wewnętrznym systemie plików:

import os
os.listdir()

Przywracanie ustawień fabrycznych

Jeśli nie możesz uzyskać dostępu do REPL przy użyciu powyższej metody, pozostałą opcją jest przywrócenie ustawień fabrycznych: skasowanie całej zawartości wewnętrznego systemu plików pamięci flash. Jest to również rozwiązanie w przypadku, gdy wewnętrzny system plików uległ uszkodzeniu.

OpenMV IDE oferuje kilka wbudowanych sposobów na zrobienie tego. Najpierw wprowadź kamerę w tryb odzyskiwania/bootloadera — metoda różni się w zależności od płytki, więc zajrzyj do sekcji Recovery and debug pins w krótkim przewodniku swojej płytki, aby dowiedzieć się, jak w niego wejść. Następnie kliknij przycisk połączenia w OpenMV IDE i postępuj zgodnie z monitami, aby skasować system plików i ponownie wgrać oprogramowanie układowe.

Ostrzeżenie

Ponowne wgranie oprogramowania układowego bez kasowania systemu plików zwykle nie pozwoli odzyskać urządzenia z miękkiego zablokowania, ponieważ normalna aktualizacja oprogramowania układowego zachowuje zawartość systemu plików. Pamiętaj, aby wybrać opcję kasowania, gdy OpenMV IDE o nią poprosi.

Jeśli utkniesz, zapytaj na forum OpenMV.