From: Jan "Yenya" Kasprzak Date: Wed, 13 Apr 2016 16:21:32 +0000 (+0200) Subject: Experimental step-up driver for chain of 5630 LEDs. X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?p=tinyboard.git;a=commitdiff_plain;h=HEAD;hp=5013d75921e37f1df3034f0d2ed39ddecb718d67 Experimental step-up driver for chain of 5630 LEDs. --- diff --git a/projects/led-blinker/.gitignore b/projects/led-blinker/.gitignore new file mode 100644 index 0000000..324be1b --- /dev/null +++ b/projects/led-blinker/.gitignore @@ -0,0 +1,4 @@ +*.eep +*.elf +*.hex +*.o diff --git a/projects/led-blinker/Makefile b/projects/led-blinker/Makefile new file mode 100644 index 0000000..1bcbac1 --- /dev/null +++ b/projects/led-blinker/Makefile @@ -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 index 0000000..70491ed --- /dev/null +++ b/projects/led-blinker/main.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +/* + * 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 index 0000000..e63225b --- /dev/null +++ b/projects/rgb-led-light/Makefile @@ -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 index 0000000..78d3010 --- /dev/null +++ b/projects/rgb-led-light/README @@ -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 index 0000000..d11275b --- /dev/null +++ b/projects/rgb-led-light/logging.c @@ -0,0 +1,81 @@ +#ifdef USE_LOGGING + +#include +#include + +#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 index 0000000..223e58f --- /dev/null +++ b/projects/rgb-led-light/main.c @@ -0,0 +1,213 @@ +#include +#include +#include + +#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 index 0000000..880b585 --- /dev/null +++ b/projects/rgb-led-light/rgbstring.h @@ -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 index 0000000..1ab2e42 --- /dev/null +++ b/projects/rgb-led-light/serial.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#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 index 0000000..cb4ecc7 --- /dev/null +++ b/projects/rgb-led-light/version.pl @@ -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 < + +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"; +} + diff --git a/projects/rgb-led-string/main.c b/projects/rgb-led-string/main.c index bd92361..a620b98 100644 --- a/projects/rgb-led-string/main.c +++ b/projects/rgb-led-string/main.c @@ -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 index 0000000..b655283 --- /dev/null +++ b/projects/step-up-1/Makefile @@ -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 index 0000000..e3bd6e3 --- /dev/null +++ b/projects/step-up-1/lights.h @@ -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 index 0000000..4582d27 --- /dev/null +++ b/projects/step-up-1/logging.c @@ -0,0 +1,81 @@ +#ifdef USE_LOGGING + +#include +#include + +#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 index 0000000..6d38f06 --- /dev/null +++ b/projects/step-up-1/main.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include + +#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 index 0000000..b93a4fa --- /dev/null +++ b/projects/step-up-1/pwm.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +#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; + } +} diff --git a/projects/step-up/lights.h b/projects/step-up/lights.h index e3bd6e3..565deef 100644 --- a/projects/step-up/lights.h +++ b/projects/step-up/lights.h @@ -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 diff --git a/projects/step-up/pwmled.c b/projects/step-up/pwmled.c index 485d024..2ede13b 100644 --- a/projects/step-up/pwmled.c +++ b/projects/step-up/pwmled.c @@ -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), };