Coding the Circuit Playground

Before you get started, make sure you've been through the basic tutorials on using the Circuit Playground. You'll need to have installed the Arduino IDE, added the Circuit Playground board to Arduino, and added the Circuit Playground library. This excellent guide, Introducing Circuit Playground and Circuit Playground lesson #0 will show you how to do all of that and get you going.

Plug your Circuit Playground into your computer now, and launch the Arduino IDE. Double check that you've selected the board and port as in the Lesson #0 tutorial and are ready to upload code.

Download the NeoAnim.zip Arduino sketch, then unzip it, and place the NeoAnim directory in your Arduino sketch directory.

The directory contains the NeoAnim.ino Arduino sketch, a 24x10 pixel neoAnim.png bitmap file, and the neoAnim.h header file that was created with the convert.py Python script we'll look at in a few steps.

Download: file
//NeoAnim for Circuit Playground
// adapted by John Park from Circuit Playground Make Believe by Phil Burgess
// for Adafruit Industries
// MIT License

#include <Adafruit_CircuitPlayground.h>
#include "neoAnim.h" //this is the name of the animation derrived from the neoAnim.png bitmap file


void setup() {
  // Initialize Circuit Playground board, NeoPixels
  CircuitPlayground.begin();
  CircuitPlayground.strip.setBrightness(20); 

  // Start looping animation
  playAnim( neoAnimPixelData, neoAnimFPS       , sizeof(neoAnimPixelData), true);
}

// Global values used by the animation and sound functions
uint16_t         *pixelBaseAddr, // Address of active animation table
                  pixelLen,      // Number of pixels in active table
                  pixelIdx,      // Index of first pixel of current frame
                  audioLen;      // Number of audio samples in active table
volatile uint16_t audioIdx;      // Index of current audio sample
uint8_t           pixelFPS,      // Frames/second for active animation
                 *audioBaseAddr; // Address of active sound table
boolean           pixelLoop,     // If true, animation repeats
                  audioLoop;     // If true, audio repeats
  
// Begin playing a NeoPixel animation from a PROGMEM table
void playAnim(const uint16_t *addr, uint8_t fps, uint16_t bytes, boolean repeat) {
  pixelBaseAddr = addr;
  if(addr) {
    pixelFPS    = fps;
    pixelLen    = bytes / 2;
    pixelLoop   = repeat; //if set to 'repeat' it'll loop, set to 0 to play once only
    pixelIdx    = 0;
  } else {
    CircuitPlayground.strip.clear();
  }
}

uint32_t prev = 0; // Time of last NeoPixel refresh

void loop() {
  uint32_t t;      // Current time in milliseconds
  
  // Until the next animation frame interval has elapsed...
  while(((t = millis()) - prev) < (1000 / pixelFPS));
    // Show LEDs rendered on prior pass.  It's done this way so animation timing
    // is a bit more consistent (frame rendering time may vary slightly).
    CircuitPlayground.strip.show();
  
   
  prev = t; // Save refresh time for next frame sync

  if(pixelBaseAddr) {
    for(uint8_t i=0; i<10; i++) { // For each NeoPixel...
      // Read pixel color from PROGMEM table
      uint16_t rgb = pgm_read_word(&pixelBaseAddr[pixelIdx++]);
      // Expand 16-bit color to 24 bits using gamma tables
      // RRRRRGGGGGGBBBBB -> RRRRRRRR GGGGGGGG BBBBBBBB
      CircuitPlayground.strip.setPixelColor(i,
        pgm_read_byte(&gamma5[ rgb >> 11        ]),
        pgm_read_byte(&gamma6[(rgb >>  5) & 0x3F]),
        pgm_read_byte(&gamma5[ rgb        & 0x1F]));
    }
  
     
      if(pixelIdx >= pixelLen) { // End of animation table reached
        if(pixelLoop) { // Repeat animation
          pixelIdx = 0; // Reset index to start of table
        } else {        // else switch off LEDs
          playAnim(NULL, neoAnimFPS, 0, false);
        }
      } 
  
  }
}

Next, you'll download the code that'll allow you to convert bitmaps to animation header files, and play these NeoPixel animations on your Circuit Playground.

Download the linked code from the button above, and then unzip the directory. Within the unzipped directory you'll find two directories: CircuitPlaygroundMakeBelieve, which you can move to your Arduino sketch directory (we won't use it for this guide, but it is useful if you want to build reactive props as shown in this guide), and the Extras directory, which you can place inside your NeoAnim directory you previously downloaded.

You can test the NeoAnim Arduino sketch by opening it in Arduino, and uploading it to your Circuit Playground. It should play a one second loop of a green pixel moving from upper left to upper right counterclockwise.

Now, you can adjust the animation. Open the neoAnim.png file in an image editor, such as Preview on OSX or MS Paint on Windows, or GIMP on Linux, and make some changes, such as the color of the non-black pixels. Save the file (it's OK to overwrite, you can redownload the original here).

In order to convert the new version of neoAnim.png to the neoAnim.h file, you'll need to follow these steps:

  1. Install Python 3.5 https://www.python.org/downloads/
  2. Add the Pillow or PIL imaging library to Python http://pillow.readthedocs.io/en/3.0.x/installation.html
  3. Open a command shell and navigate to the NeoAnim directory inside your Arduino sketches directory
  4. type the command to convert the bitmap: python convert.py neoAnim.png > neoAnim.h

This will generate the animation header file that looks something like this (yours will vary depending on the colors and placements of pixels):

Download: file
#define neoAnimFPS 30

const uint16_t PROGMEM neoAnimPixelData[] = {
  0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X07E0, 0X0000, 0X0000, 0X0000, 0X0000,
  0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X07E0 };

const uint8_t PROGMEM gamma5[] = {
  0X00, 0X00, 0X00, 0X00, 0X01, 0X02, 0X03, 0X05, 0X07, 0X09, 0X0C, 0X10,
  0X14, 0X18, 0X1E, 0X24, 0X2B, 0X32, 0X3B, 0X44, 0X4E, 0X59, 0X65, 0X72,
  0X80, 0X8F, 0X9F, 0XB0, 0XC2, 0XD5, 0XE9, 0XFF };

const uint8_t PROGMEM gamma6[] = {
  0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X01, 0X01, 0X01, 0X02, 0X02,
  0X03, 0X04, 0X04, 0X05, 0X06, 0X07, 0X09, 0X0A, 0X0C, 0X0D, 0X0F, 0X11,
  0X13, 0X15, 0X17, 0X1A, 0X1D, 0X1F, 0X22, 0X26, 0X29, 0X2C, 0X30, 0X34,
  0X38, 0X3D, 0X41, 0X46, 0X4B, 0X50, 0X55, 0X5B, 0X61, 0X67, 0X6D, 0X74,
  0X7A, 0X81, 0X89, 0X90, 0X98, 0XA0, 0XA8, 0XB1, 0XBA, 0XC3, 0XCC, 0XD6,
  0XE0, 0XEA, 0XF4, 0XFF };

This file is referenced when Arduino re-compiles your NeoAnim.ino sketch, so to test it out, simply re-upload the code to your Circuit Playground. You've just animated your own NeoPixel animation using an exposure sheet style bitmap!

In the Arduino IDE you can click on the neoAnim.h tab and change the framerate to 24 FPS if you like, or play around with different framerates to slow down or speed up the the loop.

With some code tweaks you could even use this technique on external NeoPixel rings and strips!

From here, the rest is in your hands! Try different patterns, gradations, color noise, and so on to see what you can create.

This guide was first published on Nov 07, 2016. It was last updated on Nov 07, 2016. This page (Coding the Circuit Playground) was last updated on Sep 29, 2018.