The Basics of CircuitPython for Rapid Microcontroller-Based Prototyping and Development

By Steve Leibson

Contributed By Digi-Key's North American Editors

While the Python language has made programming more accessible, it was designed to run on PCs and other machines with plenty of processing, memory, and peripheral resources. For embedded systems that face tighter resource and interface constraints, an optimized version for microcontrollers, called MicroPython, has become popular. So much so that the open source community has been adapting MicroPython to specific microcontrollers and dev boards to support serious microcontroller development.

This article will introduce one such adaptation, Adafruit's CircuitPython. After a brief discussion of Python, as it compares to the classic embedded development language C++, the article will discuss how Python has evolved to MicroPython and now CircuitPython. It will then describe the process of writing software using CircuitPython before introducing several dev boards from Adafruit and other vendors that support the CircuitPython environment.

The reason for Python

The original Arduino dev board and its many successors have been very popular microcontroller dev boards for maker, hobby, and student projects, as well as for embedded prototypes. However, the Arduino IDE and programming language are based on C++, a powerful but complex compiled language with an odd-looking syntax and rigid punctuation rules that novice programmers find off-putting.

Python is a newer programming language. It is an interpreted, interactive, object-oriented language that combines remarkable programming power with a very clear syntax. It is known for its writability and readability, as well as for its simpler syntax. These characteristics combine to reduce the number of programming errors and make code reuse easier, and so speed software development.

The language’s interpretive nature provides immediate programmer feedback that encourages experimentation and rapid learning. For these reasons, Python is now the first programming language that many students and makers learn.

One drawback is that Python was designed to run on PCs and larger machines with plenty of RAM, large amounts of mass storage, and a comprehensive user interface with a keyboard, a large display, and a mouse. It was not designed to be an embedded programming language. However, a lean, efficient implementation of the Python 3 programming language, called MicroPython, has emerged that was specifically created and optimized to run within a microcontroller’s constrained resources.

Recognizing MicroPython’s promise as an embedded programming language, the open source community has been adapting it to certain microcontrollers and dev boards to support serious microcontroller development. For example, Adafruit has developed its own flavor of MicroPython, called CircuitPython. Designed to simplify experimentation and learning to program on low-cost microcontroller boards, it is tailored for the microcontrollers and the hardware resources available on Adafruit’s dev boards. CircuitPython comes pre-installed on several of Adafruit’s dev boards and is installable on others.

Differences between C++ and Python

Given the momentum and presence of the Arduino IDE and the many Arduino dev boards now available, it’s reasonable to ask why a version of Python might be needed for embedded development. A comparison of the languages provides the answer.

C++ is an extension of the older C language with object-oriented extensions. Even with these extensions, C++ code is somewhat cryptic because it retains the C syntax that was originally created by Kernigan and Ritchie at Bell Labs during the late 1960s and early 1970s. C was intentionally designed to be mapped easily into machine instructions for a target processor. This bias towards the needs of the machine over those of the programmer is apparent in the language’s syntax. Because commercial microprocessors didn’t appear until 1971, C was originally developed for minicomputers. C compilers for microprocessors gradually evolved into useful tools during the 1980s. C has always been a compiled language, as has C++.

Danish computer scientist Bjarne Stroustrup started developing C++ in 1979. His first textbook on the language appeared in 1985. C++ did not become a standard programming language until 1998. Like C, Stroustrup’s C++ language originally targeted larger computers. The Arduino IDE (integrated development environment), developed in 2003, made C++ useful for microcontrollers.

Python is also an object-oriented language. It was developed by Dutch programmer Guido van Rossumin and first released in 1991. Python’s syntactical design emphasizes code readability—for humans—which is one key difference between Python and C++. Writability, closely associated with readability, is another trait in Python’s favor. Writability means that Python is generally credited with allowing programmers to write applications more quickly, which encourages experimentation and can shorten prototyping and development cycles.

A second major difference is that Python is an interpreted language, much like the Basic programming language that first appeared for minicomputers in the 1960s and truly blossomed in the 1970s with the introduction of microcomputers. Like Basic, the interpretive nature of Python encourages experimentation, and therefore learning by dispensing with the edit/compile/download/run development cycle used for compiled programming languages. However, unlike Basic, Python is a modern, higher level, object-oriented language that incorporates half a century’s worth of advances in computer science that have appeared since Basic was first developed.

For example, Python’s variables need not be declared or typed before use. Programmers need not worry whether a variable should be an integer or a floating-point number. The Python interpreter figures it all out and makes the appropriate choices at run time.

Two more differences between C++ and Python are string handling and punctuation. Many programmers find string handling in C++ to be obtuse and confusing. Python’s string handling is much simpler and very reminiscent of Basic’s simple and well-liked string handling capabilities, long considered a strong point for Basic.

Similarly, C and C++ punctuation—especially curly braces ({})—are another frequent stumbling block for new and even experienced programmers. It feels like there are always an odd number of curly braces in a program, which means the programmer must dig into the code to find where the missing curly brace should go. Python has no such finicky punctuation, but it does use indentation, which gives Python code its readability.

The origins of MicroPython

Like C and C++, Python was originally designed to run on larger computers. Consequently, the language required too many resources to be used for programming microcontrollers. Australian programmer and physicist Damien George therefore developed a version of Python called MicroPython that could run on a microcontroller’s more limited resources. Arduino dev boards were early hardware targets for MicroPython.

MicroPython’s interactive nature centers on its command interface, formally called the REPL (read-eval-print-loop) window, which usually operates over a serial connection that connects a host PC to a microcontroller dev board. The REPL interface strongly resembles the Basic command line interfaces of the 1970s and 1980s. It accepts user inputs (single expressions or statements), evaluates them, and then either returns results to the user through the REPL window or performs the command embedded in the statement.

Using the REPL interface, it’s possible to query a variable, toggle an I/O line, or send a string of characters to an attached peripheral. The line is interpreted and immediately executed as soon as the enter key is pressed. That’s the nature of an interpreted language.

This MicroPython feature facilitates exploratory programming and debugging and is one of the aspects of MicroPython that make the language easy to use for both beginners and experienced programmers. The REPL user interface supports faster development cycles compared to the Arduino IDE’s classic edit-compile-run-debug cycle. Even experienced programmers benefit from being able to experiment with new peripheral types interactively using MicroPython’s REPL user interface.

CircuitPython support for dev boards

Each microcontroller has a unique set of peripherals, and each dev board adds to that list. These peripherals require support libraries. This is true for both the Arduino IDE and for MicroPython. In addition, there are many add-on peripheral devices, like Adafruit’s 1655 NeoPixel addressable RGB LED, that also require library support.

To provide a higher degree of support, Adafruit has developed its own version of MicroPython, called CircuitPython, to meet the specific requirements of several of the company’s inexpensive microcontroller dev boards. The company has also converted many peripheral libraries from its immense Arduino collection to CircuitPython libraries, already providing a large and growing number of peripheral support libraries for CircuitPython.

Adafruit designed a line of microcontroller dev boards explicitly to support CircuitPython. These include:

  • 3333 Circuit Playground Express with ten addressable, controllable RGB LEDs (Figure 1)

Image of Adafruit’s 3333 Circuit Playground Express

Figure 1: Adafruit’s 3333 Circuit Playground Express features ten addressable, controllable RGB LEDs. (Image source: Adafruit)

  • 3500 Trinket M0 dev board that measures only 27 mm x 15.3 mm x 2.75 mm (Figure 2)

Image of Adafruit’s 3500 Trinket M0 dev board

Figure 2: Adafruit’s 3500 Trinket M0 dev board measures only 27 mm x 15.3 mm x 2 mm. (Image source: Adafruit)

  • 3501 Gemma M0 is about the size of a US 25 cent piece (a quarter) and can be powered from its USB port or a separate battery port (Figure 3)

Image of Adafruit’s 3501 Gemma M0

Figure 3: Adafruit’s 3501 Gemma M0 is about the size of a US 25 cent piece and can be powered from its USB port or a separate battery port. (Image source: Adafruit)

  • 3403 Feather M0 Express is a dev board that features a small breadboard area for custom circuitry (Figure 4)

Image of Adafruit’s 3403 Feather M0 Express dev board

Figure 4: Adafruit’s 3403 Feather M0 Express dev board has a small breadboard area for custom circuitry. (Image source: Adafruit)

These four Adafruit microcontroller dev boards are all based on Microchip Technology‘s (formerly Atmel‘s) SAMD21 microcontrollers with native USB support. However, CircuitPython supports more than Adafruit’s dev boards and the SAMD21 microcontroller. Versions of CircuitPython for other dev boards with other microcontrollers are also starting to appear, including Adafruit’s 3406 Feather NRF52 and Nordic Semiconductor’s nRF52-DK dev boards, both based on Nordic Semiconductor’s nRF52832 microcontroller. Additionally, Nordic Semiconductor’s nRF52840-DK dev board (Figure 5), based on the company’s nRF52840 microcontroller, is also supported by CircuitPython. Both of the microcontrollers upon which these three boards are based have Bluetooth low energy (BLE) integrated on chip, with appropriate software support.

Image of Nordic Semiconductor’s nRF52840-DK dev board

Figure 5: Nordic Semiconductor’s nRF52840-DK dev board has integrated BLE support. (Image source: Nordic Semiconductor)

Developing with CircuitPython

Adafruit has taken a unique approach to putting CircuitPython on dev boards designed to directly support the language. Plug one of these boards into a host PC’s USB port and the board appears as a disk drive to the PC. This disk drive’s root directory shows the critical CircuitPython files including the interpreter, the user program, and a folder containing the library files. This arrangement makes it easy for the host PC to access the dev board using its existing file system and drivers.

The CircuitPython user interface on the host PC requires a free, downloadable, open source editor and REPL interface. Adafruit recommends an open source application called Mu shown in Figure 6. The Mu screen is split into a code window where editing takes place, and the REPL control and monitor window where the programmer controls the dev board’s CircuitPython interpreter.

Image of Adafruit's open source programming interface called Mu

Figure 6: Adafruit recommends the use of an open source programming interface called Mu. The Mu screen is split into a code window where editing takes place, and the REPL control and monitor window where the programmer controls the dev board’s CircuitPython interpreter. (Image source:

By typing a program into the code window and clicking on Mu’s “Save” button, the code is saved on Adafruit’s CircuitPython dev boards in the SAMD21 microcontroller’s large, on-chip flash memory. All of the CircuitPython code resides on the dev board in the microcontroller’s flash memory. Remember, the CircuitPython board looks like a disk drive to the PC, so this is not an unnatural act from an operating system perspective.


The Python language offers programmers many benefits including interactive programming, experimentation, and debugging. It has a simplified, more human-like language syntax, with no need for variable declarations or typing, and no finicky punctuation. MicroPython is a variation of Python 3 that makes microcontroller programming in Python possible.

As shown, Adafruit has adapted MicroPython to derive CircuitPython for direct hardware support to further simplify experimentation and learning and accelerate software development. CircuitPython already supports several low-cost microcontroller dev boards based on Microchip’s SAMD21 microcontrollers, as well as other dev boards based on Nordic Semiconductor’s BLE-enabled nRF microcontrollers.

Additional resources


Disclaimer: The opinions, beliefs, and viewpoints expressed by the various authors and/or forum participants on this website do not necessarily reflect the opinions, beliefs, and viewpoints of Digi-Key Electronics or official policies of Digi-Key Electronics.

About this author

Steve Leibson

Steve Leibson was a systems engineer for HP and Cadnetix, the Editor in Chief for EDN and Microprocessor Report, a tech blogger for Xilinx and Cadence (among others), and he served as the technology expert on two episodes of “The Next Wave with Leonard Nimoy.” He has helped design engineers develop better, faster, more reliable systems for 33 years.

About this publisher

Digi-Key's North American Editors