Commit a1f7cb55 authored by Jan Kasprzak's avatar Jan Kasprzak
Browse files

New project: RGB LED lights

parent 85a86985
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line

PROGRAM=rgbstring
SRC=version.c main.c logging.c serial.c
OBJ=$(SRC:.c=.o)


MCU=attiny45
AVRDUDE_MCU=$(MCU)
AVRDUDE_PROGRAMMER=usbasp

CFLAGS=-Wall -Os -mmcu=$(MCU) -DUSE_LOGGING=1 -DF_CPU=8000000UL -std=gnu99
LDFLAGS=
AVRDUDE_FLAGS= -p$(AVRDUDE_MCU) -c $(AVRDUDE_PROGRAMMER) -B10

FORMAT=ihex

CC=avr-gcc
OBJCOPY=avr-objcopy
OBJDUMP=avr-objdump
AVRDUDE=avrdude

all: $(PROGRAM).hex $(PROGRAM).eep

program: $(PROGRAM).hex $(PROGRAM).eep
	$(AVRDUDE) $(AVRDUDE_FLAGS) -U flash:w:$(PROGRAM).hex:i -U eeprom:w:$(PROGRAM).eep:i

program_flash: $(PROGRAM).hex
	$(AVRDUDE) $(AVRDUDE_FLAGS) -U flash:w:$(PROGRAM).hex:i

program_eeprom: $(PROGRAM).eep
	$(AVRDUDE) $(AVRDUDE_FLAGS) eeprom:w:$(PROGRAM).eep:i

dump_eeprom:
	$(AVRDUDE) $(AVRDUDE_FLAGS) -U eeprom:r:eeprom.raw:r
	od -tx1 eeprom.raw

objdump: $(PROGRAM).elf
	$(OBJDUMP) --disassemble $<

.PRECIOUS : $(OBJ) $(PROGRAM).elf

%.hex: %.elf
	$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@

%.eep: %.elf
	$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
		--change-section-lma .eeprom=0 -O $(FORMAT) $< $@

%.elf: $(OBJ)
	$(CC) $(CFLAGS) $(OBJ) -o $@ $(LDFLAGS)

%.o: %.c rgbstring.h Makefile
	$(CC) -c $(CFLAGS) $< -o $@

%.s: %.c rgbstring.h Makefile
	$(CC) -S -c $(CFLAGS) $< -o $@

%.o: %.S
	$(CC) -c $(CFLAGS) $< -o $@

clean:
	rm -f $(PROGRAM).hex $(PROGRAM).eep $(PROGRAM).elf *.o *.s eeprom.raw

version.c:
	./version.pl > version.c

.PHONY: all clean dump_eeprom program program_flash program_eeprom objdump version.c
+25 −0
Original line number Diff line number Diff line

Controller for the string of RGB LEDs

CPU: ATtiny45

Bill of materials:

C3	10uF ceramic
U1	ATtiny45-20SU

Pin-out:

PB0 header:
	2: Button 1
PB1 header:
	2: DATA
PB2 header:
	2: CLK
PB3 header:
	2: Button 2
PB4 header:
	2: Button 3


+81 −0
Original line number Diff line number Diff line
#ifdef USE_LOGGING

#include <avr/io.h>
#include <avr/eeprom.h>

#include "rgbstring.h"

#define LOG_BUFFER 64
static unsigned char log_buffer_ee[LOG_BUFFER] EEMEM;
static unsigned char log_buffer_count;
static unsigned char log_buffer[LOG_BUFFER];
static unsigned char log_state EEMEM;
/* Upper 4 bits are reset count, lower 4 bits are reset reason from MCUSR */
static unsigned char reboot_count EEMEM = 0;
static unsigned char can_write_eeprom = 0;
static uint16_t flushed_end;

void log_set_state(unsigned char val)
{
	if (can_write_eeprom)
		eeprom_write_byte(&log_state, val);
}

void init_log()
{
	unsigned char r_count;

	r_count = eeprom_read_byte(&reboot_count);
	r_count >>= 4;

	if (r_count < 5) {
		r_count++;
		eeprom_write_byte(&reboot_count,
			(r_count << 4) | (MCUSR & 0xF));
		MCUSR = 0;
		can_write_eeprom = 1;
	} else {
		//eeprom_write_byte(&log_state, 0xFF);
		can_write_eeprom = 0;
	}

	log_set_state(1);
	log_buffer_count = 0;
	flushed_end = 0;
}

void log_byte(unsigned char byte) {
	if (log_buffer_count >= LOG_BUFFER)
		return;
	
	// eeprom_write_word(&log_buffer[log_buffer_count], word);
	log_buffer[log_buffer_count++] = byte;

	if (log_buffer_count == LOG_BUFFER)
		log_flush();
}

void log_word(uint16_t word) {
	log_byte(word & 0xFF);
	log_byte(word >> 8);
}

void log_flush() {
	unsigned char i;

	if (!can_write_eeprom)
		return;

	for (i=flushed_end; i < log_buffer_count; i++) {
		eeprom_write_byte(&log_buffer_ee[i],
			log_buffer[i]);
	}

	flushed_end = i;

	if (flushed_end == LOG_BUFFER)
		log_set_state(0x42);
}

#endif
+192 −0
Original line number Diff line number Diff line
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "rgbstring.h"

static volatile uint16_t  jiffies;

// #define CHRISTMAS_TREE 1

#define rgb_return(r, g, b)	do { send_rgb((r), (g), (b)); return 1; } while(0)

#define VERT_SIZE 47

/* RNG from ADC noise */
static unsigned char rand_pool[8], rand_pool_off, prev_bit, rand_pool_out;

static void init_rng()
{
	ADCSRA |= _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1); // enable, clk/64
	ADMUX = _BV(REFS1) | _BV(MUX0) | _BV(MUX3); // 1.1V, PB5:PB5, gain 20
	DIDR0 = _BV(ADC0D);
	ADCSRA |= _BV(ADIE) | _BV(ADSC);
	rand_pool_off = 0;
	prev_bit = 0;
}

static unsigned char rand() {
	unsigned char rv = 0;

	rv = rand_pool[rand_pool_out];
	rand_pool_out++;
	if (rand_pool_out >= sizeof(rand_pool))
		rand_pool_out = 0;

	return rv;
}

ISR(ADC_vect) {
	ADCSRA |= _BV(ADSC);
	jiffies++;
	if ((rand_pool_off & 1) == 0) { // first bit of the pair
		prev_bit = ADCW & 1;
		rand_pool_off++;
	} else {
		unsigned char bit = ADCW & 1;
		if (bit == prev_bit) { // whitening fail: try again
			rand_pool_off--;
			return;
		}

		if (bit) {
			rand_pool[rand_pool_off >> 4]
				^= 1 << ((rand_pool_off >> 1) & 7);
		}

		rand_pool_off++;
		if (rand_pool_off >= 16*sizeof(rand_pool))
			rand_pool_off = 0;
	}
}

static unsigned int slow_dim[] = {
	255, 27, 7, 2,
};

static void fill_color(unsigned char r, unsigned char g, unsigned char b)
{
	unsigned char i;

	for (i = 0; i < STRIP_SIZE; i++)
		send_rgb(r, g, b);

	end_frame();
}

unsigned int state;

static void do_buttons()
{
	static uint8_t prev_buttons = _BV(PB0) | _BV(PB3) | _BV(PB4);
	static uint16_t prev_len = 0;

	uint8_t buttons = PINB & (_BV(PB0) | _BV(PB3) | _BV(PB4));

	if (prev_buttons == buttons) {
		prev_len++;
		return;
	}

	// was change
	if (prev_len < 3 || (buttons != (_BV(PB0) | _BV(PB3) | _BV(PB4)))) {
		prev_buttons = buttons;
		prev_len = 0;
		return;
	}

	if ((prev_buttons & _BV(PB0)) == 0) {
		if (state)
			state--;
	} else if ((prev_buttons & _BV(PB3)) == 0) {
		if (state < 5)
			state++;
	} else if ((prev_buttons & _BV(PB4)) == 0) {
		state = 1;
	}

	prev_buttons = buttons;
	prev_len = 0;
}

int main(void)
{

	init_log();
	init_rng();
	init_serial();

	_delay_ms(3000/8); // wait for a bit and then increase the CPU clock
	CLKPR = _BV(CLKPCE);
	CLKPR = 0;

	PORTB |= _BV(PB0) | _BV(PB3) | _BV(PB4); // pull-ups for buttons

	state = 0;

	sei();

	while (1) {
		unsigned char i;
		static unsigned char c = 28;

		do_buttons();

		switch (state) {
		case 0:
			zero_frame();
			break;
		case 1:
			i = 0;
			while (i < STRIP_SIZE) {
				send_rgb(4, 0, 0);
				send_rgb(4, 1, 0);
				send_rgb(0, 2, 0);
				send_rgb(0, 1, 1);
				send_rgb(0, 0, 2);
				send_rgb(4, 0, 2);
				i += 6;
			}
			end_frame();
			break;
		case 2:
			if ((jiffies & 0x1ff) == 0) {
				c++;
				if (c >= 30)
					c = 0;
			}

			for (i = 0; i < STRIP_SIZE; i++) {
				unsigned char x = c; // + i / 2;
				if (x >= 30)
					x %= 30;
				if (x < 10) {
					send_rgb(8*(10-x), x, 0);
				} else if (x < 20) {
					send_rgb(0, 20-x, x-10);
				} else {
					send_rgb(8*(x-20), 0, 30-x);
				}
			}
			end_frame();
			break;
		case 3:
			fill_color(32, 4, 8);
			break;
		case 4:
			fill_color(255, 92, 92);
			break;
		case 5:
			fill_color(255, 255, 255);
			break;
		default:
			{ unsigned char light;

			light = slow_dim[sizeof(slow_dim)/sizeof(slow_dim[0]) - state];
			fill_color(4*light, light, 2*light);
			}
			break;
		}
	}
}
+29 −0
Original line number Diff line number Diff line
#ifndef LIGHTS_H__
#define LIGHTS_H__ 1

#define N_PWMLED_MODES 3

/* logging.c */
#ifdef USE_LOGGING
void init_log();
void log_set_state(unsigned char val);
void log_flush();
void log_byte(unsigned char byte);
void log_word(uint16_t word);
#else
void inline init_log() { }
void inline log_set_state(unsigned char val) { }
void inline log_flush() { }
void inline log_byte(unsigned char byte) { }
void inline log_word(uint16_t word) { }
#endif

/* serial.c */
#define STRIP_SIZE 10
void init_serial();
void zero_frame();
void end_frame();
void send_rgb(unsigned char r, unsigned char g, unsigned char b);

#endif /* !LIGHTS_H__ */
Loading