source: rtems/cpukit/sapi/include/rtems/timecounter.h @ 76ac1ee3

5
Last change on this file since 76ac1ee3 was 76ac1ee3, checked in by Sebastian Huber <sebastian.huber@…>, on 12/23/15 at 06:29:47

score: Fix simple timecounter support

Update #2502.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup SAPITimecounter
5 *
6 * @brief Timecounter API
7 */
8
9/*
10 * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#ifndef _RTEMS_TIMECOUNTER_H
24#define _RTEMS_TIMECOUNTER_H
25
26#include <rtems/score/timecounter.h>
27#include <rtems/score/basedefs.h>
28
29#ifdef __cplusplus
30extern "C" {
31#endif /* __cplusplus */
32
33/**
34 * @defgroup SAPITimecounter Timecounter Support
35 *
36 * @{
37 */
38
39/**
40 * @brief Timecounter quality for the clock drivers.
41 *
42 * Timecounter with higher quality value are used in favour of those with lower
43 * quality value.
44 */
45#define RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER 100
46
47/**
48 * @copydoc _Timecounter_Install()
49 *
50 * Below is an exemplary code snippet that shows the adjustable parameters and
51 * the following call of the install routine.
52 *
53 * @code
54 * struct timecounter tc;
55 *
56 * uint32_t get_timecount( struct timecounter *tc )
57 * {
58 *   return some_free_running_counter;
59 * }
60 *
61 * void install( void )
62 * {
63 *   tc.tc_get_timecount = get_timecount;
64 *   tc.tc_counter_mask = 0xffffffff;
65 *   tc.tc_frequency = 123456;
66 *   tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
67 *   rtems_timecounter_install( &tc );
68 * }
69 * @endcode
70 */
71RTEMS_INLINE_ROUTINE void rtems_timecounter_install(
72  struct timecounter *tc
73)
74{
75  _Timecounter_Install( tc );
76}
77
78/**
79 * @copydoc _Timecounter_Tick()
80 */
81RTEMS_INLINE_ROUTINE void rtems_timecounter_tick(void)
82{
83  _Timecounter_Tick();
84}
85
86/**
87 * @brief Simple timecounter to support legacy clock drivers.
88 */
89typedef struct {
90  struct timecounter tc;
91  uint64_t scaler;
92  uint32_t real_interval;
93  uint32_t binary_interval;
94} rtems_timecounter_simple;
95
96/**
97 * @brief At tick handling done under protection of the timecounter lock.
98 */
99typedef void rtems_timecounter_simple_at_tick(
100  rtems_timecounter_simple *tc
101);
102
103/**
104 * @brief Returns the current value of a simple timecounter.
105 */
106typedef uint32_t rtems_timecounter_simple_get(
107  rtems_timecounter_simple *tc
108);
109
110/**
111 * @brief Returns true if the interrupt of a simple timecounter is pending, and
112 * false otherwise.
113 */
114typedef bool rtems_timecounter_simple_is_pending(
115  rtems_timecounter_simple *tc
116);
117
118/**
119 * @brief Initializes and installs a simple timecounter.
120 *
121 * A simple timecounter can be used if the hardware provides no free running
122 * counter or only the module used for the clock tick is available.  The period
123 * of the simple timecounter equals the clock tick interval.  The interval is
124 * scaled up to the next power of two.
125 *
126 * @param[in] tc Zero initialized simple timecounter.
127 * @param[in] frequency_in_hz The timecounter frequency in Hz.
128 * @param[in] timecounter_ticks_per_clock_tick The timecounter ticks per clock tick.
129 * @param[in] get_timecount The method to get the current time count.
130 *
131 * @code
132 * #include <rtems/timecounter.h>
133 *
134 * static rtems_timecounter_simple some_tc;
135 *
136 * static uint32_t some_tc_get( rtems_timecounter_simple *tc )
137 * {
138 *   return some.value;
139 * }
140 *
141 * static bool some_tc_is_pending( rtems_timecounter_simple *tc )
142 * {
143 *   return some.is_pending;
144 * }
145 *
146 * static uint32_t some_tc_get_timecount( struct timecounter *tc )
147 * {
148 *   return rtems_timecounter_simple_downcounter_get(
149 *     tc,
150 *     some_tc_get,
151 *     some_tc_is_pending
152 *   );
153 * }
154 *
155 * static void some_tc_tick( void )
156 * {
157 *   rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get );
158 * }
159 *
160 * void install( void )
161 * {
162 *   uint32_t frequency = 123456;
163 *   uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
164 *   uint32_t timecounter_ticks_per_clock_tick =
165 *     ( frequency * us_per_tick ) / 1000000;
166 *
167 *   rtems_timecounter_simple_install(
168 *     &some_tc,
169 *     frequency,
170 *     timecounter_ticks_per_clock_tick,
171 *     some_tc_get_timecount
172 *   );
173 * }
174 * @endcode
175 *
176 * @see rtems_timecounter_simple_downcounter_get(),
177 * rtems_timecounter_simple_downcounter_tick(),
178 * rtems_timecounter_simple_upcounter_get() and
179 * rtems_timecounter_simple_upcounter_tick().
180 */
181void rtems_timecounter_simple_install(
182  rtems_timecounter_simple *tc,
183  uint32_t                  frequency_in_hz,
184  uint32_t                  timecounter_ticks_per_clock_tick,
185  timecounter_get_t        *get_timecount
186);
187
188/**
189 * @brief Maps a simple timecounter value into its binary frequency domain.
190 *
191 * @param[in] tc The simple timecounter.
192 * @param[in] value The value of the simple timecounter.
193 *
194 * @return The scaled value.
195 */
196RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_scale(
197  const rtems_timecounter_simple *tc,
198  uint32_t value
199)
200{
201  return (uint32_t) ( ( value * tc->scaler ) >> 32 );
202}
203
204/**
205 * @brief Performs a simple timecounter tick for downcounters.
206 *
207 * @param[in] tc The simple timecounter.
208 * @param[in] get The method to get the value of the simple timecounter.
209 * @param[in] at_tick The method to perform work under timecounter lock
210 * protection at this tick, e.g. clear a pending flag.
211 */
212RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_downcounter_tick(
213  rtems_timecounter_simple         *tc,
214  rtems_timecounter_simple_get      get,
215  rtems_timecounter_simple_at_tick  at_tick
216)
217{
218  ISR_lock_Context lock_context;
219  uint32_t current;
220
221  _Timecounter_Acquire( &lock_context );
222
223  ( *at_tick )( tc );
224
225  current = rtems_timecounter_simple_scale(
226    tc,
227    tc->real_interval - ( *get )( tc )
228  );
229
230  _Timecounter_Tick_simple( tc->binary_interval, current, &lock_context );
231}
232
233/**
234 * @brief Performs a simple timecounter tick for upcounters.
235 *
236 * @param[in] tc The simple timecounter.
237 * @param[in] get The method to get the value of the simple timecounter.
238 * @param[in] at_tick The method to perform work under timecounter lock
239 * protection at this tick, e.g. clear a pending flag.
240 */
241RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_upcounter_tick(
242  rtems_timecounter_simple         *tc,
243  rtems_timecounter_simple_get      get,
244  rtems_timecounter_simple_at_tick  at_tick
245)
246{
247  ISR_lock_Context lock_context;
248  uint32_t current;
249
250  _Timecounter_Acquire( &lock_context );
251
252  ( *at_tick )( tc );
253
254  current = rtems_timecounter_simple_scale( tc, ( *get )( tc ) );
255
256  _Timecounter_Tick_simple( tc->binary_interval, current, &lock_context );
257}
258
259/**
260 * @brief Gets the simple timecounter value mapped to its binary frequency
261 * domain for downcounters.
262 *
263 * @param[in] tc The simple timecounter.
264 * @param[in] get The method to get the value of the simple timecounter.
265 * @param[in] is_pending The method which indicates if the interrupt of the
266 * simple timecounter is pending.
267 */
268RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_downcounter_get(
269  struct timecounter                  *tc_base,
270  rtems_timecounter_simple_get         get,
271  rtems_timecounter_simple_is_pending  is_pending
272)
273{
274  rtems_timecounter_simple *tc;
275  uint32_t counter;
276  uint32_t interval;
277
278  tc = (rtems_timecounter_simple *) tc_base;
279  counter = ( *get )( tc );
280  interval = tc->real_interval;
281
282  if ( ( *is_pending )( tc ) ) {
283    counter = ( *get )( tc );
284    interval *= 2;
285  }
286
287  return rtems_timecounter_simple_scale( tc, interval - counter );
288}
289
290/**
291 * @brief Gets the simple timecounter value mapped to its binary frequency
292 * domain for upcounters.
293 *
294 * @param[in] tc The simple timecounter.
295 * @param[in] get The method to get the value of the simple timecounter.
296 * @param[in] is_pending The method which indicates if the interrupt of the
297 * simple timecounter is pending.
298 */
299RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_upcounter_get(
300  struct timecounter                  *tc_base,
301  rtems_timecounter_simple_get         get,
302  rtems_timecounter_simple_is_pending  is_pending
303)
304{
305  rtems_timecounter_simple *tc;
306  uint32_t counter;
307  uint32_t interval;
308
309  tc = (rtems_timecounter_simple *) tc_base;
310  counter = ( *get )( tc );
311  interval = 0;
312
313  if ( ( *is_pending )( tc ) ) {
314    counter = ( *get )( tc );
315    interval = tc->real_interval;
316  }
317
318  return rtems_timecounter_simple_scale( tc, interval + counter );
319}
320
321/** @} */
322
323#ifdef __cplusplus
324}
325#endif /* __cplusplus */
326
327#endif /* _RTEMS_TIMECOUNTER_H */
Note: See TracBrowser for help on using the repository browser.