Last active
January 3, 2016 22:09
-
-
Save emcniece/8526703 to your computer and use it in GitHub Desktop.
Spark.io Tinker/Neopixel sketch - fails after first colorWipe call
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* tinker_neopixel v1.3 */ | |
/* Includes ------------------------------------------------------------------*/ | |
#include "application.h" | |
/* Function prototypes -------------------------------------------------------*/ | |
int tinkerDigitalRead(String pin); | |
int tinkerDigitalWrite(String command); | |
int tinkerAnalogRead(String pin); | |
int tinkerAnalogWrite(String command); | |
class Adafruit_NeoPixel { | |
public: | |
// Constructor: number of LEDs, pin number, LED type | |
Adafruit_NeoPixel(uint16_t n, uint8_t p=6); | |
~Adafruit_NeoPixel(); | |
void | |
begin(void), | |
show(void), | |
setPin(uint8_t p), | |
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), | |
setPixelColor(uint16_t n, uint32_t c), | |
setBrightness(uint8_t); | |
uint8_t | |
*getPixels() const; | |
uint16_t | |
numPixels(void) const; | |
static uint32_t | |
Color(uint8_t r, uint8_t g, uint8_t b); | |
uint32_t | |
getPixelColor(uint16_t n) const; | |
private: | |
const uint16_t | |
numLEDs, // Number of RGB LEDs in strip | |
numBytes; // Size of 'pixels' buffer below | |
uint8_t | |
pin, // Output pin number | |
brightness, | |
*pixels; // Holds LED color values (3 bytes each) | |
uint32_t | |
endTime; // Latch timing reference | |
}; | |
/* ======================= Adafruit_NeoPixel.cpp ======================= */ | |
Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p) : numLEDs(n), numBytes(n), pin(p), pixels(NULL) | |
{ | |
if((pixels = (uint8_t *)malloc(numBytes))) { | |
memset(pixels, 0, numBytes); | |
} | |
} | |
Adafruit_NeoPixel::~Adafruit_NeoPixel() { | |
if(pixels) free(pixels); | |
pinMode(pin, INPUT); | |
} | |
void Adafruit_NeoPixel::begin(void) { | |
pinMode(pin, OUTPUT); | |
digitalWrite(pin, LOW); | |
} | |
void Adafruit_NeoPixel::show(void) { | |
if(!pixels) return; | |
while((micros() - endTime) < 50L); | |
__disable_irq(); // Need 100% focus on instruction timing | |
volatile uint32_t | |
c, // 24-bit pixel color | |
mask; // 8-bit mask | |
volatile uint16_t i = numBytes; // Output loop counter | |
volatile uint8_t | |
j, // 8-bit inner loop counter | |
*ptr = pixels, // Pointer to next byte | |
g, // Current green byte value | |
r, // Current red byte value | |
b; // Current blue byte value | |
while(i) { // While bytes left... (3 bytes = 1 pixel) | |
mask = 0x800000; // reset the mask | |
i--; // decrement bytes remaining | |
g = *ptr++; // Next green byte value | |
r = *ptr++; // Next red byte value | |
b = *ptr++; // Next blue byte value | |
c = ((uint32_t)g << 16) | ((uint32_t)r << 8) | b; // Pack the next 3 bytes to keep timing tight | |
j = 0; // reset the 24-bit counter | |
do { | |
PIN_MAP[pin].gpio_peripheral->BSRR = PIN_MAP[pin].gpio_pin; // HIGH | |
if (c & mask) { // if masked bit is high | |
// 700ns HIGH (meas. 694ns) | |
asm volatile( | |
"mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
::: "r0", "cc", "memory"); | |
// 600ns LOW (meas. 598ns) | |
PIN_MAP[pin].gpio_peripheral->BRR = PIN_MAP[pin].gpio_pin; // LOW | |
asm volatile( | |
"mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
::: "r0", "cc", "memory"); | |
} | |
else { // else masked bit is low | |
// 350ns HIGH (meas. 346ns) | |
asm volatile( | |
"mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" | |
::: "r0", "cc", "memory"); | |
// 800ns LOW (meas. 792ns) | |
PIN_MAP[pin].gpio_peripheral->BRR = PIN_MAP[pin].gpio_pin; // LOW | |
asm volatile( | |
"mov r0, r0" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" "nop" "\n\t" | |
"nop" "\n\t" "nop" "\n\t" | |
::: "r0", "cc", "memory"); | |
} | |
mask >>= 1; | |
} while ( ++j < 24 ); // ... pixel done | |
} // end while(i) ... no more pixels | |
__enable_irq(); | |
endTime = micros(); // Save EOD time for latch on next call | |
} | |
// Set the output pin number | |
void Adafruit_NeoPixel::setPin(uint8_t p) { | |
pinMode(pin, INPUT); | |
pin = p; | |
pinMode(p, OUTPUT); | |
digitalWrite(p, LOW); | |
} | |
// Set pixel color from separate R,G,B components: | |
void Adafruit_NeoPixel::setPixelColor( | |
uint16_t n, uint8_t r, uint8_t g, uint8_t b) { | |
if(n < numLEDs) { | |
if(brightness) { // See notes in setBrightness() | |
r = (r * brightness) >> 8; | |
g = (g * brightness) >> 8; | |
b = (b * brightness) >> 8; | |
} | |
uint8_t *p = &pixels[n * 3]; | |
*p++ = g; | |
*p++ = r; | |
*p = b; | |
} | |
} | |
// Set pixel color from 'packed' 32-bit RGB color: | |
void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { | |
if(n < numLEDs) { | |
uint8_t | |
r = (uint8_t)(c >> 16), | |
g = (uint8_t)(c >> 8), | |
b = (uint8_t)c; | |
if(brightness) { // See notes in setBrightness() | |
r = (r * brightness) >> 8; | |
g = (g * brightness) >> 8; | |
b = (b * brightness) >> 8; | |
} | |
uint8_t *p = &pixels[n * 3]; | |
*p++ = g; | |
*p++ = r; | |
*p = b; | |
} | |
} | |
// Convert separate R,G,B into packed 32-bit RGB color. | |
// Packed format is always RGB, regardless of LED strand color order. | |
uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { | |
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; | |
} | |
// Query color from previously-set pixel (returns packed 32-bit RGB value) | |
uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { | |
if(n < numLEDs) { | |
uint16_t ofs = n * 3; | |
return (uint32_t)(pixels[ofs + 2]) | | |
((uint32_t)(pixels[ofs ]) << 8) | | |
((uint32_t)(pixels[ofs + 1]) << 16); | |
} | |
return 0; // Pixel # is out of bounds | |
} | |
uint8_t *Adafruit_NeoPixel::getPixels(void) const { | |
return pixels; | |
} | |
uint16_t Adafruit_NeoPixel::numPixels(void) const { | |
return numLEDs; | |
} | |
void Adafruit_NeoPixel::setBrightness(uint8_t b) { | |
uint8_t newBrightness = b + 1; | |
if(newBrightness != brightness) { // Compare against prior value | |
// Brightness has changed -- re-scale existing data in RAM | |
uint8_t c, | |
*ptr = pixels, | |
oldBrightness = brightness - 1; // De-wrap old brightness value | |
uint16_t scale; | |
if(oldBrightness == 0) scale = 0; // Avoid /0 | |
else if(b == 255) scale = 65535 / oldBrightness; | |
else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; | |
for(uint16_t i=0; i<numBytes; i++) { | |
c = *ptr; | |
*ptr++ = (c * scale) >> 8; | |
} | |
brightness = newBrightness; | |
} | |
} | |
/* ======================= SparkPixel.cpp ======================= */ | |
#define PIN D0 | |
Adafruit_NeoPixel strip = Adafruit_NeoPixel(20, PIN); | |
int cRed=0; | |
int cGrn=0; | |
int cBlu=0; | |
int timOut = 0; | |
int countdown; | |
bool colorUpdated = 0; | |
void showColor() { | |
RGB.control(true); | |
RGB.color(cRed, cGrn, cBlu); | |
colorUpdated = 1; | |
countdown = 1000; | |
} | |
void setup(){ | |
Spark.function("digitalwrite", chageLEDPattern); | |
Spark.function("analogwrite", updateRGBLEDColor); | |
strip.begin(); | |
strip.show(); // Initialize all pixels to 'off' | |
} | |
void loop(){ | |
if( colorUpdated == 1){ | |
colorWipe( strip.Color(cRed, cGrn, cBlu), timOut); | |
colorUpdated = 0; | |
} | |
if (0 == countdown) | |
RGB.control(false); | |
if (0 <= countdown) | |
--countdown; | |
} | |
/******************************************************************************* | |
* Function Name : updateRGBLEDColor | |
* Description : Overrides analogWrite for display purposes | |
* Input : Pin and Value (0 to 255) | |
* Output : None. | |
* Return : 1 on success and a negative number on failure | |
*******************************************************************************/ | |
int updateRGBLEDColor(String pinAndValue) { | |
int pinNumber = pinAndValue.charAt(1) - '0'; | |
int value = pinAndValue.substring(3).toInt(); | |
if (5 == pinNumber) | |
cRed = value; | |
else if (6 == pinNumber) | |
cGrn = value; | |
else if (7 == pinNumber) | |
cBlu = value; | |
else if(0 == pinNumber) | |
timOut = value; | |
showColor(); | |
return 0; | |
} | |
/******************************************************************************* | |
* Function Name : changeLEDPattern | |
* Description : Override digitalWrite call | |
* Input : Pin and value | |
* Output : None. | |
* Return : 1 on success and a negative number on failure | |
*******************************************************************************/ | |
int chageLEDPattern(String command) | |
{ | |
return 0; | |
/* Deal with this later... | |
bool value = 0; | |
//convert ascii to integer | |
int pinNumber = command.charAt(1) - '0'; | |
//Sanity check to see if the pin numbers are within limits | |
if (pinNumber< 0 || pinNumber >7) return -1; | |
if(command.substring(3,7) == "HIGH") value = 1; | |
else if(command.substring(3,6) == "LOW") value = 0; | |
else return -2; | |
if(command.startsWith("D")) | |
{ | |
pinMode(pinNumber, OUTPUT); | |
digitalWrite(pinNumber, value); | |
return 1; | |
} | |
else if(command.startsWith("A")) | |
{ | |
pinMode(pinNumber+10, OUTPUT); | |
digitalWrite(pinNumber+10, value); | |
return 1; | |
} | |
else return -3; | |
*/ | |
} | |
/******************************************************************************* | |
* NEOPIXEL FUNCTIONS | |
*******************************************************************************/ | |
// Set all pixels in the strip to a solid color, then wait (ms) | |
void colorAll(uint32_t c, uint8_t wait) { | |
uint16_t i; | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, c); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
// Fill the dots one after the other with a color, wait (ms) after each one | |
void colorWipe(uint32_t c, uint8_t wait) { | |
for(uint16_t i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, c); | |
strip.show(); | |
delay(wait); | |
} | |
} | |
void rainbow(uint8_t wait) { | |
uint16_t i, j; | |
for(j=0; j<256; j++) { | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, Wheel((i+j) & 255)); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
} | |
// Slightly different, this makes the rainbow equally distributed throughout, then wait (ms) | |
void rainbowCycle(uint8_t wait) { | |
uint16_t i, j; | |
for(j=0; j<256; j++) { // 1 cycle of all colors on wheel | |
for(i=0; i< strip.numPixels(); i++) { | |
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
} | |
// Input a value 0 to 255 to get a color value. | |
// The colours are a transition r - g - b - back to r. | |
uint32_t Wheel(byte WheelPos) { | |
if(WheelPos < 85) { | |
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | |
} else if(WheelPos < 170) { | |
WheelPos -= 85; | |
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); | |
} else { | |
WheelPos -= 170; | |
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment