]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/msp430/timer/Msp430ClockP.nc
MSP430 clock enhancements.
[tinyos-2.x.git] / tos / chips / msp430 / timer / Msp430ClockP.nc
index 1e1a77040fad6e5512f7ed9f1de2af44ad846583..7d081ab6edb1f3c0d25e5837274986d9891454b5 100644 (file)
 
 /**
  * @author Cory Sharp <cssharp@eecs.berkeley.edu>
+ * @author Vlado Handziski <handzisk@tkn.tu-berlind.de>
  */
 
 #include "Msp430Timer.h"
 
-module Msp430ClockP
+generic module Msp430ClockP(uint16_t TARGET_DCO_KHZ, uint16_t ACLK_KHZ) @safe()
 {
   provides interface Init;
   provides interface Msp430ClockInit;
+  provides interface McuPowerOverride;
 }
 implementation
 {
@@ -39,30 +41,71 @@ implementation
   MSP430REG_NORACE(TBCTL);
   MSP430REG_NORACE(TBIV);
 
+  #if defined(__MSP430_HAS_BC2__)      /* basic clock module+ */
+  #define FIRST_STEP 0x1000
+  #else                                        /* orig basic clock module */
+  #define RSEL3 0
+  #define FIRST_STEP 0x800
+  #endif
+
   enum
   {
+    DCOX = DCO2 + DCO1 + DCO0,
+    MODX = MOD4 + MOD3 + MOD2 + MOD1 + MOD0,
+    RSELX = RSEL3 + RSEL2 + RSEL1 + RSEL0,
     ACLK_CALIB_PERIOD = 8,
-    ACLK_KHZ = 32,
-    TARGET_DCO_KHZ = 4096, // prescribe the cpu clock rate in kHz
     TARGET_DCO_DELTA = (TARGET_DCO_KHZ / ACLK_KHZ) * ACLK_CALIB_PERIOD,
   };
 
+  async command mcu_power_t McuPowerOverride.lowestState() {
+    return MSP430_POWER_LPM3;
+  }
+
+  command void Msp430ClockInit.defaultSetupDcoCalibrate()
+  {
+  
+    // --- setup ---
+
+    TACTL = TASSEL1 | MC1; // source SMCLK, continuous mode, everything else 0
+    TBCTL = TBSSEL0 | MC1;
+    BCSCTL1 = XT2OFF | RSEL2;
+    BCSCTL2 = 0;
+    TBCCTL0 = CM0;
+   }
+    
   command void Msp430ClockInit.defaultInitClocks()
   {
+    const unsigned int divider = TARGET_DCO_KHZ / 1000;
+
     // BCSCTL1
     // .XT2OFF = 1; disable the external oscillator for SCLK and MCLK
     // .XTS = 0; set low frequency mode for LXFT1
     // .DIVA = 0; set the divisor on ACLK to 1
     // .RSEL, do not modify
-    BCSCTL1 = XT2OFF | (BCSCTL1 & (RSEL2|RSEL1|RSEL0));
+    BCSCTL1 = XT2OFF | (BCSCTL1 & RSELX);
 
     // BCSCTL2
     // .SELM = 0; select DCOCLK as source for MCLK
     // .DIVM = 0; set the divisor of MCLK to 1
     // .SELS = 0; select DCOCLK as source for SCLK
-    // .DIVS = 2; set the divisor of SCLK to 4
+    // .DIVS = see below
     // .DCOR = 0; select internal resistor for DCO
-    BCSCTL2 = DIVS1;
+    //
+    // TinyOS upper layers assume SMCLK runs at 1 binary MHz, or 1,048,576HZ.
+    // If DCOCLK has been set to 1, 2, 4 or 8 binary MHz, we can correctly set
+    // SMCLK to the expected value.   Platforms using different clocks should
+    // set the divider by overriding Msp430ClockInit.initClocks(), calling
+    // Msp430ClockInit.defaultInitClocks(), then massaging the DIVS bits as
+    // required.
+    if (divider >= 8)
+      BCSCTL2 = DIVS_3;
+    else if (divider >= 4)
+      BCSCTL2 = DIVS_2;
+    else if (divider >= 2)
+      BCSCTL2 = DIVS_1;
+    else
+      BCSCTL2 = DIVS_0;
+
 
     // IE1.OFIE = 0; no interrupt for oscillator fault
     CLR_FLAG( IE1, OFIE );
@@ -98,6 +141,11 @@ implementation
     TBCTL = TBSSEL0 | TBIE;
   }
 
+  default event void Msp430ClockInit.setupDcoCalibrate()
+  {
+    call Msp430ClockInit.defaultSetupDcoCalibrate();
+  }
+  
   default event void Msp430ClockInit.initClocks()
   {
     call Msp430ClockInit.defaultInitClocks();
@@ -140,7 +188,7 @@ implementation
 
   void set_dco_calib( int calib )
   {
-    BCSCTL1 = (BCSCTL1 & ~0x07) | ((calib >> 8) & 0x07);
+    BCSCTL1 = (BCSCTL1 & ~RSELX) | ((calib >> 8) & RSELX);
     DCOCTL = calib & 0xff;
   }
 
@@ -173,29 +221,21 @@ implementation
     int calib;
     int step;
 
-    // --- setup ---
-
-    TACTL = TASSEL1 | MC1; // source SMCLK, continuous mode, everything else 0
-    TBCTL = TBSSEL0 | MC1;
-    BCSCTL1 = XT2OFF | RSEL2;
-    BCSCTL2 = 0;
-    TBCCTL0 = CM0;
-
     // --- calibrate ---
 
     // Binary search for RSEL,DCO,DCOMOD.
     // It's okay that RSEL isn't monotonic.
 
-    for( calib=0,step=0x800; step!=0; step>>=1 )
+    for( calib=0,step=FIRST_STEP; step!=0; step>>=1 )
     {
       // if the step is not past the target, commit it
       if( test_calib_busywait_delta(calib|step) <= TARGET_DCO_DELTA )
         calib |= step;
     }
 
-    // if DCOx is 7 (0x0e0 in calib), then the 5-bit MODx is not useable, set it to 0
-    if( (calib & 0x0e0) == 0x0e0 )
-      calib &= ~0x01f;
+    // if DCOx is all 1s in calib, then MODx is not useable, set it to 0
+    if( (calib & DCOX) == DCOX )
+      calib &= ~MODX;
 
     set_dco_calib( calib );
   }
@@ -210,6 +250,7 @@ implementation
 
     atomic
     {
+      signal Msp430ClockInit.setupDcoCalibrate();
       busyCalibrateDco();
       signal Msp430ClockInit.initClocks();
       signal Msp430ClockInit.initTimerA();