Contiki-NG
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 "cc2538_cm3.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 /* Period of the SysTick counter expressed as a number of ticks */
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 SYSTICK_PERIOD (SYS_CTRL_SYS_CLOCK / CLOCK_SECOND)
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  SysTick_Config(SYSTICK_PERIOD);
96 
97  /*
98  * Remove the clock gate to enable GPT0 and then initialise it
99  * We only use GPT0 for clock_delay_usec. We initialise it here so we can
100  * have it ready when it's needed
101  */
103 
104  /* Make sure GPT0 is off */
105  REG(GPT_0_BASE + GPTIMER_CTL) = 0;
106 
107  /* 16-bit */
108  REG(GPT_0_BASE + GPTIMER_CFG) = 0x04;
109 
110  /* One-Shot, Count Down, No Interrupts */
111  REG(GPT_0_BASE + GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
112 
113  /* Prescale depending on system clock used */
114  REG(GPT_0_BASE + GPTIMER_TAPR) = PRESCALER_VALUE;
115 }
116 /*---------------------------------------------------------------------------*/
117 clock_time_t
119 {
120  return rt_ticks_startup / RTIMER_CLOCK_TICK_RATIO;
121 }
122 /*---------------------------------------------------------------------------*/
123 void
124 clock_set_seconds(unsigned long sec)
125 {
126  rt_ticks_epoch = (uint64_t)sec * RTIMER_SECOND;
127 }
128 /*---------------------------------------------------------------------------*/
129 unsigned long
131 {
132  return rt_ticks_epoch / RTIMER_SECOND;
133 }
134 /*---------------------------------------------------------------------------*/
135 void
136 clock_wait(clock_time_t i)
137 {
138  clock_time_t start;
139 
140  start = clock_time();
141  while(clock_time() - start < (clock_time_t)i);
142 }
143 /*---------------------------------------------------------------------------*/
144 /*
145  * Arch-specific implementation of clock_delay_usec for the cc2538
146  *
147  * See clock_init() for GPT0 Timer A's configuration
148  */
149 void
150 clock_delay_usec(uint16_t dt)
151 {
152  REG(GPT_0_BASE + GPTIMER_TAILR) = dt;
154 
155  /* One-Shot mode: TAEN will be cleared when the timer reaches 0 */
156  while(REG(GPT_0_BASE + GPTIMER_CTL) & GPTIMER_CTL_TAEN);
157 }
158 /*---------------------------------------------------------------------------*/
159 /**
160  * \brief Obsolete delay function but we implement it here since some code
161  * still uses it
162  */
163 void
164 clock_delay(unsigned int i)
165 {
166  clock_delay_usec(i);
167 }
168 /*---------------------------------------------------------------------------*/
169 /**
170  * \brief Update the software clock ticks and seconds
171  *
172  * This function is used to update the software tick counters whenever the
173  * system clock might have changed, which can occur upon a SysTick ISR or upon
174  * wake-up from PM1/2.
175  *
176  * For the software clock ticks counter, the Sleep Timer counter value is used
177  * as the base tick value, and extended to a 64-bit value thanks to a detection
178  * of wraparounds.
179  *
180  * For the seconds counter, the changes of the Sleep Timer counter value are
181  * added to the reference time, which is either the startup time or the value
182  * passed to clock_set_seconds().
183  *
184  * This function polls the etimer process if an etimer has expired.
185  */
186 static void
188 {
189  rtimer_clock_t now;
190  uint64_t prev_rt_ticks_startup, cur_rt_ticks_startup;
191  uint32_t cur_rt_ticks_startup_hi;
192 
193  now = RTIMER_NOW();
194  prev_rt_ticks_startup = rt_ticks_startup;
195 
196  cur_rt_ticks_startup_hi = prev_rt_ticks_startup >> 32;
197  if(now < (rtimer_clock_t)prev_rt_ticks_startup) {
198  cur_rt_ticks_startup_hi++;
199  }
200  cur_rt_ticks_startup = (uint64_t)cur_rt_ticks_startup_hi << 32 | now;
201  rt_ticks_startup = cur_rt_ticks_startup;
202 
203  rt_ticks_epoch += cur_rt_ticks_startup - prev_rt_ticks_startup;
204 
205  /*
206  * Inform the etimer library that the system clock has changed and that an
207  * etimer might have expired.
208  */
209  if(etimer_pending()) {
211  }
212 }
213 /*---------------------------------------------------------------------------*/
214 /**
215  * \brief Adjust the clock following missed SysTick ISRs
216  *
217  * This function is useful when coming out of PM1/2, during which the system
218  * clock is stopped. We adjust the clock counters like after any SysTick ISR.
219  *
220  * \note This function is only meant to be used by lpm_exit(). Applications
221  * should really avoid calling this
222  */
223 void
225 {
226  /* Halt the SysTick while adjusting */
228 
229  update_ticks();
230 
231  /* Re-Start the SysTick */
233 }
234 /*---------------------------------------------------------------------------*/
235 /**
236  * \brief The clock Interrupt Service Routine
237  *
238  * It polls the etimer process if an etimer has expired. It also updates the
239  * software clock tick and seconds counter.
240  */
241 void
243 {
244  update_ticks();
245 }
246 /*---------------------------------------------------------------------------*/
247 
248 /**
249  * @}
250  * @}
251  */
Header file for the cc2538 System Control driver.
Header file for the cc2538 General Purpose Timers.
#define GPTIMER_TAPR
GPTM Timer A prescale.
Definition: gptimer.h:71
#define GPT_0_BASE
GPTIMER0.
Definition: gptimer.h:49
Header file for the energy estimation mechanism
#define GPTIMER_TAILR
GPTM Timer A interval load.
Definition: gptimer.h:67
void etimer_request_poll(void)
Make the event timer aware that the clock has changed.
Definition: etimer.c:145
CMSIS Cortex-M3 core peripheral access layer header file for CC2538.
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:150
void clock_wait(clock_time_t i)
Wait for a given number of ticks.
Definition: clock.c:136
Header file with register manipulation macro definitions.
unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:130
#define RTIMER_SECOND
Number of rtimer ticks for 1 second.
Definition: rtimer.h:112
#define GPTIMER_CTL_TAEN
Timer A enable.
Definition: gptimer.h:149
#define GPTIMER_TAMR
GPTM Timer A mode.
Definition: gptimer.h:59
static void start(void)
Start measurement.
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:185
#define SYS_CTRL_RCGCGPT
GPT[3:0] clocks - active mode.
Definition: sys-ctrl.h:67
Event timer header file.
#define SysTick
Definition: core_cm0.h:588
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
System Tick Configuration.
Definition: core_cm0.h:782
Header file for the real-time timer module.
int etimer_pending(void)
Check if there are any non-expired event timers.
Definition: etimer.c:231
void clock_delay(unsigned int i)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock.c:164
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:118
void clock_isr(void)
The clock Interrupt Service Routine.
Definition: clock.c:242
#define SYS_CTRL_RCGCGPT_GPT0
GPT0 clock enable, CPU running.
Definition: sys-ctrl.h:139
Header file with prototypes for interrupt control on the cc2538 Cortex-M3 micro.
void clock_set_seconds(unsigned long sec)
Set the value of the platform seconds.
Definition: clock.c:124
#define SysTick_CTRL_ENABLE_Msk
Definition: core_cm0.h:515
void clock_adjust(void)
Adjust the clock following missed SysTick ISRs.
Definition: clock.c:224
#define GPTIMER_CTL
GPTM control.
Definition: gptimer.h:61
static void update_ticks(void)
Update the software clock ticks and seconds.
Definition: clock.c:187
#define GPTIMER_CFG
GPTM configuration.
Definition: gptimer.h:58
void clock_init(void)
Arch-specific implementation of clock_init for the cc2538.
Definition: clock.c:93