import timer with header from qmsk-dmx
authorTero Marttila <terom@paivola.fi>
Wed, 24 Sep 2014 22:30:30 +0300
changeset 1 04b8d469ae4c
parent 0 893a25a6c372
child 2 3420bd6d2d10
import timer with header from qmsk-dmx
include/timer.h
src/timer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/timer.h	Wed Sep 24 22:30:30 2014 +0300
@@ -0,0 +1,21 @@
+#ifndef QMSK_ARDUINO_TIMER_H
+#define QMSK_ARDUINO_TIMER_H
+
+#define TIMER_FLAGS     GPIOR0
+#define TIMER1_BUSY     1
+
+/*
+ * Setup timers.
+ */
+void timer_init (void);
+
+/*
+ * Sleep on timer1 interrupt.
+ *
+ * Starts fresh timer that sleeps given cycles if given, or continues on the running timer.
+ *
+ * Returns 1 on timeout, 0 on other interrupt.
+ */
+byte timer_sleep (unsigned cycles);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/timer.c	Wed Sep 24 22:30:30 2014 +0300
@@ -0,0 +1,122 @@
+#include <avr/interrupt.h>
+
+#include "stdlib.h"
+#include "timer.h"
+
+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;
+}
+
+static void timer1_set ()
+{
+    sbi(&TIMER_FLAGS, TIMER1_BUSY);
+}
+
+static void timer1_start (short cycles)
+{
+    // count up from zero...
+    TCNT1 = 0;
+
+    // ...to the given number of timer cycles
+    OCR1A = cycles;
+
+    // start!
+    timer1_set();
+    TIMSK1 = (
+            // OCA interrupt
+            0b1 << OCIE1A       // enable
+    );
+    TCCR1B = (
+            // WGM
+            0b01  << WGM12      // CTC
+
+            // clocksource
+        |   0b101 << CS10       // 1024'th
+    );
+}
+
+/*
+ * Keep the timer running, but clear the flag..
+ */
+static void timer1_clear ()
+{
+    cbi(&TIMER_FLAGS, TIMER1_BUSY);
+}
+
+/*
+ * Stop the timer at its current value.
+ */
+static void timer1_stop ()
+{
+    // WGM: normal
+    // clocksource: stop
+    TCCR1B = 0;
+
+    timer1_clear();
+}
+
+ISR(TIMER1_COMPA_vect)
+{
+    timer1_clear();
+
+    // cpu will wake up from sleep()
+}
+
+/*
+ * Sleep on timer1 interrupt.
+ *
+ * Starts fresh timer that sleeps given cycles if given, or continues on the running timer.
+ *
+ * Returns 1 on timeout, 0 on other interrupt.
+ */
+byte timer_sleep (unsigned cycles)
+{
+    if (cycles) {
+        // set fresh timer
+        timer1_start(cycles);
+    } else {
+        // wait for next cycle...
+        timer1_set();
+    }
+
+    // sleep while timer is running
+    // XXX: atomic?
+    if (tbi(&TIMER_FLAGS, TIMER1_BUSY)) {
+        // TODO: PRR
+        SMCR = (
+                // idle sleep
+                (0b00 << SM0)
+
+                // enable sleep
+            |   (0b1 << SE)
+        );
+
+        // sleep
+        __asm__ ( "sleep" :: );
+
+        // cleanup
+        SMCR = 0;
+    }
+
+    if (tbi(&TIMER_FLAGS, TIMER1_BUSY)) {
+        // interrupt
+        return 0;
+
+    } else {
+        // timeout
+        return 1;
+    }
+}