Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:14

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSAPIClassicTimecounter
0007  *
0008  * @brief This header file provides the Timecounter Support API.
0009  */
0010 
0011 /*
0012  * Copyright (c) 2015 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifndef _RTEMS_TIMECOUNTER_H
0037 #define _RTEMS_TIMECOUNTER_H
0038 
0039 #include <rtems/score/timecounter.h>
0040 #include <rtems/score/basedefs.h>
0041 
0042 #ifdef __cplusplus
0043 extern "C" {
0044 #endif /* __cplusplus */
0045 
0046 /**
0047  * @defgroup RTEMSAPIClassicTimecounter Timecounter Support
0048  *
0049  * @ingroup RTEMSAPIClassic
0050  *
0051  * @brief The timecounter support provides directives to implement clock device
0052  *   drivers.
0053  *
0054  * @{
0055  */
0056 
0057 /**
0058  * @brief Timecounter quality for the clock drivers.
0059  *
0060  * Timecounter with higher quality value are used in favour of those with lower
0061  * quality value.
0062  */
0063 #define RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER 100
0064 
0065 /**
0066  * @copydoc _Timecounter_Install()
0067  *
0068  * Below is an exemplary code snippet that shows the adjustable parameters and
0069  * the following call of the install routine.
0070  *
0071  * @code
0072  * struct timecounter tc;
0073  *
0074  * uint32_t get_timecount( struct timecounter *tc )
0075  * {
0076  *   return some_free_running_counter;
0077  * }
0078  *
0079  * void install( void )
0080  * {
0081  *   tc.tc_get_timecount = get_timecount;
0082  *   tc.tc_counter_mask = 0xffffffff;
0083  *   tc.tc_frequency = 123456;
0084  *   tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
0085  *   rtems_timecounter_install( &tc );
0086  * }
0087  * @endcode
0088  */
0089 static inline void rtems_timecounter_install(
0090   struct timecounter *tc
0091 )
0092 {
0093   _Timecounter_Install( tc );
0094 }
0095 
0096 /**
0097  * @copydoc _Timecounter_Tick()
0098  */
0099 static inline void rtems_timecounter_tick(void)
0100 {
0101   _Timecounter_Tick();
0102 }
0103 
0104 /**
0105  * @brief Simple timecounter to support legacy clock drivers.
0106  */
0107 typedef struct {
0108   struct timecounter tc;
0109   uint64_t scaler;
0110   uint32_t real_interval;
0111   uint32_t binary_interval;
0112 } rtems_timecounter_simple;
0113 
0114 /**
0115  * @brief At tick handling done under protection of the timecounter lock.
0116  */
0117 typedef void rtems_timecounter_simple_at_tick(
0118   rtems_timecounter_simple *tc
0119 );
0120 
0121 /**
0122  * @brief Returns the current value of a simple timecounter.
0123  */
0124 typedef uint32_t rtems_timecounter_simple_get(
0125   rtems_timecounter_simple *tc
0126 );
0127 
0128 /**
0129  * @brief Returns true if the interrupt of a simple timecounter is pending, and
0130  * false otherwise.
0131  */
0132 typedef bool rtems_timecounter_simple_is_pending(
0133   rtems_timecounter_simple *tc
0134 );
0135 
0136 /**
0137  * @brief Initializes and installs a simple timecounter.
0138  *
0139  * A simple timecounter can be used if the hardware provides no free running
0140  * counter.  A periodic hardware counter must be provided.  The counter period
0141  * must be synchronous to the clock tick.  The counter ticks per clock tick is
0142  * scaled up to the next power of two.
0143  *
0144  * @param[in] tc Zero initialized simple timecounter.
0145  * @param[in] counter_frequency_in_hz The hardware counter frequency in Hz.
0146  * @param[in] counter_ticks_per_clock_tick The hardware counter ticks per clock
0147  *   tick.
0148  * @param[in] get_timecount The method to get the current time count.
0149  *
0150  * @code
0151  * #include <rtems/timecounter.h>
0152  *
0153  * static rtems_timecounter_simple some_tc;
0154  *
0155  * static uint32_t some_tc_get( rtems_timecounter_simple *tc )
0156  * {
0157  *   return some.value;
0158  * }
0159  *
0160  * static bool some_tc_is_pending( rtems_timecounter_simple *tc )
0161  * {
0162  *   return some.is_pending;
0163  * }
0164  *
0165  * static uint32_t some_tc_get_timecount( struct timecounter *tc )
0166  * {
0167  *   return rtems_timecounter_simple_downcounter_get(
0168  *     tc,
0169  *     some_tc_get,
0170  *     some_tc_is_pending
0171  *   );
0172  * }
0173  *
0174  * static void some_tc_tick( void )
0175  * {
0176  *   rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get );
0177  * }
0178  *
0179  * void some_tc_init( void )
0180  * {
0181  *   uint64_t us_per_tick;
0182  *   uint32_t counter_frequency_in_hz;
0183  *   uint32_t counter_ticks_per_clock_tick;
0184  *
0185  *   us_per_tick = rtems_configuration_get_microseconds_per_tick();
0186  *   counter_frequency_in_hz = some_tc_get_frequency();
0187  *   counter_ticks_per_clock_tick =
0188  *     (uint32_t) ( counter_frequency_in_hz * us_per_tick ) / 1000000;
0189  *
0190  *   some_tc_init_hardware( counter_ticks_per_clock_tick );
0191  *   some_tc_init_clock_tick_interrupt( some_tc_tick );
0192  *
0193  *   rtems_timecounter_simple_install(
0194  *     &some_tc,
0195  *     counter_frequency_in_hz,
0196  *     counter_ticks_per_clock_tick,
0197  *     some_tc_get_timecount
0198  *   );
0199  * }
0200  * @endcode
0201  *
0202  * @see rtems_timecounter_simple_downcounter_get(),
0203  * rtems_timecounter_simple_downcounter_tick(),
0204  * rtems_timecounter_simple_upcounter_get() and
0205  * rtems_timecounter_simple_upcounter_tick().
0206  */
0207 void rtems_timecounter_simple_install(
0208   rtems_timecounter_simple *tc,
0209   uint32_t                  counter_frequency_in_hz,
0210   uint32_t                  counter_ticks_per_clock_tick,
0211   timecounter_get_t        *get_timecount
0212 );
0213 
0214 /**
0215  * @brief Maps a simple timecounter value into its binary frequency domain.
0216  *
0217  * @param[in] tc The simple timecounter.
0218  * @param[in] value The value of the simple timecounter.
0219  *
0220  * @return The scaled value.
0221  */
0222 static inline uint32_t rtems_timecounter_simple_scale(
0223   const rtems_timecounter_simple *tc,
0224   uint32_t value
0225 )
0226 {
0227   return (uint32_t) ( ( value * tc->scaler ) >> 32 );
0228 }
0229 
0230 /**
0231  * @brief Performs a simple timecounter tick for downcounters.
0232  *
0233  * @param[in] tc The simple timecounter.
0234  * @param[in] get The method to get the value of the simple timecounter.
0235  * @param[in] at_tick The method to perform work under timecounter lock
0236  * protection at this tick, e.g. clear a pending flag.
0237  */
0238 static inline void rtems_timecounter_simple_downcounter_tick(
0239   rtems_timecounter_simple         *tc,
0240   rtems_timecounter_simple_get      get,
0241   rtems_timecounter_simple_at_tick  at_tick
0242 )
0243 {
0244   ISR_lock_Context lock_context;
0245   uint32_t current;
0246 
0247   _Timecounter_Acquire( &lock_context );
0248 
0249   ( *at_tick )( tc );
0250 
0251   current = rtems_timecounter_simple_scale(
0252     tc,
0253     tc->real_interval - ( *get )( tc )
0254   );
0255 
0256   _Timecounter_Tick_simple( tc->binary_interval, current, &lock_context );
0257 }
0258 
0259 /**
0260  * @brief Performs a simple timecounter tick for upcounters.
0261  *
0262  * @param[in] tc The simple timecounter.
0263  * @param[in] get The method to get the value of the simple timecounter.
0264  * @param[in] at_tick The method to perform work under timecounter lock
0265  * protection at this tick, e.g. clear a pending flag.
0266  */
0267 static inline void rtems_timecounter_simple_upcounter_tick(
0268   rtems_timecounter_simple         *tc,
0269   rtems_timecounter_simple_get      get,
0270   rtems_timecounter_simple_at_tick  at_tick
0271 )
0272 {
0273   ISR_lock_Context lock_context;
0274   uint32_t current;
0275 
0276   _Timecounter_Acquire( &lock_context );
0277 
0278   ( *at_tick )( tc );
0279 
0280   current = rtems_timecounter_simple_scale( tc, ( *get )( tc ) );
0281 
0282   _Timecounter_Tick_simple( tc->binary_interval, current, &lock_context );
0283 }
0284 
0285 /**
0286  * @brief Gets the simple timecounter value mapped to its binary frequency
0287  * domain for downcounters.
0288  *
0289  * @param[in] tc The simple timecounter.
0290  * @param[in] get The method to get the value of the simple timecounter.
0291  * @param[in] is_pending The method which indicates if the interrupt of the
0292  * simple timecounter is pending.
0293  */
0294 static inline uint32_t rtems_timecounter_simple_downcounter_get(
0295   struct timecounter                  *tc_base,
0296   rtems_timecounter_simple_get         get,
0297   rtems_timecounter_simple_is_pending  is_pending
0298 )
0299 {
0300   rtems_timecounter_simple *tc;
0301   uint32_t counter;
0302   uint32_t interval;
0303 
0304   tc = (rtems_timecounter_simple *) tc_base;
0305   counter = ( *get )( tc );
0306   interval = tc->real_interval;
0307 
0308   if ( ( *is_pending )( tc ) ) {
0309     counter = ( *get )( tc );
0310     interval *= 2;
0311   }
0312 
0313   return rtems_timecounter_simple_scale( tc, interval - counter );
0314 }
0315 
0316 /**
0317  * @brief Gets the simple timecounter value mapped to its binary frequency
0318  * domain for upcounters.
0319  *
0320  * @param[in] tc The simple timecounter.
0321  * @param[in] get The method to get the value of the simple timecounter.
0322  * @param[in] is_pending The method which indicates if the interrupt of the
0323  * simple timecounter is pending.
0324  */
0325 static inline uint32_t rtems_timecounter_simple_upcounter_get(
0326   struct timecounter                  *tc_base,
0327   rtems_timecounter_simple_get         get,
0328   rtems_timecounter_simple_is_pending  is_pending
0329 )
0330 {
0331   rtems_timecounter_simple *tc;
0332   uint32_t counter;
0333   uint32_t interval;
0334 
0335   tc = (rtems_timecounter_simple *) tc_base;
0336   counter = ( *get )( tc );
0337   interval = 0;
0338 
0339   if ( ( *is_pending )( tc ) ) {
0340     counter = ( *get )( tc );
0341     interval = tc->real_interval;
0342   }
0343 
0344   return rtems_timecounter_simple_scale( tc, interval + counter );
0345 }
0346 
0347 /** @} */
0348 
0349 #ifdef __cplusplus
0350 }
0351 #endif /* __cplusplus */
0352 
0353 #endif /* _RTEMS_TIMECOUNTER_H */