diff options
author | Daniel Friesel <derf@finalrewind.org> | 2018-05-31 10:56:17 +0200 |
---|---|---|
committer | Daniel Friesel <derf@finalrewind.org> | 2018-05-31 10:56:17 +0200 |
commit | d040ed5eecb104c201b330c468df3b6d8c59b7f1 (patch) | |
tree | 7ea3bf6e09734f742af1814487dd8a53a62388af |
Initial commit. Working static light, but no rgbfade yet
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 72 | ||||
-rw-r--r-- | src/main.cc | 15 | ||||
-rw-r--r-- | src/system.cc | 185 | ||||
-rw-r--r-- | src/system.h | 52 |
5 files changed, 325 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5475f99 --- /dev/null +++ b/Makefile @@ -0,0 +1,72 @@ +MCU_AVRDUDE ?= t2313 +MCU_AVRGCC ?= attiny2313a +AVRDUDE_PROGRAMMER ?= usbasp + +AVRCC ?= avr-gcc +AVRCXX ?= avr-g++ +AVRFLASH ?= avrdude +AVRNM ?= avr-nm +AVROBJCOPY ?= avr-objcopy +AVROBJDUMP ?= avr-objdump + +MCU_FLAGS = -mmcu=${MCU_AVRGCC} -DF_CPU=8000000UL + +SHARED_FLAGS = ${MCU_FLAGS} -I. -Os -Wall -Wextra -pedantic +SHARED_FLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +SHARED_FLAGS += -flto -mstrict-X + +ifeq (${LANG},DE) + SHARED_FLAGS += -DLANG_DE +endif + +CFLAGS += ${SHARED_FLAGS} -std=c11 +CXXFLAGS += ${SHARED_FLAGS} -std=c++11 -fno-rtti -fno-exceptions + +ASFLAGS += ${MCU_FLAGS} -wA,--warn +LDFLAGS += -Wl,--gc-sections + +#AVRFLAGS += -U lfuse:w:0xe4:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m +AVRFLAGS += -U flash:w:build/main.hex +#AVRFLAGS += -U eeprom:w:main.eep + +HEADERS = $(wildcard src/*.h) +ASFILES = $(wildcard src/*.S) +CFILES = $(wildcard src/*.c) +CXXFILES = $(wildcard src/*.cc) +OBJECTS = ${CFILES:src/%.c=build/%.o} ${CXXFILES:src/%.cc=build/%.o} ${ASFILES:src/%.S=build/%.o} + +all: build build/main.elf + +build: + mkdir -p build + +build/%.hex: build/%.elf + ${AVROBJCOPY} -O ihex -R .eeprom $< $@ + +build/%.eep: build/%.elf + ${AVROBJCOPY} -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O ihex $< $@ + +build/%.o: src/%.cc ${HEADERS} + ${AVRCXX} ${CXXFLAGS} -o $@ $< -c -Wl,-Map=main.map,--cref + +build/%.o: src/%.c ${HEADERS} + ${AVRCC} ${CFLAGS} -o $@ $< -c -Wl,-Map=main.map,--cref + +build/main.elf: ${OBJECTS} + ${AVRCXX} ${CXXFLAGS} -o $@ $^ ${LDFLAGS} + @echo + @avr-size --format=avr --mcu=${MCU_AVRGCC} $@ + +flash: program + +program: build/main.hex #main.eep + ${AVRFLASH} -p ${MCU_AVRDUDE} -c ${AVRDUDE_PROGRAMMER} ${AVRFLAGS} + +secsize: build/main.elf + ${AVROBJDUMP} -hw -j.text -j.bss -j.data $< + +funsize: build/main.elf + ${AVRNM} --print-size --size-sort $< + +.PHONY: all program secsize funsize diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..39a3e38 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,15 @@ +#include <avr/io.h> +#include <stdlib.h> + +#include "system.h" + +int main (void) +{ + blinkencat.initialize(); + + while (1) { + blinkencat.loop(); + } + + return 0; +} diff --git a/src/system.cc b/src/system.cc new file mode 100644 index 0000000..9b04f69 --- /dev/null +++ b/src/system.cc @@ -0,0 +1,185 @@ +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/wdt.h> +#include <avr/pgmspace.h> +#include <util/delay.h> +#include <stdlib.h> + +// Debian's avr-libc lacks the ATTiny2313A WDTCSR definition +#define WDTCSR _SFR_IO8(0x21) + +#include "system.h" + +/* + * Charge Status IN -> PD3 (PCINT14) + * Piezo IN -X + * Charge Status LED OUT -> PD1 + * Vcc -> VCC + * GND -> GND + * Warm White OUT -> PD5 (OC0B) + * Blue OUT -> PB2 (OC0A) + * Button IN -> PD2 (PCINT13) + * Red OUT -> PB3 (OC1A) + * Green OUT -> PB4 (OC1B) + * + */ + +System blinkencat; + +void System::initialize() +{ + + // disable analog comparator + ACSR |= _BV(ACD); + + // disable unused modules + PRR |= _BV(PRUSI) | _BV(PRUSART); + + wdt_disable(); + + DDRA = 0; + DDRB = _BV(DDB2) | _BV(DDB3) | _BV(DDB4); + DDRD = _BV(DDD1) | _BV(DDD5); + PORTD = _BV(PD2); + + /* + * Pin change interrupts on PD2 and PD3. + * They are also used to wake the chip from sleep, hence we can't use + * INT0/INT1 directly. For those, only a level interrupt is detected + * asynchronously. + */ + + PCMSK2 = _BV(PCINT13) | _BV(PCINT14); + GIMSK = _BV(PCIE2); + + sei(); +} + +void System::idle() +{ + MCUCR &= ~_BV(SM0); + MCUCR |= _BV(SE); + asm("sleep"); + MCUCR &= ~_BV(SE); +} + +void System::sleep() +{ + MCUCR |= _BV(SM0) | _BV(SE); + asm("sleep"); + MCUCR &= ~_BV(SE); +} + +void System::set_outputs() +{ + if (warmwhite) { + PORTD |= _BV(PD5); + } else { + PORTD &= ~_BV(PD5); + } + if (red) { + PORTB |= _BV(PB3); + } else { + PORTB &= ~_BV(PB3); + } + if (green) { + PORTB |= _BV(PB4); + } else { + PORTB &= ~_BV(PB4); + } + if (blue) { + PORTB |= _BV(PB2); + } else { + PORTB &= ~_BV(PB2); + } +} + +void System::loop() +{ + switch (mode) { + case OFF: + warmwhite = red = green = blue = 0; + break; + case WARMWHITE: + warmwhite = 255; + red = green = blue = 0; + break; + case RED: + red = 255; + warmwhite = green = blue = 0; + break; + case GREEN: + green = 255; + warmwhite = red = blue = 0; + break; + case BLUE: + blue = 255; + warmwhite = red = green = 0; + break; + case YELLOW: + red = green = 255; + warmwhite = blue = 0; + break; + case MAGENTA: + red = blue = 255; + warmwhite = green = 0; + break; + case CYAN: + green = blue = 255; + warmwhite = red = 0; + break; + case SUN: + warmwhite = red = green = blue = 255; + break; + default: + break; + } + set_outputs(); + + if (mode == OFF && !btn_debounce) { + sleep(); + } else { + idle(); + } +} + +void System::next_mode(void) +{ + if (!btn_debounce) { + mode = (BCMode)((mode + 1) % MODE_ENUM_MAX); + } +} + +void System::debounce_start(void) +{ + btn_debounce = 1; + wdt_reset(); + WDTCSR = _BV(WDE) | _BV(WDCE); + WDTCSR = _BV(WDIE) | _BV(WDP1) | _BV(WDP0); +} + +void System::debounce_done(void) +{ + btn_debounce = 0; + wdt_disable(); +} + +ISR(WDT_OVERFLOW_vect) +{ + blinkencat.debounce_done(); +} + +ISR(PCINT2_vect) +{ + if (!(PIND & _BV(PD2))) { + blinkencat.next_mode(); + } + if (PIND & _BV(PD3)) { + blinkencat.is_charging = 1; + PORTD |= _BV(PD1); + } else { + blinkencat.is_charging = 0; + PORTD &= ~_BV(PD1); + } + blinkencat.debounce_start(); +} diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..35c7172 --- /dev/null +++ b/src/system.h @@ -0,0 +1,52 @@ +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ + +class System { + private: + uint8_t btn_debounce; + + void idle(void); + void sleep(void); + + uint8_t warmwhite; + uint8_t red; + uint8_t green; + uint8_t blue; + + void set_outputs(); + + public: + + void initialize(void); + + void loop(void); + + uint8_t is_charging; + + enum BCMode : uint8_t { + OFF = 0, + WARMWHITE, + RED, + GREEN, + BLUE, + YELLOW, + MAGENTA, + CYAN, + SUN, + MODE_ENUM_MAX, + }; + + BCMode mode; + + void next_mode(void); + + void debounce_done(void); + + void debounce_start(void); + + System() { btn_debounce = 0; mode = OFF; is_charging = 0; }; +}; + +extern System blinkencat; + +#endif |