Mistake on this page?
Report an issue in GitHub or email us
SysTimer.h
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2019 ARM Limited
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #ifndef MBED_SYS_TIMER_H
18 #define MBED_SYS_TIMER_H
19 
20 #include "platform/NonCopyable.h"
21 #include "platform/mbed_atomic.h"
22 #include "drivers/TimerEvent.h"
23 #include <chrono>
24 #include "cmsis.h"
25 
26 extern "C" {
27 #if defined(TARGET_CORTEX_A)
28 #include "irq_ctrl.h"
29 #endif
30 }
31 
32 namespace mbed {
33 namespace internal {
34 
35 /**
36  * \defgroup mbed_SysTimer SysTimer class
37  * \ingroup platform-internal-api
38  * @{
39  */
40 
41 /**
42  * The SysTimer class is used to provide timing for system suspension, and
43  * the idle loop in TICKLESS mode.
44  *
45  * Template for speed for testing - only one instance will be used normally.
46  *
47  * @note SysTimer is not the part of Mbed API.
48  */
49 template <class Period, bool IRQ = true>
50 class SysTimer: private mbed::TimerEvent, private mbed::NonCopyable<SysTimer<Period, IRQ> > {
51 public:
52 
53  /* pseudo-Clock for our ticks - see TickerDataClock for more discussion */
54  using rep = uint64_t;
55  using period = Period;
56  using duration = std::chrono::duration<uint64_t, period>;
57  using time_point = std::chrono::time_point<SysTimer>;
58  static const bool is_steady = false;
59 
60  /** duration type used for underlying high-res timer */
61  using highres_duration = TickerDataClock::duration;
62  /** time_point type used for underlying high-res timer */
63  using highres_time_point = TickerDataClock::time_point;
64  /** period of underlying high-res timer */
65  using highres_period = TickerDataClock::period;
66 
67  static_assert(std::ratio_divide<period, highres_period>::den == 1, "Tick period must be an exact multiple of highres time period");
68 
69  /**
70  * Default constructor uses LPTICKER if available (so the timer will
71  * continue to run in deep sleep), else USTICKER.
72  */
73  SysTimer();
74 
75  SysTimer(const ticker_data_t *data);
76 
77 protected:
78  ~SysTimer();
79 
80 public:
81  /**
82  * Get the interrupt number for the tick
83  *
84  * @return interrupt number
85  */
86 #if TARGET_CORTEX_A
87  static IRQn_ID_t get_irq_number();
88 #elif TARGET_CORTEX_M
89  static IRQn_Type get_irq_number();
90 #endif
91 
92  /**
93  * Set the wake time
94  *
95  * Schedules an interrupt to cause wake-up in time for the event. Interrupt
96  * may be arranged early to account for latency. If the time has already
97  * passed, no interrupt will be scheduled.
98  *
99  * This is called from outside a critical section, as it is known to be
100  * a slow operation.
101  *
102  * If the wake time is already set, this is a no-op. But that check is racy,
103  * which means wake_time_set() should be rechecked after taking a critical
104  * section.
105  *
106  * As a side-effect, this clears the unacknowledged tick count - the caller
107  * is expected to use update_and_get_tick() after the suspend operation.
108  *
109  * @param at Wake up tick
110  * @warning If the ticker tick is already scheduled it needs to be cancelled first!
111  */
112  void set_wake_time(time_point at);
113 
114  /**
115  * Check whether the wake time has passed
116  *
117  * This is a fast operation, based on checking whether the wake interrupt
118  * has run.
119  *
120  * @return true if the specified wake tick has passed
121  */
122  bool wake_time_passed() const
123  {
124  return core_util_atomic_load_bool(&_wake_time_passed);
125  }
126 
127  /**
128  * Check whether wake timer is active
129  *
130  * @return true if the wake timer is active.
131  */
132  bool wake_time_set() const
133  {
134  return core_util_atomic_load_bool(&_wake_time_set);
135  }
136 
137  /**
138  * Cancel any pending wake
139  */
140  void cancel_wake();
141 
142  /**
143  * Schedule an os tick to fire
144  *
145  * Ticks will be rescheduled automatically every tick until cancel_tick is called.
146  *
147  * A tick will be fired immediately if there are any unacknowledged ticks.
148  *
149  * @warning If a tick is already scheduled it needs to be cancelled first!
150  */
151  void start_tick();
152 
153  /**
154  * Acknowledge an os tick
155  *
156  * This will queue another os tick immediately if the os is running slow
157  */
158  void acknowledge_tick();
159 
160  /**
161  * Prevent any more scheduled ticks from triggering
162  *
163  * If called from OS tick context, there may be remaining unacknowledged ticks.
164  */
165  void cancel_tick();
166 
167  /**
168  * Check whether ticker is active
169  *
170  * Each time the tick interrupt fires, it is automatically rescheduled,
171  * so this will remain true once the tick is started, except during
172  * processing.
173  *
174  * @return true if the ticker is active.
175  */
176  bool ticking() const
177  {
178  return core_util_atomic_load_bool(&_ticking);
179  }
180 
181  /**
182  * Check unacknowledged ticks
183  *
184  * Returns the count of how many times the OS timer has been queued minus
185  * the number of times is has been acknowledged.
186  *
187  * get_tick() - unacknowledged_ticks() should equal the OS's tick count,
188  * although such a calculation is not atomic if the ticker is currently running.
189  *
190  * @return number of unacknowledged ticks
191  */
192  std::chrono::duration<int, period> unacknowledged_ticks() const
193  {
194  return std::chrono::duration<int, period>(core_util_atomic_load_u32(&_unacknowledged_ticks));
195  }
196 
197  /** Get the current tick count
198  *
199  * This count is updated by the ticker interrupt, if the ticker interrupt
200  * is running. It the ticker interrupt is not running, update_and_get_tick()
201  * should be used instead.
202  *
203  * This indicates how many ticks have been generated by the tick interrupt.
204  * The os_timer should equal this number minus the number of unacknowledged ticks.
205  *
206  * @return The number of ticks since timer creation.
207  */
208  time_point get_tick() const;
209 
210  /** Update and get the current tick count
211  *
212  * This is a slow operation that reads the timer and adjusts for elapsed time.
213  * Can only be used when the ticker is not running, as there is no IRQ
214  * synchronization.
215  *
216  * This clears the unacknowledged tick counter - the caller is assumed to update
217  * their timer based on this return.
218  *
219  * @return The number of ticks since timer creation.
220  */
221  time_point update_and_get_tick();
222 
223  /**
224  * Returns time since last tick
225  *
226  * @return Relative time in microseconds
227  */
229 
230  /**
231  * Get the time
232  *
233  * Returns the instantaneous precision time from underlying timer.
234  * This is a slow operation so should not be called from critical sections.
235  *
236  * @return Current time in microseconds
237  */
239 
240 protected:
241  using highres_duration_u32 = std::chrono::duration<uint32_t, highres_period>;
242  void handler() override;
243  void _increment_tick();
244  void _schedule_tick();
245  duration _elapsed_ticks() const;
246  static void _set_irq_pending();
247  static void _clear_irq_pending();
248  const highres_time_point _epoch;
249  highres_time_point _time;
250  uint64_t _tick;
251  uint32_t _unacknowledged_ticks;
252  bool _wake_time_set;
253  bool _wake_time_passed;
254  bool _wake_early;
255  bool _ticking;
256  bool _deep_sleep_locked;
257 };
258 
259 /** @} */
260 
261 }
262 }
263 
264 #endif
TickerDataClock::period highres_period
period of underlying high-res timer
Definition: SysTimer.h:65
void cancel_wake()
Cancel any pending wake.
void start_tick()
Schedule an os tick to fire.
TickerDataClock::time_point highres_time_point
time_point type used for underlying high-res timer
Definition: SysTimer.h:63
Ticker&#39;s data structure.
Definition: ticker_api.h:93
SysTimer()
Default constructor uses LPTICKER if available (so the timer will continue to run in deep sleep)...
Prevents generation of copy constructor and copy assignment operator in derived classes.
Definition: NonCopyable.h:162
highres_time_point get_time() const
Get the time.
bool wake_time_passed() const
Check whether the wake time has passed.
Definition: SysTimer.h:122
bool wake_time_set() const
Check whether wake timer is active.
Definition: SysTimer.h:132
time_point get_tick() const
Get the current tick count.
time_point update_and_get_tick()
Update and get the current tick count.
The SysTimer class is used to provide timing for system suspension, and the idle loop in TICKLESS mod...
Definition: SysTimer.h:50
Base abstraction for timer interrupts.
Definition: TimerEvent.h:37
MBED_FORCEINLINE bool core_util_atomic_load_bool(const volatile bool *valuePtr)
Atomic load.
TickerDataClock::duration highres_duration
duration type used for underlying high-res timer
Definition: SysTimer.h:61
void set_wake_time(time_point at)
Get the interrupt number for the tick.
void cancel_tick()
Prevent any more scheduled ticks from triggering.
bool ticking() const
Check whether ticker is active.
Definition: SysTimer.h:176
highres_duration get_time_since_tick() const
Returns time since last tick.
MBED_FORCEINLINE uint32_t core_util_atomic_load_u32(const volatile uint32_t *valuePtr)
Atomic load.
Definition: ATHandler.h:46
std::chrono::duration< int, period > unacknowledged_ticks() const
Check unacknowledged ticks.
Definition: SysTimer.h:192
void acknowledge_tick()
Acknowledge an os tick.
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.