If you're new to programming, and looking for an easy way to get started with your Circuit Playground Express and CircuitPython, the important thing to know is that this library provides exactly that. However, if you'd like a deeper explanation of how it does that, we've got you covered. This section gets into some fairly technical concepts, so don't worry if you don't follow everything. We've included this to clear up any questions more advanced users may have about how the library works behind the scenes.

There are multiple layers to how this library functions. The following is an explanation of the Circuit Playground library.

Note: This library works with the Circuit Playground Express and Circuit Playground Bluefruit, NOT the Circuit Playground Classic. Any reference in this explanation to "Circuit Playground" is referring to the Express and Bluefruit only.

This section is not meant for beginners. It includes a very technical explanation of how the Circuit Playground library works. It assumes that you have a certain level of knowledge about CircuitPython, its underlying code, and how modules work.

Circuit Playground Library Modules

The library is divided up into multiple modules. The circuit_playground_base module defines a base class called CircuitPlaygroundBase, which includes the library features available for all of the Circuit Playground boards, such as red_led, button_a, etc. The express module defines the Express class, which is a subclass of CircuitPlaygroundBase, which adds features available for only the Circuit Playground Express, such as an alias for touch.A7 to touch.TX (only the CPX has the A7 label on the seventh touch pad). The bluefruit module similarly defines the Bluefruit class, which adds features available for only the Circuit Playground Bluefruit, such as sound_level and loud_sound. The Express and Bluefruit classes inherit the features of the CircuitPlaygroundBase class so when either of the board-specific modules is imported, all of the base and board-specific features are made available.

Within the modules, all of the necessary libraries and CircuitPython modules are imported. All of the hardware and software initialisation is done in __init__() within the module, such as initialising the accelerometer or creating variables for later use. Then we use methods and properties to expose the features for use in your code.

Circuit Playground Library Use

To use the library, you include from adafruit_circuitplayground import cp at the beginning of your program. The first thing the library does is use sys.platform to determine whether the connected board is an Atmel SAMD21 or an nRF52840 microcontroller. This code is contained within the __init__.py file, and is run on import before any other code. Based on the results, it imports the appropriate library module, either express or bluefruit. So for instance if you are running on a Circuit Playground Bluefruit, all of the bluefruit features will be imported. This import mechanism allows the same piece of code to work with all Circuit Playground boards. Here is the essence of __init__.py:

import sys
if sys.platform == 'nRF52840':
    from .bluefruit import cpb as cp
elif sys.platform == 'Atmel SAMD21':
    from .express import cpx as cp

Once imported, all of features for the connected board are available for use as cp.feature_name. For example, to address the little red status LED, you would include cp.red_led in your program.

This library is unusual in that you don't create the primary object yourself. Instead, the object is created on import. When you do from adafruit_circuitplayground import cp, you're importing the cp object has already been created and assigned  the name cp. You do not use the Express or Bluefruit class directly.

This library was originally written only for Circuit Playground Express. Previously, you would have used the import from adafruit_circuitplayground.express import cpx. cpx is the name for the Express class object created inside the express.py module. When we added support for Circuit Playground Bluefruit, we had the bluefruit.py module create an object named cpb, analogous to cpx. However, we realized that any code written to use both boards would have to have all its references to cpb change to cpx or vice versa. To alleviate this, we added  __init__.py, which, as described above discovers which board is the code is running on, and imports either cpx or cpb, renaming it to just cp

Circuit Playground Library vs. Basic CircuitPython

Without this library, each feature of the board would require setup in your code, ranging from one to several extra lines of code necessary. Consider the following examples.

The first example turns on the red LED without using the Circuit Playground library.

import digitalio
import board

led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT

led.value = True

The second example turns on the red LED using the Circuit Playground library.

from adafruit_circuitplayground import cp

cp.red_led = True

Instead of including the setup in the program, the Circuit Playground library includes all the setup in __init__() within the module, so setup is automatically done when you import the library. This is a simple example for comparison; some hardware requires significantly more setup than the red LED.

The Library on Circuit Playground Express

The Circuit Playground library has always pushed the memory limits on the Circuit Playground Express. This led us to include the Circuit Playground library and all of its dependencies in the CircuitPython build for Circuit Playground Express as frozen modules.

Frozen modules are library modules that are "frozen" into, or built into, CircuitPython. Freezing a module into CircuitPython moves execution to the flash to save RAM. Normally when a module is imported, the following occurs:

  • If it is a .py file, it is compiled into byte codes, which are put in RAM and executed there.
  • If it is a .mpy file, it is already compiled into byte codes, and they are put in RAM.

Both of these options use available RAM. This module is complex enough that it quickly outgrew the available RAM on the Circuit Playground Express. So, instead, we freeze the .mpy file into CircuitPython. A frozen .mpy file is already compiled into byte codes like any .mpy file, but the byte codes are already in directly accessible memory (flash), so they don't have to be copied in RAM. This saves on RAM.

In short, it allows us to run a module that would normally run out of memory on import and cause a memory allocation failure. It also means that to use the library with Circuit Playground Express, you simply need to install CircuitPython as the library and all of its dependencies are included in the build.

Normally, you load library modules onto your microcontroller board and place them in the lib folder. However, as explained, this module will not function if it is running from the local copy. The express module uses sys.path on import to specify where the library module should be pulled from. It prefers frozen modules over those contained within the /lib folder to ensure that if a user installs the library locally in the /lib folder, it will still use the frozen module. It also, however, check the root directory first. In order, it checks root, then frozen, then the /lib folder. This order was put in place to ensure the ability to test libraries locally without modifying the library. If you wish to test modifications to one of the modules frozen into CircuitPython for Circuit Playground Express, place the library file in your root directory and it will use that version.

Memory Allocation Failure on Circuit Playground Express

You may find with larger amounts of code or more complicated projects involving external peripherals, that your code fails to run and returns a MemoryError in the serial console. The Circuit Playground library includes all the imports and setup necessary to use all of the functionality it provides. This means that it has a relatively large memory footprint. The Circuit Playground Express has limited memory available. The library was designed to make it easy to get started with Circuit Playground and all of the fun stuff that is built in. If you try to use it with a significant amount of code or with many other libraries, you'll find that you may run out of memory on your board. If this happens from either of these scenarios, you're probably ready to move on to using the individual libraries necessary for the hardware you're trying to utilise in your code. This means you would use basic CircuitPython to "manually" initialise all of the hardware you intend to use, instead of relying on the Circuit Playground library. This allows you to initialise only the hardware you will use in your project versus the Circuit Playground library initialising all available features of the CPX.

This guide was first published on Jun 05, 2018. It was last updated on Jun 14, 2024.

This page (The Technical Side) was last updated on Mar 08, 2024.

Text editor powered by tinymce.