Reset- en opstartsequentie

Een apparaat waarop MicroPython draait, volgt een bepaalde opstartsequentie om te starten en zichzelf te initialiseren na een reset.

Notitie

De _boot.pyboot.pymain.py → REPL-sequentie die hieronder wordt beschreven, is wat de firmware bij elke reset uitvoert, ongeacht hoe je verbinding maakt — dus deze is altijd van toepassing. Wanneer je een script uitvoert vanuit OpenMV IDE, onderbreekt de IDE de momenteel draaiende main.py en voert in plaats daarvan het in de editor geopende script uit, via zijn eigen debugprotocol. Het gebruikt niet de REPL op het apparaat, dus de REPL-specifieke verwijzingen op deze pagina (de interactieve prompt, Ctrl-D / Ctrl-C op een seriële terminal, enz.) zijn van toepassing op standalone werking en directe seriële-terminalsessies — maar de opstartsequentie zelf is in alle gevallen van toepassing.

Harde reset

Opstarten vanuit een harde reset is wat er gebeurt wanneer een board voor het eerst wordt ingeschakeld, een koude start. Dit is een volledige reset van de MCU-hardware.

De MicroPython-portcode initialiseert alle essentiële hardware (waaronder ingebedde klokken en spanningsregelaars, interne seriële UART, enz.) en start vervolgens de MicroPython-omgeving. Bestaande RTC-configuratie kan na een harde reset behouden blijven, maar alle andere hardwaretoestand wordt gewist.

Dezelfde harde-reset-opstartsequentie kan worden geactiveerd door een aantal gebeurtenissen, zoals:

  • Python-code die machine.reset() uitvoert.

  • De gebruiker drukt op een fysieke Reset-knop op het board (waar van toepassing).

  • Ontwaken uit diepe slaap (op de meeste ports).

  • Reset door de hardware-watchdog van de MCU.

  • Brown-out-detector van de MCU-hardware.

De details van hardwarespecifieke reset-triggers hangen af van de port en de bijbehorende hardware. De functie machine.reset_cause() kan worden gebruikt om de oorzaak van een reset nader te bepalen.

Zachte reset

Wanneer MicroPython al draait, is het mogelijk een zachte reset te activeren door Ctrl-D te typen in de REPL of door machine.soft_reset() uit te voeren.

Een zachte reset wist de Python-interpreter, geeft al het Python-geheugen vrij en start de MicroPython-omgeving opnieuw.

Toestand die door een zachte reset wordt gewist, omvat:

  • Alle Python-variabelen, objecten, geïmporteerde modules, enz.

  • De meeste randapparaten die zijn geconfigureerd met de machine-module. Er zijn zeer beperkte uitzonderingen; zo worden bijvoorbeeld de machine.Pin-modi (d.w.z. of een pin invoer of uitvoer is, hoog of laag) op de meeste ports niet gereset. Meer geavanceerde configuratie zoals Pin.irq() wordt altijd gereset.

  • Bluetooth.

  • Netwerksockets. Open TCP-sockets worden netjes gesloten ten opzichte van de andere partij.

  • Open bestanden. Het bestandssysteem wordt in een geldige toestand achtergelaten.

Sommige systeemtoestand blijft na een zachte reset hetzelfde, waaronder:

  • Bestaande netwerkverbindingen (Ethernet, Wi-Fi, enz.) blijven actief op de IP-netwerklaag. Het opvragen van de netwerkinterface vanuit code kan aangeven dat de netwerkinterface nog steeds actief is met een geconfigureerd IP-adres, enz.

  • Een actieve REPL lijkt voor en na een zachte reset doorlopend, behalve in enkele ongebruikelijke gevallen:

    • Een seriële UART-REPL herstelt zijn standaard hardwareconfiguratie (baudrate, enz.).

  • De kloksnelheid van de CPU wordt doorgaans niet gewijzigd door een zachte reset.

  • RTC-configuratie (d.w.z. het instellen van de huidige tijd) wordt niet gewijzigd door een zachte reset.

Opstartsequentie

Wanneer MicroPython opstart na een harde of zachte reset, volgt het deze opstartsequentie in volgorde:

_boot.py

Dit is een intern script dat in de MicroPython-firmware is bevroren. Het wordt door MicroPython op veel ports geleverd om essentiële initialisatie uit te voeren.

Op de meeste ports detecteert _boot.py bijvoorbeeld de eerste opstart van een nieuw apparaat en formatteert het het interne flash-bestandssysteem om klaar te zijn voor gebruik.

Tenzij je een aangepaste MicroPython-build maakt of een nieuwe port toevoegt, hoef je je waarschijnlijk geen zorgen te maken over _boot.py. Je kunt de inhoud beter niet wijzigen, tenzij je echt weet wat je doet.

boot.py

Een bestand met de naam boot.py kan met mpremote naar het interne bestandssysteem van het board worden gekopieerd.

Als boot.py wordt gevonden, wordt het uitgevoerd. Je kunt code toevoegen aan boot.py om aangepaste eenmalige initialisatie uit te voeren (bijvoorbeeld om de hardware van het board te configureren).

Een gangbare werkwijze is om de netwerkverbinding van een board te configureren in boot.py, zodat deze na een reset altijd beschikbaar is voor gebruik met de REPL, mpremote, enz.

Waarschuwing

boot.py moet altijd afsluiten en niet onbeperkt blijven draaien.

Afhankelijk van het board wordt sommige hardware-initialisatie uitgesteld tot na het afsluiten van boot.py. Dit omvat het initialiseren van USB op de STM32-gebaseerde OpenMV Cams. Op deze boards is uitvoer die vanuit boot.py wordt afgedrukt mogelijk pas zichtbaar op de ingebouwde seriële USB-poort nadat boot.py klaar is met uitvoeren.

Het doel van deze late initialisatie is dat het mogelijk is om bepaalde hardware vooraf te configureren in boot.py en deze vervolgens met de juiste configuratie te laten starten.

Notitie

Soms is het eenvoudiger om geen boot.py-bestand te hebben en in plaats daarvan eventuele initialisatiecode bovenaan main.py te plaatsen.

main.py

Net als boot.py kan een bestand met de naam main.py naar het interne bestandssysteem van het board worden gekopieerd. Als het wordt gevonden, wordt het als volgende in het opstartproces uitgevoerd.

main.py is bedoeld voor Python-code die je elke keer dat je apparaat start wilt uitvoeren.

Enkele tips voor het gebruik van main.py:

  • main.py hoeft niet af te sluiten; je kunt er gerust een oneindige while True-lus in plaatsen.

  • Voor complexe Python-applicaties hoef je niet al je code in main.py te plaatsen. main.py kan een eenvoudig startpunt zijn dat je applicatie importeert en de uitvoering start:

    import my_app
    my_app.main()
    

    Dit kan helpen de structuur van je applicatie overzichtelijk te houden. Het maakt het ook eenvoudig om meerdere applicaties op een board te installeren en daartussen te wisselen.

  • Het is een goede gewoonte bij het schrijven van robuuste apps om code in main.py te omhullen met een exception-handler om passende actie te ondernemen als de code crasht. Bijvoorbeeld:

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

    Anders valt MicroPython na elke crash of wanneer main afsluit terug naar de REPL (zie hieronder).

  • Alle globale variabelen die in boot.py zijn ingesteld, blijven ingesteld in de globale context van main.py.

  • Om het gebruik van flashgeheugen en geheugenverbruik volledig te optimaliseren, kun je vooraf gecompileerde main.mpy- en/of boot.mpy-bestanden naar het bestandssysteem kopiëren, of ze zelfs bevriezen in de firmware-build.

  • De uitvoering van main.py wordt overgeslagen wanneer een zachte reset wordt geïnitieerd vanuit de raw REPL-modus (bijvoorbeeld wanneer mpremote of een ander programma rechtstreeks met MicroPython communiceert).

Interactieve interpreter (REPL)

Als main.py niet wordt gevonden, of als main.py afsluit, wordt De interactieve interpretermodus van MicroPython (ook wel REPL) onmiddellijk gestart.

Notitie

Zelfs als main.py een oneindige lus bevat, zal het typen van Ctrl-C op de seriële REPL-poort een KeyboardInterrupt injecteren. Als geen enkele exception-handler deze opvangt, sluit main.py af en start de REPL.

Alle globale variabelen die in boot.py en main.py zijn ingesteld, blijven ingesteld in de globale context van de REPL.

De REPL blijft uitvoeren totdat Python-code een harde of zachte reset activeert.

Soft bricking (mislukken van opstarten)

Het is zeldzaam maar mogelijk dat MicroPython tijdens het opstarten niet meer reageert, een toestand die soms “soft bricked” wordt genoemd. Bijvoorbeeld:

  • Als de uitvoering van boot.py vastloopt en de native seriële USB-poort nooit initialiseert.

  • Als Python-code de REPL-interface herconfigureert waardoor deze ontoegankelijk wordt.

Wees gerust, herstel is mogelijk!

Als je OpenMV IDE gebruikt, is alleen verbinding maken vaak al genoeg — de IDE stopt de draaiende main.py en neemt het over. Als de camera helemaal geen verbinding wil maken, gebruik dan de Factory Reset hieronder. De Ctrl-C-methode die hierna wordt beschreven, is voor directe seriële-terminalsessies — deze is afhankelijk van de REPL op het apparaat, die OpenMV IDE niet gebruikt.

KeyboardInterrupt

In veel gevallen zal het openen van de seriële REPL-poort en het typen van Ctrl-C een KeyboardInterrupt injecteren, wat ertoe kan leiden dat het draaiende script afsluit en een REPL start. Vanuit de REPL kun je os.remove() gebruiken om het zich misdragende Python-bestand te verwijderen:

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

Om te bevestigen welke bestanden nog aanwezig zijn in het interne bestandssysteem:

import os
os.listdir()

Factory Reset

Als je met de bovenstaande methode niet bij een REPL kunt komen, is de overgebleven optie een factory reset: het wissen van de volledige inhoud van het interne flash-bestandssysteem. Dit is ook de oplossing als het interne bestandssysteem beschadigd is geraakt.

OpenMV IDE heeft hiervoor verschillende ingebouwde manieren. Zet de camera eerst in zijn recovery-/bootloader-modus — de methode verschilt per board, dus zie het gedeelte Recovery and debug pins van de snelle referentie van je board voor hoe je deze activeert. Klik vervolgens op de verbindingsknop in OpenMV IDE en volg de aanwijzingen om het bestandssysteem te wissen en de firmware opnieuw te flashen.

Waarschuwing

Het opnieuw flashen van de firmware zonder het bestandssysteem te wissen, herstelt doorgaans niet van soft bricking, aangezien een normale firmware-update de inhoud van het bestandssysteem behoudt. Zorg ervoor dat je de wisoptie kiest wanneer OpenMV IDE daarom vraagt.

Als je vastloopt, vraag het dan op de OpenMV-forums.