diff options
author | Angus Gratton <angus@redyak.com.au> | 2024-10-02 19:16:39 +1000 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2024-11-19 10:57:26 +1100 |
commit | 0e7c3901b897a1edd53b56b6119f2d4119e88842 (patch) | |
tree | 1264a33779159677fa6550cfc8bdecd91c2ee6ea /docs/reference | |
parent | cbffe61f96d060ed4af2bde7e3043a3664dc147a (diff) | |
download | micropython-0e7c3901b897a1edd53b56b6119f2d4119e88842.tar.gz micropython-0e7c3901b897a1edd53b56b6119f2d4119e88842.zip |
docs: Add a "Reset and Boot Sequence" reference page.
Previously individual ports documented these aspects to varying degrees,
but most of the information is common to all ports.
In particular, this adds a canonical explanation of `boot.py` and
`main.py`.
This work was funded through GitHub Sponsors.
Signed-off-by: Angus Gratton <angus@redyak.com.au>
Diffstat (limited to 'docs/reference')
-rw-r--r-- | docs/reference/index.rst | 1 | ||||
-rw-r--r-- | docs/reference/mpremote.rst | 6 | ||||
-rw-r--r-- | docs/reference/repl.rst | 9 | ||||
-rw-r--r-- | docs/reference/reset_boot.rst | 260 |
4 files changed, 272 insertions, 4 deletions
diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 98f6b65737..1558c0fdfa 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -21,6 +21,7 @@ implementation and the best practices to use them. glossary.rst repl.rst + reset_boot.rst mpremote.rst mpyfiles.rst isr_rules.rst diff --git a/docs/reference/mpremote.rst b/docs/reference/mpremote.rst index b47ec76c98..d4c6983595 100644 --- a/docs/reference/mpremote.rst +++ b/docs/reference/mpremote.rst @@ -547,9 +547,9 @@ device at ``/dev/ttyACM1``, printing each result. mpremote resume exec "print_state_info()" soft-reset -Connect to the device without triggering a soft reset and execute the -``print_state_info()`` function (e.g. to find out information about the current -program state), then trigger a soft reset. +Connect to the device without triggering a :ref:`soft reset <soft_reset>` and +execute the ``print_state_info()`` function (e.g. to find out information about +the current program state), then trigger a soft reset. .. code-block:: bash diff --git a/docs/reference/repl.rst b/docs/reference/repl.rst index 55f76ee1a0..be02ddebde 100644 --- a/docs/reference/repl.rst +++ b/docs/reference/repl.rst @@ -143,10 +143,12 @@ the auto-indent feature, and changes the prompt from ``>>>`` to ``===``. For exa Paste Mode allows blank lines to be pasted. The pasted text is compiled as if it were a file. Pressing Ctrl-D exits paste mode and initiates the compilation. +.. _repl_soft_reset: + Soft reset ---------- -A soft reset will reset the python interpreter, but tries not to reset the +A :ref:`soft_reset` will reset the python interpreter, but tries not to reset the method by which you're connected to the MicroPython board (USB-serial, or Wifi). You can perform a soft reset from the REPL by pressing Ctrl-D, or from your python @@ -182,6 +184,9 @@ variables no longer exist: ['__name__', 'pyb'] >>> +For more information about reset types and the startup process, see +:doc:`/reference/reset_boot`. + The special variable _ (underscore) ----------------------------------- @@ -196,6 +201,8 @@ So you can use the underscore to save the result in a variable. For example: 15 >>> +.. _raw_repl: + Raw mode and raw-paste mode --------------------------- diff --git a/docs/reference/reset_boot.rst b/docs/reference/reset_boot.rst new file mode 100644 index 0000000000..7c0d5f334a --- /dev/null +++ b/docs/reference/reset_boot.rst @@ -0,0 +1,260 @@ +Reset and Boot Sequence +======================= + +A device running MicroPython follows a particular boot sequence to start up and +initialise itself after a reset. + +.. _hard_reset: + +Hard reset +---------- + +Booting from hard reset is what happens when a board is first powered up, a cold +boot. This is a complete reset of the MCU hardware. + +The MicroPython port code initialises all essential hardware (including embedded +clocks and power regulators, internal serial UART, etc), and then starts the +MicroPython environment. Existing :doc:`RTC </library/machine.RTC>` +configuration may be retained after a hard reset, but all other hardware state +is cleared. + +The same hard reset boot sequence can be triggered by a number of events such as: + +- Python code executing :func:`machine.reset()`. +- User presses a physical Reset button on the board (where applicable). +- Waking from deep sleep (on most ports). +- MCU hardware watchdog reset. +- MCU hardware brown out detector. + +The details of hardware-specific reset triggers depend on the port and +associated hardware. The :func:`machine.reset_cause()` function can be used to +further determine the cause of a reset. + +.. _soft_reset: + +Soft Reset +---------- + +When MicroPython is already running, it's possible to trigger a soft reset by +:ref:`typing Ctrl-D in the REPL <repl_soft_reset>` or executing +:func:`machine.soft_reset()`. + +A soft reset clears the Python interpreter, frees all Python memory, and starts +the MicroPython environment again. + +State which is cleared by a soft reset includes: + +- All Python variables, objects, imported modules, etc. +- Most peripherals configured using the :doc:`machine module + </library/machine>`. There are very limited exceptions, for example + :doc:`machine.Pin </library/machine.Pin>` modes (i.e. if a pin is input or + output, high or low) are not reset on most ports. More advanced configuration + such as :func:`Pin.irq()` is always reset. +- Bluetooth. +- Network sockets. Open TCP sockets are closed cleanly with respect to the other party. +- Open files. The filesystem is left in a valid state. + +Some system state remains the same after a soft reset, including: + +- Any existing network connections (Ethernet, Wi-Fi, etc) remain active at the + IP Network layer. Querying the :doc:`network interface from code + </library/network>` may indicate the network interface is still active with a + configured IP address, etc. +- An active :doc:`REPL <repl>` appears continuous before and after soft reset, + except in some unusual cases: + + * If the :ref:`machine.USBDevice <machine.USBDevice>` class has been used to + create a custom USB interface then any built-in USB serial device will + appear to disconnect and reconnect as the custom USB interface must be + cleared during reset. + * A serial UART REPL will restore its default hardware configuration (baud + rate, etc). + +- CPU clock speed is usually not changed by a soft reset. +- :doc:`RTC </library/machine.RTC>` configuration (i.e. setting of the current + time) is not changed by soft reset. + +.. _boot_sequence: + +Boot Sequence +------------- + +When MicroPython boots following either a hard or soft reset, it follows this +boot sequence in order: + +_boot.py +^^^^^^^^ + +This is an internal script :doc:`frozen into the MicroPython firmware +<manifest>`. It is provided by MicroPython on many ports to do essential +initialisation. + +For example, on most ports ``_boot.py`` will detect the first boot of a new +device and format the :doc:`internal flash filesystem <filesystem>` ready for +use. + +Unless you're creating a custom MicroPython build or adding a new port then you +probably don't need to worry about ``_boot.py``. It's best not to change the +contents unless you really know what you're doing. + +.. _boot.py: + +boot.py +^^^^^^^ + +A file named ``boot.py`` can be copied to the board's internal :ref:`filesystem +<filesystem>` using :doc:`mpremote <mpremote>`. + +If ``boot.py`` is found then it is executed. You can add code in ``boot.py`` to +perform custom one-off initialisation (for example, to configure the board's +hardware). + +A common practice is to configure a board's network connection in ``boot.py`` so +that it's always available after reset for use with the :doc:`REPL <repl>`, +:doc:`mpremote <mpremote>`, etc. + +.. warning:: boot.py should always exit and not run indefinitely. + + Depending on the port, some hardware initialisation is delayed until after + ``boot.py`` exits. This includes initialising USB on the stm32 port and all + ports which support :ref:`machine.USBDevice <machine.USBDevice>`. On these + ports, output printed from ``boot.py`` may not be visible on the built-in USB + serial port until after ``boot.py`` finishes running. + + The purpose of this late initialisation is so that it's possible to + pre-configure particular hardware in ``boot.py``, and then have it start with + the correct configuration. + +.. note:: It is sometimes simpler to not have a ``boot.py`` file and place any + initialisation code at the top of ``main.py`` instead. + +.. _main.py: + +main.py +^^^^^^^ + +Similar to ``boot.py``, a file named ``main.py`` can be copied to the board's +internal :ref:`filesystem <filesystem>`. If found then it is executed next in the +startup process. + +``main.py`` is for any Python code that you want to run each time your device +starts. + +Some tips for ``main.py`` usage: + +- ``main.py`` doesn't have to exit, feel free to put an infinite ``while + True`` loop in there. +- For complex Python applications then you don't need to put all your + code in ``main.py``. ``main.py`` can be a simple entry point that + imports your application and starts execution:: + + import my_app + my_app.main() + + This can help keep the structure of your application clear. It also makes + it easy to install multiple applications on a board and switch among them. +- It's good practice when writing robust apps to wrap code in ``main.py`` with an + exception handler to take appropriate action if the code crashes. For example:: + + 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() + + Otherwise MicroPython will drop to the REPL following any crash or if main + exits (see below). + +- Any global variables that were set in ``boot.py`` will still be set in the + global context of ``main.py``. + +- To fully optimise flash usage and memory consumption, you can copy + :doc:`pre-compiled <mpyfiles>` ``main.mpy`` and/or ``boot.mpy`` files to the + filesystem, or even :doc:`freeze <manifest>` them into the firmware build + instead. +- ``main.py`` execution is skipped when a soft reset is initiated from :ref:`raw + REPL mode <raw_repl>` (for example, when :doc:`mpremote <mpremote>` or another + program is interacting directly with MicroPython). + +Interactive Interpreter (REPL) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If ``main.py`` is not found, or if ``main.py`` exits, then :doc:`repl` +will start immediately. + +.. note:: Even if ``main.py`` contains an infinite loop, typing Ctrl-C on the + REPL serial port will inject a `KeyboardInterrupt`. If no exception + handler catches it then ``main.py`` will exit and the REPL will start. + +Any global variables that were set in ``boot.py`` and ``main.py`` will still be +set in the global context of the REPL. + +The REPL continues executing until Python code triggers a hard or soft reset. + +.. _soft_bricking: + +Soft Bricking (failure to boot) +--------------------------------- + +It is rare but possible for MicroPython to become unresponsive during startup, a +state sometimes called "soft bricked". For example: + +- If ``boot.py`` execution gets stuck and the native USB serial port + never initialises. +- If Python code reconfigures the REPL interface, making it inaccessible. + +Rest assured, recovery is possible! + +KeyboardInterrupt +^^^^^^^^^^^^^^^^^ + +In many cases, opening the REPL serial port and typing ``Ctrl-C`` will inject +`KeyboardInterrupt` and may cause the running script to exit and a REPL to +start. From the REPL, you can use :func:`os.remove()` to remove the misbehaving +Python file:: + + import os + os.remove('main.py') + +To confirm which files are still present in the internal filesystem:: + + import os + os.listdir() + +Safe Mode and Factory Reset +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you're unable to easily access the REPL then you may need to perform one of +two processes: + +1. "Safe mode" boot, which skips ``boot.py`` and ``main.py`` and immediately + starts a REPL, allowing you to clean up. This is only supported on some ports. +2. Factory Reset to erase the entire contents of the flash filesystem. This may + also be necessary if the internal flash filesystem has become corrupted + somehow. + +The specific process(es) are different on each port: + +- :doc:`pyboard and stm32 port instructions </pyboard/tutorial/reset>` +- :doc:`renesas-ra port instructions </renesas-ra/tutorial/reset>` +- :doc:`wipy port instructions </wipy/tutorial/reset>` + +For ports without specific instructions linked above, the factory reset process +involves erasing the board's entire flash and then flashing MicroPython again +from scratch. Usually this will involve the same tool(s) that were originally +used to install MicroPython. Consult the installation docs for your board, or +ask on the `GitHub Discussions`_ if you're not sure. + +.. warning:: Re-flashing the MicroPython firmware without erasing the entire + flash first will usually not recover from soft bricking, as a + firmware update usually preserves the contents of the filesystem. + +.. _GitHub Discussions: https://github.com/orgs/micropython/discussions |