SCK is connected to board.TFT_SCK
Arduino 5 .
MISO is connected to board.TFT_MISO
Arduino 6 .
MOSI is connected to board.TFT_MOSI
Arduino 7 .
CS is connected to board.TFT_CS
Arduino 15 and includes a 10K Pull-up
resistor.
Analog Connector/Pins
On the bottom side towards the right,
there is a connector labeledA0. This is
a3-pin JST analog connectorfor sensors,
NeoPixels, or analog output or input.
For the JST connected, there is a jumper
above that can be cut and soldered to use
3V instead of 5V.
Along the bottom there are also pins
labeled A0 and A1 .
When CircuitPython finishes installing, or you plug a CircuitPython board into your
computer with CircuitPython already installed, the board shows up on your computer
as a USB drive called CIRCUITPY.
The CIRCUITPY drive is where your code and the necessary libraries and files will live.
You can edit your code directly on this drive and when you save, it will run
automatically. When you create and edit code, you'll save your code in a code.py file
located on the CIRCUITPY drive.If you're following along with a Learn guide, you can
paste the contents of the tutorial example into code.py on the CIRCUITPY drive and
save it to run the example.
With a fresh CircuitPython install, on your CIRCUITPY drive, you'll find a code.py file
containing print("Hello World!") and an empty lib folder. If your CIRCUITPY
drive does not contain a code.py file, you can easily create one and save it to the
drive. CircuitPython looks for code.py and executes the code within the file
automatically when the board starts up or resets. Following a change to the contents
of CIRCUITPY, such as making a change to the code.py file, the board will reset, and
the code will be run. You do not need to manually run the code. This is what makes it
so easy to get started with your project and update your code!
Note that all changes to the contents of CIRCUITPY, such as saving a new file,
renaming a current file, or deleting an existing file will trigger a reset of the board.
CircuitPython is available for some microcontrollers that do not support native USB.
Those boards cannot present a CIRCUITPY drive. This includes boards using ESP32
or ESP32-C3 microcontrollers.
On these boards, there are alternative ways to transfer and edit files. You can use the
Thonny editor(), which uses hidden commands sent to the REPL to read and write
files. Or you can use the CircuitPython web workflow, introduced in Circuitpython 8.
The web workflow provides browser-based WiFi access to the CircuitPython
filesystem. These guides will help you with the web workflow:
CircuitPython on ESP32 Quick Start()
•
CircuitPython Web Workflow Code Editor Quick Start()
•
CircuitPython Pins and Modules
CircuitPython is designed to run on microcontrollers and allows you to interface with
all kinds of sensors, inputs and other hardware peripherals. There are tons of guides
showing how to wire up a circuit, and use CircuitPython to, for example, read data
from a sensor, or detect a button press. Most CircuitPython code includes hardware
setup which requires various modules, such as board or digitalio . You import
these modules and then use them in your code. How does CircuitPython know to look
for hardware in the specific place you connected it, and where do these modules
come from?
This page explains both. You'll learn how CircuitPython finds the pins on your
microcontroller board, including how to find the available pins for your board and
what each pin is named. You'll also learn about the modules built into CircuitPython,
including how to find all the modules available for your board.
When using hardware peripherals with a CircuitPython compatible microcontroller,
you'll almost certainly be utilising pins. This section will cover how to access your
board's pins using CircuitPython, how to discover what pins and board-specific
objects are available in CircuitPython for your board, how to use the board-specific
objects, and how to determine all available pin names for a given pin on your board.
import board
When you're using any kind of hardware peripherals wired up to your microcontroller
board, the import list in your code will include import board . The board module is
built into CircuitPython, and is used to provide access to a series of board-specific
objects, including pins. Take a look at your microcontroller board. You'll notice that
next to the pins are pin labels. You can always access a pin by its pin label. However,
there are almost always multiple names for a given pin.
To see all the available board-specific objects and pins for your board, enter the REPL
( >>> ) and run the following commands:
import board
dir(board)
Here is the output for the QT Py SAMD21. You may have a different board, and this list
will vary, based on the board.
The following pins have labels on the physical QT Py SAMD21 board: A0, A1, A2, A3,
SDA, SCL, TX, RX, SCK, MISO, and MOSI. You see that there are many more entries
available in board than the labels on the QT Py.
You can use the pin names on the physical board, regardless of whether they seem to
be specific to a certain protocol.
For example, you do not have to use the SDA pin for I2C - you can use it for a button
On the flip side, there may be multiple names for one pin. For example, on the QT Py
SAMD21, pin A0 is labeled on the physical board silkscreen, but it is available in
CircuitPython as both A0 and D0 . For more information on finding all the names for a
given pin, see the What Are All the Available Pin Names?() section below.
The results of dir(board) for CircuitPython compatible boards will look similar to
the results for the QT Py SAMD21 in terms of the pin names, e.g. A0, D0, etc.
However, some boards, for example, the Metro ESP32-S2, have different styled pin
names. Here is the output for the Metro ESP32-S2.
Note that most of the pins are named in an IO# style, such as IO1 and IO2. Those pins
on the physical board are labeled only with a number, so an easy way to know how to
access them in CircuitPython, is to run those commands in the REPL and find the pin
naming scheme.
If your code is failing to run because it can't find a pin name you provided, verify
that you have the proper pin name by running these commands in the REPL.
I2C, SPI, and UART
You'll also see there are often (but not always!) three special board-specific objects
included: I2C , SPI , and UART - each one is for the default pin-set used for each of
the three common protocol busses they are named for. These are called singletons.
What's a singleton? When you create an object in CircuitPython, you are instantiating
('creating') it. Instantiating an object means you are creating an instance of the object
with the unique values that are provided, or "passed", to it.
For example, When you instantiate an I2C object using the busio module, it expects
two pins: clock and data, typically SCL and SDA. It often looks like this:
i2c = busio.I2C(board.SCL, board.SDA)
Then, you pass the I2C object to a driver for the hardware you're using. For example,
if you were using the TSL2591 light sensor and its CircuitPython library, the next line
However, CircuitPython makes this simpler by including the I2C singleton in the boa
rd module. Instead of the two lines of code above, you simply provide the singleton
as the I2C object. So if you were using the TSL2591 and its CircuitPython library, the
two above lines of code would be replaced with:
tsl2591 = adafruit_tsl2591.TSL2591(board.I2C())
The board.I2C(), board.SPI(), and board.UART() singletons do not exist on all
boards. They exist if there are board markings for the default pins for those
devices.
This eliminates the need for the busio module, and simplifies the code. Behind the
scenes, the board.I2C() object is instantiated when you call it, but not before, and
on subsequent calls, it returns the same object. Basically, it does not create an object
until you need it, and provides the same object every time you need it. You can call
board.I2C() as many times as you like, and it will always return the same object.
The UART/SPI/I2C singletons will use the 'default' bus pins for each board - often
labeled as RX/TX (UART), MOSI/MISO/SCK (SPI), or SDA/SCL (I2C). Check your
board documentation/pinout for the default busses.
What Are All the Available Names?
Many pins on CircuitPython compatible microcontroller boards have multiple names,
however, typically, there's only one name labeled on the physical board. So how do
you find out what the other available pin names are? Simple, with the following script!
Each line printed out to the serial console contains the set of names for a particular
pin.
On a microcontroller board running CircuitPython, first, connect to the serial console.
In the example below, click the Download Project Bundle button below to download
the necessary libraries and the code.py file in a zip file. Extract the contents of the zip
file, open the directory CircuitPython_Essentials/Pin_Map_Script/ and then click on
the directory that matches the version of CircuitPython you're using and copy the
contents of that directory to your CIRCUITPY drive.
Your CIRCUITPY drive should now look similar to the following image:
board_pins = []
for pin in dir(microcontroller.pin):
if (isinstance(getattr(microcontroller.pin, pin), microcontroller.Pin) or
(cyw43 and isinstance(getattr(microcontroller.pin, pin), cyw43.CywPin))):
pins = []
for alias in dir(board):
if getattr(board, alias) is getattr(microcontroller.pin, pin):
pins.append(f"board.{alias}")
# Add the original GPIO name, in parentheses.
if pins:
# Only include pins that are in board.
pins.append(f"({str(pin)})")
board_pins.append(" ".join(pins))
for pins in sorted(board_pins):
print(pins)
Here is the result when this script is run on QT Py SAMD21:
Each line represents a single pin. Find the line containing the pin name that's labeled
on the physical board, and you'll find the other names available for that pin. For
example, the first pin on the board is labeled A0. The first line in the output is board.
A0 board.D0 (PA02) . This means that you can access pin A0 in CircuitPython using
The pins in parentheses are the microcontroller pin names. See the next section for
more info on those.
You'll notice there are two "pins" that aren't labeled on the board but appear in the
list: board.NEOPIXEL and board.NEOPIXEL_POWER . Many boards have several of
these special pins that give you access to built-in board hardware, such as an LED or
an on-board sensor. The QT Py SAMD21 only has one on-board extra piece of
hardware, a NeoPixel LED, so there's only the one available in the list. But you can
also control whether or not power is applied to the NeoPixel, so there's a separate pin
for that.
That's all there is to figuring out the available names for a pin on a compatible
microcontroller board in CircuitPython!
Microcontroller Pin Names
The pin names available to you in the CircuitPython board module are not the same
as the names of the pins on the microcontroller itself. The board pin names are
aliases to the microcontroller pin names. If you look at the datasheet for your
microcontroller, you'll likely find a pinout with a series of pin names, such as "PA18" or
"GPIO5". If you want to get to the actual microcontroller pin name in CircuitPython,
you'll need the microcontroller.pin module. As with board , you can run dir(mi
crocontroller.pin) in the REPL to receive a list of the microcontroller pin names.
CircuitPython Built-In Modules
There is a set of modules used in most CircuitPython programs. One or more of these
modules is always used in projects involving hardware. Often hardware requires
installing a separate library from the Adafruit CircuitPython Bundle. But, if you try to
find board or digitalio in the same bundle, you'll come up lacking. So, where do
these modules come from? They're built into CircuitPython! You can find an
comprehensive list of built-in CircuitPython modules and the technical details of their
functionality from CircuitPython here() and the Python-like modules included here().
However, not every module is available for every board due to size constraints or
hardware limitations. How do you find out what modules are available for your board?
If you are using one of our not-recommended-editors, not all is lost! You can still make
it work.
On Windows, you can Eject or Safe Remove the CIRCUITPY drive. It won't actually
eject, but it will force the operating system to save your file to disk. On Linux, use the
sync command in a terminal to force the write to disk.
You also need to do this if you use Windows Explorer or a Linux graphical file
manager to drag a file onto CIRCUITPY.
Oh No I Did Something Wrong and Now The CIRCUITPY
Drive Doesn't Show Up!!!
Don't worry! Corrupting the drive isn't the end of the world (or your board!). If this
happens, follow the steps found on the Troubleshooting() page of every board
guide to get your board up and running again.
Back to Editing Code...
Now! Let's try editing the program you added to your board. Open your code.py file
into your editor. You'll make a simple change. Change the first 0.5 to 0.1 . The code
should look like this:
import board
import digitalio
import time
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
while True:
led.value = True
time.sleep(0.1)
led.value = False
time.sleep(0.5)
Leave the rest of the code as-is. Save your file. See what happens to the LED on your
board? Something changed! Do you know why?
You don't have to stop there! Let's keep going. Change the second 0.5 to 0.1 so it
Each CircuitPython program you run needs to have a lot of information to work. The
reason CircuitPython is so simple to use is that most of that information is stored in
other files and works in the background. The files built into CircuitPython are called m
odules, and the files you load separately are called libraries. Modules are built into
CircuitPython. Libraries are stored on your CIRCUITPY drive in a folder called lib.
import board
import digitalio
import time
The import statements tells the board that you're going to use a particular library or
module in your code. In this example, you imported three modules: board ,
digitalio , and time . All three of these modules are built into CircuitPython, so no
separate library files are needed. That's one of the things that makes this an excellent
first example. You don't need anything extra to make it work!
These three modules each have a purpose. The first one, board , gives you access to
the hardware on your board. The second, digitalio , lets you access that hardware
as inputs/outputs.The third, time , let's you control the flow of your code in multiple
ways, including passing time by 'sleeping'.
Setting Up The LED
The next two lines setup the code to use the LED.
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
Your board knows the red LED as LED . So, you initialise that pin, and you set it to
output. You set led to equal the rest of that information so you don't have to type it
all out again later in our code.
Loop-de-loops
The third section starts with a while statement. while True: essentially means,
"forever do the following:". while True: creates a loop. Code will loop "while" the
condition is "true" (vs. false), and as True is never False, the code will loop forever.
All code that is indented under while True: is "inside" the loop.
while True:
led.value = True
time.sleep(0.5)
led.value = False
time.sleep(0.5)
First, you have led.value = True . This line tells the LED to turn on. On the next
line, you have time.sleep(0.5) . This line is telling CircuitPython to pause running
code for 0.5 seconds. Since this is between turning the led on and off, the led will be
on for 0.5 seconds.
The next two lines are similar. led.value = False tells the LED to turn off, and tim
e.sleep(0.5) tells CircuitPython to pause for another 0.5 seconds. This occurs
between turning the led off and back on so the LED will be off for 0.5 seconds too.
Then the loop will begin again, and continue to do so as long as the code is running!
So, when you changed the first 0.5 to 0.1 , you decreased the amount of time that
the code leaves the LED on. So it blinks on really quickly before turning off!
Great job! You've edited code in a CircuitPython program!
What Happens When My Code Finishes Running?
When your code finishes running, CircuitPython resets your microcontroller board to
prepare it for the next run of code. That means any set up you did earlier no longer
applies, and the pin states are reset.
For example, try reducing the code snippet above by eliminating the loop entirely,
and replacing it with led.value = True . The LED will flash almost too quickly to
see, and turn off. This is because the code finishes running and resets the pin state,
and the LED is no longer receiving a signal.
To that end, most CircuitPython programs involve some kind of loop, infinite or
otherwise.
What if I Don't Have the Loop?
If you don't have the loop, the code will run to the end and exit. This can lead to some
unexpected behavior in simple programs like this since the "exit" also resets the state
of the hardware. This is a different behavior than running commands via REPL. So if
Usually when you run into errors, it's not because you introduced them on purpose.
You may have 200 lines of code, and have no idea where your error could be hiding.
This is where the serial console can help. Let's take a look!
The Traceback (most recent call last): is telling you that the last thing it was
able to run was line 10 in your code. The next line is your error: NameError: name
'Tru' is not defined . This error might not mean a lot to you, but combined with
knowing the issue is on line 10, it gives you a great place to start!
Go back to your code, and take a look at line 10. Obviously, you know what the
problem is already. But if you didn't, you'd want to look at line 10 and see if you could
figure it out. If you're still unsure, try googling the error to get some help. In this case,
you know what to look for. You spelled True wrong. Fix the typo and save your file.
Nice job fixing the error! Your serial console is streaming and your red LED Is blinking
again.
The serial console will display any output generated by your code. Some sensors,
such as a humidity sensor or a thermistor, receive data and you can use print
statements to display that information. You can also use print statements for
troubleshooting, which is called "print debugging". Essentially, if your code isn't
working, and you want to know where it's failing, you can put print statements in
various places to see where it stops printing.
The serial console has many uses, and is an amazing tool overall for learning and
programming!
The REPL
The other feature of the serial connection is the Read-Evaluate-Print-Loop, or REPL.
The REPL allows you to enter individual lines of code and have them run immediately.
It's really handy if you're running into trouble with a particular program and can't
figure out why. It's interactive so it's great for testing new ideas.
Entering the REPL
To use the REPL, you first need to be connected to the serial console. Once that
connection has been established, you'll want to press CTRL+C.
If there is code running, in this case code measuring distance, it will stop and you'll
see Press any key to enter the REPL. Use CTRL-D to reload. Follow those
instructions, and press any key on your keyboard.
The Traceback (most recent call last): is telling you the last thing your board
was doing before you pressed Ctrl + C and interrupted it. The KeyboardInterrupt
is you pressing CTRL+C. This information can be handy when troubleshooting, but for
now, don't worry about it. Just note that it is expected behavior.
If your code.py file is empty or does not contain a loop, it will show an empty output
and Code done running. . There is no information about what your board was
doing before you interrupted it because there is no code running.
If you have no code.py on your CIRCUITPY drive, you will enter the REPL immediately
after pressing CTRL+C. Again, there is no information about what your board was
doing before you interrupted it because there is no code running.
Regardless, once you press a key you'll see a >>> prompt welcoming you to the
REPL!
If you have trouble getting to the >>> prompt, try pressing Ctrl + C a few more times.
The first thing you get from the REPL is information about your board.
This line tells you the version of CircuitPython you're using and when it was released.
Next, it gives you the type of board you're using and the type of microcontroller the
board uses. Each part of this may be different for your board depending on the
versions you're working with.
This is followed by the CircuitPython prompt.
Interacting with the REPL
From this prompt you can run all sorts of commands and code. The first thing you'll do
is run help() . This will tell you where to start exploring the REPL. To run code in the
First part of the message is another reference to the version of CircuitPython you're
using. Second, a URL for the CircuitPython related project guides. Then... wait. What's
this? To list built-in modules type `help("modules")`. Remember the
modules you learned about while going through creating code? That's exactly what
this is talking about! This is a perfect place to start. Let's take a look!
Type help("modules") into the REPL next to the prompt, and press enter.
This is a list of all the core modules built into CircuitPython, including board .
Remember, board contains all of the pins on the board that you can use in your
code. From the REPL, you are able to see that list!
Type import board into the REPL and press enter. It'll go to a new prompt. It might
look like nothing happened, but that's not the case! If you recall, the import
statement simply tells the code to expect to do something with that module. In this
case, it's telling the REPL that you plan to do something with that module.
Next, type dir(board) into the REPL and press enter.
However, import statements can also sometimes look like the following:
from library_or_module import name
•
from library_or_module.subpackage import name
•
from library_or_module import name as local_name
•
They can also have more complicated formats, such as including a try / except
block, etc.
The important thing to know is that an import statement will always include the
name of the module or library that you're importing.
Therefore, the best place to start is by reading through the import statements.
Here is an example import list for you to work with in this section. There is no setup or
other code shown here, as the purpose of this section involves only the import list.
import time
import board
import neopixel
import adafruit_lis3dh
import usb_hid
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
Keep in mind, not all imported items are libraries. Some of them are almost always
built-in CircuitPython modules. How do you know the difference? Time to visit the
REPL.
In the Interacting with the REPL section() on The REPL page() in this guide, the
help("modules") command is discussed. This command provides a list of all of the
built-in modules available in CircuitPython for your board. So, if you connect to the
serial console on your board, and enter the REPL, you can run help("modules") to
see what modules are available for your board. Then, as you read through the impor
t statements, you can, for the purposes of figuring out which libraries to load, ignore
the statement that import modules.
The following is the list of modules built into CircuitPython for the Feather RP2040.
Your list may look similar or be anything down to a significant subset of this list for
Now that you know what you're looking for, it's time to read through the import
statements. The first two, time and board , are on the modules list above, so they're
built-in.
The next one, neopixel , is not on the module list. That means it's your first library!
So, you would head over to the bundle zip you downloaded, and search for neopixel.
There is a neopixel.mpy file in the bundle zip. Copy it over to the lib folder on your CI
RCUITPY drive. The following one, adafruit_lis3dh , is also not on the module list.
Follow the same process for adafruit_lis3dh, where you'll find adafruit_lis3dh.mpy,
and copy that over.
The fifth one is usb_hid , and it is in the modules list, so it is built in. Often all of the
built-in modules come first in the import list, but sometimes they don't! Don't assume
that everything after the first library is also a library, and verify each import with the
modules list to be sure. Otherwise, you'll search the bundle and come up empty!
The final two imports are not as clear. Remember, when import statements are
formatted like this, the first thing after the from is the library name. In this case, the
library name is adafruit_hid . A search of the bundle will find an adafruit_hid folder.
When a library is a folder, you must copy the entire folder and its contentsas it is in
the bundle to the lib folder on your CIRCUITPY drive. In this case, you would copy the
entire adafruit_hid folder to your CIRCUITPY/lib folder.
Notice that there are two imports that begin with adafruit_hid . Sometimes you will
need to import more than one thing from the same library. Regardless of how many
times you import the same library, you only need to load the library by copying over
the adafruit_hid folder once.
That is how you can use your example code to figure out what libraries to load on
There are cases, however, where libraries require other libraries internally. The
internally required library is called a dependency. In the event of library
dependencies, the easiest way to figure out what other libraries are required is to
connect to the serial console and follow along with the ImportError printed there.
The following is a very simple example of an ImportError , but the concept is the
same for any missing library.
Example: ImportError Due to Missing
Library
If you choose to load libraries as you need them, or you're starting fresh with an
existing example, you may end up with code that tries to use a library you haven't yet
loaded. This section will demonstrate what happens when you try to utilise a library
that you don't have loaded on your board, and cover the steps required to resolve the
issue.
This demonstration will only return an error if you do not have the required library
loaded into the lib folder on your CIRCUITPY drive.
Let's use a modified version of the Blink example.
import board
import time
import simpleio
led = simpleio.DigitalOut(board.LED)
while True:
led.value = True
time.sleep(0.5)
led.value = False
time.sleep(0.5)
Save this file. Nothing happens to your board. Let's check the serial console to see
You have an ImportError . It says there is no module named 'simpleio' . That's
the one you just included in your code!
Click the link above to download the correct bundle. Extract the lib folder from the
downloaded bundle file. Scroll down to find simpleio.mpy. This is the library file you're
looking for! Follow the steps above to load an individual library file.
The LED starts blinking again! Let's check the serial console.
No errors! Excellent. You've successfully resolved an ImportError !
If you run into this error in the future, follow along with the steps above and choose
the library that matches the one you're missing.
Library Install on Non-Express Boards
If you have an M0 non-Express board such as Trinket M0, Gemma M0, QT Py M0, or
one of the M0 Trinkeys, you'll want to follow the same steps in the example above to
install libraries as you need them. Remember, you don't need to wait for an ImportEr
ror if you know what library you added to your code. Open the library bundle you
downloaded, find the library you need, and drag it to the lib folder on your CIRCUITPY
drive.
You can still end up running out of space on your M0 non-Express board even if you
only load libraries as you need them. There are a number of steps you can use to try
to resolve this issue. You'll find suggestions on the Troubleshooting page().
Updating CircuitPython Libraries and
Examples
Libraries and examples are updated from time to time, and it's important to update the
files you have on your CIRCUITPY drive.
To update a single library or example, follow the same steps above. When you drag
the library file to your lib folder, it will ask if you want to replace it. Say yes. That's it!
The main page covers the basics including where to download CircuitPython, how to
contribute, differences from MicroPython, information about the project structure, and
a full table of contents for the rest of the documentation.
The list along the left side leads to more information about specific topics.
The first section is API and Usage. This is where you can find information about how
to use individual built-in core modules, such as time and digitalio , details about
the supported ports, suggestions for troubleshooting, and basic info and links to the li
brary bundles. The Core Modules section also includes the Support Matrix, which is a
table of which core modules are available on which boards.
The second section is Design and Porting Reference. It includes a design guide, archit
ecture information, details onporting, and adding module support to other ports.
The third section is MicroPython Specific. It includes information on MicroPython and
related libraries, and a glossary of terms.
The fourth and final section is About the Project. It includes further information
including details on building, testing, and debugging CircuitPython, along with various
other useful links including the Adafruit Community Code of Conduct.
Whether you're a seasoned pro or new to electronics and programming, you'll find a
wealth of information to help you along your CircuitPython journey in the
available functionality of the library will be contained within that first and only
subsection. However, in the case of a library that has subpackages, each item will
contain the features of the particular subpackage indicated by the link. The
documentation will cover all of the available functions of the library, including more
complex ones that may not interest you.
The first list item is the animation subpackage. If you scroll down, you'll begin to see
the available features of animation. They are listed alphabetically. Each of these
things can be called in your code. It includes the name and a description of the
specific function you would call, and if any parameters are necessary, lists those with
a description as well.
You can view the other subpackages by clicking the link on the left or scrolling down
the page. You may be interested in something a little more practical. Here is an
example. To use the LED Animation library Comet animation, you would run the
following example.
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
This example animates a jade comet that bounces from end to end of the strip.
For QT Py Haxpress and a NeoPixel strip. Update pixel_pin and pixel_num to match
your wiring if
using a different board or form of NeoPixels.
This example will run on SAMD21 (M0) Express boards (such as Circuit Playground
Express or QT Py
Haxpress), but not on SAMD21 non-Express boards (such as QT Py or Trinket).
"""
import board
import neopixel
from adafruit_led_animation.animation.comet import Comet
from adafruit_led_animation.color import JADE
# Update to match the pin connected to your NeoPixels
pixel_pin = board.A3
# Update to match the number of NeoPixels you have connected
pixel_num = 30
Note the line where you create the comet object. There are a number of items inside
the parentheses. In this case, you're provided with a fully working example. But what
if you want to change how the comet works? The code alone does not explain what
the options mean.
So, in the API Reference documentation list, click the
adafruit_led_animation.animation.comet link and scroll down a bit until you
see the following.
Look familiar? It is! This is the documentation for setting up the comet object. It
explains what each argument provided in the comet setup in the code meant, as well
as the other available features. For example, the code includes speed=0.02 . The
documentation clarifies that this is the "Animation speed in seconds". The code
doesn't include ring . The documentation indicates this is an available setting that
enables "Ring mode".
This type of information is available for any function you would set up in your code. If
you need clarification on something, wonder whether there's more options available,
or are simply interested in the details involved in the code you're writing, check out
the documentation for the CircuitPython libraries!
Great job! You've connected to the serial console!
Advanced Serial Console on Mac
Connecting to the serial console on Mac does not require installing any drivers or
extra software. You'll use a terminal program to find your board, and screen to
connect to it. Terminal and screen both come installed by default.
What's the Port?
First you'll want to find out which serial port your board is using. When you plug your
board in to USB on your computer, it connects to a serial port. The port is like a door
through which your board can communicate with your computer using USB.
The easiest way to determine which port the board is using is to first check without
the board plugged in. Open Terminal and type the following:
ls /dev/tty.*
Each serial connection shows up in the /dev/ directory. It has a name that starts with
tty. . The command ls shows you a list of items in a directory. You can use * as a
wildcard, to search for files that start with the same letters but end in something
different. In this case, you're asking to see all of the listings in /dev/ that start with t
ty. and end in anything. This will show us the current serial connections.
This will show you the current serial connections, which will now include your board.
A new listing has appeared called /dev/tty.usbmodem141441 . The tty.usbmodem1
41441 part of this listing is the name the example board is using. Yours will be called
something similar.
Using Linux, a new listing has appeared called /dev/ttyACM0 . The ttyACM0 part of
this listing is the name the example board is using. Yours will be called something
similar.
Connect with screen
Now that you know the name your board is using, you're ready connect to the serial
console. You're going to use a command called screen . The screen command is
included with MacOS. To connect to the serial console, use Terminal. Type the
following command, replacing board_name with the name you found your board is
using:
screen /dev/tty.board_name 115200
The first part of this establishes using the screen command. The second part tells
screen the name of the board you're trying to use. The third part tells screen what
baud rate to use for the serial connection. The baud rate is the speed in bits per
second that data is sent over the serial connection. In this case, the speed required
Press enter to run the command. It will open in the same window. If no code is
running, the window will be blank. Otherwise, you'll see the output of your code.
Great job! You've connected to the serial console!
Advanced Serial Console on Linux
Connecting to the serial console on Linux does not require installing any drivers, but
you may need to install screen using your package manager. You'll use a terminal
program to find your board, and screen to connect to it. There are a variety of
terminal programs such as gnome-terminal (called Terminal) or Konsole on KDE.
The tio program works as well to connect to your board, and has the benefit of
automatically reconnecting. You would need to install it using your package manager.
What's the Port?
First you'll want to find out which serial port your board is using. When you plug your
board in to USB on your computer, it connects to a serial port. The port is like a door
through which your board can communicate with your computer using USB.
The easiest way to determine which port the board is using is to first check without
the board plugged in. Open your terminal program and type the following:
ls /dev/ttyACM*
Each serial connection shows up in the /dev/ directory. It has a name that starts with tt
yACM. The command ls shows you a list of items in a directory. You can use * as a
wildcard, to search for files that start with the same letters but end in something
different. In this case, You're asking to see all of the listings in /dev/ that start with ttyA
CM and end in anything. This will show us the current serial connections.
In the example below, the error is indicating that are no current serial connections
starting with ttyACM.
Now plug in your board. In your terminal program, type:
ls /dev/ttyACM*
This will show you the current serial connections, which will now include your board.
A new listing has appeared called /dev/ttyACM0. The ttyACM0 part of this listing is
the name the example board is using. Yours will be called something similar.
Connect with screen
Now that you know the name your board is using, you're ready connect to the serial
console. You'll use a command called screen . You may need to install it using the
To connect to the serial console, use your terminal program. Type the following
command, replacing board_name with the name you found your board is using:
screen /dev/tty.board_name 115200
The first part of this establishes using the screen command. The second part tells
screen the name of the board you're trying to use. The third part tells screen what
baud rate to use for the serial connection. The baud rate is the speed in bits per
second that data is sent over the serial connection. In this case, the speed required
by the board is 115200 bits per second.
Press enter to run the command. It will open in the same window. If no code is
running, the window will be blank. Otherwise, you'll see the output of your code.
Great job! You've connected to the serial console!
Permissions on Linux
If you try to run screen and it doesn't work, then you may be running into an issue
with permissions. Linux keeps track of users and groups and what they are allowed to
do and not do, like access the hardware associated with the serial connection for
running screen . So if you see something like this:
then you may need to grant yourself access. There are generally two ways you can do
this. The first is to just run screen using the sudo command, which temporarily
The second way is to add yourself to the group associated with the hardware. To
figure out what that group is, use the command ls -l as shown below. The group
name is circled in red.
Then use the command adduser to add yourself to that group. You need elevated
privileges to do this, so you'll need to use sudo . In the example below, the group is a
dm and the user is ackbar.
After you add yourself to the group, you'll need to logout and log back in, or in some
cases, reboot your machine. After you log in again, verify that you have been added
to the group using the command groups . If you are still not in the group, reboot and
check again.
And now you should be able to run screen without using sudo .
Are there other ways to communicate by radio with
CircuitPython?
Check out Adafruit's RFM boards ()for simple radio communication supported by
CircuitPython, which can be used over distances of 100m to over a km, depending
on the version. The RFM SAMD21 M0 boards can be used, but they were not
designed for CircuitPython, and have limited RAM and flash space; using the RFM
breakouts or FeatherWings with more capable boards will be easier.
Asyncio and Interrupts
Is there asyncio support in CircuitPython?
There is support for asyncio starting with CircuitPython 7.1.0, on all boards except
the smallest SAMD21 builds. Read about using it in the Cooperative Multitasking in
CircuitPython() Guide.
Does CircuitPython support interrupts?
No. CircuitPython does not currently support interrupts - please use asyncio for
multitasking / 'threaded' control of your code
Status RGB LED
My RGB NeoPixel/DotStar LED is blinking funny colors what does it mean?
The status LED can tell you what's going on with your CircuitPython board. Read
more here for what the colors mean!()
Memory Issues
What is a MemoryError?
Memory allocation errors happen when you're trying to store too much on the
board. The CircuitPython microcontroller boards have a limited amount of memory
available. You can have about 250 lines of code on the M0 Express boards. If you
try to import too many libraries, a combination of large libraries, or run a program
with too many lines of code, your code will fail to run and you will receive a
Try resetting your board. Each time you reset the board, it reallocates the memory.
While this is unlikely to resolve your issue, it's a simple step and is worth trying.
Make sure you are using .mpy versions of libraries. All of the CircuitPython libraries
are available in the bundle in a .mpy format which takes up less memory than .py
format. Be sure that you're using the latest library bundle() for your version of
CircuitPython.
If that does not resolve your issue, try shortening your code. Shorten comments,
remove extraneous or unneeded code, or any other clean up you can do to
shorten your code. If you're using a lot of functions, you could try moving those
into a separate library, creating a .mpy of that library, and importing it into your
code.
You can turn your entire file into a .mpy and import that into code.py. This means
you will be unable to edit your code live on the board, but it can save you space.
Can the order of my import statements affect memory?
It can because the memory gets fragmented differently depending on allocation
order and the size of objects. Loading .mpy files uses less memory so its
recommended to do that for files you aren't editing.
How can I create my own .mpy files?
You can make your own .mpy versions of files with mpy-cross .
You can download mpy-cross for your operating system from here(). Builds are
available for Windows, macOS, x64 Linux, and Raspberry Pi Linux. Choose the
latest mpy-cross whose version matches the version of CircuitPython you are
using.
To make a .mpy file, run ./mpy-cross path/to/yourfile.py to create a
yourfile.mpy in the same directory as the original file.
How do I check how much memory I have free?
Run the following to see the number of bytes available for use:
Always Run the Latest Version of
CircuitPython and Libraries
As CircuitPython development continues and there are new releases, Adafruit will
stop supporting older releases. You need to update to the latest CircuitPython.().
You need to download the CircuitPython Library Bundle that matches your version of
CircuitPython. Please update CircuitPython and then download the latest bundle().
As new versions of CircuitPython are released, Adafruit will stop providing the
previous bundles as automatically created downloads on the Adafruit CircuitPython
Library Bundle repo. If you must continue to use an earlier version, you can still
download the appropriate version of mpy-cross from the particular release of
CircuitPython on the CircuitPython repo and create your own compatible .mpy library
files. However, it is best to update to the latest for both CircuitPython and the library
bundle.
I have to continue using CircuitPython 7.x or earlier.
Where can I find compatible libraries?
Adafruit is no longer building or supporting the CircuitPython 7.x or earlier library
bundles. You are highly encourged to update CircuitPython to the latest version() and
use the current version of the libraries(). However, if for some reason you cannot
update, links to the previous bundles are available in the FAQ().
Bootloader (boardnameBOOT) Drive Not
Present
You may have a different board.
Only Adafruit Express boards and the SAMD21 non-Express boards ship with the UF2
bootloader ()installed. The Feather M0 Basic, Feather M0 Adalogger, and similar
boards use a regular Arduino-compatible bootloader, which does not show a boardna
Depending on the size of your screen or Mu window, when you open the serial
console, the serial console panel may be very small. This can be a problem. A basic
CircuitPython error takes 10 lines to display!
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Traceback (most recent call last):
File "code.py", line 7
SyntaxError: invalid syntax
Press any key to enter the REPL. Use CTRL-D to reload.
More complex errors take even more lines!
Therefore, if your serial console panel is five lines tall or less, you may only see blank
lines or blank lines followed by Press any key to enter the REPL. Use CTRL-D
to reload. . If this is the case, you need to either mouse over the top of the panel to
utilise the option to resize the serial panel, or use the scrollbar on the right side to
scroll up and find your message.
This applies to any kind of serial output whether it be error messages or print
statements. So before you start trying to debug your problem on the hardware side,
be sure to check that you haven't simply missed the serial messages due to serial
output panel height.
code.py Restarts Constantly
CircuitPython will restart code.py if you or your computer writes to something on the
CIRCUITPY drive. This feature is called auto-reload, and lets you test a change to your
program immediately.
Some utility programs, such as backup, anti-virus, or disk-checking apps, will write to
the CIRCUITPY as part of their operation. Sometimes they do this very frequently,
causing constant restarts.
Acronis True Image and related Acronis programs on Windows are known to cause
this problem. It is possible to prevent this by disabling the "()Acronis Managed
These are followed by flashes indicating the line number, including place value. WHIT
E flashes are thousands' place, BLUE are hundreds' place, YELLOW are tens' place,
and CYAN are one's place. So for example, an error on line 32 would flash YELLOW
three times and then CYAN two times. Zeroes are indicated by an extra-long dark gap.
Serial console showing ValueError:
Incompatible .mpy file
This error occurs when importing a module that is stored as a .mpy binary file that
was generated by a different version of CircuitPython than the one its being loaded
into. In particular, the mpy binary format changed between CircuitPython versions 6.x
and 7.x, 2.x and 3.x, and 1.x and 2.x.
So, for instance, if you upgraded to CircuitPython 7.x from 6.x you’ll need to download
a newer version of the library that triggered the error on import . All libraries are
available in the Adafruit bundle().
CIRCUITPY Drive Issues
You may find that you can no longer save files to your CIRCUITPY drive. You may find
that your CIRCUITPY stops showing up in your file explorer, or shows up as NO_NAM
E. These are indicators that your filesystem has issues. When the CIRCUITPY disk is
not safely ejected before being reset by the button or being disconnected from USB,
it may corrupt the flash drive. It can happen on Windows, Mac or Linux, though it is
However there are still some cases where hidden files will be created by MacOS. In
particular if you copy a file that was downloaded from the internet it will have special
metadata that MacOS stores as a hidden file. Luckily you can run a copy command
from the terminal to copy files without this hidden metadata file. See the steps below.
Copy Files on MacOS Without Creating Hidden Files
Once you've disabled and removed hidden files with the above commands on macOS
you need to be careful to copy files to the board with a special command that
prevents future hidden files from being created. Unfortunately you cannotuse drag
and drop copy in Finder because it will still create these hidden extended attribute
files in some cases (for files downloaded from the internet, like Adafruit's modules).
To copy a file or folder use the-Xoption for thecpcommand in a terminal. For
example to copy a file_name.mpy file to the board use a command like:
cp -X file_name.mpy /Volumes/CIRCUITPY
(Replace file_name.mpy with the name of the file you want to copy.)
Or to copy a folder and all of the files and folders contained within, use a command
like:
cp -rX folder_to_copy /Volumes/CIRCUITPY
If you are copying to the lib folder, or another folder, make sure it exists before
copying.
# if lib does not exist, you'll create a file named lib !
cp -X file_name.mpy /Volumes/CIRCUITPY/lib
# This is safer, and will complain if a lib folder does not exist.
cp -X file_name.mpy /Volumes/CIRCUITPY/lib/
Other MacOS Space-Saving Tips
If you'd like to see the amount of space used on the drive and manually delete hidden
files here's how to do so. First, move into the Volumes/ directory with cd /Volumes/ ,
and then list the amount of space used on the CIRCUITPY drive with the df
That's not very much space left! The next step is to show a list of the files currently on
the CIRCUITPY drive, including the hidden files, using the ls command. You cannot
use Finder to do this, you must do it via command line!
There are a few of the hidden files that MacOS loves to generate, all of which begin
with a ._ before the file name. Remove the ._ files using the rm command. You can
remove them all once by running rm CIRCUITPY/._* . The * acts as a wildcard to
apply the command to everything that begins with ._ at the same time.
Finally, you can run df again to see the current space used.
Nice! You have 12Ki more than before! This space can now be used for libraries and
code!
Device Locked Up or Boot Looping
In rare cases, it may happen that something in your code.py or boot.py files causes
the device to get locked up, or even go into a boot loop. A boot loop occurs when the
board reboots repeatedly and never fully loads. These are not caused by your
everyday Python exceptions, typically it's the result of a deeper problem within
CircuitPython. In this situation, it can be difficult to recover your device if CIRCUITPY
is not allowing you to modify the code.py or boot.py files. Safe mode is one recovery
option. When the device boots up in safe mode it will not run the code.py or boot.py