Contiki-NG
clock-arch.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018, 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  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /**
31  * \addtogroup cc13xx-cc26xx-clock
32  * @{
33  *
34  * \file
35  * Implementation of the clock libary for CC13xx/CC26xx.
36  *
37  * The periodic polling of etimer is implemented using SysTick. Since
38  * SysTick is paused when the system clock stopped, that is when the
39  * device enters some low-power mode, a wakeup clock is armed with the
40  * next etimer expiration time OR watchdog timeout everytime the device
41  * enters some low-power mode.
42  */
43 /*---------------------------------------------------------------------------*/
44 #include "contiki.h"
45 #include "sys/cc.h"
46 #include "sys/clock.h"
47 #include "sys/etimer.h"
48 /*---------------------------------------------------------------------------*/
49 #include <ti/devices/DeviceFamily.h>
50 #include DeviceFamily_constructPath(driverlib/aon_rtc.h)
51 #include DeviceFamily_constructPath(driverlib/systick.h)
52 
53 #include <ti/drivers/dpl/ClockP.h>
54 #include <ti/drivers/power/PowerCC26XX.h>
55 /*---------------------------------------------------------------------------*/
56 #include "watchdog-arch.h"
57 /*---------------------------------------------------------------------------*/
58 #include <stdbool.h>
59 #include <stdint.h>
60 /*---------------------------------------------------------------------------*/
61 static ClockP_Struct wakeup_clk;
62 /*---------------------------------------------------------------------------*/
63 #define H_WAKEUP_CLK (ClockP_handle(&wakeup_clk))
64 
65 #define NO_TIMEOUT (~(uint32_t)0)
66 
67 #define CLOCK_TO_SYSTEM(t) \
68  (uint32_t)(((uint64_t)(t) * 1000 * 1000) / (CLOCK_SECOND * ClockP_getSystemTickPeriod()))
69 #define SYSTEM_TO_CLOCK(t) \
70  (clock_time_t)(((uint64_t)(t) * CLOCK_SECOND * ClockP_getSystemTickPeriod()) / (1000 * 1000))
71 
72 #define RTC_SUBSEC_FRAC ((uint64_t)1 << 32) /* Important to cast to 64-bit */
73 /*---------------------------------------------------------------------------*/
74 static void
75 check_etimer(void)
76 {
77  clock_time_t now;
78  clock_time_t next_etimer;
79 
80  if(etimer_pending()) {
81  now = clock_time();
82  next_etimer = etimer_next_expiration_time();
83 
84  if(!CLOCK_LT(now, next_etimer)) {
86  }
87  }
88 }
89 /*---------------------------------------------------------------------------*/
90 static void
91 systick_fxn(void)
92 {
93  check_etimer();
94 }
95 /*---------------------------------------------------------------------------*/
96 static void
97 wakeup_fxn(uintptr_t arg)
98 {
99  (void)arg;
100  check_etimer();
101 }
102 /*---------------------------------------------------------------------------*/
103 static uint32_t
104 get_etimer_timeout(void)
105 {
106  clock_time_t now;
107  clock_time_t next_etimer;
108 
109  if(etimer_pending()) {
110  now = clock_time();
111  next_etimer = etimer_next_expiration_time();
112 
113  if(!CLOCK_LT(now, next_etimer)) {
115  /* etimer already expired, return 0 */
116  return 0;
117 
118  } else {
119  /* Convert from clock ticks to system ticks */
120  return CLOCK_TO_SYSTEM(next_etimer - now);
121  }
122  } else {
123  /* No expiration */
124  return NO_TIMEOUT;
125  }
126 }
127 /*---------------------------------------------------------------------------*/
128 static uint32_t
129 get_watchdog_timeout(void)
130 {
131 #if (WATCHDOG_DISABLE == 0)
132  /* Convert from watchdog ticks to system ticks */
133  return watchdog_arch_next_timeout() / ClockP_getSystemTickPeriod();
134 
135 #else
136  /* No expiration */
137  return NO_TIMEOUT;
138 #endif
139 }
140 /*---------------------------------------------------------------------------*/
141 bool
143 {
144  /*
145  * If the Watchdog is enabled, we must take extra care to wakeup before the
146  * Watchdog times out if the next watchdog timeout is before the next etimer
147  * timeout. This is because the Watchdog only pauses if the device enters
148  * standby. If the device enters idle, the Watchdog still runs and hence the
149  * watchdog will timeout if the next etimer timeout is longer than the
150  * watchdog timeout.
151  */
152 
153  uint32_t etimer_timeout;
154  uint32_t watchdog_timeout;
155  uint32_t timeout;
156 
157  etimer_timeout = get_etimer_timeout();
158  watchdog_timeout = get_watchdog_timeout();
159 
160  timeout = MIN(etimer_timeout, watchdog_timeout);
161  if(timeout == 0) {
162  /* We are not going to sleep, and hence we don't arm the wakeup clock. */
163  return false;
164  }
165 
166  /* We are dropping to some low-power mode */
167 
168  /* Arm the wakeup clock with the calculated timeout if there is any */
169  if(timeout != NO_TIMEOUT) {
170  ClockP_setTimeout(H_WAKEUP_CLK, timeout);
171  ClockP_start(H_WAKEUP_CLK);
172  }
173 
174  return true;
175 }
176 /*---------------------------------------------------------------------------*/
177 void
179 {
180  ClockP_stop(H_WAKEUP_CLK);
181 }
182 /*---------------------------------------------------------------------------*/
183 void
185 {
186  /*
187  * XXX: Workaround for an observed issue where if SysTick interrupt is not
188  * disabled when entering/leaving some low-power mode may in very rare
189  * occasions clobber the CPU and cause a crash.
190  */
191  SysTickIntDisable();
192 
193  /* Drop to some low-power mode */
194  PowerCC26XX_standbyPolicy();
195 
196  SysTickIntEnable();
197 }
198 /*---------------------------------------------------------------------------*/
199 void
201 {
202  ClockP_Params clk_params;
203  ClockP_FreqHz freq;
204 
205  ClockP_Params_init(&clk_params);
206  clk_params.startFlag = false;
207  clk_params.period = 0;
208  ClockP_construct(&wakeup_clk, wakeup_fxn, 0, &clk_params);
209 
210  ClockP_getCpuFreq(&freq);
211 
212  SysTickPeriodSet(freq.lo / CLOCK_SECOND);
213  SysTickIntRegister(systick_fxn);
214  SysTickIntEnable();
215  SysTickEnable();
216 }
217 /*---------------------------------------------------------------------------*/
218 clock_time_t
220 {
221  /*
222  * RTC counter is in a 64-bits format (SEC[31:0].SUBSEC[31:0]), where SUBSEC
223  * is represented in fractions of a second (VALUE/2^32).
224  */
225  uint64_t now = AONRTCCurrent64BitValueGet();
226  clock_time_t ticks = (clock_time_t)(now / (RTC_SUBSEC_FRAC / CLOCK_SECOND));
227  return ticks;
228 }
229 /*---------------------------------------------------------------------------*/
230 unsigned long
232 {
233  unsigned long sec = (unsigned long)AONRTCSecGet();
234  return sec;
235 }
236 /*---------------------------------------------------------------------------*/
237 void
238 clock_wait(clock_time_t i)
239 {
240  uint32_t usec;
241 
242  usec = (uint32_t)((1000 * 1000 * i) / CLOCK_SECOND);
243  clock_delay_usec(usec);
244 }
245 /*---------------------------------------------------------------------------*/
246 void
247 clock_delay_usec(uint16_t usec)
248 {
249  ClockP_usleep(usec);
250 }
251 /*---------------------------------------------------------------------------*/
252 /**
253  * \brief Obsolete delay function but we implement it here since some code
254  * still uses it.
255  */
256 void
257 clock_delay(unsigned int i)
258 {
259  clock_delay_usec(i);
260 }
261 /*---------------------------------------------------------------------------*/
262 /**
263  * @}
264  */
void clock_delay(unsigned int i)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock-arch.c:257
void etimer_request_poll(void)
Make the event timer aware that the clock has changed.
Definition: etimer.c:145
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock-arch.c:219
Header file of the CC13xx/CC26xx watchdog driver.
bool clock_arch_enter_idle(void)
Prepare to enter some low-power mode.
Definition: clock-arch.c:142
clock_time_t etimer_next_expiration_time(void)
Get next event timer expiration time.
Definition: etimer.c:237
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
void clock_arch_exit_idle(void)
Cleanup after returning from low-power mode.
Definition: clock-arch.c:178
Event timer header file.
uint32_t watchdog_arch_next_timeout(void)
Return the next expiration time for the Watchdog.
Definition: watchdog-arch.c:84
void clock_wait(clock_time_t i)
Wait for a given number of ticks.
Definition: clock-arch.c:238
int etimer_pending(void)
Check if there are any non-expired event timers.
Definition: etimer.c:231
void clock_init(void)
Initialize the clock library.
Definition: clock-arch.c:200
unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock-arch.c:231
Default definitions of C compiler quirk work-arounds.
void clock_delay_usec(uint16_t usec)
Delay a given number of microseconds.
Definition: clock-arch.c:247
void clock_arch_standby_policy(void)
Called by the Power driver when dropping to some low-power state.
Definition: clock-arch.c:184