Skip to content

Instantly share code, notes, and snippets.

@nseidle
Last active December 25, 2015 02:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nseidle/66d8966463aabee7e6ac to your computer and use it in GitHub Desktop.
Save nseidle/66d8966463aabee7e6ac to your computer and use it in GitHub Desktop.
Example Imp code to control a WS2812 string of LEDs (like these: https://www.sparkfun.com/products/11820)
/* Example of interfacing Imp to WS2812 LED strip using hardware SPI on the electric imp
by: Nathan Seidle
SparkFun Electronics
date: October 4, 2013
license: BeerWare
Please use, reuse, and modify this code as you need.
We hope it saves you some time, or helps you learn something!
If you find it handy, and we meet some day, you can buy me a beer or iced tea in return.
I was only able to get spi257 working reliably with the WS2812. I'm guessing the BSS138 MOSFET
interface circuit on the SparkFun Imp shield is causing the signals to be corrupted.
Note: pin 7 is ImpOutput/MOSI when using spi257
I am powering the WS2812 at 5V. Imp talks at 3.3V. Strip works well.
Current width of data for 120 pixels is 4.17ms
Current time between strip updates is 95ms (max update rate of 10Hz, not great)
*/
imp.configure("WS2812 LED Strip Controller", [], []);
const sizeOfStrip = 120; //How may LEDs are you working with?
pixels <- blob(sizeOfStrip * 3); //Array of 24-bit pixel color data
//Load some values into array then display them
function staticExample() {
//Load some color data
writeColor(0, 0, 255, 0); //Store blue in pixel 0
writeColor(0, 255, 0, 1); //Store red in pixel 1
writeColor(0, 255, 255, 2); //Store pink in pixel 2
writeColor(255, 0, 0, 3); //Store green in pixel 3
/*writeColor(0, 0, 0, 0);
writeColor(0, 0, 0, 1);
writeColor(0, 0, 0, 2);
writeColor(0, 0, 0, 3);
writeColor(0, 0, 255, 4);
*/
updateStrip(); //Send the current pixel array to the strip
//server.log("Done! Strip should now be lit up.");
}
//Light up LEDs, one after another, with a random color
function movingExample(delayAmount) {
for(local j = 0 ; j < 100 ; j++){
shiftPixelArray(); //Shift array one to the right (takes about 15ms)
//Write a new random color into spot 0
local randomColor = math.rand() % 3; //Random from 0 to 2;
if(randomColor == 0) writeColor(255, 0, 0, 0);
if(randomColor == 1) writeColor(0, 255, 0, 0);
if(randomColor == 2) writeColor(0, 0, 255, 0);
/*
local randomGreen = math.rand()%256; //Pick a random color 0 to 255
local randomRed = math.rand()%256;
local randomBlue = math.rand()%256;
writeColor(randomGreen, randomRed, randomBlue, 0); //Pick a random color and store it in the array
*/
updateStrip(); //Push the entire array to the strip (takes about 80ms)
imp.sleep(delayAmount);
}
}
//Shifts the entire array to the right by 1
//Most often used to shift array so we can add a new color to the start of the strip
function shiftPixelArray() {
//Start with the next to last color and move it to the last spot
for(local i = sizeOfStrip - 2 ; i > -1 ; i--) {
//Write this color to the next spot in the array
pixels[((i+1) * 3) + 0] = pixels[(i * 3) + 0];
pixels[((i+1) * 3) + 1] = pixels[(i * 3) + 1];
pixels[((i+1) * 3) + 2] = pixels[(i * 3) + 2];
}
}
//Sends the pixel array to the strip
//Converts colors (red = 255) to 'bits' that WS2812 can understand
function updateStrip(){
const ONBIT = 0xFC; //1.2 / .25us = 1.45us, 83% on time
const OFFBIT = 0x80; //0.5 / .91us = 1.41us, 35% on time
//Each pixel requires 24 bits
//Each "bit" going to the WS2812 is actually a byte (0xFC or 0x80)
//The extra 2 bytes are for the leading and ending 0x00s
stringData <- blob( (sizeOfStrip * 24) + 2);
//The 0x00 at the beginning gets the SPI hardware working correctly
//so that the first bit of actual data has proper timing
stringData.writen(0x00, 'b');
//Step through all the bytes in the pixel array, three bytes per pixel
for(local j = 0 ; j < sizeOfStrip * 3; j++)
{
local myByte = pixels[j];
//Convert this one part of a pixel (r g or b data) into ON/OFFBITs
for(local i = 0 ; i < 8 ; ++i)
{
if(myByte & 0x80)
stringData.writen(ONBIT, 'b')
else
stringData.writen(OFFBIT, 'b');
myByte = myByte << 1;
}
}
//The 0x00 at the end will keep the data line low when done.
stringData.writen(0x00, 'b');
hardware.spi257.write(stringData);
}
//Takes three values and a pixel number
//Creates one 24-bit number and stores it in that location in the array
//pixel blob acts like an array of 8 bit numbers
//This assumes the WS2812 is GRB from world-semi: https://www.sparkfun.com/products/11821
function writeColor(green, red, blue, location) {
pixels[(location * 3) + 0] = green;
pixels[(location * 3) + 1] = red;
pixels[(location * 3) + 2] = blue;
}
//We need 6.666MHz SPI data rate to hit 150ns per bit but Imp only does 3.75MHz, 7.5MHz, or 15MHz
//15MHz seems to be the most stable, 7.5MHz also works ok
function setupHardware() {
local actualSpeed = hardware.spi257.configure(SIMPLEX_TX | MSB_FIRST | CLOCK_IDLE_LOW, 7500);
server.log(format("SPI setup. Actual SPI speed: %d", actualSpeed));
//Zero out the pixel array
for(local i = 0 ; i < sizeOfStrip ; i++)
writeColor(0, 0, 0, i);
}
// Start this party going!
setupHardware(); //Setup SPI
//staticExample();
movingExample(0.5); //Call with amount of seconds (0.1 = 100ms) between changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment