|
|
Subscribe / Log in / New account

MicroPython 1.20: Python for microcontrollers

May 11, 2023

This article was contributed by Koen Vervloesem

The MicroPython programming language implements a sizable subset of Python that can run on microcontrollers, thus bringing Python's easy-to-learn syntax, readability, and versatility to the embedded world. With its recent 1.20 release, MicroPython introduces a new package manager, reduces its code size, and adds support for many new boards, including the Raspberry Pi Pico W. The project has come a long way since its inception ten years ago, making it an easy-to-use tool for developing software for resource-constrained environments.

$ sudo subscribe today

Subscribe today and elevate your LWN privileges. You’ll have access to all of LWN’s high-quality articles as soon as they’re published, and help support LWN in the process. Act now and you can start with a free trial subscription.

The MIT-licensed MicroPython was created in 2013 by Damien George as a Kickstarter project, along with the pyboard, a microcontroller board to run it on. LWN looked at MicroPython on the pyboard in 2015. There are still updated versions of the pyboard available in the MicroPython store; they are the official MicroPython boards and their sales support the ongoing development of the project.

By using MicroPython, developers can build on their knowledge of Python to create software for microcontrollers, where they typically would need to write C code. The resulting program may not be as fast as a compiled C program, but in many cases the tradeoff for ease of development is worth it. However, developers should be aware of the (well documented) differences from CPython, the canonical Python interpreter. MicroPython implements Python 3.4, as well as some select features of Python 3.5 and above. Some of Python's built-in types and standard library modules are not implemented fully. For example, slicing a string with a step other than one is not implemented, and user-defined attributes for built-in exceptions aren't supported either.

There's a reason for many of the differences from CPython: the interpreter needs to be able to run on devices with low resources. Additionally, the project applies several optimizations. One of these is that small integers are not allocated on the heap, as explained in the documentation about memory management. To avoid storing duplicate copies of the same string (including function and variable names), MicroPython uses string interning. The documentation also lists some tips to maximize speed.

Instead of letting MicroPython load a Python module, parse it, generate its bytecode and then execute it, developers can instead pre-compile their modules and load the resulting .mpy file on the board. This avoids the overhead of parsing and generating the bytecode on the microcontroller. This is similar to the CPython .pyc files, but MicroPython has its own bytecode representation.

A further optimization is frozen bytecode: this allows building the pre-compiled bytecode into the firmware image when compiling MicroPython for a specific board. When this firmware image is installed to the board, the bytecode will be executed from flash memory rather than copied into RAM, and objects of immutable types (such as strings and tuples) are loaded from flash memory as well. This results in less RAM usage and reduces heap fragmentation.

Supported hardware

MicroPython offers firmware downloads for more than 150 microcontroller boards. This includes boards with Espressif's ESP32 and ESP8266 microcontroller families, boards with an STM32 ARM Cortex-M processor, Microchip's SAMD microcontrollers with ARM Cortex-M0+ core, Nordic Semiconductor's nRF5 chips, and the Raspberry Pi Foundation's RP2040-based boards (including the Raspberry Pi Pico W). Each board's download page includes installation instructions. For example, a Raspberry Pi Pico with the UF2 bootloader requires the user to hold down the BOOTSEL button while plugging the board into USB, after which the firmware file can be copied to the USB mass storage device that appears. Other boards have their own specific requirements.

MicroPython has also been ported to the Zephyr real-time operating system. In MicroPython 1.20, this port is based on Zephyr 3.1.0, which was released in June 2022; the current Zephyr release is 3.3.0. A Zephyr development environment can be used to build MicroPython for every target board supported by Zephyr, although not all have been tested. It also gives MicroPython code access to Zephyr's uniform sensor API using the zsensor module. More information can be found in MicroPython's documentation about the Zephyr port.

The Zephyr port allows MicroPython to run on the BBC micro:bit v2, whereas there's only a direct port for the BBC micro:bit v1. The process of setting up the development environment, building the Zephyr port for the target board, and then flashing the firmware to the board is explained in the port's README file.

Development environment

When the MicroPython interpreter, which is written in C, is running on a microcontroller board, it offers a read-eval-print loop (REPL) shell. For most boards, the REPL is available using a serial connection over the board's USB port. This allows the user to connect to the MicroPython REPL with a tool such as GNU Screen and then interactively run commands on the board. The project also offers the mpremote tool to interact with a MicroPython device over a serial connection.

Thonny and Mu Editor are two popular development environments that not only support the MicroPython language and integrate the REPL, but also let the user install the MicroPython firmware on a connected board. Last year, the Arduino developers published an experimental pre-release of their own lightweight editor for MicroPython programs: Arduino Lab for MicroPython.

Using mpremote or one of the supported development environments, a developer can upload Python code to the board's filesystem. The MicroPython interpreter evaluates two files at boot: boot.py and main.py (or .mpy versions instead). The boot.py file is supposed to contain initialization code, for example to connect to a WiFi network. The main.py file should contain the main code of the program, which often executes the device's task indefinitely in an infinite loop.

As an example, here's some MicroPython code for a NeoPixel stick with its IN pin connected to the GPIO22 pin of a board (which I tested using an ESP32 board):

    from machine import Pin
    from neopixel import NeoPixel
    from time import sleep

    PIXELS = 8
    RED = (32, 0, 0)
    OFF = (0, 0, 0)
    np = NeoPixel(Pin(22), PIXELS)

    while True:
	for i in range(PIXELS):
	    np[i] = RED
	    np.write()
	    sleep(0.1)
	    np[i] = OFF
	    np.write()
	    sleep(0.1)

After importing the modules it needs, the program starts by declaring some constants. Since the neopixel library needs its colors specified as a tuple of red, green, and blue components, the color RED uses 32 as the red component (the maximum value 255 is blindingly bright on those LEDs). After this, the code creates a NeoPixel object for GPIO pin 22 and the number of pixels (LEDs) defined. This object is indexable, so the infinite loop just cycles through all the pixels, setting them one by one to the red color for 100 ms, before turning them off again.

Libraries

MicroPython comes with three types of libraries. Some modules are reimplementations of part of the Python standard library. These are modules such as collections, json, socket, and uasyncio (a subset of Python's asyncio module).

The second type of libraries implements functionality specific to MicroPython. These include the bluetooth module that offers low-level access to Bluetooth Low Energy, the machine module that is useful to control I/O pins, use a board's analog-to-digital converters, or use the I2C protocol, and the network module for network access. MicroPython also has some libraries that are specific to a board family.

Due to resource constraints or other hardware-specific limitations, MicroPython's libraries don't include all functions, classes or even modules on all devices. This information should always be consulted in the "Quick reference" for the device family's port in the sidebar of MicroPython's documentation.

While those two types of libraries are directly built into the MicroPython firmware, there are some additional external libraries that are maintained in the micropython-lib repository. Some of these libraries are implementations of parts of the CPython standard library that are not built in the firmware to save space. Others implement a subset of popular Python packages, such as the urequests version of the Requests HTTP library. It also hosts some MicroPython-specific packages, such as drivers for sensors, displays, and other hardware.

The recent MicroPython 1.20 release replaced the previous package manager upip with mip, which can be used to install libraries from the micropython-lib repository. The firmware includes the mip module on any network-capable board, after which libraries can be installed from the REPL as long as there's a network connection set up on the board:

    >>> import mip 
    >>> mip.install("neopixel")

The default behavior is to fetch .mpy files with pre-compiled bytecode (which is versioned) for libraries from micropython-lib. The package manager installs the files in the board's file system, where they are available to the developer's Python files.

Instead of supplying a package name from the micropython-lib repository, it's also possible to point to a GitHub repository or an arbitrary URL if it contains a package.json file with information about the files to install and the package's dependencies.

MicroPython on the web

Another interesting target is WebAssembly (Wasm), which allows MicroPython to run in a web browser. The WebAssembly port's README includes instructions to compile the MicroPython firmware to Wasm using Emscripten. When Anaconda founder Peter Wang announced PyScript at PyCon 2022, it was using CPython compiled to WebAssembly (from Pyodide) and making that available in the web browser so developers could create web apps in Python.

In November 2022, Anaconda followed up with the announcement of a second runtime for PyScript, based on MicroPython. This is currently a technical preview to explore the tradeoffs of using different Python runtimes. PyScript's MicroPython runtime has a total size of only 303KB and starts running the developer's script in less than 100ms, while the Pyodide runtime weights 11MB and is slower to start up.

Since the announcement in November, there hasn't been anything more about this alternative runtime on Anaconda's blog, but it looks like some things are cooking. In early April, Ted Patrick, PyScript's Engineering Manager, opened a GitHub issue in the PyScript repository with the message "MicroPython is going to be supported as an alternative Python interpreter to Pyodide", and assigning it to the project's 2023-Q2 milestone. So it looks like MicroPython will be supported quite soon as an alternative PyScript runtime.

Conclusion

For those looking for an easy way to program microcontrollers, MicroPython has much to offer. Together with alternatives like Adafruit's MicroPython fork CircuitPython and the education-focused Snek, it shows that Python has a place in the embedded world. The closest competitor for microcontroller development, Arduino, requires at least some knowledge of C++, but Python is generally easier to pick up. Moreover, as the WebAssembly port and its use as a smaller and faster PyScript runtime shows, MicroPython seems to be well suited for other constrained environments as well.


Index entries for this article
GuestArticlesVervloesem, Koen
PythonEmbedded
PythonImplementations
PythonMicroPython


to post comments

MicroPython 1.20: Python for microcontrollers

Posted May 11, 2023 14:17 UTC (Thu) by strombrg (subscriber, #2178) [Link]

There are additional reasons to be interested in Micropython:
1) It runs on Linux. https://docs.micropython.org/en/latest/develop/gettingsta...
2) It appears to thread well:https://stromberg.dnsalias.org/~strombrg/python-thread-co...
3) It is small enough to download quickly, making it an interesting way of getting python inside a web browser. I'm not sure how far along this is, but I've heard there's motion in the Right Direction (TM). https://pyscript.net/tech-preview/micropython/about.html

BTW, Python (the language) is also interesting because it gives rise to rapid development - it's not just easy to learn, it's quick to code in.

Full disclosure: I did the thread comparison, and it is not exhaustive; it only looks at one embarallel problem.


Copyright © 2023, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds