]> www.fi.muni.cz Git - tinyboard.git/commitdiff
Experimental step-up driver for chain of 5630 LEDs. master
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Wed, 13 Apr 2016 16:21:32 +0000 (18:21 +0200)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Wed, 13 Apr 2016 16:21:32 +0000 (18:21 +0200)
18 files changed:
projects/led-blinker/.gitignore [new file with mode: 0644]
projects/led-blinker/Makefile [new file with mode: 0644]
projects/led-blinker/main.c [new file with mode: 0644]
projects/rgb-led-light/Makefile [new file with mode: 0644]
projects/rgb-led-light/README [new file with mode: 0644]
projects/rgb-led-light/logging.c [new file with mode: 0644]
projects/rgb-led-light/main.c [new file with mode: 0644]
projects/rgb-led-light/rgbstring.h [new file with mode: 0644]
projects/rgb-led-light/serial.c [new file with mode: 0644]
projects/rgb-led-light/version.pl [new file with mode: 0755]
projects/rgb-led-string/main.c
projects/step-up-1/Makefile [new file with mode: 0644]
projects/step-up-1/lights.h [new file with mode: 0644]
projects/step-up-1/logging.c [new file with mode: 0644]
projects/step-up-1/main.c [new file with mode: 0644]
projects/step-up-1/pwm.c [new file with mode: 0644]
projects/step-up/lights.h
projects/step-up/pwmled.c

diff --git a/projects/led-blinker/.gitignore b/projects/led-blinker/.gitignore
new file mode 100644 (file)
index 0000000..324be1b
--- /dev/null
@@ -0,0 +1,4 @@
+*.eep
+*.elf
+*.hex
+*.o
diff --git a/projects/led-blinker/Makefile b/projects/led-blinker/Makefile
new file mode 100644 (file)
index 0000000..1bcbac1
--- /dev/null
@@ -0,0 +1,68 @@
+
+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
+
diff --git a/projects/led-blinker/main.c b/projects/led-blinker/main.c
new file mode 100644 (file)
index 0000000..70491ed
--- /dev/null
@@ -0,0 +1,134 @@
+#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);
+       }
+
+}
diff --git a/projects/rgb-led-light/Makefile b/projects/rgb-led-light/Makefile
new file mode 100644 (file)
index 0000000..e63225b
--- /dev/null
@@ -0,0 +1,68 @@
+
+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
+
diff --git a/projects/rgb-led-light/README b/projects/rgb-led-light/README
new file mode 100644 (file)
index 0000000..78d3010
--- /dev/null
@@ -0,0 +1,25 @@
+
+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
+
+
+
diff --git a/projects/rgb-led-light/logging.c b/projects/rgb-led-light/logging.c
new file mode 100644 (file)
index 0000000..d11275b
--- /dev/null
@@ -0,0 +1,81 @@
+#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
+
diff --git a/projects/rgb-led-light/main.c b/projects/rgb-led-light/main.c
new file mode 100644 (file)
index 0000000..223e58f
--- /dev/null
@@ -0,0 +1,213 @@
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/interrupt.h>
+
+#include "rgbstring.h"
+
+// #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);
+       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;
+}
+
+#define LED_MAX (2*STRIP_SIZE/5)
+#define N_COLORS 8
+#define R_BIAS(x)      ((x) << 3)
+#define G_BIAS(x)      ((x) >> 1)
+#define B_BIAS(x)      ((x) << 1)
+
+static void do_hue()
+{
+       static unsigned char color, led_off;
+       static uint16_t jiffies;
+       unsigned char i, c0, l0;
+
+       if ((jiffies++ & 0x03f) == 0) {
+               if (++led_off >= LED_MAX) {
+                       led_off = 0;
+                       color++;
+                       if (color >= 3*N_COLORS)
+                               color = 0;
+               }
+       }
+
+       l0 = led_off;
+       c0 = color;
+
+       for (i = 0; i < STRIP_SIZE; i++) {
+               if (c0 < N_COLORS) {
+                       send_rgb(R_BIAS(N_COLORS-c0), G_BIAS(c0), 0);
+               } else if (c0 < 2*N_COLORS) {
+                       send_rgb(0, G_BIAS(2*N_COLORS-c0), B_BIAS(c0-N_COLORS));
+               } else {
+                       send_rgb(R_BIAS(c0-2*N_COLORS), 0, B_BIAS(3*N_COLORS-c0));
+               }
+
+               if (++l0 >= LED_MAX) {
+                       l0 = 0;
+                       c0++;
+                       if (c0 >= 3*N_COLORS)
+                               c0 = 0;
+               }
+       }
+       end_frame();
+}
+
+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;
+
+               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:
+                       do_hue();
+                       break;
+               case 3:
+                       fill_color(16, 4, 8);
+                       break;
+               case 4:
+                       fill_color(96, 64, 64);
+                       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;
+               }
+       }
+}
+
diff --git a/projects/rgb-led-light/rgbstring.h b/projects/rgb-led-light/rgbstring.h
new file mode 100644 (file)
index 0000000..880b585
--- /dev/null
@@ -0,0 +1,29 @@
+#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 72
+void init_serial();
+void zero_frame();
+void end_frame();
+void send_rgb(unsigned char r, unsigned char g, unsigned char b);
+
+#endif /* !LIGHTS_H__ */
+
diff --git a/projects/rgb-led-light/serial.c b/projects/rgb-led-light/serial.c
new file mode 100644 (file)
index 0000000..1ab2e42
--- /dev/null
@@ -0,0 +1,88 @@
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/interrupt.h>
+
+#include "rgbstring.h"
+
+void init_serial()
+{
+       PORTB &= ~(_BV(PB1) | _BV(PB2));
+       DDRB |= _BV(PB1) | _BV(PB2);
+
+#if 0
+       TCCR0A = _BV(WGM01) | _BV(WGM00);
+       TCCR0B = _BV(WGM02) | _BV(CS00);
+       OCR0A = 2;
+#endif
+
+       zero_frame();
+}
+
+static void send_byte(unsigned char b)
+{
+       unsigned char i, mask;
+
+#if 0
+       USIDR = b;
+       USISR = _BV(USIOIF);
+       USICR = _BV(USIWM0) | _BV(USICS0);
+
+       while (!(USISR & _BV(USIOIF)))
+               ;
+#endif
+
+#if 0
+       USIDR = b;
+       USISR = _BV(USIOIF);
+
+       while ( (USISR & _BV(USIOIF)) == 0 ) {
+               USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK);
+               USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);
+       }
+#endif
+
+#if 0
+       for (i = 0; i < 8; i++) {
+               USICR = _BV(USIWM0) | _BV(USITC);
+               USICR = _BV(USIWM0) | _BV(USITC) | _BV(USICLK);
+       }
+#endif
+
+#if 1
+       for (i = 0; i < 8; i++) {
+               PORTB &= ~_BV(PB2);             // clock low
+               if (b & 0x80)                   // data bit on or off
+                       PORTB |= _BV(PB1);
+               else
+                       PORTB &= ~_BV(PB1);
+               b <<= 1;
+               PORTB |= _BV(PB2);              // clock high
+       }
+#endif
+}
+
+void end_frame()
+{
+       PORTB &= ~_BV(PB2);                     // clock low
+       _delay_us(1000);
+}
+
+void send_rgb(unsigned char r, unsigned char g, unsigned char b)
+{
+       send_byte(r);
+       send_byte(g);
+       send_byte(b);
+}
+
+
+void zero_frame()
+{
+       unsigned char i;
+
+       for (i = 0; i < STRIP_SIZE; i++) {
+               send_rgb(0, 0, 0);
+       }
+
+       end_frame();
+}
+
diff --git a/projects/rgb-led-light/version.pl b/projects/rgb-led-light/version.pl
new file mode 100755 (executable)
index 0000000..cb4ecc7
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/perl -w
+
+use strict;
+use POSIX qw(strftime);
+
+my $git = `git rev-parse --short HEAD`;
+chomp $git;
+
+my $now = strftime('%Y%m%d', localtime(time));
+
+print <<EOF;
+/* DO NOT EDIT - GENERATED BY $0 */
+
+#include <avr/eeprom.h>
+
+unsigned char version[] EEMEM = {
+EOF
+
+print hex2c($git, "git revision");
+print hex2c($now, "date");
+
+print "};\n\n/* EOF - this file has not been truncated */\n\n";
+
+sub hex2c {
+       my ($data, $comment) = @_;
+
+       my $data1 = $data;
+       $data1 .= '0' if (length($data1) & 1 == 1);
+       $data1 =~ s/(..)/0x$1, /g;
+       return "\t$data1 /* $comment $data */\n";
+}
+
index bd923612f57f30dd0cba6093daaf2e02894caee2..a620b98ed491956f58534a69c4ed53dcb37dec88 100644 (file)
@@ -6,7 +6,7 @@
 
 static unsigned char jiffies;
 
-// #define CHRISTMAS_TREE 1
+#define CHRISTMAS_TREE 1
 
 #define rgb_return(r, g, b)    do { send_rgb((r), (g), (b)); return 1; } while(0)
 
@@ -232,14 +232,16 @@ static unsigned char midstar_pixel(unsigned char pos)
 static void background(unsigned char pos)
 {
 #ifdef CHRISTMAS_TREE
-       switch ((pos >> 4) & 3) {
-       case 0: if (pos & 1) send_rgb(7, 0, 0); else send_rgb(0, 7, 0);
+       switch ((pos >> 3) & 3) {
+       //case 0: if (pos & 1) send_rgb(7, 0, 7); else send_rgb(0, 7, 5);
+       //case 0: if (pos & 1) send_rgb(0, 0, 7); else send_rgb(7, 7, 7);
+       case 0: if (pos & 1) send_rgb(0, 0, 7); else send_rgb(0, 7, 0);
                break;
-       case 1: if (pos & 1) send_rgb(0, 0, 7); else send_rgb(7, 7, 7);
+       case 1: if (pos & 1) send_rgb(7, 0, 7); else send_rgb(7, 0, 0);
                break;
-       case 2: if (pos & 1) send_rgb(7, 0, 7); else send_rgb(0, 7, 5);
+       case 2: if (pos & 1) send_rgb(7, 5, 0); else send_rgb(7, 7, 7);
                break;
-       case 3: if (pos & 1) send_rgb(7, 5, 0); else send_rgb(7, 7, 7);
+       case 3: if (pos & 1) send_rgb(7, 0, 0); else send_rgb(0, 7, 0);
                break;
        }
 #else
diff --git a/projects/step-up-1/Makefile b/projects/step-up-1/Makefile
new file mode 100644 (file)
index 0000000..b655283
--- /dev/null
@@ -0,0 +1,70 @@
+
+PROGRAM=lights
+# SRC=version.c main.c logging.c pwm.c adc.c pwmled.c pattern.c buttons.c \
+#      control.c battery.c wdt.c
+SRC=main.c logging.c pwm.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) -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 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
+
diff --git a/projects/step-up-1/lights.h b/projects/step-up-1/lights.h
new file mode 100644 (file)
index 0000000..e3bd6e3
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef LIGHTS_H__
+#define LIGHTS_H__ 1
+
+#define N_PWMLED_MODES 4
+
+/* 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
+
+/* adc.c */
+#define PWMLED_ADC_SHIFT 1 /* 1<<1 measurements per single callback */
+extern volatile unsigned char need_battery_adc;
+extern volatile unsigned char need_pwmled_adc;
+extern volatile unsigned char adc_enabled;
+void init_adc();
+void susp_adc();
+void start_next_adc();
+
+/* pwm.c */
+#define PWM_MAX 0xFF
+extern volatile unsigned char pwm_enabled;
+void init_pwm();
+void susp_pwm();
+void pwm_off();
+void pwm_set(uint8_t stride);
+
+/* pwmled.c */
+void init_pwmled();
+void pwmled_adc(uint16_t adcval);
+void pwmled_set_target(unsigned char mode);
+void pwmled_on_off(unsigned char on);
+
+/* pattern.c */
+void init_pattern();
+void patterns_next_tick();
+void led_set_pattern(unsigned char led, unsigned char bits_len,
+       unsigned char bits_start, unsigned char *data);
+void led_set_number_pattern(unsigned char led,
+       unsigned char num, unsigned char inv);
+void pattern_reload();
+
+/* buttons.c */
+void init_buttons();
+void susp_buttons();
+void timer_check_buttons();
+unsigned char buttons_wait_for_release();
+void status_led_on_off(unsigned char on);
+
+/* battery.c */
+void battery_adc();
+void init_battery();
+unsigned char battery_gauge();
+
+/* control.c */
+void init_control();
+void long_press_start();
+void long_press();
+void short_press();
+void brake_on();
+void brake_off();
+void pwmled_pattern_select(unsigned char led);
+void status_led_pattern_select(unsigned char led);
+#define ERR_BATTERY 1
+#define ERR_PWMLED  2
+void set_error(unsigned char err);
+
+/* wdt.c */
+extern volatile uint16_t jiffies;
+void init_wdt();
+void susp_wdt();
+
+/* main.c */
+void power_down();
+
+#endif /* !LIGHTS_H__ */
+
diff --git a/projects/step-up-1/logging.c b/projects/step-up-1/logging.c
new file mode 100644 (file)
index 0000000..4582d27
--- /dev/null
@@ -0,0 +1,81 @@
+#ifdef USE_LOGGING
+
+#include <avr/io.h>
+#include <avr/eeprom.h>
+
+#include "lights.h"
+
+#define LOG_BUFFER 32
+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
+
diff --git a/projects/step-up-1/main.c b/projects/step-up-1/main.c
new file mode 100644 (file)
index 0000000..6d38f06
--- /dev/null
@@ -0,0 +1,236 @@
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+#include <avr/wdt.h>
+
+#include "lights.h"
+
+#if 0
+static void hw_setup()
+{
+       power_all_disable();
+
+//     init_battery();
+       init_pwm();
+//     init_adc();
+//     init_wdt();
+//
+//     init_buttons();
+
+//     init_pwmled();
+//     init_pattern();
+//     init_control();
+
+//     set_sleep_mode(SLEEP_MODE_IDLE);
+}
+
+static void hw_suspend()
+{
+       susp_pwm();
+       susp_adc();
+       susp_wdt();
+
+       susp_buttons();
+
+       power_all_disable();
+}
+
+void power_down()
+{
+       hw_suspend();
+
+       do {
+               // G'night
+               set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+               sleep_enable();
+               sleep_bod_disable();
+               sei();
+               sleep_cpu();
+
+               // G'morning
+               cli();
+               sleep_disable();
+
+               // allow wakeup by long button-press only
+       } while (!buttons_wait_for_release());
+
+       // ok, so I will wake up
+       hw_setup();
+}
+#endif
+
+
+uint16_t read_adc_sync()
+{
+       uint16_t rv;
+
+       ADCSRA |= _BV(ADSC); // start the conversion
+
+       // wait for the conversion to finish
+       while((ADCSRA & _BV(ADIF)) == 0)
+               ;
+
+       rv = ADCW;
+       ADCSRA |= _BV(ADIF); // clear the IRQ flag
+
+       return rv;
+}
+
+void init_adc()
+{
+       power_adc_enable();
+       ACSR |= _BV(ACD);       // but disable the analog comparator
+
+       ADCSRA = _BV(ADEN)                      // enable
+               // | _BV(ADPS1) | _BV(ADPS0)    // CLK/8 = 125 kHz
+               | _BV(ADPS2)                    // CLK/16 = 62.5 kHz
+               ;
+
+       // Disable digital input on all bits used by ADC
+       DIDR0 = _BV(ADC3D) | _BV(ADC2D);
+       
+       ADMUX = _BV(REFS1) | _BV(MUX1) | _BV(MUX0);
+
+       /* Do first conversion and drop the result */
+       read_adc_sync();
+
+       // ADCSRA |= _BV(ADIE); // enable IRQ
+}
+
+int main(void)
+{
+       uint16_t a, p, c, target;
+       int32_t sum;
+       uint8_t micro;
+       init_log();
+
+       log_set_state(3);
+
+       init_pwm();
+       init_adc();
+       // init_pwmled();
+
+       pwm_set(1);
+       // setup_mux(0);
+       // pwmled_on_off(1);
+       // pwmled_set_target(1);
+       
+       sum = 0;
+       c = 0;
+       micro = 0;
+       sei();
+
+       target = 0xf0;
+#if 0
+       while(1) {
+               unsigned char p;
+               for (p = 0xd4; p <= 0xd5; p+= 0x1) {
+                       unsigned char i, j;
+                       uint16_t sum;
+
+                       pwm_set(p);
+
+                       for (j = 0; j < 12; j++) {
+                               sum = 0;
+                               for (i = 0; i < 2; i++) {
+                                       sum += read_adc_sync();
+                               }
+                               log_byte(sum);
+                               for (i = 0; i < 14; i++) {
+                                       sum += read_adc_sync();
+                               }
+                       }
+                       log_flush();
+               }
+       }
+#endif
+       while (1) {
+               sum += target - read_adc_sync() - (sum >> 7);
+               micro++;
+               if (micro > 7)
+                       micro = 0;
+       
+               p = ((sum >> 4) + micro) >> 3;
+               if (p > 0xd8)
+                       p = 0xd8;
+               pwm_set(p);
+               if (++c > 200) {
+                       log_byte(p);
+                       log_flush();
+                       c = 0;
+               }
+       }
+
+       p = a = c = 0;
+       while (1) {
+               uint16_t i;
+               for (i = 0; i < 25; i++) {
+                       uint16_t val;
+                       val = read_adc_sync();
+                       a += val - (a >> 5);
+               }
+               
+               if (a < (42 << 5) && p < 250) {
+                       p++;
+               } else if (p > 1 && a > (38 << 5)) {
+                       p--;
+               }
+               pwm_set(p);
+               if (++c > 1000) {
+                       log_byte(0xbb);
+                       // log_word(read_adc_sync());
+                       log_word(a);
+                       log_word(p);
+                       log_flush();
+                       c = 0;
+               }
+       }
+
+       while(1) {
+               uint16_t i, t;
+               for (t = 0; t < 3; t++) {
+                       pwmled_set_target(t);
+                       for (i = 0; i < 1000; i++) {
+                               need_pwmled_adc = 1;
+                               while (need_pwmled_adc == 1)
+                                       ;
+                       }
+               }
+       }
+
+#if 0
+       hw_setup();
+       power_down();
+
+#if 1
+       while (1) {
+               cli();
+               if (pwm_enabled) {
+                       set_sleep_mode(SLEEP_MODE_IDLE);
+               } else if (adc_enabled) {
+                       set_sleep_mode(SLEEP_MODE_ADC);
+               } else {
+                       set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+               }
+
+               sleep_enable();
+               // keep BOD active, no sleep_bod_disable();
+               sei();
+               sleep_cpu();
+               sleep_disable();
+       }
+#endif
+
+#if 0
+       DDRB |= _BV(PB2);
+       while (1) {
+               PORTB |=  _BV( PB2 );
+               _delay_ms(200);
+               PORTB &=~ _BV( PB2 );
+               _delay_ms(200);
+       }
+#endif
+#endif
+}
diff --git a/projects/step-up-1/pwm.c b/projects/step-up-1/pwm.c
new file mode 100644 (file)
index 0000000..b93a4fa
--- /dev/null
@@ -0,0 +1,74 @@
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/power.h>
+#include <util/delay.h>
+#include <util/atomic.h>
+
+#include "lights.h"
+
+/*
+ * Single PWM channel on OC1B (pin PB4 of Tiny45).
+ * Counts from 0 to 0xFF, without OCR1C compare.
+ */
+
+volatile unsigned char pwm_enabled;
+
+static void inline enable_pll()
+{
+       /* Async clock */
+       PLLCSR = _BV(PLLE) | _BV(LSM);
+
+       /* Synchronize to the phase lock */
+       _delay_us(100);
+       while ((PLLCSR & _BV(PLOCK)) == 0)
+               ;
+       PLLCSR |= _BV(PCKE);
+}
+
+void init_pwm()
+{
+       pwm_enabled = 0;
+       power_timer1_enable();
+
+       TCCR1 = _BV(CTC1) | _BV(CS11);  // pll_clk/2
+       GTCCR = _BV(COM1B1) | _BV(PWM1B);
+
+       OCR1C = PWM_MAX;
+       OCR1B = 0;              // initial stride is 0
+
+       DDRB &= ~(_BV( PB4 ));
+       PORTB &= ~_BV(PB4); // set to zero
+}
+
+void susp_pwm()
+{
+       DDRB &= ~(_BV( PB4 ));
+       PORTB &= ~(_BV( PB4 ));
+       TCCR1 = 0;
+       TIMSK = 0;
+       TIFR = 0;
+
+       PLLCSR &= ~(_BV(PLLE) | _BV(PCKE));
+}
+
+void pwm_off()
+{
+       OCR1B = 0;
+       DDRB &= ~_BV(PB4);
+
+       PLLCSR &= ~(_BV(PLLE) | _BV(PCKE));
+       power_timer1_disable();
+       pwm_enabled = 0;
+}
+
+void pwm_set(uint8_t stride)
+{
+       OCR1B = stride;
+
+       if (!pwm_enabled) {
+               power_timer1_enable();
+               enable_pll();
+               DDRB |= _BV(PB4);
+               pwm_enabled = 1;
+       }
+}
index e3bd6e385b8c5ad6aa85bc21d42ff5be932a5f3e..565deef5d8297fcde3f0e2dc5d6bba55b28653e7 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef LIGHTS_H__
 #define LIGHTS_H__ 1
 
-#define N_PWMLED_MODES 4
+#define N_PWMLED_MODES 3
 
 /* logging.c */
 #ifdef USE_LOGGING
index 485d024d8f0719007113f36b82f903189442c660..2ede13b3026bec1ac80ef2d68bf755125ff045b2 100644 (file)
@@ -25,8 +25,7 @@ static uint16_t adc_max = MA_TO_ADC(30);
 
 static uint16_t targets[N_PWMLED_MODES] = {
        MA_TO_ADC( 2),
-       MA_TO_ADC( 6),
-       MA_TO_ADC(12),
+       MA_TO_ADC(10),
        MA_TO_ADC(20),
 };