diff --git a/Source/TODO b/Source/TODO new file mode 100644 index 0000000..632776c --- /dev/null +++ b/Source/TODO @@ -0,0 +1,13 @@ +- After turning off, turning on doesn't really respond well to the option button +- Store value in EEPROM (after a timeout) +- Long press shows menu with reset option (menu prevents accidental resets) + + + + + +Pin-out reminder: + +SW2 = - = pin 2, PB3 +SW3 = menu = pin 3, PB4 +SW1 = + = pin 6, PB1 \ No newline at end of file diff --git a/Source/src/buttons.c b/Source/src/buttons.c index 3f6637a..a221ce0 100644 --- a/Source/src/buttons.c +++ b/Source/src/buttons.c @@ -37,7 +37,6 @@ void buttons_init() // Enable timer interrupt TIMSK = _BV(OCIE0A); - sei(); } diff --git a/Source/src/main.c b/Source/src/main.c index 4f3f9ec..5bba500 100644 --- a/Source/src/main.c +++ b/Source/src/main.c @@ -17,6 +17,7 @@ int main() // Delay is required on power-on for the SSD1306 to initialize, _delay_ms(40); ssd1306_init(); + ssd1306_clear(); buttons_init(); @@ -28,6 +29,7 @@ int main() if (powerState == On) { handleCurrentScreen(); + sleepUntilButton(_BV(BUTTON_UP) | _BV(BUTTON_DOWN) | _BV(BUTTON_OPTION)); } } } diff --git a/Source/src/power.c b/Source/src/power.c index 1ef0a8f..fe62ef2 100644 --- a/Source/src/power.c +++ b/Source/src/power.c @@ -1,10 +1,19 @@ #include "power.h" #include #include +#include +#include #include #include +// I'm not really keen on referencing the buttons directly from here, +// feels like a coding red flag. It'll do for now until I come up with +// a better design. Or forget about it most likely. +#include "buttons.h" + + + #define VccOffTreshold 3000 #define VccOnTreshold 3100 @@ -12,6 +21,7 @@ #define SSD1306CommandOff 0xAE #define SSD1306CommandOn 0xAF +#define SleepInterval8s (_BV(WDP3) | _BV(WDP0)) PowerState powerState = BatteryLow; @@ -41,9 +51,7 @@ void checkPower() if (vcc < VccOffTreshold) { setPowerState(BatteryLow); - - // TODO go into a sleep cycle until the battery is recharged - _delay_ms(10); + sleepUntilTimer(SleepInterval8s); } break; @@ -52,16 +60,12 @@ void checkPower() if (vcc > VccOnTreshold) setPowerState(On); else - { - // TODO continue sleep cycle - _delay_ms(10); - } + sleepUntilTimer(SleepInterval8s); break; case ManualOff: - // TODO go into sleep mode - _delay_ms(10); + sleepUntilButton(_BV(BUTTON_OPTION)); break; } } @@ -75,6 +79,7 @@ void setPowerState(PowerState newState) { case On: ssd1306_send_command(SSD1306CommandOn); + //buttons_init(); TODO this doesn't help, fix it! break; case BatteryLow: @@ -144,4 +149,75 @@ uint16_t readVCC() { ADCSRA &= ~(_BV(ADEN)); return result == 0 ? 0 : 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 +} + + +inline void sleepStart() +{ + // Turn ADC off + ADCSRA &= ~_BV(ADEN); + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + + // Set sleep bit and halt the CPU + sleep_enable(); + sei(); + sleep_cpu(); + + // ...goooood morning! + cli(); +} + + +inline void sleepEnd() +{ + sleep_disable(); + ADCSRA |= _BV(ADEN); + + sei(); +} + + +void sleepUntilButton(uint8_t pinMask) +{ + // Enable pin change interrupts + GIMSK |= _BV(PCIE); + + // Set up pin change mask + PCMSK = pinMask; + + sleepStart(); + PCMSK = 0; + sleepEnd(); +} + + +void sleepUntilTimer(uint8_t prescaler) +{ + // Disable watchdog reset flag + MCUSR &= ~_BV(WDRF); + + // Enable watchdog + WDTCR |= _BV(WDCE) | _BV(WDE); + + // Set timeout value and enable interrupt mode + WDTCR = prescaler | _BV(WDIE); + + sleepStart(); + + // Disable watchdog (need to write a logic one first, see datasheet) + WDTCR |= _BV(WDCE) | _BV(WDE); + WDTCR = 0; + + sleepEnd(); +} + + +// Interrupt for pin changes +ISR(PCINT0_vect) +{ +} + +// Interrupt for watchdog timer +ISR(WDT_vect) +{ } \ No newline at end of file diff --git a/Source/src/power.h b/Source/src/power.h index 4fa9815..4ce151f 100644 --- a/Source/src/power.h +++ b/Source/src/power.h @@ -13,6 +13,21 @@ extern uint16_t vcc; extern void checkPower(); extern void setPowerState(PowerState newState); +extern void sleepUntilButton(uint8_t pinMask); + +// 0 = 16 ms +// 1 = 32 ms +// 2 = 64 ms +// 3 = 128 ms +// 4 = 250 ms +// 5 = 500 ms +// 6 = 1 sec +// 7 = 2 sec +// 8 = 4 sec +// 9 = 8 sec +extern void sleepUntilTimer(uint8_t interval); + + extern uint8_t getScreenInvalidated(); extern void setScreenInvalidated();