]> oss.titaniummirror.com Git - rgblamp.git/blobdiff - tmr.c
Incorporate new tmr and isr code
[rgblamp.git] / tmr.c
diff --git a/tmr.c b/tmr.c
new file mode 100644 (file)
index 0000000..fec23f9
--- /dev/null
+++ b/tmr.c
@@ -0,0 +1,155 @@
+/*
+ * File:   tmr.c
+ *
+ * Generic timer module.  Currently uses Timer0 to generate ticks every
+ * 32 ms.  Later will use Timer1, a crystal, and optionally a compare
+ * module to be able to generate ticks and wake up from sleep.
+ */
+
+
+#include <htc.h>
+#include "tmr.h"
+#include "isr.h"
+#include "bit.h"
+
+persistent tmr_time_t _tmr_ticks;
+static tmr_time_t _tmr_t0[TMR_COUNT];
+static tmr_time_t _tmr_elapsed[TMR_COUNT];
+static tmr_bitno_t _tmr_on;
+static tmr_bitno_t _tmr_periodic;
+static tmr_bitno_t _tmr_fired;
+
+/* Timer0 with 1:256 prescale given Fosc (_XTAL_FREQ).
+ * Timer0 is clocked by Fosc/4.
+ *
+ * Fosc       Overflow, ms
+ * -------    ----------
+ *  32 MHz         8.192
+ *  16 MHz        16.384
+ *   8 MHz        32.768
+ *   4 MHz        65.536
+ *   2 MHz       131.072
+ *   1 MHz       262.144
+ * 500 KHz       524.288
+ * 250 KHz     1,048.576
+ * 125 KHz     2,097.152
+ */
+
+void tmr_init()
+{
+  /* Configure Timer0 to overflow every 32 msec.  Adjust with
+   * Fosc as set in picinit.[ch].  At 4 MHz, prescale is 1:128.
+   * TMR0CS = 0, PSA = 0, PS = 0b110
+  */
+  OPTION_REG = (OPTION_REG & 0b11010000) + 0b0110;
+  TMR0IF = 0;
+  TMR0IE = 1;
+  GIE = 1;
+}
+
+void tmr_start(tmr_bitno_t t, tmr_time_t elapsed)
+{
+  ndi();
+  bit_set(_tmr_on, t);
+  bit_clr(_tmr_periodic, t);
+  bit_clr(_tmr_fired, t);
+  _tmr_t0[t] = _tmr_ticks;
+  _tmr_elapsed[t] = elapsed;
+  nei();
+}
+
+void tmr_startAt(tmr_bitno_t t, tmr_time_t t0, tmr_time_t elapsed)
+{
+  ndi();
+  bit_set(_tmr_on, t);
+  bit_clr(_tmr_periodic, t);
+  bit_clr(_tmr_fired, t);
+  _tmr_t0[t] = t0 + elapsed;
+  nei();
+}
+
+void tmr_startPeriodic(tmr_bitno_t t, tmr_time_t elapsed)
+{
+  ndi();
+  bit_set(_tmr_on, t);
+  bit_set(_tmr_periodic, t);
+  bit_clr(_tmr_fired, t);
+  _tmr_t0[t] = _tmr_ticks + elapsed;
+  _tmr_elapsed[t] = elapsed;
+  nei();
+}
+
+void tmr_startPeriodicAt(tmr_bitno_t t, tmr_time_t t0, tmr_time_t elapsed)
+{
+  ndi();
+  bit_set(_tmr_on, t);
+  bit_set(_tmr_periodic, t);
+  bit_clr(_tmr_fired, t);
+  _tmr_t0[t] = t0 + elapsed;
+  _tmr_elapsed[t] = elapsed;
+  nei();
+}
+
+bit tmr_fired(tmr_bitno_t t)
+{
+  /* FIXME: if called from ISR ndi()/nei() is not required */
+  static unsigned char last_fired;
+  unsigned char fired;
+
+  ndi();
+  fired = bit_get(_tmr_fired, t) != 0;
+  if (fired)
+    bit_clr(_tmr_fired, t);
+  nei();
+  return fired;
+}
+
+void tmr_isr()
+{
+  if (TMR0IF) {
+    TMR0IF = 0;
+    _tmr_ticks++;
+    for (tmr_bitno_t t = 0; t < TMR_COUNT; t++) {
+      if (_tmr_ticks - _tmr_t0[t] <= 0) {
+        bit_set(_tmr_fired, t);
+        if (bit_get(_tmr_periodic, t))
+          _tmr_t0[t] += _tmr_elapsed[t];
+        else
+          bit_clr(_tmr_on, t);
+      }
+    }
+  }
+}
+
+/* Wait for a specific timer value t */
+#define tmr_wait(t) while (TMR0 != t);
+
+void tmr_uwait(unsigned us)
+{
+  unsigned t0 = TMR0;
+
+  while (us >= 32768) {
+    tmr_wait(t0);
+    us -= 32768;
+  }
+  while (us >= 16384) {
+    tmr_cwait(128);
+    us -= 16384;
+  }
+  tmr_cwait(us / 128);
+}
+
+void tmr_mwait(unsigned ms)
+{
+  unsigned t0 = TMR0;
+
+  while (ms >= 32) {
+    tmr_wait(t0);
+    ms -= 32;
+  }
+  while (ms >= 16) {
+    tmr_cwait(128);
+    ms -= 16;
+  }
+  tmr_cwait(ms * 8);
+}