Contiki 3.x
clock.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Texas Instruments Incorporated - http://www.ti.com/
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /**
32  * \addtogroup cc2538
33  * @{
34  *
35  * \defgroup cc2538-clock cc2538 Clock
36  *
37  * Implementation of the clock module for the cc2538
38  *
39  * To implement the clock functionality, we use the SysTick peripheral on the
40  * cortex-M3. We run the system clock at 16 MHz and we set the SysTick to give
41  * us 128 interrupts / sec. However, the Sleep Timer counter value is used for
42  * the number of elapsed ticks in order to avoid a significant time drift caused
43  * by PM1/2. Contrary to the Sleep Timer, the SysTick peripheral is indeed
44  * frozen during PM1/2, so adjusting upon wake-up a tick counter based on this
45  * peripheral would hardly be accurate.
46  * @{
47  *
48  * \file
49  * Clock driver implementation for the TI cc2538
50  */
51 #include "contiki.h"
52 #include "systick.h"
53 #include "reg.h"
54 #include "cpu.h"
55 #include "dev/gptimer.h"
56 #include "dev/sys-ctrl.h"
57 
58 #include "sys/energest.h"
59 #include "sys/etimer.h"
60 #include "sys/rtimer.h"
61 
62 #include <stdint.h>
63 /*---------------------------------------------------------------------------*/
64 #define RTIMER_CLOCK_TICK_RATIO (RTIMER_SECOND / CLOCK_SECOND)
65 #define RELOAD_VALUE (125000 - 1) /** Fire 128 times / sec */
66 
67 static volatile uint64_t rt_ticks_startup = 0, rt_ticks_epoch = 0;
68 /*---------------------------------------------------------------------------*/
69 /**
70  * \brief Arch-specific implementation of clock_init for the cc2538
71  *
72  * We initialise the SysTick to fire 128 interrupts per second, giving us a
73  * value of 128 for CLOCK_SECOND
74  *
75  * We also initialise GPT0:Timer A, which is used by clock_delay_usec().
76  * We use 16-bit range (individual), count-down, one-shot, no interrupts.
77  * The system clock is at 16MHz giving us 62.5 nano sec ticks for Timer A.
78  * Prescaled by 16 gives us a very convenient 1 tick per usec
79  */
80 void
82 {
83  REG(SYSTICK_STRELOAD) = RELOAD_VALUE;
84 
85  /* System clock source, Enable */
86  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_CLK_SRC | SYSTICK_STCTRL_ENABLE;
87 
88  /* Enable the SysTick Interrupt */
89  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_INTEN;
90 
91  /*
92  * Remove the clock gate to enable GPT0 and then initialise it
93  * We only use GPT0 for clock_delay_usec. We initialise it here so we can
94  * have it ready when it's needed
95  */
97 
98  /* Make sure GPT0 is off */
99  REG(GPT_0_BASE | GPTIMER_CTL) = 0;
100 
101 
102  /* 16-bit */
103  REG(GPT_0_BASE | GPTIMER_CFG) = 0x04;
104 
105  /* One-Shot, Count Down, No Interrupts */
106  REG(GPT_0_BASE | GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
107 
108  /* Prescale by 16 (thus, value 15 in TAPR) */
109  REG(GPT_0_BASE | GPTIMER_TAPR) = 0x0F;
110 }
111 /*---------------------------------------------------------------------------*/
112 CCIF clock_time_t
114 {
115  return rt_ticks_startup / RTIMER_CLOCK_TICK_RATIO;
116 }
117 /*---------------------------------------------------------------------------*/
118 void
119 clock_set_seconds(unsigned long sec)
120 {
121  rt_ticks_epoch = (uint64_t)sec * RTIMER_SECOND;
122 }
123 /*---------------------------------------------------------------------------*/
124 CCIF unsigned long
126 {
127  return rt_ticks_epoch / RTIMER_SECOND;
128 }
129 /*---------------------------------------------------------------------------*/
130 void
131 clock_wait(clock_time_t i)
132 {
133  clock_time_t start;
134 
135  start = clock_time();
136  while(clock_time() - start < (clock_time_t)i);
137 }
138 /*---------------------------------------------------------------------------*/
139 /**
140  * \brief Arch-specific implementation of clock_delay_usec for the cc2538
141  * \param len Delay \e len uSecs
142  *
143  * See clock_init() for GPT0 Timer A's configuration
144  */
145 void
146 clock_delay_usec(uint16_t len)
147 {
148  REG(GPT_0_BASE | GPTIMER_TAILR) = len;
150 
151  /* One-Shot mode: TAEN will be cleared when the timer reaches 0 */
152  while(REG(GPT_0_BASE | GPTIMER_CTL) & GPTIMER_CTL_TAEN);
153 }
154 /*---------------------------------------------------------------------------*/
155 /**
156  * \brief Obsolete delay function but we implement it here since some code
157  * still uses it
158  */
159 void
160 clock_delay(unsigned int i)
161 {
162  clock_delay_usec(i);
163 }
164 /*---------------------------------------------------------------------------*/
165 /**
166  * \brief Update the software clock ticks and seconds
167  *
168  * This function is used to update the software tick counters whenever the
169  * system clock might have changed, which can occur upon a SysTick ISR or upon
170  * wake-up from PM1/2.
171  *
172  * For the software clock ticks counter, the Sleep Timer counter value is used
173  * as the base tick value, and extended to a 64-bit value thanks to a detection
174  * of wraparounds.
175  *
176  * For the seconds counter, the changes of the Sleep Timer counter value are
177  * added to the reference time, which is either the startup time or the value
178  * passed to clock_set_seconds().
179  *
180  * This function polls the etimer process if an etimer has expired.
181  */
182 static void
183 update_ticks(void)
184 {
185  rtimer_clock_t now;
186  uint64_t prev_rt_ticks_startup, cur_rt_ticks_startup;
187  uint32_t cur_rt_ticks_startup_hi;
188 
189  now = RTIMER_NOW();
190  prev_rt_ticks_startup = rt_ticks_startup;
191 
192  cur_rt_ticks_startup_hi = prev_rt_ticks_startup >> 32;
193  if(now < (rtimer_clock_t)prev_rt_ticks_startup) {
194  cur_rt_ticks_startup_hi++;
195  }
196  cur_rt_ticks_startup = (uint64_t)cur_rt_ticks_startup_hi << 32 | now;
197  rt_ticks_startup = cur_rt_ticks_startup;
198 
199  rt_ticks_epoch += cur_rt_ticks_startup - prev_rt_ticks_startup;
200 
201  /*
202  * Inform the etimer library that the system clock has changed and that an
203  * etimer might have expired.
204  */
205  if(etimer_pending()) {
207  }
208 }
209 /*---------------------------------------------------------------------------*/
210 /**
211  * \brief Adjust the clock following missed SysTick ISRs
212  *
213  * This function is useful when coming out of PM1/2, during which the system
214  * clock is stopped. We adjust the clock counters like after any SysTick ISR.
215  *
216  * \note This function is only meant to be used by lpm_exit(). Applications
217  * should really avoid calling this
218  */
219 void
221 {
222  /* Halt the SysTick while adjusting */
223  REG(SYSTICK_STCTRL) &= ~SYSTICK_STCTRL_ENABLE;
224 
225  update_ticks();
226 
227  /* Re-Start the SysTick */
228  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_ENABLE;
229 }
230 /*---------------------------------------------------------------------------*/
231 /**
232  * \brief The clock Interrupt Service Routine
233  *
234  * It polls the etimer process if an etimer has expired. It also updates the
235  * software clock tick and seconds counter.
236  */
237 void
239 {
240  ENERGEST_ON(ENERGEST_TYPE_IRQ);
241 
242  update_ticks();
243 
244  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
245 }
246 /*---------------------------------------------------------------------------*/
247 
248 /**
249  * @}
250  * @}
251  */
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:94
Header file with prototypes for interrupt control on the cc2538 Cortex-M3 micro.
Header for with definitions related to the cc2538 SysTick.
void clock_init(void)
Initialize the clock library.
Definition: clock.c:76
Header file with register manipulation macro definitions.
Header file for the energy estimation mechanism
void clock_adjust(void)
Adjust the clock following missed SysTick ISRs.
Definition: clock.c:220
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
#define GPTIMER_TAMR
GPTM Timer A mode.
Definition: gptimer.h:59
Header file for the cc2538 System Control driver.
#define GPT_0_BASE
GPTIMER0.
Definition: gptimer.h:49
Header file for the real-time timer module.
#define GPTIMER_TAPR
GPTM Timer A prescale.
Definition: gptimer.h:71
void etimer_request_poll(void)
Make the event timer aware that the clock has changed.
Definition: etimer.c:145
void clock_set_seconds(unsigned long sec)
Set the value of the platform seconds.
Definition: clock.c:49
CCIF unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:57
int etimer_pending(void)
Check if there are any non-expired event timers.
Definition: etimer.c:223
#define SYS_CTRL_RCGCGPT_GPT0
GPT0 clock enable, CPU running.
Definition: sys-ctrl.h:132
#define GPTIMER_CFG
GPTM configuration.
Definition: gptimer.h:58
void clock_delay(unsigned int delay)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock.c:60
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:133
#define GPTIMER_TAILR
GPTM Timer A interval load.
Definition: gptimer.h:67
Header file for the cc2538 General Purpose Timers.
void clock_wait(clock_time_t t)
Wait for a given number of ticks.
Definition: clock.c:166
#define GPTIMER_CTL_TAEN
Timer A enable.
Definition: gptimer.h:149
Event timer header file.
#define GPTIMER_CTL
GPTM control.
Definition: gptimer.h:61
#define SYS_CTRL_RCGCGPT
GPT[3:0] clocks - active mode.
Definition: sys-ctrl.h:65
void clock_isr(void)
The clock Interrupt Service Routine.
Definition: clock.c:238