--- /dev/null
+
+PROGRAM=blinker
+SRC=main.c
+OBJ=$(SRC:.c=.o)
+
+
+MCU=attiny25
+AVRDUDE_MCU=$(MCU)
+AVRDUDE_PROGRAMMER=usbasp
+
+CFLAGS=-Wall -Os -mmcu=$(MCU) -DUSE_LOGGING=1 -DF_CPU=1000000UL -std=gnu99
+LDFLAGS=
+AVRDUDE_FLAGS= -p$(AVRDUDE_MCU) -c $(AVRDUDE_PROGRAMMER) -B100
+
+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 lights.h Makefile
+ $(CC) -c $(CFLAGS) $< -o $@
+
+%.s: %.c lights.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
+
--- /dev/null
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/sleep.h>
+#include <avr/power.h>
+
+/*
+ * Overview:
+ * three LEDs:
+ * PB1/OC1A yellow
+ * PB2 yellow
+ * PB4/OC1B red
+ */
+
+static void init()
+{
+ DDRB |= _BV(PB1) | _BV(PB2) | _BV(PB4);
+
+ // PWM setup, use T/C 1
+ TCCR1 = _BV(CS10) // clock at CLK/1
+ | _BV(PWM1A) // OCR1A in PWM mode
+ | _BV(COM1A1); // clear on compare match
+ GTCCR = _BV(PWM1B) // OCR1B in PWM mode
+ | _BV(COM1B1); // clear on compare match)
+
+ OCR1C = 255;
+ OCR1A = 0;
+ OCR1B = 0;
+}
+
+
+static unsigned char levels[] = {
+ 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 255
+};
+#define N_LEVELS (sizeof(levels)/sizeof(levels[0]))
+
+static void led_set(unsigned char led, unsigned char val)
+{
+ switch (led) {
+ case 0:
+ OCR1A = val < N_LEVELS ? levels[val] : levels[N_LEVELS-1];
+ break;
+ case 1:
+ if (val) {
+ PORTB |= _BV(PB2);
+ } else {
+ PORTB &= ~_BV(PB2);
+ }
+ break;
+ case 2:
+ OCR1B = val < N_LEVELS ? levels[val] : levels[N_LEVELS-1];
+ break;
+ }
+}
+
+static unsigned char rand[] = {
+193, 33, 133, 97, 139, 225, 40, 105, 110, 238, 57, 250, 26, 221, 166, 247, 138, 23, 107, 122, 154, 33, 201, 66, 154, 78, 137, 198, 86, 232, 38, 182, 16, 198, 73, 231, 58, 114, 58, 105,
+};
+#define N_RAND (sizeof(rand)/sizeof(rand[0]))
+
+static void led0()
+{
+ static unsigned char r, l, exp;
+
+again:
+ if (l == exp) {
+ r++;
+ if (r > N_RAND-7)
+ r = 0;
+ exp = rand[r] >> 4;
+ if (exp >= N_LEVELS-4)
+ goto again;
+ }
+
+ if (l < exp) {
+ l++;
+ } else if (l > exp) {
+ l--;
+ }
+
+ led_set(0, l);
+}
+
+static void led1()
+{
+ static unsigned char r;
+ unsigned char exp;
+
+ led_set(1, 1);
+#if 0
+again:
+ r++;
+ if (r > N_RAND)
+ r = 0;
+ exp = rand[r];
+
+ led_set(1, ((exp >> 3) & 1) ^ ((exp >> 5) & 1));
+#endif
+}
+
+static void led2()
+{
+ static unsigned char r, l, exp;
+
+again:
+ if (l == exp) {
+ r++;
+ if (r > N_RAND)
+ r = 0;
+ exp = rand[r] & 0xF;
+ if (exp >= N_LEVELS)
+ goto again;
+ }
+
+ if (l < exp) {
+ l++;
+ } else if (l > exp) {
+ l--;
+ }
+
+ led_set(2, l);
+}
+
+int main(void)
+{
+ init();
+
+ while (1) {
+ led0();
+ led1();
+ led2();
+ _delay_ms(40);
+ }
+
+}