src/timer.c
author Tero Marttila <terom@paivola.fi>
Thu, 03 Apr 2014 19:44:53 +0300
changeset 52 237d1f5c1c32
child 53 dfe67409fbcd
permissions -rw-r--r--
hello: split out timer; add serial
#include <avr/interrupt.h>

#define TIMER_FLAGS     GPIOR0
#define TIMER1_BUSY     1

/*
 * Setup timers.
 */
void timer_init (void)
{
    TCCR1A = (
            // OC1A output pin disconnected
            0b00 << COM1A0
            // OC1B output pin disconnected
        |   0b00 << COM1B0
            // no PWM
        |   0b00 << WGM10
    );
    TCCR1B = (
            // CTC mode
            0b01 << WGM12 
    );
    TCCR1C = 0;
}

void timer1_start (short cycles)
{
    // count up from zero...
    TCNT1 = 0;

    // ...to the given number of timer cycles
    OCR1A = cycles;

    // start!
    sbi(&TIMER_FLAGS, TIMER1_BUSY);
    TIMSK1 = (
            // OCA interrupt
            0b1 << OCIE1A       // enable
    );
    TCCR1B = (
            // WGM
            0b01  << WGM12      // CTC

            // clocksource
        |   0b101 << CS10       // 1024'th
    );
}

static void timer1_stop ()
{
    // WGM: normal
    // clocksource: stop
    TCCR1B = 0;

    cbi(&TIMER_FLAGS, TIMER1_BUSY);
}

ISR(TIMER1_COMPA_vect)
{
    timer1_stop();

    // XXX: cpu will automatically wake up from sleep()
}

/*
 * Sleep on timer1 interrupt.
 */
void timer_sleep (int cycles)
{
    // set timer
    timer1_start(cycles);

    // sleep
    // TODO: PRR
    SMCR = (
            // idle sleep
            (0b00 << SM0)

            // enable sleep
        |   (0b1 << SE)
    );
    
    // sleep
    while (tbi(&TIMER_FLAGS, TIMER1_BUSY)) {
        __asm__ ( "sleep" :: );
    }

    // cleanup
    SMCR = 0;
}