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