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.
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.
Page last edited March 08, 2024
Text editor powered by tinymce.