CircuitPython Code

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.

These directions are specific to the “M0” GEMMA. The GEMMA v2 with an 8-bit AVR microcontroller doesn’t run CircuitPython…for those boards, use the Arduino sketch on the “Arduino code” page of this 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 “main.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.

Required Libraries

Additional libraries will be necessary to run both of the CircuitPython examples on this page. 

  • neopixel.mpy
  • adafruit_irremote.mpy

These libraries are available for download here:

Install Circuit Python Libraries

Now that we have all of the libraries and know which ones this project needs, we'll need to copy them onto the USB drive (which will be named CIRCUITPY after flashing the firmware). In the CIRCUITPY drive, create a new folder and name it "lib". Then, copy the libraries to that "lib" folder. The lib folder should contain neopixel.mpy and adafruit_irremote.mpy

There are two different CircuitPython sketches to choose from:

  1. NeoPixel_Basketball_Hoop - Hoop Lights are always on. No point sensor hardware.
  2. NeoPixel_Basketball_Hoop-Point_Sensor - Uses IR sensor and IR LED to illuminate only when a point is scored.

Strand Test Code for NeoPixels

The code below is probably what you want to start with. It is based off of the Strand Test code for NeoPixels. This can easily be modified to any animation you want to program.

import time
import board
import neopixel

pixpin = board.D1
numpix = 60

strip = neopixel.NeoPixel(pixpin, numpix, brightness=1, auto_write=True)

# Fill the dots one after the other with a color
def colorWipe(color, wait):
    for j in range(len(strip)):
        strip[j] = (color)
        time.sleep(wait)

def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if (pos < 0) or (pos > 255):
        return (0, 0, 0)
    if pos < 85:
        return (int(pos * 3), int(255 - (pos * 3)), 0)
    elif pos < 170:
        pos -= 85
        return (int(255 - pos * 3), 0, int(pos * 3))

    pos -= 170
    return (0, int(pos * 3), int(255 - pos * 3))

def rainbow_cycle(wait):
    for j in range(255):
        for i in range(len(strip)):
            idx = int((i * 256 / len(strip)) + j)
            strip[i] = wheel(idx & 255)
        time.sleep(wait)

def rainbow(wait):
    for j in range(255):
        for i in range(len(strip)):
            idx = int(i + j)
            strip[i] = wheel(idx & 255)
        time.sleep(wait)

while True:
    colorWipe((255, 0, 0), .05)  # red and delay
    colorWipe((0, 255, 0), .05)  # green and delay
    colorWipe((0, 0, 255), .05)  # blue and delay

    rainbow(0.02)
    rainbow_cycle(0.02)

Point Sensor Code

So far our hoop will just light up all the time. Using an IR sensor and IR LED we can make the NeoPixels light up whenever we score.

The IR LED pulses out IR light (940nm wavelength) at 38KHz, same as an IR remote. The IR receiver will pick up the signal as long as it can 'see' the LED. When the basketball goes through the hoop, the sensor will say it can't see the LED any more because its blocked - thats how we know it's time to light up the LEDs.

import time
import board
import neopixel
import adafruit_irremote
import pulseio

pixpin = board.D1
ir_led = board.D0
ir_sensor = board.D2
basket_check_seconds = 0.1
numpix = 60

# NeoPixel LED
strip = neopixel.NeoPixel(pixpin, numpix, brightness=1, auto_write=False)

# IR LED output for 38kHz PWM
pwm = pulseio.PWMOut(ir_led, frequency=38000)

# IR Sensor input to detect basketball
pulses = pulseio.PulseIn(ir_sensor, maxlen=200, idle_state=True)
decoder = adafruit_irremote.GenericDecode()

def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if (pos < 0) or (pos > 255):
        return (0, 0, 0)
    if pos < 85:
        return (int(pos * 3), int(255 - (pos * 3)), 0)
    elif pos < 170:
        pos -= 85
        return (int(255 - pos * 3), 0, int(pos * 3))

    pos -= 170
    return (0, int(pos * 3), int(255 - pos * 3))

def timed_rainbow_cycle(seconds, wait):
    # Get the starting time in seconds.
    start = time.monotonic()
    # Use a counter to increment the current color position.
    j = 0

    # Loop until it's time to stop (desired number of milliseconds have elapsed).
    while (time.monotonic() - start) < seconds:
        for i in range(len(strip)):
            idx = int((i * 256 / len(strip)) + j)
            strip[i] = wheel(idx & 255)
        strip.show()
        # Wait the desired number of milliseconds.
        time.sleep(wait)
        j += 1

    # Turn all the pixels off after the animation is done.
    for i in range(len(strip)):
        strip[i] = (0,0,0)
    strip.show()

def pulse_ir():
    # enable IR LED
    pwm.duty_cycle = (2 ** 16) - 1

def is_ball_in_hoop():
    # Check if the IR sensor picked up the pulse
    pulse = decoder.read_pulses(pulses)
    ir_detect = (len(pulse))

    if ir_detect == 0:
        return False    # Sensor can see LED, return false.
    return True         # Sensor can't see LED, return true.


while True:
    pulse_ir()
    is_ball_in_hoop()

    if is_ball_in_hoop():
        timed_rainbow_cycle(2, 0.01)
    time.sleep(basket_check_seconds)
This guide was first published on Mar 11, 2014. It was last updated on Mar 11, 2014. This page (CircuitPython Code) was last updated on Dec 03, 2019.