X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=tos%2Fchips%2Fmsp430%2Ftimer%2FMsp430ClockP.nc;h=7d081ab6edb1f3c0d25e5837274986d9891454b5;hb=e9bfab607e051bae6afb47b44892ce37541d1b44;hp=094cda714f7652a649361b9bbc1e42a5e72c6e9d;hpb=a06d8962cacb303b05074f2c45fda451ecb42a67;p=tinyos-2.x.git diff --git a/tos/chips/msp430/timer/Msp430ClockP.nc b/tos/chips/msp430/timer/Msp430ClockP.nc index 094cda71..7d081ab6 100644 --- a/tos/chips/msp430/timer/Msp430ClockP.nc +++ b/tos/chips/msp430/timer/Msp430ClockP.nc @@ -22,16 +22,16 @@ /** * @author Cory Sharp + * @author Vlado Handziski */ -#include - #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 { @@ -41,29 +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_HZ = 32768U, - TARGET_DCO_DELTA = (TARGET_DCO_HZ / ACLK_HZ) * ACLK_CALIB_PERIOD, + 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 ); @@ -99,6 +141,11 @@ implementation TBCTL = TBSSEL0 | TBIE; } + default event void Msp430ClockInit.setupDcoCalibrate() + { + call Msp430ClockInit.defaultSetupDcoCalibrate(); + } + default event void Msp430ClockInit.initClocks() { call Msp430ClockInit.defaultInitClocks(); @@ -141,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; } @@ -174,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 ); } @@ -211,6 +250,7 @@ implementation atomic { + signal Msp430ClockInit.setupDcoCalibrate(); busyCalibrateDco(); signal Msp430ClockInit.initClocks(); signal Msp430ClockInit.initTimerA();