terom@52: #include terom@52: terom@52: #define TIMER_FLAGS GPIOR0 terom@52: #define TIMER1_BUSY 1 terom@52: terom@52: /* terom@52: * Setup timers. terom@52: */ terom@52: void timer_init (void) terom@52: { terom@52: TCCR1A = ( terom@52: // OC1A output pin disconnected terom@52: 0b00 << COM1A0 terom@52: // OC1B output pin disconnected terom@52: | 0b00 << COM1B0 terom@52: // no PWM terom@52: | 0b00 << WGM10 terom@52: ); terom@52: TCCR1B = ( terom@52: // CTC mode terom@78: 0b01 << WGM12 terom@52: ); terom@52: TCCR1C = 0; terom@52: } terom@52: terom@78: static void timer1_set () terom@78: { terom@78: sbi(&TIMER_FLAGS, TIMER1_BUSY); terom@78: } terom@78: terom@52: void timer1_start (short cycles) terom@52: { terom@52: // count up from zero... terom@52: TCNT1 = 0; terom@52: terom@52: // ...to the given number of timer cycles terom@52: OCR1A = cycles; terom@52: terom@52: // start! terom@78: timer1_set(); terom@52: TIMSK1 = ( terom@52: // OCA interrupt terom@52: 0b1 << OCIE1A // enable terom@52: ); terom@52: TCCR1B = ( terom@52: // WGM terom@52: 0b01 << WGM12 // CTC terom@52: terom@52: // clocksource terom@52: | 0b101 << CS10 // 1024'th terom@52: ); terom@52: } terom@52: terom@78: /* terom@78: * Keep the timer running, but clear the flag.. terom@78: */ terom@78: static void timer1_clear () terom@78: { terom@78: cbi(&TIMER_FLAGS, TIMER1_BUSY); terom@78: } terom@78: terom@78: /* terom@78: * Stop the timer at its current value. terom@78: */ terom@52: static void timer1_stop () terom@52: { terom@52: // WGM: normal terom@52: // clocksource: stop terom@52: TCCR1B = 0; terom@52: terom@78: timer1_clear(); terom@52: } terom@52: terom@52: ISR(TIMER1_COMPA_vect) terom@52: { terom@78: timer1_clear(); terom@52: terom@78: // cpu will wake up from sleep() terom@52: } terom@52: terom@52: /* terom@52: * Sleep on timer1 interrupt. terom@53: * terom@78: * Starts fresh timer that sleeps given cycles if given, or continues on the running timer. terom@78: * terom@78: * Returns 1 on timeout, 0 on other interrupt. terom@52: */ terom@63: char timer_sleep (unsigned cycles) terom@52: { terom@54: if (cycles) { terom@78: // set fresh timer terom@54: timer1_start(cycles); terom@78: } else { terom@78: // wait for next cycle... terom@78: timer1_set(); terom@54: } terom@52: terom@78: // sleep while timer is running terom@78: // XXX: atomic? terom@78: if (tbi(&TIMER_FLAGS, TIMER1_BUSY)) { terom@78: // TODO: PRR terom@78: SMCR = ( terom@78: // idle sleep terom@78: (0b00 << SM0) terom@52: terom@78: // enable sleep terom@78: | (0b1 << SE) terom@78: ); terom@52: terom@78: // sleep terom@78: __asm__ ( "sleep" :: ); terom@78: terom@78: // cleanup terom@78: SMCR = 0; terom@78: } terom@78: terom@78: if (tbi(&TIMER_FLAGS, TIMER1_BUSY)) { terom@78: // interrupt terom@78: return 0; terom@78: terom@78: } else { terom@54: // timeout terom@54: return 1; terom@53: } terom@52: } terom@52: terom@52: