CircuitPython: Python for microcontrollers, simplified
CircuitPython is an open-source implementation of the Python programming language for microcontroller boards. The project, which is sponsored by Adafruit Industries, is designed with new programmers in mind, but it also has many features that may be of interest to more-experienced developers. The recent 9.1.0 release adds a few minor features, but it follows just a few months after CircuitPython 9.0.0, which brings some more significant changes, including improved graphics and USB support.
CircuitPython is a fork of MicroPython (previously covered on LWN) with several changes designed to make the language easier for beginners to use. CircuitPython has a universal hardware API and is more compatible with the CPython standard library, for example. CircuitPython has some limitations compared to MicroPython, particularly with respect to concurrency, but is otherwise just as powerful.
CircuitPython 9.0.0, which was released in March, includes new graphics modules, such as jpegio, which decodes JPEG images, and bitmapfilter, which provides simple image-manipulation tools. That release also improves USB compatibility with Android devices, allowing users of these devices to more easily edit code on CircuitPython boards. Another new feature, involving both graphics and USB, is the usb_video module, which emulates a USB webcam and sends images back to the host computer.
History and goals
The first stable version, CircuitPython 1.0.0, was released in 2017, though the project was announced with a beta release earlier in the year. Since then, new versions have been periodically released; beyond just updates to CircuitPython, changes incorporated from MicroPython have generally been included as well.
Information on Adafruit's original reasons for forking MicroPython, rather than simply using it, is scarce. In an email reply to my inquiry, Phillip Torrone, Adafruit's managing director, passed along some information from the development team. The original purpose for creating a fork was to add support for SAMD21 microcontrollers. However, beyond just adding this new port, other features were released, including a new hardware API.
At the time the CircuitPython project was started, MicroPython's hardware API was not consistent across ports. To improve code portability, Adafruit's team decided to create a new, unified API. The MicroPython project, however, opted not to use the new API "because it prevents special chip-specific behavior from being exposed in the common API" and "can be slightly slower [...] due to an extra C function call".
This difference in APIs make sense when looking at the main goals of each
project. MicroPython describes the language as "a lean and efficient
implementation of the Python 3 programming language that includes a
small subset of the Python standard library and is optimised to run on
microcontrollers and in constrained environments
". In contrast,
Adafruit's "What
is CircuitPython?" page says: "CircuitPython is a programming
language designed to simplify experimenting and learning to program on
low-cost microcontroller boards.
" Adafruit recommends CircuitPython for
users who "want to get up and running quickly
" or "are new to
programming
".
The Adafruit team explained that, despite the differences between the two projects, they are still similar internally, and Adafruit does contribute changes to MicroPython when it makes sense to do so; Torrone also mentioned that the company financially supports the MicroPython project. Overall, since the projects' goals would be difficult to reconcile in one codebase, it seems that having two separate but related projects is a reasonable solution for both user communities.
Main features
CircuitPython supports most of the core language features of CPython,
although some features are missing due to the limited resources found on
microcontroller boards compared to the much more powerful computers on
which CPython typically runs. Many of those missing features will be the
same as those on a comparison
between CPython and MicroPython reports. In addition, as CircuitPython's main README explains: "Modules with a CPython counterpart,
such as time, os and random, are strict subsets
of their CPython version. Therefore, code from CircuitPython is runnable on
CPython but not necessarily the reverse.
"
This is a change from MicroPython, which prefixes module names with u (e.g. CPython's os becomes uos) and often adds incompatible features. This practice increases the difference from standard Python implementations, making it more difficult to move from one to the other. In contrast, CircuitPython's design of using one-way compatible modules for functionality that overlaps with CPython, and separate modules for additional features, helps users to learn which functionality is standard and what has been added by CircuitPython.
Of course, the main reason to run code on a microcontroller board is to interact with hardware. CircuitPython provides a unified API for all boards. For example, on any supported board with a built-in LED, the following code (taken from a tutorial) will blink the LED on and off for a half-second each:
import board import digitalio import time led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT while True: led.value = True time.sleep(0.5) led.value = False time.sleep(0.5)
A previous article on LWN, covering a talk given by software engineer Nina Zakharenko at PyCon 2019, gives examples of some more things CircuitPython can do, including controlling Adafruit's NeoPixel line of addressable RGB LEDs.
CircuitPython's APIs are extensively documented; additionally, the Adafruit web site provides a wide variety of tutorials and guides showing how to use various devices and build many practical projects with CircuitPython. (MicroPython's API is also well-documented, and appears to be more unified now than it was in 2016, when Adafruit decided to create a new API for CircuitPython, although there are still some differences between ports.)
CircuitPython has almost all of the language features that MicroPython
does, although often with different APIs. The only major limitation is CircuitPython's support for concurrency;
"interrupts and threading are disabled
", as explained by the
project's documentation. On certain boards, though, asynchronous
programming is supported with the async and await
keywords, and some modules do provide concurrency for limited tasks, "such
as audio file playback
".
In addition to the standard library, there are many other libraries that can be used with CircuitPython; as with the standard library, each of these (most of which are device drivers) has its own documentation. All of them can be downloaded in a bundle from the CircuitPython web site.
Editing code
On most boards, editing code files is quite simple and requires no special software; after installing CircuitPython, the user can simply plug the board into a computer running any operating system that supports USB mass storage. This is the same protocol used by USB flash drives, so virtually all systems support it. The board will appear as a mass storage device called CIRCUITPY, and the user can place code on this device in a file called code.py. Saving a new version of that file will cause the board to restart and run it; it will also run whenever the board is power-cycled.
Having a serial console is also important for debugging and read–eval–print loop (REPL) access. Adafruit recommends that beginners use the Mu editor, which includes an integrated serial console. I prefer to use Neovim for file editing and the pyserial-miniterm utility provided by pySerial for serial access; any pairing of editor and console should work fine.
On a few boards, however, this standard workflow is not available; in addition, some users may want to develop code using a wireless connection, particularly for mobile devices (although it is possible to edit files over USB for Android devices, starting with CircuitPython 9.0.0, and for iOS devices, starting with iOS 13). For these and other cases where USB is unsuitable, two alternatives are available: the Bluetooth Low Energy (BLE) and Web workflows.
Both of these are supported by the online CircuitPython Code Editor; the difference is in the connection protocol. The BLE workflow, of course, connects using Bluetooth, while the Web workflow connects to the board using HTTP requests. The Code Editor also supports USB; the Web workflow should work in all modern browsers, while BLE and USB are only supported in Chrome-based browsers. I did not actually test the Code Editor, however.
Supported hardware
CircuitPython is available for a wide range of microcontroller boards, including the popular and inexpensive Raspberry Pi Pico and Pico W (a similar board with WiFi connectivity), and some Arduino boards, such as the Arduino Zero and several boards in the "Nano" family like the Arduino Nano 33 BLE. The classic Arduino Uno is not supported, however; its limited resources make a port of CircuitPython infeasible.
Additionally, many of CircuitPython's libraries have been ported to run on CPython on Linux through the Blinka project; this enables code written for microcontroller boards using CircuitPython to be used with few or no modifications on single-board computers (SBCs) such as the Linux-based Raspberry Pi boards.
Development
CircuitPython development takes place in a GitHub repository, forked from the MicroPython repository. It appears that most commits are from Adafruit employees and contractors, but pull requests are also merged from outside users.
CircuitPython's documentation has several pages explaining how to contribute to the project. The main "Contributing" page has useful information on several topics, including licensing (CircuitPython, like MicroPython, is released under the MIT license), code guidelines (the project largely follows MicroPython's guidelines to allow for upstreaming, but also has its own guidelines), and suggestions of ways to contribute.
Users interested in low-level work, particularly porting CircuitPython to new boards, will find helpful information on the Porting page. The page describes three core pieces that make up CircuitPython. The first is the Python virtual machine (VM), which is mostly copied from MicroPython. The VM is designed in such a way that there is typically little work needed to port it to a new processor.
The next component is referred to as the "supervisor". It initializes the
hardware and filesystem, starts the user's code, then "monitors and
facilitates
" the Python virtual machine. A large portion of the work involved in
porting CircuitPython pertains to the supervisor, because many of its tasks
are closely related to the hardware.
Finally, there is the Common Hardware Abstraction Layer (HAL), which interfaces between the hardware and the standardized CircuitPython APIs. There is a separate page on porting this layer, which allows developers using CircuitPython to write code that will run on any supported board.
Conclusion
Overall, CircuitPython is a great choice for users who are new to programming. However, for projects that do not require concurrency or the higher performance of a compiled language, there is no reason for more experienced developers to avoid it; the simple API and easy development workflows benefit anyone who wants to get a hardware project working quickly. Complicated projects may be best served by using MicroPython directly, or by writing bare-metal code in a compiled language, perhaps using a development environment like the C++-based Arduino platform. However, for simpler projects, it definitely makes sense to consider CircuitPython.
Index entries for this article | |
---|---|
GuestArticles | Sloniker, Sam |
Python | CircuitPython |
Posted Aug 6, 2024 14:45 UTC (Tue)
by mb (subscriber, #50428)
[Link] (1 responses)
They have basically dropped this practice a couple of months ago.
Posted Aug 6, 2024 15:55 UTC (Tue)
by KJ7RRV (subscriber, #153595)
[Link]
Posted Aug 6, 2024 15:37 UTC (Tue)
by mattdm (subscriber, #18)
[Link] (1 responses)
Posted Aug 6, 2024 15:57 UTC (Tue)
by KJ7RRV (subscriber, #153595)
[Link]
Posted Aug 6, 2024 16:48 UTC (Tue)
by tomtom45 (subscriber, #83541)
[Link] (1 responses)
Posted Aug 8, 2024 17:38 UTC (Thu)
by KJ7RRV (subscriber, #153595)
[Link]
Posted Aug 8, 2024 12:42 UTC (Thu)
by khim (subscriber, #9252)
[Link] (1 responses)
I suspect that most CircuitPython users don't even know they are using CircuitPython because they use it on calculators. And it's funny how TI found it easier to add separate CPU just for CircuitPython than port CircuitPython to 24bit CPU.
Posted Aug 9, 2024 1:52 UTC (Fri)
by KJ7RRV (subscriber, #153595)
[Link]
No u-prefix anymore in MicroPython
See https://docs.micropython.org/en/latest/library/index.html
No u-prefix anymore in MicroPython
so much fun!
so much fun!
displayio
definitely does look interesting! I haven't used it, but I do have a small display that should be compatible; maybe I'll try it out some time.
IDE Thonny
IDE Thonny
What about calculators?
What about calculators?