]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/platforms/mica/MeasureClockC.nc
Merge devel code into the trunk.
[tinyos-2.x.git] / tos / platforms / mica / MeasureClockC.nc
diff --git a/tos/platforms/mica/MeasureClockC.nc b/tos/platforms/mica/MeasureClockC.nc
new file mode 100644 (file)
index 0000000..898d801
--- /dev/null
@@ -0,0 +1,124 @@
+// $Id$
+/*
+ * Copyright (c) 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.
+ */
+#include <MicaTimer.h>
+#include <scale.h>
+
+/**
+ * Measure cpu clock frequency at boot time. Provides an Atm128Calibrate
+ * interface so that other components can adjust their calibration as
+ * needed.
+ *
+ * @author David Gay
+ */
+
+module MeasureClockC {
+  provides {
+    /**
+     * This code MUST be called from PlatformP only, hence the exactlyonce.
+     */
+    interface Init @exactlyonce();
+    interface Atm128Calibrate;
+  }
+}
+implementation 
+{
+  enum {
+    /* This is expected number of cycles per jiffy at the platform's
+       specified MHz. Assumes PLATFORM_MHZ == 1, 2, 4, 8 or 16. */
+    MAGIC = 488 / (16 / PLATFORM_MHZ)
+  };
+
+  uint16_t cycles;
+
+  command error_t Init.init() {
+    /* Measure clock cycles per Jiffy (1/32768s) */
+    /* This code doesn't use the HPL to avoid timing issues when compiling
+       with debugging on */
+    atomic
+      {
+       uint8_t now, wraps;
+       uint16_t start;
+
+       /* Setup timer0 to count 32 jiffies, and timer1 cpu cycles */
+       TCCR1B = 1 << CS10;
+       ASSR = 1 << AS0;
+       TCCR0 = 1 << CS01 | 1 << CS00;
+
+       /* Wait for 1s for counter to stablilize after power-up (yes, it
+          really does take that long). That's 122 wrap arounds of timer 1
+          at 8MHz. */
+       start = TCNT1;
+       for (wraps = MAGIC / 2; wraps; )
+         {
+           uint16_t next = TCNT1;
+
+           if (next < start)
+             wraps--;
+           start = next;
+         }
+
+       /* Wait for a TCNT0 change */
+       now = TCNT0;
+       while (TCNT0 == now) ;
+
+       /* Read cpu cycles and wait for next TCNT0 change */
+       start = TCNT1;
+       now = TCNT0;
+       while (TCNT0 == now) ;
+       cycles = TCNT1;
+
+       cycles = (cycles - start + 16) >> 5;
+
+       /* Reset to boot state */
+       ASSR = TCCR1B = TCCR0 = 0;
+       TCNT0 = 0;
+       TCNT1 = 0;
+       ETIFR = TIFR = 0xff;
+       while (ASSR & (1 << TCN0UB | 1 << OCR0UB | 1 << TCR0UB))
+         ;
+      }
+    return SUCCESS;
+  }
+
+  async command uint16_t Atm128Calibrate.cyclesPerJiffy() {
+    return cycles;
+  }
+
+  async command uint32_t Atm128Calibrate.calibrateMicro(uint32_t n) {
+    return scale32(n + MAGIC / 2, cycles, MAGIC);
+  }
+
+  async command uint32_t Atm128Calibrate.actualMicro(uint32_t n) {
+    return scale32(n + (cycles >> 1), MAGIC, cycles);
+  }
+
+  async command uint8_t Atm128Calibrate.adcPrescaler() {
+    /* This is also log2(cycles/3.05). But that's a pain to compute */
+    if (cycles >= 390)
+      return ATM128_ADC_PRESCALE_128;
+    if (cycles >= 195)
+      return ATM128_ADC_PRESCALE_64;
+    if (cycles >= 97)
+      return ATM128_ADC_PRESCALE_32;
+    if (cycles >= 48)
+      return ATM128_ADC_PRESCALE_16;
+    if (cycles >= 24)
+      return ATM128_ADC_PRESCALE_8;
+    if (cycles >= 12)
+      return ATM128_ADC_PRESCALE_4;
+    return ATM128_ADC_PRESCALE_2;
+  }
+
+  async command uint16_t Atm128Calibrate.baudrateRegister(uint32_t baudrate) {
+    // value is (cycles*32768) / (8*baudrate) - 1
+    return ((uint32_t)cycles << 12) / baudrate - 1;
+  }
+}