Contiki 2.5
system-timer.c
Go to the documentation of this file.
1 /** @file hal/micro/cortexm3/system-timer.c
2  * @brief STM32W108 System Timer HAL functions.
3  *
4  * \b NOTE: The Sleep Timer count and compare registers are only 16 bits, but
5  * the counter and comparators themselves are actually 32bits. To deal with
6  * this, there are High ("H") and Low ("L") registers. The High register is
7  * the "action" register. When working with SLEEPTMR_CNT, reading the "H"
8  * register will return the upper 16 bits and simultaneously trigger the
9  * capture of the lower 16bits in the "L" register. The "L" register may then
10  * be read. When working with the SLEEPTMR_CMP registers, writing "L" will
11  * set a shadow register. Writing "H" will cause the value from the "H" write
12  * and the "L" shadow register to be combined and simultaneously loaded into
13  * the true 32bit comparator.
14  *
15  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved. -->
16  */
17 #include PLATFORM_HEADER
18 #include "error.h"
19 #include "hal/micro/micro-common.h"
21 #include "micro/system-timer.h"
22 
23 
24 //A simple flag used by internalSleepForQs to check that it has exited
25 //from sleep mode at the request of the expected timer interrupt.
26 static boolean sleepTimerInterruptOccurred = FALSE;
27 
28 // halInternalStartSystemTimer() was moved to micro.c
29 
30 /**
31  * Return a 16 bit real time clock value. With 1024 clock ticks per second,
32  * a single clock tick occurs every 0.9769625 milliseconds, and a rollover
33  * of the 16-bit timer occurs every 64 seconds.
34  */
36 {
37  return (int16u)halCommonGetInt32uMillisecondTick();
38 }
39 
41 {
42  return (int16u)(halCommonGetInt32uMillisecondTick() >> 8);
43 }
44 
45 /**
46  * Return a 32 bit real time clock value. With 1024 clock ticks per second,
47  * a single clock tick occurs every 0.9769625 milliseconds, and a rollover
48  * of the 32-bit timer occurs approximately every 48.5 days.
49  */
51 {
52  int32u time;
53 
54  time = SLEEPTMR_CNTH<<16;
55  time |= SLEEPTMR_CNTL;
56 
57  return time;
58 }
59 
60 
61 void halSleepTimerIsr(void)
62 {
63  //clear the second level interrupts
64  INT_SLEEPTMRFLAG = INT_SLEEPTMRWRAP | INT_SLEEPTMRCMPA | INT_SLEEPTMRCMPB;
65 
66  //mark a sleep timer interrupt as having occurred
67  sleepTimerInterruptOccurred = TRUE;
68 }
69 
70 #define CONVERT_QS_TO_TICKS(x) ((x) << 8)
71 #define CONVERT_TICKS_TO_QS(x) ((x) >> 8)
72 #define TIMER_MAX_QS 0x1000000 // = 4194304 seconds * 4 = 16777216
73 static StStatus internalSleepForQs(boolean useGpioWakeMask,
74  int32u *duration,
75  int32u gpioWakeBitMask)
76 {
77  StStatus status = ST_SUCCESS;
78  int32u sleepOverflowCount;
79  int32u remainder;
80  int32u startCount;
81 
82  //There is really no reason to bother with a duration of 0qs
83  if(*duration==0) {
84  INTERRUPTS_ON();
85  return status;
86  }
87 
88  ATOMIC(
89  //disable top-level interrupt while configuring
90  INT_CFGCLR = INT_SLEEPTMR;
91 
92  //Our tick is calibrated to 1024Hz, giving a tick of 976.6us and an
93  //overflow of 4194304.0 seconds. Calculate the number of sleep overflows
94  //in the duration
95  sleepOverflowCount = (*duration)/TIMER_MAX_QS;
96  //calculate the remaining ticks
97  remainder = CONVERT_QS_TO_TICKS((*duration)%TIMER_MAX_QS);
98  //grab the starting sleep count
99  startCount = halCommonGetInt32uMillisecondTick();
100 
101  sleepTimerInterruptOccurred = FALSE;
102 
103  if(remainder) {
104  //set CMPA value
105  SLEEPTMR_CMPAL = (startCount+remainder)&0xFFFF;
106  SLEEPTMR_CMPAH = ((startCount+remainder)>>16)&0xFFFF;
107  //clear any stale interrupt flag and set the CMPA interrupt
108  INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPA;
109  INT_SLEEPTMRCFG = INT_SLEEPTMRCMPA;
110  }
111  if(sleepOverflowCount) {
112  //set CMPB value
113  SLEEPTMR_CMPBL = startCount&0xFFFF;
114  SLEEPTMR_CMPBH = (startCount>>16)&0xFFFF;
115  //clear any stale interrupt flag and set the CMPB interrupt
116  //this will also disable the CMPA interrupt, since we only want to wake
117  //on overflows, not the remainder yet
118  INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPB;
119  INT_SLEEPTMRCFG = INT_SLEEPTMRCMPB;
120  }
121 
122  //enable top-level interrupt
123  INT_CFGSET = INT_SLEEPTMR;
124  )
125 
126  while(*duration > 0) {
127  {
128  halSleepWithOptions(SLEEPMODE_WAKETIMER, gpioWakeBitMask);
129  }
130 
131  INT_SLEEPTMRCFG = INT_SLEEPTMRCFG_RESET; //disable all SleepTMR interrupts
132 
133  //If we didn't come out of sleep via a compare or overflow interrupt,
134  //it was an abnormal sleep interruption; report the event.
135  if(!sleepTimerInterruptOccurred) {
136  status = ST_SLEEP_INTERRUPTED;
137  //Update duration to account for how long last sleep was. Using the
138  //startCount variable is always valid because full timer wraps always
139  //return to this value and the remainder is an offset from this value.
140  //And since the duration is always reduced after each full timer wrap,
141  //we only need to calculate the final duration here.
142  *duration -= CONVERT_TICKS_TO_QS(halCommonGetInt32uMillisecondTick() -
143  startCount);
144  break;
145  } else {
146  if(sleepOverflowCount) {
147  sleepOverflowCount--;
148  *duration -= TIMER_MAX_QS;
149  } else {
150  *duration -= CONVERT_TICKS_TO_QS(remainder);
151  }
152  sleepTimerInterruptOccurred = FALSE;
153  if(sleepOverflowCount) {
154  //enable sleeping for a full timer wrap
155  INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPB;
156  INT_SLEEPTMRCFG = INT_SLEEPTMRCMPB;
157  } else if(!sleepOverflowCount && (*duration>0)){
158  //enable sleeping for the remainder
159  INT_SLEEPTMRFLAG = INT_SLEEPTMRCMPA;
160  INT_SLEEPTMRCFG = INT_SLEEPTMRCMPA;
161  }
162  }
163  }
164 
165  return status;
166 }
167 
168 StStatus halSleepForQsWithOptions(int32u *duration, int32u gpioWakeBitMask)
169 {
170  return internalSleepForQs(TRUE, duration, gpioWakeBitMask);
171 }
172