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  /* enable sync with radio timer */
218  HWREGBITW(AON_RTC_BASE + AON_RTC_O_CTL, AON_RTC_CTL_RTC_UPD_EN_BITN) = 1;
219 }
220 /*---------------------------------------------------------------------------*/
221 clock_time_t
223 {
224  /*
225  * RTC counter is in a 64-bits format (SEC[31:0].SUBSEC[31:0]), where SUBSEC
226  * is represented in fractions of a second (VALUE/2^32).
227  */
228  uint64_t now = AONRTCCurrent64BitValueGet();
229  clock_time_t ticks = (clock_time_t)(now / (RTC_SUBSEC_FRAC / CLOCK_SECOND));
230  return ticks;
231 }
232 /*---------------------------------------------------------------------------*/
233 unsigned long
235 {
236  unsigned long sec = (unsigned long)AONRTCSecGet();
237  return sec;
238 }
239 /*---------------------------------------------------------------------------*/
240 void
241 clock_wait(clock_time_t i)
242 {
243  uint32_t usec;
244 
245  usec = (uint32_t)((1000 * 1000 * i) / CLOCK_SECOND);
246  clock_delay_usec(usec);
247 }
248 /*---------------------------------------------------------------------------*/
249 void
250 clock_delay_usec(uint16_t usec)
251 {
252  ClockP_usleep(usec);
253 }
254 /*---------------------------------------------------------------------------*/
255 /**
256  * \brief Obsolete delay function but we implement it here since some code
257  * still uses it.
258  */
259 void
260 clock_delay(unsigned int i)
261 {
262  clock_delay_usec(i);
263 }
264 /*---------------------------------------------------------------------------*/
265 /**
266  * @}
267  */
void clock_delay(unsigned int i)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock-arch.c:260
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:222
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:241
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:234
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:250
void clock_arch_standby_policy(void)
Called by the Power driver when dropping to some low-power state.
Definition: clock-arch.c:184