summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/arch/arduino-nano/driver/gpio.h3
-rw-r--r--src/app/blinkencat3/Makefile.inc1
-rw-r--r--src/app/blinkencat3/main.cc262
-rw-r--r--src/arch/arduino-nano/arch.cc2
-rw-r--r--src/arch/arduino-nano/driver/gpio.cc2
5 files changed, 270 insertions, 0 deletions
diff --git a/include/arch/arduino-nano/driver/gpio.h b/include/arch/arduino-nano/driver/gpio.h
index 0b4ca26..74aa879 100644
--- a/include/arch/arduino-nano/driver/gpio.h
+++ b/include/arch/arduino-nano/driver/gpio.h
@@ -148,10 +148,13 @@ class GPIO {
if (pin < 8) {
} else if (pin < 16) {
PCMSK0 |= _BV(pin - 8);
+ PCICR |= _BV(PCIE0);
} else if (pin < 24) {
PCMSK1 |= _BV(pin - 16);
+ PCICR |= _BV(PCIE1);
} else if (pin < 32) {
PCMSK2 |= _BV(pin - 24);
+ PCICR |= _BV(PCIE2);
}
}
inline void disable_int(unsigned char const pin) {
diff --git a/src/app/blinkencat3/Makefile.inc b/src/app/blinkencat3/Makefile.inc
new file mode 100644
index 0000000..2cb8a42
--- /dev/null
+++ b/src/app/blinkencat3/Makefile.inc
@@ -0,0 +1 @@
+loop ?= 1
diff --git a/src/app/blinkencat3/main.cc b/src/app/blinkencat3/main.cc
new file mode 100644
index 0000000..79753b6
--- /dev/null
+++ b/src/app/blinkencat3/main.cc
@@ -0,0 +1,262 @@
+#include "arch.h"
+#include "driver/neopixel.h"
+#include "driver/stdout.h"
+#include <util/delay.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/wdt.h>
+
+#define NUM_PIXELS 27
+
+Adafruit_NeoPixel np(NUM_PIXELS, GPIO::pb0, NEO_GRB+NEO_KHZ800);
+
+class Blinkencat {
+ private:
+ uint8_t btn_debounce;
+
+ public:
+ enum Mode : uint8_t {
+ OFF = 0,
+ RGBWHEEL_FAST,
+ RGBWHEEL_SLOW,
+ RGBFADE_FAST,
+ RGBFADE_SLOW,
+ COLD_WHITE,
+ BEEDOO,
+ STROBE,
+ COLOR_STROBE,
+ MODE_ENUM_MAX
+ };
+
+ Mode mode;
+
+ void setup(void);
+ void next_mode(void);
+ void debounce_done(void);
+ void debounce_start(void);
+ void check_battery(void);
+ void sleep(void);
+ void idle(void);
+ void loop(void);
+
+ Blinkencat() : btn_debounce(0), mode(OFF) {}
+};
+
+void Blinkencat::setup(void)
+{
+ np.setup();
+ gpio.input(GPIO::pb1, 0);
+ gpio.input(GPIO::pd3, 1);
+ gpio.enable_int(GPIO::pd3);
+
+ // One ADC conversion per four seconds
+ TCCR1A = 0;
+ TCCR1B = _BV(CS12) | _BV(CS10);
+
+ // Measure internal 1.1V bandgap using VCC as reference on each Timer 1 overflow
+ ADMUX = _BV(REFS0) | 0x0e;
+ ADCSRB = _BV(ADTS2) | _BV(ADTS1);
+ ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADPS2) | _BV(ADPS1);
+}
+
+void Blinkencat::idle(void)
+{
+ SMCR = _BV(SE);
+ asm("sleep");
+ SMCR = 0;
+}
+
+void Blinkencat::sleep(void)
+{
+ SMCR = _BV(SM1) | _BV(SE);
+ asm("sleep");
+ SMCR = 0;
+}
+
+void Blinkencat::debounce_start(void)
+{
+ if (!btn_debounce) {
+ btn_debounce = 1;
+ wdt_reset();
+ WDTCSR = _BV(WDE) | _BV(WDCE);
+ WDTCSR = _BV(WDIE) | _BV(WDP2);
+ }
+}
+
+void Blinkencat::debounce_done(void)
+{
+ btn_debounce = 0;
+ wdt_disable();
+ // long press? -> turn off
+ if (!gpio.read(GPIO::pd3)) {
+ mode = OFF;
+ }
+}
+
+void Blinkencat::next_mode(void)
+{
+ if (!btn_debounce) {
+ mode = (Mode)((mode + 1) % MODE_ENUM_MAX);
+ }
+}
+
+void Blinkencat::check_battery(void)
+{
+ if (ADCSRA & _BV(ADIF)) {
+ uint8_t adcr_l = ADCL;
+ uint8_t adcr_h = ADCH;
+ uint16_t adcr = adcr_l + (adcr_h << 8);
+ uint16_t vcc = 1100L * 1023 / adcr;
+
+ TIFR1 |= _BV(TOV1);
+ ADCSRA |= _BV(ADIF);
+
+ //kout << "VCC is " << vcc << endl;
+ // 3 V under load ~~ 3.5 V idle
+ if (vcc < 3000) {
+ for (uint8_t i = 0; i < 5; i++) {
+ for (uint8_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.Color(0, 0, 0));
+ }
+ np.show();
+ _delay_ms(400);
+ for (uint8_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.Color(127 * ((i % 7) == 0), 0, 0));
+ }
+ np.show();
+ _delay_ms(400);
+ }
+ for (uint8_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.Color(0, 0, 0));
+ }
+ np.show();
+ sleep();
+ }
+ }
+}
+
+void Blinkencat::loop(void)
+{
+ static uint16_t rgbwheel_offset = 0;
+ static uint16_t rgbfade_hsv = 0;
+ static uint8_t beedoo_pos = 0;
+ static uint8_t strobe_on = 0;
+
+ /*
+ // not working due to bad logic levels
+ if (gpio.read(GPIO::pb1)) {
+ // Arduino and WS2812 strip are connected in parallel with the battery,
+ // which will significantly confuse the charging circuit when the
+ // strip is active while charging. So we make sure that it isn't.
+ mode = OFF;
+ }
+ */
+
+ switch (mode) {
+ case OFF:
+ // the mode may have been set by an ISR, which may in turn have
+ // been handled immediately after an np.show() call. So we must
+ // observe the 300us idle time mandated by WS2812.
+ _delay_ms(1);
+ for (uint16_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.Color(0, 0, 0));
+ }
+ np.show();
+ sleep();
+ break;
+ case RGBWHEEL_FAST:
+ case RGBWHEEL_SLOW:
+ for (uint16_t i = 0; i < NUM_PIXELS; i++) {
+ uint16_t hsv = (i * 252 + rgbwheel_offset) % 6553;
+ np.setPixelColor(i, np.gamma32(np.ColorHSV(hsv * 10)));
+ }
+ rgbwheel_offset = (rgbwheel_offset + 10) % 6553;
+ np.show();
+ _delay_ms(1);
+ if (mode == RGBWHEEL_SLOW) {
+ _delay_ms(9);
+ }
+ break;
+ case RGBFADE_FAST:
+ case RGBFADE_SLOW:
+ for (uint16_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.ColorHSV(rgbfade_hsv * 10));
+ }
+ rgbfade_hsv = (rgbfade_hsv + 10) % 6553;
+ np.show();
+ _delay_ms(1);
+ if (mode == RGBFADE_SLOW) {
+ _delay_ms(99);
+ }
+ break;
+ case COLD_WHITE:
+ for (uint16_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.Color(127, 127, 127));
+ }
+ np.show();
+ sleep();
+ break;
+ case BEEDOO:
+ for (uint16_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.Color(0, 0, (i+2 - beedoo_pos <= 2) * 255));
+ }
+ np.show();
+ beedoo_pos = (beedoo_pos + 1) % NUM_PIXELS;
+ _delay_ms(20);
+ break;
+ case STROBE:
+ for (uint16_t i = 0; i < NUM_PIXELS; i++) {
+ np.setPixelColor(i, np.Color(strobe_on, strobe_on, strobe_on));
+ }
+ np.show();
+ strobe_on = 127 - strobe_on;
+ _delay_ms(40);
+ break;
+ case COLOR_STROBE:
+ for (uint16_t i = 0; i < NUM_PIXELS; i++) {
+ if (strobe_on) {
+ np.setPixelColor(i, np.ColorHSV(rgbfade_hsv * 10));
+ } else {
+ np.setPixelColor(i, np.Color(0, 0, 0));
+ }
+ }
+ rgbfade_hsv = (rgbfade_hsv + 50) % 6553;
+ np.show();
+ strobe_on = 127 - strobe_on;
+ _delay_ms(40);
+ break;
+ }
+}
+
+Blinkencat blinkencat;
+
+int main(void)
+{
+ arch.setup();
+ gpio.setup();
+ kout.setup();
+
+ blinkencat.setup();
+
+ while (1) {
+ blinkencat.check_battery();
+ blinkencat.loop();
+ }
+
+ return 0;
+}
+
+
+ISR(WDT_vect)
+{
+ blinkencat.debounce_done();
+}
+
+
+ISR(PCINT2_vect)
+{
+ if (!gpio.read(GPIO::pd3)) {
+ blinkencat.next_mode();
+ }
+ blinkencat.debounce_start();
+}
diff --git a/src/arch/arduino-nano/arch.cc b/src/arch/arduino-nano/arch.cc
index 752b3f4..9103d10 100644
--- a/src/arch/arduino-nano/arch.cc
+++ b/src/arch/arduino-nano/arch.cc
@@ -1,10 +1,12 @@
#include "arch.h"
#include <avr/io.h>
#include <avr/interrupt.h>
+#include <avr/wdt.h>
#include <util/delay.h>
void Arch::setup(void)
{
+ wdt_disable();
#if F_CPU == 16000000UL
/* default */
diff --git a/src/arch/arduino-nano/driver/gpio.cc b/src/arch/arduino-nano/driver/gpio.cc
index 3b870b1..edfc2d0 100644
--- a/src/arch/arduino-nano/driver/gpio.cc
+++ b/src/arch/arduino-nano/driver/gpio.cc
@@ -13,7 +13,9 @@ ISR(PCINT1_vect)
{
}
+/*
ISR(PCINT2_vect)
{
}
+*/
#endif