Sequência de Reset e Arranque

Um dispositivo a executar MicroPython segue uma sequência de arranque específica para iniciar e inicializar-se após um reset.

Nota

A sequência _boot.pyboot.pymain.py → REPL descrita abaixo é o que o firmware executa em cada reset, independentemente de como se liga — portanto aplica-se sempre. Quando executa um script a partir do OpenMV IDE, o IDE interrompe o main.py em execução e executa em seu lugar o script aberto no editor, através do seu próprio protocolo de depuração. Não utiliza o REPL do dispositivo, pelo que as referências específicas ao REPL nesta página (a linha de comandos interativa, Ctrl-D / Ctrl-C num terminal série, etc.) aplicam-se ao funcionamento autónomo e a sessões diretas de terminal série — mas a sequência de arranque em si aplica-se em todos os casos.

Reset forçado

O arranque após reset forçado é o que acontece quando uma placa é ligada pela primeira vez, um arranque a frio. Trata-se de um reset completo do hardware do MCU.

O código do port MicroPython inicializa todo o hardware essencial (incluindo relógios embebidos e reguladores de tensão, UART série interno, etc.) e depois inicia o ambiente MicroPython. A configuração existente do RTC pode ser mantida após um reset forçado, mas todos os outros estados de hardware são limpos.

A mesma sequência de arranque após reset forçado pode ser desencadeada por vários eventos, tais como:

  • Código Python a executar machine.reset().

  • O utilizador prime um botão físico de Reset na placa (quando aplicável).

  • Despertar do modo de sono profundo (na maioria dos ports).

  • Reset do watchdog de hardware do MCU.

  • Detetor de subtensão de hardware do MCU.

Os detalhes dos gatilhos de reset específicos do hardware dependem do port e do hardware associado. A função machine.reset_cause() pode ser utilizada para determinar melhor a causa de um reset.

Reset suave

Quando o MicroPython já está em execução, é possível desencadear um reset suave digitando Ctrl-D no REPL ou executando machine.soft_reset().

Um reset suave limpa o interpretador Python, liberta toda a memória Python e reinicia o ambiente MicroPython.

O estado que é limpo por um reset suave inclui:

  • Todas as variáveis Python, objetos, módulos importados, etc.

  • A maioria dos periféricos configurados com o módulo machine. Existem exceções muito limitadas; por exemplo, os modos de machine.Pin (ou seja, se um pino é entrada ou saída, alto ou baixo) não são repostos na maioria dos ports. Configurações mais avançadas como Pin.irq() são sempre repostas.

  • Bluetooth.

  • Sockets de rede. Os sockets TCP abertos são fechados de forma limpa em relação à outra parte.

  • Ficheiros abertos. O sistema de ficheiros é deixado num estado válido.

Algum estado do sistema permanece igual após um reset suave, incluindo:

  • Quaisquer ligações de rede existentes (Ethernet, Wi-Fi, etc.) permanecem ativas na camada de Rede IP. A consulta da interface de rede a partir do código pode indicar que a interface de rede ainda está ativa com um endereço IP configurado, etc.

  • Um REPL ativo aparece de forma contínua antes e depois do reset suave, exceto em alguns casos invulgares:

    • Um REPL de UART série irá restaurar a sua configuração de hardware predefinida (taxa de baud, etc.).

  • A velocidade do relógio da CPU normalmente não é alterada por um reset suave.

  • A configuração do RTC (ou seja, a definição da hora atual) não é alterada pelo reset suave.

Sequência de Arranque

Quando o MicroPython arranca após um reset forçado ou suave, segue esta sequência de arranque por ordem:

_boot.py

Este é um script interno incorporado no firmware MicroPython. É fornecido pelo MicroPython em muitos ports para realizar a inicialização essencial.

Por exemplo, na maioria dos ports, o _boot.py irá detetar o primeiro arranque de um novo dispositivo e formatar o sistema de ficheiros flash interno pronto para utilização.

A menos que esteja a criar uma compilação personalizada do MicroPython ou a adicionar um novo port, provavelmente não precisa de se preocupar com o _boot.py. É preferível não alterar o conteúdo a não ser que saiba mesmo o que está a fazer.

boot.py

Um ficheiro chamado boot.py pode ser copiado para o sistema de ficheiros interno da placa usando mpremote.

Se o boot.py for encontrado, então é executado. Pode adicionar código em boot.py para realizar inicialização personalizada única (por exemplo, para configurar o hardware da placa).

Uma prática comum é configurar a ligação de rede de uma placa em boot.py para que esteja sempre disponível após o reset para utilização com o REPL, mpremote, etc.

Aviso

O boot.py deve sempre terminar e não executar indefinidamente.

Dependendo da placa, alguma inicialização de hardware é adiada até após a saída do boot.py. Isto inclui a inicialização do USB nas OpenMV Cams baseadas em STM32. Nessas placas, a saída impressa a partir do boot.py pode não ser visível na porta série USB integrada até que o boot.py termine de executar.

O objetivo desta inicialização tardia é possibilitar a pré-configuração de hardware específico em boot.py e depois iniciá-lo com a configuração correta.

Nota

Por vezes é mais simples não ter um ficheiro boot.py e colocar qualquer código de inicialização no início do main.py.

main.py

De forma semelhante ao boot.py, um ficheiro chamado main.py pode ser copiado para o sistema de ficheiros interno da placa. Se for encontrado, é executado a seguir no processo de arranque.

O main.py destina-se a qualquer código Python que pretenda executar de cada vez que o seu dispositivo arrancar.

Algumas dicas para a utilização do main.py:

  • O main.py não tem de terminar; à vontade para colocar um ciclo while True infinito.

  • Para aplicações Python complexas, não precisa de colocar todo o código em main.py. O main.py pode ser um ponto de entrada simples que importa a sua aplicação e inicia a execução:

    import my_app
    my_app.main()
    

    Isto pode ajudar a manter clara a estrutura da sua aplicação. Também facilita a instalação de múltiplas aplicações numa placa e a alternância entre elas.

  • É boa prática, ao escrever aplicações robustas, envolver o código em main.py com um tratador de exceções para tomar a ação adequada se o código falhar. Por exemplo:

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

    Caso contrário, o MicroPython passará para o REPL após qualquer falha ou se o main terminar (ver abaixo).

  • Quaisquer variáveis globais que tenham sido definidas em boot.py ainda estarão definidas no contexto global de main.py.

  • Para otimizar totalmente a utilização do flash e o consumo de memória, pode copiar ficheiros main.mpy e/ou boot.mpy pré-compilados para o sistema de ficheiros, ou mesmo incorporá-los na compilação do firmware.

  • A execução do main.py é ignorada quando um reset suave é iniciado a partir do modo REPL bruto (por exemplo, quando o mpremote ou outro programa está a interagir diretamente com o MicroPython).

Interpretador Interativo (REPL)

Se o main.py não for encontrado, ou se o main.py terminar, então o O Modo de Interpretador Interativo do MicroPython (também conhecido como REPL) iniciará imediatamente.

Nota

Mesmo que o main.py contenha um ciclo infinito, digitar Ctrl-C na porta série REPL irá injetar um KeyboardInterrupt. Se nenhum tratador de exceções o capturar, o main.py irá terminar e o REPL iniciará.

Quaisquer variáveis globais que tenham sido definidas em boot.py e main.py ainda estarão definidas no contexto global do REPL.

O REPL continua a executar até que o código Python desencadeie um reset forçado ou suave.

Bloqueio Suave (falha no arranque)

É raro mas possível que o MicroPython fique sem resposta durante o arranque, um estado por vezes chamado de «bloqueio suave». Por exemplo:

  • Se a execução do boot.py ficar bloqueada e a porta série USB nativa nunca inicializar.

  • Se o código Python reconfigurar a interface REPL, tornando-a inacessível.

Fique descansado, a recuperação é possível!

Se usar o OpenMV IDE, simplesmente ligar é frequentemente suficiente — o IDE para o main.py em execução e assume o controlo. Se a câmara não conseguir ligar de todo, use a opção Factory Reset abaixo. O método Ctrl-C descrito a seguir é para sessões diretas de terminal série — depende do REPL no dispositivo, que o OpenMV IDE não utiliza.

KeyboardInterrupt

Em muitos casos, abrir a porta série REPL e digitar Ctrl-C irá injetar KeyboardInterrupt e pode fazer com que o script em execução termine e um REPL inicie. A partir do REPL, pode usar os.remove() para remover o ficheiro Python com comportamento indevido:

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

Para confirmar quais os ficheiros ainda presentes no sistema de ficheiros interno:

import os
os.listdir()

Factory Reset

Se não conseguir aceder a um REPL usando o método acima, a opção restante é uma reposição de fábrica: apagar todo o conteúdo do sistema de ficheiros flash interno. Esta é também a solução se o sistema de ficheiros interno ficar corrompido.

O OpenMV IDE tem várias formas integradas de o fazer. Primeiro coloque a câmara no modo de recuperação/bootloader — o método difere por placa, por isso consulte a secção Recovery and debug pins da referência rápida da sua placa para saber como entrar nesse modo. Depois clique no botão de ligação no OpenMV IDE e siga as instruções para apagar o sistema de ficheiros e re-instalar o firmware.

Aviso

Re-instalar o firmware sem apagar o sistema de ficheiros normalmente não recupera de um bloqueio suave, pois uma atualização normal de firmware preserva o conteúdo do sistema de ficheiros. Certifique-se de escolher a opção de apagar quando o OpenMV IDE solicitar.

Se ficar bloqueado, pergunte nos fóruns OpenMV.