Contiki 2.6

system-timer.c

Go to the documentation of this file.
00001 /** @file hal/micro/cortexm3/system-timer.c
00002  * @brief STM32W108 System Timer HAL functions.
00003  * 
00004  * \b NOTE:  The Sleep Timer count and compare registers are only 16 bits, but
00005  * the counter and comparators themselves are actually 32bits.  To deal with
00006  * this, there are High ("H") and Low ("L") registers.  The High register is
00007  * the "action" register.  When working with SLEEPTMR_CNT, reading the "H"
00008  * register will return the upper 16 bits and simultaneously trigger the
00009  * capture of the lower 16bits in the "L" register.  The "L" register may then
00010  * be read.  When working with the SLEEPTMR_CMP registers, writing "L" will
00011  * set a shadow register.  Writing "H" will cause the value from the "H" write
00012  * and the "L" shadow register to be combined and simultaneously loaded into
00013  * the true 32bit comparator.
00014  * 
00015  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved.        -->
00016  */
00017 #include PLATFORM_HEADER
00018 #include "error.h"
00019 #include "hal/micro/micro-common.h"
00020 #include "hal/micro/cortexm3/micro-common.h"
00021 #include "micro/system-timer.h"
00022 
00023 
00024 //A simple flag used by internalSleepForQs to check that it has exited
00025 //from sleep mode at the request of the expected timer interrupt.
00026 static boolean sleepTimerInterruptOccurred = FALSE;
00027 
00028 // halInternalStartSystemTimer() was moved to micro.c
00029 
00030 /**
00031  * Return a 16 bit real time clock value.  With 1024 clock ticks per second,
00032  * a single clock tick occurs every 0.9769625 milliseconds, and a rollover
00033  * of the 16-bit timer occurs every 64 seconds.
00034  */
00035 int16u halCommonGetInt16uMillisecondTick(void)
00036 {
00037   return (int16u)halCommonGetInt32uMillisecondTick();
00038 }
00039 
00040 int16u halCommonGetInt16uQuarterSecondTick(void)
00041 {
00042   return (int16u)(halCommonGetInt32uMillisecondTick() >> 8);
00043 }
00044 
00045 /**
00046  * Return a 32 bit real time clock value.  With 1024 clock ticks per second,
00047  * a single clock tick occurs every 0.9769625 milliseconds, and a rollover
00048  * of the 32-bit timer occurs approximately every 48.5 days.
00049  */
00050 int32u halCommonGetInt32uMillisecondTick(void)
00051 {
00052   int32u time;
00053   
00054   time = SLEEPTMR_CNTH<<16;
00055   time |= SLEEPTMR_CNTL;
00056   
00057   return time;
00058 }
00059 
00060 
00061 void halSleepTimerIsr(void)
00062 {
00063   //clear the second level interrupts
00064   INT_SLEEPTMRFLAG = INT_SLEEPTMRWRAP | INT_SLEEPTMRCMPA | INT_SLEEPTMRCMPB;
00065   
00066   //mark a sleep timer interrupt as having occurred
00067   sleepTimerInterruptOccurred = TRUE;
00068 }
00069 
00070 #define CONVERT_QS_TO_TICKS(x) ((x) << 8)
00071 #define CONVERT_TICKS_TO_QS(x) ((x) >> 8)
00072 #define TIMER_MAX_QS           0x1000000 // = 4194304 seconds * 4 = 16777216
00073 static StStatus internalSleepForQs(boolean useGpioWakeMask,
00074                                       int32u *duration,
00075                                       int32u gpioWakeBitMask)
00076 {
00077   StStatus status = ST_SUCCESS;
00078   int32u sleepOverflowCount;
00079   int32u remainder;
00080   int32u startCount;
00081   
00082   //There is really no reason to bother with a duration of 0qs
00083   if(*duration==0) {
00084     INTERRUPTS_ON();
00085     return status;
00086   }
00087   
00088   ATOMIC(
00089     //disable top-level interrupt while configuring
00090     INT_CFGCLR = INT_SLEEPTMR;
00091     
00092     //Our tick is calibrated to 1024Hz, giving a tick of 976.6us and an
00093     //overflow of 4194304.0 seconds.  Calculate the number of sleep overflows
00094     //in the duration
00095     sleepOverflowCount = (*duration)/TIMER_MAX_QS;
00096     //calculate the remaining ticks
00097     remainder = CONVERT_QS_TO_TICKS((*duration)%TIMER_MAX_QS);
00098     //grab the starting sleep count
00099     startCount = halCommonGetInt32uMillisecondTick();
00100     
00101     sleepTimerInterruptOccurred = FALSE;
00102     
00103     if(remainder) {
00104       //set CMPA value
00105       SLEEPTMR_CMPAL = (startCount+remainder)&0xFFFF;
00106       SLEEPTMR_CMPAH = ((startCount+remainder)>>16)&0xFFFF;
00107       //clear any stale interrupt flag and set the CMPA interrupt
00108       INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPA;
00109       INT_SLEEPTMRCFG = INT_SLEEPTMRCMPA;
00110     }
00111     if(sleepOverflowCount) {
00112       //set CMPB value
00113       SLEEPTMR_CMPBL = startCount&0xFFFF;
00114       SLEEPTMR_CMPBH = (startCount>>16)&0xFFFF;
00115       //clear any stale interrupt flag and set the CMPB interrupt
00116       //this will also disable the CMPA interrupt, since we only want to wake
00117       //on overflows, not the remainder yet
00118       INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPB;
00119       INT_SLEEPTMRCFG = INT_SLEEPTMRCMPB;
00120     }
00121     
00122     //enable top-level interrupt
00123     INT_CFGSET = INT_SLEEPTMR;
00124   )
00125   
00126   while(*duration > 0) {
00127     {
00128       halSleepWithOptions(SLEEPMODE_WAKETIMER, gpioWakeBitMask);
00129     }
00130     
00131     INT_SLEEPTMRCFG = INT_SLEEPTMRCFG_RESET; //disable all SleepTMR interrupts
00132     
00133     //If we didn't come out of sleep via a compare or overflow interrupt,
00134     //it was an abnormal sleep interruption; report the event.
00135     if(!sleepTimerInterruptOccurred) {
00136       status = ST_SLEEP_INTERRUPTED;
00137       //Update duration to account for how long last sleep was.  Using the
00138       //startCount variable is always valid because full timer wraps always
00139       //return to this value and the remainder is an offset from this value.
00140       //And since the duration is always reduced after each full timer wrap,
00141       //we only need to calculate the final duration here.
00142       *duration -= CONVERT_TICKS_TO_QS(halCommonGetInt32uMillisecondTick() -
00143                                        startCount);
00144       break;
00145     } else {
00146       if(sleepOverflowCount) {
00147         sleepOverflowCount--;
00148         *duration -= TIMER_MAX_QS;
00149       } else {
00150         *duration -= CONVERT_TICKS_TO_QS(remainder);
00151       }
00152       sleepTimerInterruptOccurred = FALSE;
00153       if(sleepOverflowCount) {
00154         //enable sleeping for a full timer wrap
00155         INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPB;
00156         INT_SLEEPTMRCFG = INT_SLEEPTMRCMPB;
00157       } else if(!sleepOverflowCount && (*duration>0)){
00158         //enable sleeping for the remainder
00159         INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPA;
00160         INT_SLEEPTMRCFG = INT_SLEEPTMRCMPA;
00161       }
00162     }
00163   }
00164   
00165   return status;
00166 }
00167 
00168 StStatus halSleepForQsWithOptions(int32u *duration, int32u gpioWakeBitMask)
00169 {
00170   return internalSleepForQs(TRUE, duration, gpioWakeBitMask);
00171 }
00172