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 a configurable speed and set the
41  * SysTick to give us 128 interrupts / sec. However, the Sleep Timer counter
42  * value is used for the number of elapsed ticks in order to avoid a
43  * significant time drift caused by PM1/2. Contrary to the Sleep Timer, the
44  * SysTick peripheral is indeed frozen during PM1/2, so adjusting upon wake-up
45  * a tick counter based on this 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 
66 /* Prescaler for GPT0:Timer A used for clock_delay_usec(). */
67 #if SYS_CTRL_SYS_CLOCK < SYS_CTRL_1MHZ
68 #error System clock speeds below 1MHz are not supported
69 #endif
70 #define PRESCALER_VALUE (SYS_CTRL_SYS_CLOCK / SYS_CTRL_1MHZ - 1)
71 
72 /* Reload value for SysTick counter */
73 #if SYS_CTRL_SYS_CLOCK % CLOCK_SECOND
74 /* Too low clock speeds will lead to reduced accurracy */
75 #error System clock speed too slow for CLOCK_SECOND, accuracy reduced
76 #endif
77 #define RELOAD_VALUE (SYS_CTRL_SYS_CLOCK / CLOCK_SECOND - 1)
78 
79 static volatile uint64_t rt_ticks_startup = 0, rt_ticks_epoch = 0;
80 /*---------------------------------------------------------------------------*/
81 /**
82  * \brief Arch-specific implementation of clock_init for the cc2538
83  *
84  * We initialise the SysTick to fire 128 interrupts per second, giving us a
85  * value of 128 for CLOCK_SECOND
86  *
87  * We also initialise GPT0:Timer A, which is used by clock_delay_usec().
88  * We use 16-bit range (individual), count-down, one-shot, no interrupts.
89  * The prescaler is computed according to the system clock in order to get 1
90  * tick per usec.
91  */
92 void
94 {
95  REG(SYSTICK_STRELOAD) = RELOAD_VALUE;
96 
97  /* System clock source, Enable */
98  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_CLK_SRC | SYSTICK_STCTRL_ENABLE;
99 
100  /* Enable the SysTick Interrupt */
101  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_INTEN;
102 
103  /*
104  * Remove the clock gate to enable GPT0 and then initialise it
105  * We only use GPT0 for clock_delay_usec. We initialise it here so we can
106  * have it ready when it's needed
107  */
109 
110  /* Make sure GPT0 is off */
111  REG(GPT_0_BASE + GPTIMER_CTL) = 0;
112 
113  /* 16-bit */
114  REG(GPT_0_BASE + GPTIMER_CFG) = 0x04;
115 
116  /* One-Shot, Count Down, No Interrupts */
117  REG(GPT_0_BASE + GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
118 
119  /* Prescale depending on system clock used */
120  REG(GPT_0_BASE + GPTIMER_TAPR) = PRESCALER_VALUE;
121 }
122 /*---------------------------------------------------------------------------*/
123 CCIF clock_time_t
125 {
126  return rt_ticks_startup / RTIMER_CLOCK_TICK_RATIO;
127 }
128 /*---------------------------------------------------------------------------*/
129 void
130 clock_set_seconds(unsigned long sec)
131 {
132  rt_ticks_epoch = (uint64_t)sec * RTIMER_SECOND;
133 }
134 /*---------------------------------------------------------------------------*/
135 CCIF unsigned long
137 {
138  return rt_ticks_epoch / RTIMER_SECOND;
139 }
140 /*---------------------------------------------------------------------------*/
141 void
142 clock_wait(clock_time_t i)
143 {
144  clock_time_t start;
145 
146  start = clock_time();
147  while(clock_time() - start < (clock_time_t)i);
148 }
149 /*---------------------------------------------------------------------------*/
150 /*
151  * Arch-specific implementation of clock_delay_usec for the cc2538
152  *
153  * See clock_init() for GPT0 Timer A's configuration
154  */
155 void
156 clock_delay_usec(uint16_t dt)
157 {
158  REG(GPT_0_BASE + GPTIMER_TAILR) = dt;
160 
161  /* One-Shot mode: TAEN will be cleared when the timer reaches 0 */
162  while(REG(GPT_0_BASE + GPTIMER_CTL) & GPTIMER_CTL_TAEN);
163 }
164 /*---------------------------------------------------------------------------*/
165 /**
166  * \brief Obsolete delay function but we implement it here since some code
167  * still uses it
168  */
169 void
170 clock_delay(unsigned int i)
171 {
172  clock_delay_usec(i);
173 }
174 /*---------------------------------------------------------------------------*/
175 /**
176  * \brief Update the software clock ticks and seconds
177  *
178  * This function is used to update the software tick counters whenever the
179  * system clock might have changed, which can occur upon a SysTick ISR or upon
180  * wake-up from PM1/2.
181  *
182  * For the software clock ticks counter, the Sleep Timer counter value is used
183  * as the base tick value, and extended to a 64-bit value thanks to a detection
184  * of wraparounds.
185  *
186  * For the seconds counter, the changes of the Sleep Timer counter value are
187  * added to the reference time, which is either the startup time or the value
188  * passed to clock_set_seconds().
189  *
190  * This function polls the etimer process if an etimer has expired.
191  */
192 static void
194 {
195  rtimer_clock_t now;
196  uint64_t prev_rt_ticks_startup, cur_rt_ticks_startup;
197  uint32_t cur_rt_ticks_startup_hi;
198 
199  now = RTIMER_NOW();
200  prev_rt_ticks_startup = rt_ticks_startup;
201 
202  cur_rt_ticks_startup_hi = prev_rt_ticks_startup >> 32;
203  if(now < (rtimer_clock_t)prev_rt_ticks_startup) {
204  cur_rt_ticks_startup_hi++;
205  }
206  cur_rt_ticks_startup = (uint64_t)cur_rt_ticks_startup_hi << 32 | now;
207  rt_ticks_startup = cur_rt_ticks_startup;
208 
209  rt_ticks_epoch += cur_rt_ticks_startup - prev_rt_ticks_startup;
210 
211  /*
212  * Inform the etimer library that the system clock has changed and that an
213  * etimer might have expired.
214  */
215  if(etimer_pending()) {
217  }
218 }
219 /*---------------------------------------------------------------------------*/
220 /**
221  * \brief Adjust the clock following missed SysTick ISRs
222  *
223  * This function is useful when coming out of PM1/2, during which the system
224  * clock is stopped. We adjust the clock counters like after any SysTick ISR.
225  *
226  * \note This function is only meant to be used by lpm_exit(). Applications
227  * should really avoid calling this
228  */
229 void
231 {
232  /* Halt the SysTick while adjusting */
233  REG(SYSTICK_STCTRL) &= ~SYSTICK_STCTRL_ENABLE;
234 
235  update_ticks();
236 
237  /* Re-Start the SysTick */
238  REG(SYSTICK_STCTRL) |= SYSTICK_STCTRL_ENABLE;
239 }
240 /*---------------------------------------------------------------------------*/
241 /**
242  * \brief The clock Interrupt Service Routine
243  *
244  * It polls the etimer process if an etimer has expired. It also updates the
245  * software clock tick and seconds counter.
246  */
247 void
249 {
250  ENERGEST_ON(ENERGEST_TYPE_IRQ);
251 
252  update_ticks();
253 
254  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
255 }
256 /*---------------------------------------------------------------------------*/
257 
258 /**
259  * @}
260  * @}
261  */
void clock_isr(void)
The clock Interrupt Service Routine.
Definition: clock.c:248
Header file for the real-time timer module.
#define SYS_CTRL_RCGCGPT_GPT0
GPT0 clock enable, CPU running.
Definition: sys-ctrl.h:139
Header file with register manipulation macro definitions.
static void start(void)
Start measurement.
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:135
void etimer_request_poll(void)
Make the event timer aware that the clock has changed.
Definition: etimer.c:145
int etimer_pending(void)
Check if there are any non-expired event timers.
Definition: etimer.c:231
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
#define GPTIMER_CTL_TAEN
Timer A enable.
Definition: gptimer.h:149
Header file for the energy estimation mechanism
void clock_init()
Initialize the clock library.
Definition: clock.c:76
static void update_ticks(void)
Update the software clock ticks and seconds.
Definition: clock.c:193
Header for with definitions related to the cc2538 SysTick.
void clock_adjust(void)
Adjust the clock following missed SysTick ISRs.
Definition: clock.c:230
#define GPT_0_BASE
GPTIMER0.
Definition: gptimer.h:49
Header file for the cc2538 System Control driver.
#define SYS_CTRL_RCGCGPT
GPT[3:0] clocks - active mode.
Definition: sys-ctrl.h:67
void clock_delay(unsigned int i)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock.c:170
Event timer header file.
#define GPTIMER_TAILR
GPTM Timer A interval load.
Definition: gptimer.h:67
void clock_wait(clock_time_t i)
Wait for a given number of ticks.
Definition: clock.c:162
#define GPTIMER_CFG
GPTM configuration.
Definition: gptimer.h:58
#define GPTIMER_TAPR
GPTM Timer A prescale.
Definition: gptimer.h:71
unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:54
Header file for the cc2538 General Purpose Timers.
#define GPTIMER_CTL
GPTM control.
Definition: gptimer.h:61
void clock_delay_usec(uint16_t usec)
Delay a given number of microseconds.
Definition: clock.c:94
void clock_set_seconds(unsigned long sec)
Set the value of the platform seconds.
Definition: clock.c:147