]> oss.titaniummirror.com Git - rgblamp.git/commitdiff
Incorporate new tmr and isr code
authorR. Steve McKown <rsmckown@gmail.com>
Thu, 8 Dec 2011 21:34:04 +0000 (14:34 -0700)
committerR. Steve McKown <rsmckown@gmail.com>
Thu, 8 Dec 2011 21:34:04 +0000 (14:34 -0700)
13 files changed:
bit.h [new file with mode: 0644]
isr.c [new file with mode: 0644]
isr.h [new file with mode: 0644]
main.c
picinit.c
picinit.h
rgb.c
rgb.h
timer.c [deleted file]
timer.h [deleted file]
tmr.c [new file with mode: 0644]
tmr.h [new file with mode: 0644]
tmr_defs.h [new file with mode: 0644]

diff --git a/bit.h b/bit.h
new file mode 100644 (file)
index 0000000..fa3c03d
--- /dev/null
+++ b/bit.h
@@ -0,0 +1,20 @@
+/*
+ * File:   bits.h
+ *
+ * Bit handling macros
+ */
+
+
+#ifndef _BIT_H
+#define _BIT_H
+
+/* bit_set() and bit_clr() are converted to single assembly instructions.
+ * Not sure yet about bit_get and bit_toggle.
+ */
+
+#define bit_get(var, bitno) ((var) & (1UL << (bitno)))
+#define bit_set(var, bitno) ((var) |= 1UL << (bitno))
+#define bit_clr(var, bitno) ((var) &= ~(1UL << (bitno)))
+#define bit_toggle(var, bitno) ((var) ^= (1UL << (bitno))
+
+#endif
diff --git a/isr.c b/isr.c
new file mode 100644 (file)
index 0000000..f466c55
--- /dev/null
+++ b/isr.c
@@ -0,0 +1,17 @@
+/*
+ * File:   isr.c
+ *
+ * Interrupt handling routines
+ */
+
+
+#include <htc.h>
+#include "tmr.h"
+
+bit isr_gie; /* Used to store the state of GIE for nested ndi()/nei() */
+unsigned char isr_di; /* Count of nested ndi() */
+
+void interrupt isr()
+{
+  tmr_isr();
+}
diff --git a/isr.h b/isr.h
new file mode 100644 (file)
index 0000000..7b1ede0
--- /dev/null
+++ b/isr.h
@@ -0,0 +1,36 @@
+/*
+ * File:   isr.h
+ *
+ * Interrupt handling routines
+ */
+
+#ifndef _ISR_H
+#define _ISR_H
+
+#include <htc.h>
+
+extern bit isr_gie;
+extern unsigned char isr_di;
+
+/* Nested disable interrupts inline function, for use outside ISR */
+#define ndi() \
+  do { \
+    if (isr_di++ == 0) \
+      isr_gie = GIE; \
+      if (isr_gie) \
+        di(); \
+  } while (0)
+
+/* Nested enable interrupts inline function, for use outside ISR */
+#define nei() \
+  do { \
+    if (--isr_di == 0) \
+      if (isr_gie) { \
+       isr_gie = 0; \
+        ei(); \
+      } \
+  } while (0)
+
+void interrupt isr();
+
+#endif
diff --git a/main.c b/main.c
index fbf88d349a10c7e8b9e04c295c1a16f7abfa17c4..65cff5565ab684b1d875cdc5e0667a5c10dab461 100644 (file)
--- a/main.c
+++ b/main.c
 #include "unused.h"
 #include "buttons.h"
 #include "rgb.h"
-#include "timer.h"
+#include "tmr.h"
 #include "adc_random.h"
 
-#define AUTO_OFF_COUNT          549316UL /* 5 hrs in 32.768 ms units */
+#if 0
+#define AUTO_OFF_COUNT          549316UL  /*  5 hrs in 32.768 ms units */
+#define AUTO_ON_COUNT           2087402UL /* 19 hrs in 32.768 ms units */
+#else
+#define AUTO_OFF_COUNT          1831 /* 1 minute in 32.768 ms units */
+#define AUTO_ON_COUNT           3662 /* 2 minutes in 32.768 ms units */
+#endif
 #define reset_steps()           do { incolor_steps = 1; fade_steps = 0; } \
                                     while (0)
 #define rand_u8()               (rand() & 0xff)
@@ -52,8 +58,9 @@
                                     RA2 = 0; \
                                     TRISA2 = 0; \
                                 } while (0)
-#define dbgpin_high() RA2 = 1;
-#define dbgpin_low()  RA2 = 0;
+#define dbgpin_high() (RA2 = 1)
+#define dbgpin_low()  (RA2 = 0)
+#define dbgpin_toggle()  (RA2 = (LATA2 == 0) ? 1 : 0)
 
 typedef struct {
   int value;
@@ -90,7 +97,7 @@ int main(void)
     unused_init();
     buttons_init();
     rgb_init();
-    timer_init();
+    tmr_init();
     dbgpin_init();
 
     srand((adc_random() << 8) + adc_random());
@@ -99,13 +106,14 @@ int main(void)
       rgb_on();
 
     dbgpin_high();
+    tmr_startPeriodic(TMR_FADE, 1);  /* 32.768 msec */
     while (1) {
         unsigned char buttons = buttons_read();
 
         if ((buttons & IN_ROCKERB) && auto_off == 0)
-            auto_off = AUTO_OFF_COUNT;
+            tmr_startPeriodic(TMR_AUTO_OFFON, AUTO_OFF_COUNT);
 
-        if (((buttons & IN_ROCKERB) && auto_off && --auto_off == 0) ||
+        if ((buttons & IN_ROCKERB) && tmr_fired(TMR_AUTO_OFFON) ||
             (!(buttons & (IN_ROCKERA | IN_ROCKERB)))) {
             /* Sleep when auto-off time has expired or if rocker switch is
              * turned off.
@@ -174,7 +182,7 @@ int main(void)
               wht.remainder = neww - (wht.value + wht.increment * fade_steps);
             }
             dbgpin_low();
-            timer_owait(); /* wait 32 ms since last return from last call() */
+            while (!tmr_fired(TMR_FADE));
             dbgpin_high();
         }
     }
index 882aaaa7778158e75fe7766839d14187d6561ecd..4274e2a43e9dc752554cc7e97479000f850fef8f 100644 (file)
--- a/picinit.c
+++ b/picinit.c
@@ -13,7 +13,7 @@ __CONFIG(LVP_OFF);
 void pic_init()
 {
     /* Setting below must match _XTAL_FREQ in picinit.h */
-    OSCCON = 0b01100000;
+    OSCCON = 0b01101000;
 
     /* OSCSTAT.HFIOFL is set when oscillator is locked (accurate within 2%) */
     while (!HFIOFL);
index 19250034c2b15548b997982ef70b5d963cc6b325..e2a50cfde7b851f3ddfaed2cd177837aa24da19d 100644 (file)
--- a/picinit.h
+++ b/picinit.h
@@ -7,7 +7,7 @@
 #ifndef _PICINIT_H
 #define _PICINIT_H
 
-#define _XTAL_FREQ 2000000
+#define _XTAL_FREQ 4000000
 
 void pic_init();
 
diff --git a/rgb.c b/rgb.c
index 13c36daaf40103eb222e26226f8dc13579367484..85254429a5f4871bfedcde1b55a1e3dec5bae9f3 100644 (file)
--- a/rgb.c
+++ b/rgb.c
@@ -14,9 +14,9 @@ void rgb_init()
     /* Initialize rgb
      * CCP1 on RB3, CCP2 on RA7, CCP3 on RA3, CCP4 on RA4
      * - Fosc =     8 MHz,    4 MHz,    2 MHz
-     * - Prescale = 4,        4,        1
+     * - Prescale = 4,        1,        1
      * - PRx value = 0xff
-     * = f(rgb) =   1.95 kHz, 0.98 kHz, 1.95 kHz
+     * = f(rgb) =   1.95 kHz, 3.90 kHz, 1.95 kHz
      */
 
     /* Set rgb Rxn pins as outputs. */
diff --git a/rgb.h b/rgb.h
index 663e1890f89f8d9a6f97c4ee1b0b784c60254b47..d24b41bf34cd3a389cb62b6865551911009608d5 100644 (file)
--- a/rgb.h
+++ b/rgb.h
@@ -8,6 +8,8 @@
 #ifndef _RGB_H
 #define _RGB_H
 
+#include "isr.h"
+
 /* Initialize the RGB LED assembly.  Outputs are zero, PWM is off. */
 void rgb_init();
 
@@ -19,10 +21,12 @@ void rgb_off();
 
 /* Set a PWM value for each color LED.  0=off, 255=full on. */
 #define rgb_set(red, grn, blu, wht) do { \
+    ndi(); /* FIXME: doesn't seem to fix flicker */ \
     CCPR1L = (red); \
     CCPR2L = (grn); \
     CCPR3L = (blu); \
     CCPR4L = (wht); \
+    nei(); \
 } while (0)
 
 #endif
diff --git a/timer.c b/timer.c
deleted file mode 100644 (file)
index 0975cb8..0000000
--- a/timer.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * File:   timer.c
- *
- * Timer 0 + Timer 1 for timekeeping
- */
-
-
-#include <htc.h>
-#include "timer.h"
-
-void timer_uwait(unsigned us)
-{
-  unsigned t0 = TMR0;
-
-  TMR0IF = 0;
-  while (us >= 32768) {
-    timer_owait();
-    us -= 32768;
-  }
-  while (us >= 16384) {
-    timer_cwait(128);
-    us -= 16384;
-  }
-  timer_cwait(us / 128);
-}
-
-void timer_mwait(unsigned ms)
-{
-  unsigned t0 = TMR0;
-
-  TMR0IF = 0;
-  while (ms >= 32) {
-    timer_owait();
-    ms -= 32;
-  }
-  while (ms >= 16) {
-    timer_cwait(128);
-    ms -= 16;
-  }
-  timer_cwait(ms * 8);
-}
diff --git a/timer.h b/timer.h
deleted file mode 100644 (file)
index 20e0c8b..0000000
--- a/timer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * File:   timer.h
- *
- * Timer 0 + Timer 1 for timekeeping
- */
-
-
-#ifndef _TIMER_H
-#define _TIMER_H
-
-/* Timer 0 with 1:256 prescale given Fosc (_XTAL_FREQ).
- * Timer 0 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
- */
-
-/* Configure Timer0 to overflow every 32 msec.  Adjust with
- * Fosc as set in picinit.[ch].  At 2 MHz, prescale is 1:64.
- */
-#define timer_init() \
-  do { \
-    /* TMR0CS = 0, PSA = 0, PS = 0b101 */ \
-    OPTION_REG = (OPTION_REG & 0b11010000) + 0b0101; \
-  } while (0)
-
-/* Wait for the timer to overflow.  This is 32 msec from the last overflow. */
-#define timer_owait() \
-  { \
-    while (!TMR0IF); \
-    TMR0IF = 0; \
-  } while (0)
-
-/* Wait for c clocks, 0 <= c < 128. */
-#define timer_cwait(c) \
-  { \
-    unsigned t0 = TMR0; \
-    while ((unsigned)(TMR0 - t0) <= c); /* cast prevents integral promotion */ \
-  } while (0)
-
-void timer_uwait(unsigned us);
-void timer_mwait(unsigned ms);
-
-#endif
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);
+}
diff --git a/tmr.h b/tmr.h
new file mode 100644 (file)
index 0000000..716ff65
--- /dev/null
+++ b/tmr.h
@@ -0,0 +1,105 @@
+/*
+ * File:   tmr.h
+ *
+ * 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.
+ *
+ * The user code must call tmr_isr() from the interrupt function.  It then
+ * will call tmr functions to activate and query timers.  For example:
+ *
+ * void interrupt isr()
+ * {
+ *   tmr_isr();
+ *
+ *   // ISR may take actions based on timers being fired.
+ *   if (tmr_fired(TMR_SOMESUCH)) {
+ *     // do something that is critically time important
+ *   }
+ * }
+ *
+ * void main()
+ * {
+ *   tmr_init();
+ *   tmr_startPeriodic(TMR_SOMESUCH, 1000);
+ *   tmr_startPeriodic(TMR_ANOTHER, 500);
+ *
+ *   while (1) {
+ *     if (tmr_fired(TMR_ANOTHER)) {
+ *      // Do stuff that doesn't have to be in the ISR
+ *     }
+ *     SLEEP();
+ *   }
+ * }
+ */
+
+
+#ifndef _TMR_H
+#define _TMR_H
+
+#include "tmr_defs.h"
+#include "isr.h"
+#include "bit.h"
+
+/* Only access when in ISR or if interrupts are disabled */
+extern persistent tmr_time_t _tmr_ticks;
+
+/* Initialize the tmr subsystem */
+void tmr_init();
+
+/* Return non-zero if the timer is on */
+/* FIXME: this may not be atomic WRT ISR */
+#define tmr_on(t) (bit_get(_tmr_on, (t)))
+
+/* Return non-zero if the timer is periodic */
+/* FIXME: this may not be atomic WRT ISR */
+#define tmr_periodic(t) (bit_get(_tmr_periodic, (t)))
+
+/* Start a timer, expecting it to fire in elapsed ticks */
+void tmr_start(tmr_bitno_t t, tmr_time_t elapsed);
+
+/* Start a timer, expecting it to fire in elapsed ticks from t0 */
+void tmr_startAt(tmr_bitno_t t, tmr_time_t t0, tmr_time_t elapsed);
+
+/* Start a periodic timer, expecting it to fire every elapsed ticks */
+void tmr_startPeriodic(tmr_bitno_t t, tmr_time_t elapsed);
+
+/* Start a periodic timer, expecting it to fire every elapsed ticks */
+void tmr_startPeriodicAt(tmr_bitno_t t, tmr_time_t t0, tmr_time_t elapsed);
+
+/* Stop a timer */
+#define tmr_stop(t) \
+  do { \
+    ndi(); \
+    bit_clr(_tmr_on, (t)); \
+    nei(); \
+  } while(0)
+
+/* Return 1 if the timer has fired, resetting the fired bit */
+bit tmr_fired(tmr_bitno_t t);
+
+/* Return the current number of timer ticks, for use outside ISR */
+#define tmr_time(ptr_time) \
+  do { \
+    ndi(); \
+    *(ptr_time) = _tmr_ticks; \
+    nei(); \
+  } while (0)
+
+/* Used in the ISR to update timer */
+void tmr_isr();
+
+/* Wait for c clocks, 0 <= c < 128. */
+#define tmr_cwait(c) \
+  do { \
+    unsigned t0 = TMR0; \
+    while ((unsigned)(TMR0 - t0) <= c); /* cast prevents integral promotion */ \
+  } while (0)
+
+/* Wait for a number of us.  This is pretty accurate. */
+void tmr_uwait(unsigned us);
+
+/* Wait for a number of ms.  Each 32 ms actually waits about 32,768 us */
+void tmr_mwait(unsigned ms);
+
+#endif
diff --git a/tmr_defs.h b/tmr_defs.h
new file mode 100644 (file)
index 0000000..34ffda5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * File:   tmr_defs.h
+ *
+ * User defines this file to create the timers it wishes.  This is a
+ * generic template.
+ */
+
+
+#ifndef _TMR_DEFS_H
+#define _TMR_DEFS_H
+
+/* Define the timers to use.  Last enum, TIMER_COUNT, is used by the
+ * tmr module to know the number of timers and allocate resources
+ * accordingly.
+ */
+enum {
+  TMR_AUTO_ONOFF = 0,
+  TMR_FADE,
+  TMR_DIM,
+  TMR_BTN,
+  TMR_ROCKER,
+
+  TMR_COUNT
+};
+
+/* The tmr module can support unsigned and unsigned long tmr_time_t.
+ * tmr_time_t is the timer value, which is incremented by one for
+ * each tick using Timer0.  When transitioned to Timer1, it will be
+ * the value of TMR1, likely extended to a larger width in software.
+ */
+typedef unsigned long tmr_time_t;
+
+/* The tmr module can support unsigned char, unsigned, and unsigned long
+ * tmr_bit_t.  The number of bits in tmr_bit_t must be >= TIMER_COUNT, as
+ * this type allocates a bit to each virtual timer.
+ */
+typedef unsigned char tmr_bitno_t;
+
+#endif