#include <avr/io.h>
#include <util/delay.h>
+#include <util/atomic.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include "lights.h"
+static unsigned char prev_jiffies_8;
+
static void hw_setup()
{
- wdt_enable(WDTO_1S);
-
init_battery();
init_pwm();
init_adc();
init_tmr();
init_buttons();
- pwmled_init();
- gpio_init();
- ambient_init();
- pattern_init();
+ init_pwmled();
+ init_gpio();
+ init_ambient();
+ init_pattern();
+ init_control();
set_sleep_mode(SLEEP_MODE_IDLE);
}
-static void hw_suspend()
+static void inline hw_suspend()
{
susp_pwm();
susp_adc();
susp_tmr();
susp_gpio();
+ susp_ambient();
susp_buttons();
-
- wdt_disable();
}
-void power_down()
+void power_down(unsigned char err)
{
hw_suspend();
do {
+ if (err)
+ gpio_set(0, 1);
+
// G'night
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
hw_setup();
}
-int main(void)
+static void inline first_boot()
{
- log_init();
+ unsigned char mcusr_save;
+
+ // disable the WDT if running
+ wdt_reset();
+ mcusr_save = MCUSR;
+ MCUSR = 0;
+ wdt_disable();
+
+ if (mcusr_save & _BV(WDRF)) // was watchdog reset?
+ gpio_set(0, 1);
+
+ init_log(mcusr_save);
power_usi_disable(); // Once for lifetime
ACSRA |= _BV(ACD); // disable analog comparator
log_set_state(3);
hw_setup();
- power_down();
+ power_down(mcusr_save & _BV(WDRF));
+
+ prev_jiffies_8 = jiffies;
sei();
-#if 1
- while (1) {
- wdt_reset();
- sleep_mode();
+}
+
+static void inline do_timer()
+{
+ // For now, we run them all in their own atomic blocks
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ timer_check_buttons();
}
-#endif
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ patterns_next_tick();
+ }
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ pwm_disable_if_not_needed();
+ }
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ timer_start_slow_adcs();
+ }
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ if ((jiffies & 0x1FF) == 0)
+ ambient_log_min_max();
+ }
+}
+
+static void inline main_loop_iteration()
+{
+ unsigned char jiffies_8; /*
+ * we use only lower 8-bits in order to
+ * avoid the need for locking of 16-bit
+ * accesses.
+ */
+
+ cli();
+ if (TIMER1_IS_ON()) {
+ set_sleep_mode(SLEEP_MODE_IDLE);
+ } else if (adc_is_on) {
+ 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();
+
+ jiffies_8 = jiffies;
+
+ if (jiffies_8 != prev_jiffies_8) { // was timer IRQ
+ if (jiffies_8 - prev_jiffies_8 > 1) { // overrun
+ log_byte(0xee);
+ log_byte(jiffies_8 - prev_jiffies_8);
+ log_flush();
+ }
+
+ prev_jiffies_8 = jiffies_8;
+
+ do_timer();
+ }
+}
+
+int main(void)
+{
+ first_boot();
+
+ while (1)
+ main_loop_iteration();
#if 0
DDRB |= _BV(PB2);