GEMMA M0 boards can run CircuitPython — a different approach to programming compared to Arduino sketches. In fact, CircuitPython comes factory pre-loaded on GEMMA M0. If you’ve overwritten it with an Arduino sketch, or just want to learn the basics of setting up and using CircuitPython, this is explained in the Adafruit GEMMA M0 guide.
Below is CircuitPython code that works similarly (though not exactly the same) as the Arduino sketch shown on a prior page. To use this, plug the GEMMA M0 into USB…it should show up on your computer as a small flash drive…then edit the file “code.py” with your text editor of choice. Select and copy the code below and paste it into that file, entirely replacing its contents (don’t mix it in with lingering bits of old code). When you save the file, the code should start running almost immediately (if not, see notes at the bottom of this page).
If GEMMA M0 doesn’t show up as a drive, follow the GEMMA M0 guide link above to prepare the board for CircuitPython.
This code requires the neopixel.py library. A factory-fresh board will have this already installed. If you’ve just reloaded the board with CircuitPython, create the “lib” directory and then download neopixel.py from Github.
# SPDX-FileCopyrightText: 2014 HerrRausB https://github.com/HerrRausB
# SPDX-FileCopyrightText: 2017 Mikey Sklar for Adafruit Industries
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
# 3D_Printed_NeoPixel_Ring_Hair_Dress.py
#
# this was ported to CircuitPython from the 'Gemma Hoop Animator'
#
# https://github.com/HerrRausB/GemmaHoopAnimator
#
# unless you # don't like the preset animations or find a
# major bug, you don't need tochange anything here
#
import time
import board
import neopixel
try:
import urandom as random # for v1.0 API support
except ImportError:
import random
from analogio import AnalogIn
# available actions
ACT_NOP = 0x00 # all leds off, do nothing
ACT_SIMPLE_RING = 0x01 # all leds on
ACT_CYCLING_RING_ACLK = 0x02 # anti clockwise cycling colors
ACT_CYCLING_RING_CLKW = 0x04 # clockwise cycling colors
ACT_WHEEL_ACLK = 0x08 # anti clockwise spinning wheel
ACT_WHEEL_CLKW = 0x10 # clockwise spinning wheel
ACT_SPARKLING_RING = 0x20 # sparkling effect
numpix = 16 # total number of NeoPixels
pixel_output = board.D0 # pin where NeoPixels are connected
analog_input = board.A0 # needed to seed the random generator
strip = neopixel.NeoPixel(pixel_output, numpix,
brightness=.3, auto_write=False)
# available color generation methods
COL_RANDOM = 0x40 # colors will be generated randomly
COL_SPECTRUM = 0x80 # colors will be set as cyclic spectral wipe
# specifiyng the action list
# the action's overall duration in milliseconds (be careful not
action_duration = 0
# to use values > 2^16-1 - roughly one minute :-)
action_and_color_gen = 1 # the color generation method
# the duration of each action step rsp. the delay of the main
action_step_duration = 2
# loop in milliseconds - thus, controls the action speed (be
# careful not to use values > 2^16-1 - roughly one minute :-)
color_granularity = 3 # controls the increment of the R, G, and B
# portions of the rsp. color. 1 means the increment is 0,1,2,3,...,
# 10 means the increment is 0,10,20,... don't use values > 255, and
# note that even values > 127 wouldn't make much sense...
# controls the speed of color changing independently from action
color_interval = 4
# general global variables
color = 0
color_timer = 0
action_timer = 0
action_step_timer = 0
color_idx = 0
curr_color_interval = 0
curr_action_step_duration = 0
curr_action_duration = 0
curr_action = 0
curr_color_gen = COL_RANDOM
idx = 0
offset = 0
number_of_actions = 31
curr_action_idx = 0
curr_color_granularity = 1
spectrum_part = 0
# defining the animation actions by simply initializing the array of actions
# this array variable must be called theactionlist !!!
#
# valid actions are:
# ACT_NOP simply do nothing and switch everything off
# ACT_SIMPLE_RING all leds on
# ACT_CYCLING_RING_ACLK anti clockwise cycling colors
# ACT_CYCLING_RING_CLKW clockwise cycling colors acording
# ACT_WHEEL_ACLK anti clockwise spinning wheel
# ACT_WHEEL_CLKW clockwise spinning wheel
# ACT_SPARKLING_RING sparkling effect
#
# valid color options are:
# COL_RANDOM colors will be selected randomly, which might
# be not very sufficient due to well known
# limitations of the random generation algorithm
# COL_SPECTRUM colors will be set as cyclic spectral wipe
# R -> G -> B -> R -> G -> B -> R -> ...
# action action name & action step color color change
# duration color generation method duration granularity interval
theactionlist = [
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2, ACT_CYCLING_RING_CLKW | COL_RANDOM,
0.02, 1, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2, ACT_CYCLING_RING_ACLK | COL_RANDOM,
0.02, 1, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.01, 25, 1],
[2.5, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.25, 20, 0.020],
[1, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.50, 1, 0.020],
[.750, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.075, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.100, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.125, 1, 0.020],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.150, 1, 0.050],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.175, 1, 0.100],
[.500, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.200, 1, 0.200],
[.750, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.225, 1, 0.250],
[1, ACT_CYCLING_RING_CLKW | COL_SPECTRUM,
0.250, 1, 0.350],
[30, ACT_SIMPLE_RING | COL_SPECTRUM,
0.050, 1, 0.010],
[2.5, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.010, 1, 0.010],
[2.5, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.015, 1, 0.020],
[2, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.025, 1, 0.030],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.050, 1, 0.040],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.075, 1, 0.040],
[1, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.100, 1, 0.050],
[.500, ACT_WHEEL_ACLK | COL_SPECTRUM,
0.125, 1, 0.060],
[.500, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.125, 5, 0.050],
[1, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.100, 10, 0.040],
[1.5, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.075, 15, 0.030],
[2, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.050, 20, 0.020],
[2.5, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.025, 25, 0.010],
[3, ACT_WHEEL_CLKW | COL_SPECTRUM,
0.010, 30, 0.005],
[5, ACT_SPARKLING_RING | COL_RANDOM, 0.010, 25, 1],
[5, ACT_NOP, 0, 0, 0]
]
# pylint: disable=global-statement
def nextspectrumcolor():
global spectrum_part, color_idx, curr_color_granularity, color
# spectral wipe from green to red
if spectrum_part == 2:
color = (color_idx, 0, 255-color_idx)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 0
color_idx = 0
# spectral wipe from blue to green
elif spectrum_part == 1:
color = (0, 255 - color_idx, color_idx)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 2
color_idx = 0
# spectral wipe from red to blue
elif spectrum_part == 0:
color = (255 - color_idx, color_idx, 0)
color_idx += curr_color_granularity
if color_idx > 255:
spectrum_part = 1
color_idx = 0
def nextrandomcolor():
global color
# granularity = 1 --> [0 .. 255] * 1 --> 0,1,2,3 ... 255
# granularity = 10 --> [0 .. 25] * 10 --> 0,10,20,30 ... 250
# granularity = 100 --> [0 .. 2] * 100 --> 0,100, 200 (boaring...)
random_red = random.randint(0, int(256 / curr_color_granularity))
random_red *= curr_color_granularity
random_green = random.randint(0, int(256 / curr_color_granularity))
random_green *= curr_color_granularity
random_blue = random.randint(0, int(256 / curr_color_granularity))
random_blue *= curr_color_granularity
color = (random_red, random_green, random_blue)
def nextcolor():
# save some RAM for more animation actions
if curr_color_gen & COL_RANDOM:
nextrandomcolor()
else:
nextspectrumcolor()
def setup():
# fingers corssed, the seeding makes sense to really get random colors...
apin = AnalogIn(analog_input)
random.seed(apin.value)
apin.deinit()
# let's go!
nextcolor()
strip.write()
setup()
while True: # Loop forever...
# do we need to load the next action?
if (time.monotonic() - action_timer) > curr_action_duration:
current_action = theactionlist[curr_action_idx]
curr_action_duration = current_action[action_duration]
curr_action = current_action[action_and_color_gen] & 0x3F
curr_action_step_duration = current_action[action_step_duration]
curr_color_gen = current_action[action_and_color_gen] & 0xC0
curr_color_granularity = current_action[color_granularity]
curr_color_interval = current_action[color_interval]
curr_action_idx += 1
# take care to rotate the action list!
curr_action_idx %= number_of_actions
action_timer = time.monotonic()
# do we need to change to the next color?
if (time.monotonic() - color_timer) > curr_color_interval:
nextcolor()
color_timer = time.monotonic()
# do we need to step up the current action?
if (time.monotonic() - action_step_timer) > curr_action_step_duration:
if curr_action:
is_act_cycling = (ACT_CYCLING_RING_ACLK or ACT_CYCLING_RING_CLKW)
if curr_action == ACT_NOP:
# rather trivial even tho this will be repeated as long as the
# NOP continues - i could have prevented it from repeating
# unnecessarily, but that would mean more code and less
# space for more actions within the animation
for i in range(0, numpix):
strip[i] = (0, 0, 0)
elif curr_action == ACT_SIMPLE_RING:
# even more trivial - just set the new color, if there is one
for i in range(0, numpix):
strip[i] = color
elif curr_action == is_act_cycling:
# spin the ring clockwise or anti clockwise
if curr_action == ACT_CYCLING_RING_ACLK:
idx += 1
else:
idx -= 1
# prevent overflows or underflows
idx %= numpix
# set the new color, if there is one
strip[idx] = color
elif curr_action == ACT_WHEEL_ACLK or ACT_WHEEL_CLKW:
# switch on / off the appropriate pixels according to
# the current offset
for idx in range(0, numpix):
if ((offset + idx) & 7) < 2:
strip[idx] = color
else:
strip[idx] = (0, 0, 0)
# advance the offset and thus, spin the wheel
if curr_action == ACT_WHEEL_CLKW:
offset += 1
else:
offset -= 1
# prevent overflows or underflows
offset %= numpix
elif curr_action == ACT_SPARKLING_RING:
# switch current pixel off
strip[idx] = (0, 0, 0)
# pick a new pixel
idx = random.randint(0, numpix)
# set new pixel to the current color
strip[idx] = color
strip.write()
action_step_timer = time.monotonic()
Page last edited November 18, 2025
Text editor powered by tinymce.