]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
comments, overflow and increase mindt
authoridgay <idgay>
Mon, 26 Mar 2007 22:38:39 +0000 (22:38 +0000)
committeridgay <idgay>
Mon, 26 Mar 2007 22:38:39 +0000 (22:38 +0000)
still under test

tos/chips/atm128/timer/Atm128AlarmAsyncP.nc

index 29f90147f8dbda2676783b145113cf526c872fd6..dec6b0a0eeb3003953cfc8b29ab3be5baa7b5e26 100644 (file)
@@ -1,3 +1,23 @@
+// $Id$
+/*
+ * Copyright (c) 2005-2006 Intel Corporation
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached INTEL-LICENSE     
+ * file. If you do not find these files, copies can be found by writing to
+ * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
+ * 94704.  Attention:  Intel License Inquiry.
+ */
+/**
+ * Build a 32-bit alarm and counter from the atmega128's 8-bit timer 0
+ * in asynchronous mode. Attempting to use the generic Atm128AlarmC
+ * component and the generic timer components runs into problems
+ * apparently related to letting timer 0 overflow.
+ * 
+ * So, instead, this version (inspired by the 1.x code and a remark from
+ * Martin Turon) directly builds a 32-bit alarm and counter on top of timer 0
+ * and never lets timer 0 overflow.
+ */
 generic module Atm128AlarmAsyncP(typedef precision, int divider) {
   provides {
     interface Init;
@@ -12,39 +32,85 @@ generic module Atm128AlarmAsyncP(typedef precision, int divider) {
 }
 implementation
 {
-  uint8_t set;
-  uint32_t t0, dt;
-  uint32_t base;
+  uint8_t set;                         /* Is the alarm set? */
+  uint32_t t0, dt;             /* Time of the next alarm */
+  uint32_t base;               /* base+TCNT0 is the current time if no
+                                  interrupt is pending. See Counter.get()
+                                  for the full details. */
 
   enum {
-    MINDT = 2,
-    MAXT = 230
+    MINDT = 3,                 /* Minimum interval between interrupts */
+    MAXT = 230                 /* Maximum value to let timer 0 reach
+                                  (from Joe Polastre and Robert Szewczyk's
+                                  painful experiences with the 1.x timer ;-)) */
   };
 
+  void setInterrupt();
+
+  /* Configure timer 0 */
+  command error_t Init.init() {
+    atomic
+      {
+       Atm128TimerControl_t x;
+
+       call Compare.start();
+       x.flat = 0;
+       x.bits.cs = divider;
+       x.bits.wgm1 = 1; /* We use the clear-on-compare mode */
+       call TimerCtrl.setControl(x);
+       call Compare.set(MAXT);
+       setInterrupt();
+      }
+    return SUCCESS;
+  }
+
+  /* Set compare register for timer 0 to n. But increment n by 1 if TCNT0 
+     reaches this value before we can set the compare register.
+     Direct register access used because the HPL doesn't allow us to do this.
+  */
   void setOcr0(uint8_t n) {
     while (ASSR & 1 << OCR0UB)
       ;
     if (n == TCNT0)
       n++;
+    /* Support for overflow. Force interrupt at wrap around value. 
+       This does not cause a backwards-in-time value as we do this
+       every time we set OCR0. */
+    if (base + n + 1 < base)
+      n = -base - 1;
     OCR0 = n; 
   }
 
+  void fire() {
+    __nesc_enable_interrupt();
+    signal Alarm.fired();
+  }
+
+  /* Update the compare register to trigger an interrupt at the
+     appropriate time based on the current alarm settings
+   */
   void setInterrupt() {
     bool fired = FALSE;
 
     atomic
       {
+       /* interrupt_in is the time to the next interrupt. Note that
+          compare register values are off by 1 (i.e., if you set OCR0 to
+          3, the interrupt will happen whjen TCNT0 is 4) */
        uint8_t interrupt_in = 1 + call Compare.get() - call Timer.get();
        uint8_t newOcr0;
 
        if (interrupt_in < MINDT || (call TimerCtrl.getInterruptFlag()).bits.ocf0)
          return; // wait for next interrupt
+
+       /* When no alarm is set, we just ask for an interrupt every MAXT */
        if (!set)
          newOcr0 = MAXT;
        else
          {
            uint32_t now = call Counter.get();
 
+           /* Check if alarm expired */
            if ((uint32_t)(now - t0) >= dt)
              {
                set = FALSE;
@@ -53,6 +119,8 @@ implementation
              }
            else
              {
+               /* No. Set compare register to time of next alarm if it's
+                  within the next MAXT units */
                uint32_t alarm_in = (t0 + dt) - base;
 
                if (alarm_in > MAXT)
@@ -67,50 +135,58 @@ implementation
        setOcr0(newOcr0);
       }
     if (fired)
-      signal Alarm.fired();
+      fire();
+  }
+
+  void overflow() {
+    __nesc_enable_interrupt();
+    signal Counter.overflow();
   }
 
   async event void Compare.fired() {
-    base += call Compare.get() + 1;
+    /* Compare register fired. Update time knowledge */
+    base += call Compare.get() + 1; // interrupt is 1ms late
     setInterrupt();
+    if (!base)
+      overflow();
   }  
 
-  command error_t Init.init() {
-    atomic
-      {
-       Atm128TimerControl_t x;
-
-       call Compare.start();
-       x.flat = 0;
-       x.bits.cs = divider;
-       x.bits.wgm1 = 1;
-       call TimerCtrl.setControl(x);
-       call Compare.set(MAXT);
-       setInterrupt();
-      }
-    return SUCCESS;
-  }
-
   async command uint32_t Counter.get() {
     uint32_t now;
 
     atomic
       {
+       /* Current time is base+TCNT0 if no interrupt is pending. But if
+          an interrupt is pending, then it's base + compare value + 1 + TCNT0 */
        uint8_t now8 = call Timer.get();
 
        if ((call TimerCtrl.getInterruptFlag()).bits.ocf0)
-         now = base + call Counter.get() + call Timer.get();
+         /* We need to reread TCNT0 as it might've overflowed after we
+            read TCNT0 the first time */
+         now = base + call Counter.get() + 1 + call Timer.get();
        else
+         /* We need to use the value of TCNT0 from before we check the
+            interrupt flag, as it might wrap around after the check */
          now = base + now8;
       }
     return now;
   }
 
   async command bool Counter.isOverflowPending() {
-    return FALSE;
+    atomic
+      return (call TimerCtrl.getInterruptFlag()).bits.ocf0 &&
+       !(base + call Counter.get() + 1);
   }
 
-  async command void Counter.clearOverflow() { }
+  async command void Counter.clearOverflow() { 
+    atomic
+      if (call Counter.isOverflowPending())
+       {
+         base = 0;
+         call Compare.reset();
+         setInterrupt();
+       }
+  }
 
   async command void Alarm.start(uint32_t ndt) {
     call Alarm.startAt(call Counter.get(), ndt);