Setup ItsyBitsy M4 with CircuitPython

We'll need to get our board setup so we can run the CircuitPython code. Let's walk through these steps to get the latest version of CircuitPython onto your board. 

The Mu Python Editor

Mu is a simple Python editor that works with Adafruit CircuitPython hardware. It's written in Python and works on Windows, MacOS, Linux and Raspberry Pi. The serial console is built right in, so you get immediate feedback from your board's serial output! While you can use any text editor with your code, Mu makes it super simple.

Installing or upgrading CircuitPython

You should ensure you have CircuitPython 4.0 or greater on your board. Plug your board in with a known good data + power cable (not the cheesy USB cable that comes with USB power packs, they are power only). You should see a new flash drive pop up.

If the drive is CIRCUITPY, then open the boot_out.txt file to ensure the version number is 4.0 or greater. 

Adafruit CircuitPython 5.0.0-beta.0 on 2019-11-19; Adafruit ItsyBitsy M4 Express with samd51g19

Download the Adafruit CircuitPython Library Bundle

In order to run the code, we'll need to download a few libraries. Libraries contain code to help interface with hardware a lot easier for us.

Use the ItsyBitsy M4 page on Installing Libraries to get the library that matches the major version of CircuitPython you are using noted above, i.e. 4.x for the versiond starting with 4, 5.x for the versions starting with 5, etc.

To run the code for this project, we need the two libraries in the Required Libraries list below. Unzip the library bundle and search for the libraries. Drag and drop the files into a folder named lib on the CIRCUITPY drive (create the folder if it is not already on the ItsyBitsy M4).

Required Libraries 

  • neopixel.mpy
  • adafruit_fancyled

Once we have all the files we need, a directory listing will look similar to above as far as files and directories.

Upload Code

Click on the download link below to grab the main code directly from GitHub. Rename the file to code.py and drop it onto the CIRCUITPY main (root) directory. The code will run properly when all of the files have been uploaded including libraries.

Use any text editor or favorite IDE to modify the code. We suggest using Mu as noted above.

# pylint: disable=import-error

"""
NeoPixel goggles inspired by Rezz

No interactive controls; speed, color and directions randomize periodically.
"""

from random import random, randrange
from time import monotonic
import board
import neopixel
import adafruit_fancyled.adafruit_fancyled as fancy

# Configurable defaults

BRIGHTNESS = 0.15  # 0.0 (off) to 1.0 (max brightness)

# Global variables

# Declare NeoPixel object. Data from ItsyBitsy pin 5 because it has built-in
# level shifting. Each LED eye has 44 pixels, so 88 total. Leave brightness
# at 1.0 here (NeoPixel library runs faster at full brightness) and adjust
# the global BRIGHTNESS above instead (used later when selecting HSV colors).
PIXELS = neopixel.NeoPixel(
    board.D5, 88, auto_write=False, brightness=1.0, pixel_order=neopixel.RGB)

# MODE indicates the current animation state through several bit fields.
# Bit 0 indicates the second eye is x-axis mirrored (1) or an exact copy
# of the first (0). Bit 1 indicates hue is slowly cycling (2) vs holding
# steady (0). Bit 2 indicates the middle of the 3 LED rings moves the
# opposite (4) or same (0) direction as the other 2.
MODE = randrange(8)  # 0 to 7
# Every few seconds, one of the above attributes is randomly toggled.
# This keeps track of the last time.
TIME_OF_LAST_MODE_SWITCH = 0
# HUE works around the color wheel, see FancyLED docs.
HUE = random()
# Relative position of MIDDLE of 3 rings, 0 to 143
MIDDLE_POS = randrange(144)
# Relative position of INNER and OUTER rings, 0 to 143
POS = randrange(144)
# Amount to increment POS and MIDDLE_POS each frame
SPEED = 2 + random() * 5

# The MIRROR_X and OFFSET(OUTER,MIDDLE,INNER) arrays precompute some values
# for each pixel so we don't need to repeat that math every frame or LED.
MIRROR_X = []
OFFSET_OUTER = []
OFFSET_MIDDLE = []
OFFSET_INNER = []
for i in range(24):
    MIRROR_X.append(67 - ((i + 11) % 24))
    OFFSET_OUTER.append(i * 6)
for i in range(16):
    MIRROR_X.append(83 - ((i + 7) % 16))
    OFFSET_MIDDLE.append(i * 9)
for i in range(4):
    MIRROR_X.append(87 - ((i + 2) % 4))
    OFFSET_INNER.append(i * 36)


def set_pixel(index, color):
    """Set one pixel in both eyes. Pass in pixel index (0 to 43) and
       color (as a packed RGB value). If MODE bit 0 is set, second eye
       will be X-axis mirrored, else an exact duplicate."""
    # Set pixel in first eye
    PIXELS[index] = color
    # Set pixel in second eye (mirrored or direct)
    if MODE & 1:
        PIXELS[MIRROR_X[index]] = color
    else:
        PIXELS[44 + index] = color


# Main loop, repeat indefinitely...
while True:

    # Check if 5 seconds have passed since last mode switch
    NOW = monotonic()
    if (NOW - TIME_OF_LAST_MODE_SWITCH) > 5:
        # Yes. Save the time, change ONE mode bit, randomize speed
        TIME_OF_LAST_MODE_SWITCH = NOW
        MODE ^= 1 << randrange(3)
        SPEED = 2 + random() * 5

    # Generate packed RGB value based on current HUE value
    COLOR = fancy.CHSV(HUE, 1.0, BRIGHTNESS).pack()

    # Draw outer ring; 24 pixels, 8 lit
    for i in range(24):
        j = (POS + OFFSET_OUTER[i]) % 72
        if j < 24:
            set_pixel(i, COLOR)
        else:
            set_pixel(i, 0)
    # Draw middle ring; 16 pixels, 6 lit
    for i in range(16):
        j = (OFFSET_MIDDLE[i] + MIDDLE_POS) % 72
        if j < 27:
            set_pixel(24 + i, COLOR)
        else:
            set_pixel(24 + i, 0)
    # Draw inner ring; 4 pixels, 3 lit
    for i in range(4):
        j = (POS + OFFSET_INNER[i]) % 144
        if j < 108:
            set_pixel(40 + i, COLOR)
        else:
            set_pixel(40 + i, 0)

    # Push new state to LEDs
    PIXELS.show()

    # If MODE bit 1 is set, advance hue (else holds steady)
    if MODE & 2:
        HUE += 0.003

    # Increment position of inner & outer ring
    POS = (POS + SPEED) % 144
    # Middle ring advances one way or other depending on MODE bit 2
    if MODE & 4:
        MIDDLE_POS = (MIDDLE_POS - SPEED) % 144
    else:
        MIDDLE_POS = (MIDDLE_POS + SPEED) % 144

Double Check

See the directory listing above and double check that you have all the files listed to make this project function. If any are missing or in an incorrect directory, move them so they're in the right places.

This guide was first published on Jan 01, 2020. It was last updated on Jan 01, 2020.

This page (Software) was last updated on Jun 23, 2021.

Text editor powered by tinymce.