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 /*---------------------------------------------------------------------------*/
55 #include "watchdog-arch.h"
56 /*---------------------------------------------------------------------------*/
57 #include <stdbool.h>
58 #include <stdint.h>
59 /*---------------------------------------------------------------------------*/
60 static ClockP_Struct wakeup_clk;
61 /*---------------------------------------------------------------------------*/
62 #define H_WAKEUP_CLK (ClockP_handle(&wakeup_clk))
63 
64 #define NO_TIMEOUT (~(uint32_t)0)
65 
66 #define CLOCK_TO_SYSTEM(t) \
67  (uint32_t)(((uint64_t)(t) * 1000 * 1000) / (CLOCK_SECOND * ClockP_getSystemTickPeriod()))
68 #define SYSTEM_TO_CLOCK(t) \
69  (clock_time_t)(((uint64_t)(t) * CLOCK_SECOND * ClockP_getSystemTickPeriod()) / (1000 * 1000))
70 
71 #define RTC_SUBSEC_FRAC ((uint64_t)1 << 32) /* Important to cast to 64-bit */
72 /*---------------------------------------------------------------------------*/
73 static void
74 check_etimer(void)
75 {
76  clock_time_t now;
77  clock_time_t next_etimer;
78 
79  if(etimer_pending()) {
80  now = clock_time();
81  next_etimer = etimer_next_expiration_time();
82 
83  if(!CLOCK_LT(now, next_etimer)) {
85  }
86  }
87 }
88 /*---------------------------------------------------------------------------*/
89 static void
90 systick_fxn(void)
91 {
92  check_etimer();
93 }
94 /*---------------------------------------------------------------------------*/
95 static void
96 wakeup_fxn(uintptr_t arg)
97 {
98  (void)arg;
99  check_etimer();
100 }
101 /*---------------------------------------------------------------------------*/
102 static uint32_t
103 get_etimer_timeout(void)
104 {
105  clock_time_t now;
106  clock_time_t next_etimer;
107 
108  if(etimer_pending()) {
109  now = clock_time();
110  next_etimer = etimer_next_expiration_time();
111 
112  if(!CLOCK_LT(now, next_etimer)) {
114  /* etimer already expired, return 0 */
115  return 0;
116 
117  } else {
118  /* Convert from clock ticks to system ticks */
119  return CLOCK_TO_SYSTEM(next_etimer - now);
120  }
121  } else {
122  /* No expiration */
123  return NO_TIMEOUT;
124  }
125 }
126 /*---------------------------------------------------------------------------*/
127 static uint32_t
128 get_watchdog_timeout(void)
129 {
130 #if (WATCHDOG_DISABLE == 0)
131  /* Convert from watchdog ticks to system ticks */
132  return watchdog_arch_next_timeout() / ClockP_getSystemTickPeriod();
133 
134 #else
135  /* No expiration */
136  return NO_TIMEOUT;
137 #endif
138 }
139 /*---------------------------------------------------------------------------*/
140 bool
142 {
143  /*
144  * If the Watchdog is enabled, we must take extra care to wakeup before the
145  * Watchdog times out if the next watchdog timeout is before the next etimer
146  * timeout. This is because the Watchdog only pauses if the device enters
147  * standby. If the device enters idle, the Watchdog still runs and hence the
148  * watchdog will timeout if the next etimer timeout is longer than the
149  * watchdog timeout.
150  */
151 
152  uint32_t etimer_timeout;
153  uint32_t watchdog_timeout;
154  uint32_t timeout;
155 
156  etimer_timeout = get_etimer_timeout();
157  watchdog_timeout = get_watchdog_timeout();
158 
159  timeout = MIN(etimer_timeout, watchdog_timeout);
160  if(timeout == 0) {
161  /* We are not going to sleep, and hence we don't arm the wakeup clock. */
162  return false;
163  }
164  if(timeout == NO_TIMEOUT) {
165  /* We are going to some low-power mode without arming the wakeup clock. */
166  return true;
167  }
168 
169  /*
170  * We are going to some low-power mode. Arm the wakeup clock with the
171  * calculated.
172  */
173  ClockP_setTimeout(H_WAKEUP_CLK, timeout);
174  ClockP_start(H_WAKEUP_CLK);
175  return true;
176 }
177 /*---------------------------------------------------------------------------*/
178 void
180 {
181  ClockP_stop(H_WAKEUP_CLK);
182 }
183 /*---------------------------------------------------------------------------*/
184 void
186 {
187  ClockP_Params clk_params;
188  ClockP_FreqHz freq;
189 
190  ClockP_Params_init(&clk_params);
191  clk_params.startFlag = false;
192  clk_params.period = 0;
193  ClockP_construct(&wakeup_clk, wakeup_fxn, 0, &clk_params);
194 
195  ClockP_getCpuFreq(&freq);
196 
197  SysTickPeriodSet(freq.lo / CLOCK_SECOND);
198  SysTickIntRegister(systick_fxn);
199  SysTickIntEnable();
200  SysTickEnable();
201 }
202 /*---------------------------------------------------------------------------*/
203 clock_time_t
205 {
206  /*
207  * RTC counter is in a 64-bits format (SEC[31:0].SUBSEC[31:0]), where SUBSEC
208  * is represented in fractions of a second (VALUE/2^32).
209  */
210  uint64_t now = AONRTCCurrent64BitValueGet();
211  clock_time_t ticks = (clock_time_t)(now / (RTC_SUBSEC_FRAC / CLOCK_SECOND));
212  return ticks;
213 }
214 /*---------------------------------------------------------------------------*/
215 unsigned long
217 {
218  unsigned long sec = (unsigned long)AONRTCSecGet();
219  return sec;
220 }
221 /*---------------------------------------------------------------------------*/
222 void
223 clock_wait(clock_time_t i)
224 {
225  uint32_t usec;
226 
227  usec = (uint32_t)((1000 * 1000 * i) / CLOCK_SECOND);
228  clock_delay_usec(usec);
229 }
230 /*---------------------------------------------------------------------------*/
231 void
232 clock_delay_usec(uint16_t usec)
233 {
234  ClockP_usleep(usec);
235 }
236 /*---------------------------------------------------------------------------*/
237 /**
238  * \brief Obsolete delay function but we implement it here since some code
239  * still uses it.
240  */
241 void
242 clock_delay(unsigned int i)
243 {
244  clock_delay_usec(i);
245 }
246 /*---------------------------------------------------------------------------*/
247 /**
248  * @}
249  */
void clock_delay(unsigned int i)
Obsolete delay function but we implement it here since some code still uses it.
Definition: clock-arch.c:242
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:204
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:141
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:179
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:223
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:185
unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock-arch.c:216
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:232