1 #include <avr/interrupt.h>
6 #include <util/delay.h>
11 static unsigned char steps[] = { 60, 85, 121, 171, 242 };
12 static unsigned char intensity = 0;
14 static void timer_init()
16 power_timer1_enable();
20 // TCCR1 = _BV(CS10); // clk/1 = 1 MHz
21 TCCR1 = _BV(CS11) | _BV(CS13); // clk/512 = 2 kHz
22 GTCCR = _BV(COM1B1) | _BV(PWM1B);
25 TIMSK = _BV(OCIE1B) | _BV(TOIE1);
28 volatile unsigned char adc_type, adc_drop;
44 static void set_pwm(unsigned char pwm)
49 static void adc_init()
53 ADCSRA = _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0) | _BV(ADIE); // clk/8 = 125 kHz
54 ADMUX = _BV(REFS1) | _BV(MUX1) | _BV(MUX0); // 1.1V ref., PB3 single-ended
58 volatile uint16_t batt_on, batt_off;
72 batt_off += adcw - (batt_off >> 5);
78 batt_on += adcw - (batt_on >> 5);
85 static void status_led_init()
91 static void status_led_on()
96 static void status_led_off()
101 static unsigned char status_led_is_on()
103 return PORTB & _BV(PB2) ? 1 : 0;
106 static void buttons_init()
108 DDRB &= ~(_BV(PB0) | _BV(PB1)); // set as input
109 PORTB |= _BV(PB0) | _BV(PB1); // internal pull-up
111 GIMSK &= ~_BV(PCIE); // disable pin-change IRQs
112 PCMSK = 0; // disable pin-change IRQs on all pins of port B
115 static void buttons_susp()
120 PCMSK |= _BV(PCINT0) | _BV(PCINT1);
123 static unsigned char buttons_pressed()
126 (PINB & _BV(PB0) ? 0 : 1)
128 (PINB & _BV(PB1) ? 0 : 2)
132 #define WAKEUP_POLL 100 // msec
133 #define WAKEUP_LIMIT 5 // times WAKEUP_POLL
135 static unsigned char buttons_wait_for_release()
137 uint16_t wake_count = 0;
140 if (++wake_count > WAKEUP_LIMIT)
141 status_led_on(); // inform the user
143 _delay_ms(WAKEUP_POLL);
144 } while (buttons_pressed());
148 return wake_count > WAKEUP_LIMIT;
153 // empty - let it wake us from sleep, but do nothing else
156 static void wdt_init()
158 WDTCR = _BV(WDIE) | _BV(WDP1); // interrupt mode, 64 ms
161 static void wdt_susp()
166 static void hw_setup()
176 static void hw_suspend()
178 ADCSRA &= ~_BV(ADEN); // disable ADC
179 TCCR1 = 0; // disable T/C 1
188 static volatile unsigned char wdt_timer_fired;
194 static void power_down()
200 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
210 // allow wakeup by long button-press only
211 } while (!buttons_wait_for_release());
217 static void button_one_pressed()
220 set_pwm(steps[--intensity]);
226 static void button_two_pressed()
228 if (intensity < N_STEPS-1) {
229 set_pwm(steps[++intensity]);
233 static unsigned char button_state, button_state_time;
235 static void timer_check_buttons()
237 unsigned char newstate = buttons_pressed();
239 if (newstate == button_state) {
240 if (newstate && button_state_time < 4)
246 button_state = newstate;
247 button_state_time = 0;
252 switch (button_state) {
253 case 1: button_one_pressed();
255 case 2: button_two_pressed();
257 default: // ignore when both are preseed
261 button_state = newstate;
264 static unsigned char blink_on_time, blink_off_time, n_blinks;
265 static unsigned char blink_counter;
267 static void timer_blink()
271 } else if (status_led_is_on()) {
273 blink_counter = blink_off_time;
274 } else if (n_blinks) {
277 blink_counter = blink_on_time;
279 n_blinks = intensity + 1;
285 log_byte(batt_on >> 7);
286 log_byte(batt_off >> 7);
299 // we try to be completely IRQ-driven, so just wait for IRQs here
302 set_sleep_mode(SLEEP_MODE_IDLE);
304 // keep BOD active, no sleep_bod_disable();
309 if (wdt_timer_fired) {
311 timer_check_buttons();