summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2018-05-31 10:56:17 +0200
committerDaniel Friesel <derf@finalrewind.org>2018-05-31 10:56:17 +0200
commitd040ed5eecb104c201b330c468df3b6d8c59b7f1 (patch)
tree7ea3bf6e09734f742af1814487dd8a53a62388af
Initial commit. Working static light, but no rgbfade yet
-rw-r--r--.gitignore1
-rw-r--r--Makefile72
-rw-r--r--src/main.cc15
-rw-r--r--src/system.cc185
-rw-r--r--src/system.h52
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