/* hackspacecon wand firmware rgb led control and programs */ #include #include "rgbled.h" #include "hsv2rgb.h" tinyNeoPixel rgb = tinyNeoPixel(RGB_COUNT, PIN_PA1, NEO_GRB, rgbled); // rgb program prototypes uint8_t rgbp_rainbow(uint8_t init); uint8_t rgbp_circlefade(uint8_t init); // rgb program function pointer array uint8_t (*rgb_program[PROG_COUNT])(uint8_t) = { rgbp_rainbow, rgbp_circlefade }; uint8_t rgbled[3 * RGB_COUNT]; // configures and enables the 50Hz timer interrupt that is used for RGB program updates void conf_rgb_timer() { // this timer will run at half speed. // so 8MHz / 2 (prescale) / 1 (CLK_PER) = 4MHz // this will allow a full cycle time of ~61Hz. _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0); // disable CLK_PER divider disable_rgb_timer(); TCB0.CTRLA = TCB_CLKSEL_CLKDIV2_gc; // prescale timer to run at half speed TCB0.CCMP = 0xffff; // count to full TCB0.CNT = 0; } // globals for all rgb programs uint16_t prog_timeout; uint16_t hue; uint8_t r, g, b; // rgb program 0: rainbow puke #define RAINBOW_HUE_INC 40 // how much to increment the hue every frame #define RAINBOW_OFFSET (1536/5) // offset between each LED #define RAINBOW_TIMEOUT 240 // how long to show this program #define RAINBOW_SAT 0xff // saturation #define RAINBOW_VAL 0x40 // value (brightness); keep low enough to keep average current down uint16_t rainbow_hue = 0; uint8_t rgbp_rainbow(uint8_t init) { uint8_t i; // set our timer when initializing. otherwise every call is identical if (init) { prog_timeout = RAINBOW_TIMEOUT; } if (--prog_timeout) { // copy stored hue to working hue hue = rainbow_hue; for (i = 0; i < RGB_COUNT; i++) { // each LED will increment its hue hue += RAINBOW_OFFSET; // hue wheel is 256*6 large, so bound the value if (hue >= 1536) hue -= 1536; // compute rgb from hue/sat/value hsv2rgb(hue, RAINBOW_SAT, RAINBOW_VAL, &r, &g, &b); // apply it to this LED rgb.setPixelColor(i, r, g, b); } // increment stored hue wheel for the next cycle through the program rainbow_hue += RAINBOW_HUE_INC; if (rainbow_hue > 1536) rainbow_hue -= 1536; return 1; } // done with program return 0; } // rgb program 2: circle loops with fading #define CF_TIMEOUT 90 // how long to show this program (max 255, ideally (20*loopcount)+10) #define CF_BRIGHTNESS 64 // how bright to make the LED. don't make too bright or badge will brown out #define CF_FADERATE 12 // how much to fade all LEDs each frame uint8_t circlefade_idx = 0; uint8_t rgbp_circlefade(uint8_t init) { uint8_t i; uint8_t t; // set our timer when initializing. otherwise every call is identical if (init) { prog_timeout = CF_TIMEOUT; circlefade_idx = 4; // top LED } if (--prog_timeout) { t = (uint8_t)(CF_TIMEOUT - prog_timeout); // get time elapsed t &= 0x3; // light a new LED every 4th loop // fade each LED down every frame for (i = 0; i < (sizeof(rgbled) / sizeof(rgbled[0])); i++) { if (rgbled[i] >= CF_FADERATE) { rgbled[i] -= CF_FADERATE; } else { rgbled[i] = 0; } } // set the next LED in sequence on to full brightness every 4 cycles if (prog_timeout >= 10) { // as long as >10 loops remain, if (!t) { // then on a loop boundary, light the next LED rgb.setPixelColor(circlefade_idx, CF_BRIGHTNESS, CF_BRIGHTNESS, CF_BRIGHTNESS); if (++circlefade_idx >= RGB_COUNT) { // then work on the next LED in sequence circlefade_idx = 0; } } } } }