led-strip / led-strip.c

/* LED strip driver
 *
 * Derived from:
 * http://www.pjrc.com/teensy/
 * Copyright (c) 2008, 2010 PJRC.COM, LLC
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "usb_debug_only.h"
#include "print.h"


// Teensy 2.0: LED is active high
#if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB1286__)
#define LED_ON		(PORTD |= (1<<6))
#define LED_OFF		(PORTD &= ~(1<<6))

// Teensy 1.0: LED is active low
#else
#define LED_ON	(PORTD &= ~(1<<6))
#define LED_OFF	(PORTD |= (1<<6))
#endif

#define LED_CONFIG	(DDRD |= (1<<6))
#define CPU_PRESCALE(n)	(CLKPR = 0x80, CLKPR = (n))


#define NUM_LEDS ((int16_t) (32 * 5))
#define LED_SCALE 8

static inline void clock(const uint8_t value)
{
	if (value)
		PORTB |= (1 << 1);
	else
		PORTB &= ~(1 << 1);
}


static void send_zero(void)
{
	unsigned i;
	PORTB &= ~(1 << 2);

	for (i = 0 ; i < 8 ; i++)
	{
		clock(1);
		clock(0);
	}
}


static void send_byte(uint8_t v)
{
	unsigned bit;
	for (bit = 0x80 ; bit ; bit >>= 1)
	{
		clock(0);
		if (v & bit)
			PORTB |=  (1 << 2);
		else
			PORTB &= ~(1 << 2);
		clock(1);
	}
}


static void latch(void)
{
	unsigned i;
	const unsigned zeros = 3 * ((NUM_LEDS + 63) / 64);
	for (i = 0 ; i < zeros ; i++)
		send_zero();
}

static uint8_t pixels[NUM_LEDS][3];

static void send_pixels(void)
{
	uint16_t i;
	for (i = 0 ; i < NUM_LEDS ; i++)
	{
		uint8_t * const p = pixels[i];
		uint8_t r = p[0];
		uint8_t g = p[1];
		uint8_t b = p[2];

		send_byte(0x80 | (r >> 1));
		send_byte(0x80 | (g >> 1));
		send_byte(0x80 | (b >> 1));
	}

	latch();
}

static void fade_pixels(void)
{
	uint16_t i;
	for (i = 0 ; i < NUM_LEDS ; i++)
	{
		uint8_t * const p = pixels[i];
		uint8_t j;
		for (j = 0 ; j < 3 ; j++)
		{
			uint16_t v = (p[j] * (uint16_t) 31) / 32;
			if (v > 0xFF)
				v = 0xFF;
			p[j] = v;
		}
	}
}

struct sprite
{
	int16_t pos;
	int16_t v;
	uint8_t r;
	uint8_t b;
	uint8_t g;
};



int main(void)
{
	// set for 16 MHz clock, and make sure the LED is off
	CPU_PRESCALE(0);
	LED_CONFIG;
	LED_OFF;

	// initialize the USB, but don't want for the host to
	// configure.  The first several messages sent will be
	// lost because the PC hasn't configured the USB yet,
	// but we care more about blinking than debug messages!
	usb_init();

	LED_ON;

	DDRB |= 1 << 2;
	DDRB |= 1 << 1;

	latch();

	uint16_t i;
	for (i = 0 ; i < NUM_LEDS ; i++)
		pixels[i][0] = pixels[i][1] = pixels[i][2] = 0xFF;
	send_pixels();
	//while(1);

	struct sprite sprites[] = {
		{ .v = +1, .r = 0xFF, .b = 0x00, .g = 0x00 },
		{ .v = +2, .r = 0x00, .b = 0xFF, .g = 0x00, .pos = NUM_LEDS*LED_SCALE/2 },
		{ .v = +3, .r = 0xFF, .b = 0xFF, .g = 0xFF },
		{ .v = +4, .r = 0x00, .b = 0xFF, .g = 0xFF },
		{ .v = +5, .r = 0x80, .b = 0x80, .g = 0x10 },
		{ .v = +6, .r = 0x00, .b = 0x00, .g = 0xFF, .pos = NUM_LEDS*LED_SCALE/2 },
		{ .v = +7, .r = 0xFF, .b = 0x00, .g = 0xFF, .pos = NUM_LEDS*LED_SCALE/2 },
	};
	const int num_sprites = sizeof(sprites) / sizeof(*sprites);

	while (1)
	{
		send_pixels();
		fade_pixels();

		// Compute the next position
		for (int i = 0 ; i < num_sprites ; i++)
		{
			struct sprite * const s = &sprites[i];
			int16_t pos = s->pos + s->v;

			if (pos >= NUM_LEDS * LED_SCALE)
			{
				pos = NUM_LEDS * LED_SCALE - 1;
				s->v = -s->v;
			} else
			if (pos < 0) {
				pos = 0;
				s->v = -s->v;
			}
				
			s->pos = pos;

			uint8_t * const p = pixels[pos / LED_SCALE];
			p[0] = (s->r * (uint16_t) 3 + p[0]) / 4;
			p[1] = (s->g * (uint16_t) 3 + p[1]) / 4;
			p[2] = (s->b * (uint16_t) 3 + p[2]) / 4;
		}

		_delay_ms(30);
	}
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.