Contiki 2.6
|
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