From 0cb6bc9b9d260beb05fcc9e2ec4d72f0ba621b71 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 28 Jul 2013 12:15:57 +0000 Subject: RT measurements unit added. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/kernel_3_dev@6036 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/kernel/include/ch.h | 4 +- os/kernel/include/chrt.h | 98 ++++++-------------- os/kernel/include/chvt.h | 17 ++-- os/kernel/kernel.mk | 1 + os/kernel/src/chrt.c | 206 ++++++++++++++++++++++++++++++++++++++++++ os/kernel/src/chsys.c | 3 + os/kernel/src/chthreads.c | 2 +- os/ports/GCC/ARMCMx/chtypes.h | 7 ++ 8 files changed, 257 insertions(+), 81 deletions(-) create mode 100644 os/kernel/src/chrt.c diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h index c7e3ec80d..1d1e053ce 100644 --- a/os/kernel/include/ch.h +++ b/os/kernel/include/ch.h @@ -109,11 +109,11 @@ typedef struct thread thread_t; #include "chtypes.h" #include "chdebug.h" #include "chcore.h" +#include "chsys.h" +#include "chvt.h" #include "chrt.h" #include "chthreads.h" #include "chlists.h" -#include "chsys.h" -#include "chvt.h" #include "chschd.h" #include "chregistry.h" #include "chsem.h" diff --git a/os/kernel/include/chrt.h b/os/kernel/include/chrt.h index bac5635dc..dfb2a4277 100644 --- a/os/kernel/include/chrt.h +++ b/os/kernel/include/chrt.h @@ -22,7 +22,7 @@ * @file chrt.h * @brief Real Time Counter and Measurement module macros and structures. * - * @addtogroup rt_measurement + * @addtogroup realtime_counter * @{ */ @@ -45,17 +45,29 @@ /* Derived constants and error checks. */ /*===========================================================================*/ -#if !CH_PORT_SUPPORTS_RT -#error "the port layer does not support the realtime counter functionality" -#endif - /*===========================================================================*/ /* Module data structures and types. */ /*===========================================================================*/ +/** + * @brief Type of a Time Measurement object. + * @note The maximum measurable time period depends on the implementation + * of the realtime counter and its clock frequency. + * @note The measurement is not 100% cycle-accurate, it can be in excess + * of few cycles depending on the compiler and target architecture. + * @note Interrupts can affect measurement if the measurement is performed + * with interrupts enabled. + */ +typedef struct { + rtcnt_t last; /**< @brief Last measurement. */ + rtcnt_t worst; /**< @brief Worst measurement. */ + rtcnt_t best; /**< @brief Best measurement. */ +} time_measurement_t; + /*===========================================================================*/ /* Module macros. */ /*===========================================================================*/ + /** * @name Time conversion utilities for the realtime counter * @{ @@ -137,6 +149,11 @@ #ifdef __cplusplus extern "C" { #endif + bool chRTIsCounterWithin(rtcnt_t start, rtcnt_t end); + void chRTPolledDelay(rtcnt_t cycles); + void chRTTimeMeasurementObjectInit(time_measurement_t *tmp); + NOINLINE void chRTTimeMeasurementStartX(time_measurement_t *tmp); + NOINLINE void chRTTimeMeasurementStopX(time_measurement_t *tmp); #ifdef __cplusplus } #endif @@ -154,74 +171,13 @@ extern "C" { * * @special */ -static inline rtcnt_t chRTGetCounterValue(void) { +static inline rtcnt_t chRTGetCounterValueX(void) { +#if !CH_PORT_SUPPORTS_RT return port_rt_get_counter_value(); -} - -/** - * @brief Realtime window test. - * @details This function verifies if the current realtime counter value - * lies within the specified range or not. The test takes care - * of the realtime counter wrapping to zero on overflow. - * @note When start==end then the function returns always true because the - * whole time range is specified. - * @note This function can be called from any context. - * - * @par Example 1 - * Example of a guarded loop using the realtime counter. The loop implements - * a timeout after one second. - * @code - * rtcnt_t start = chRTGetCounterValue(); - * rtcnt_t timeout = start + S2RTC(1); - * while (my_condition) { - * if (!chRTIsCounterWithin(start, timeout) - * return TIMEOUT; - * // Do something. - * } - * // Continue. - * @endcode - * - * @par Example 2 - * Example of a loop that lasts exactly 50 microseconds. - * @code - * rtcnt_t start = chRTGetCounterValue(); - * rtcnt_t timeout = start + US2RTC(50); - * while (chRTIsCounterWithin(start, timeout)) { - * // Do something. - * } - * // Continue. - * @endcode - * - * @param[in] start the start of the time window (inclusive) - * @param[in] end the end of the time window (non inclusive) - * @retval true current time within the specified time window. - * @retval false current time not within the specified time window. - * - * @special - */ -static inline bool chRTIsCounterWithin(rtcnt_t start, rtcnt_t end) { - rtcnt_t now = chRTGetCounterValue(); - - return end > start ? (now >= start) && (now < end) : - (now >= start) || (now < end); -} - -/** - * @brief Polled delay. - * @note The real delay is always few cycles in excess of the specified - * value. - * @note This function can be called from any context. - * - * @param[in] ticks number of ticks - * - * @special - */ -static inline void chRTPolledDelay(rtcnt_t ticks) { - rtcnt_t start = chRTGetCounterValue(); - rtcnt_t timeout = start + (ticks); - while (chRTIsCounterWithin(start, timeout)) - ; +#else + return chVTGetSystemTimeX(); +#endif } #endif /* CH_CFG_USE_RT */ diff --git a/os/kernel/include/chvt.h b/os/kernel/include/chvt.h index 39f03b995..a53a3f502 100644 --- a/os/kernel/include/chvt.h +++ b/os/kernel/include/chvt.h @@ -202,14 +202,15 @@ static inline void chVTObjectInit(virtual_timer_t *vtp) { * @details Returns the number of system ticks since the @p chSysInit() * invocation. * @note The counter can reach its maximum and then restart from zero. + * @note This function can be called from any context but its atomicity + * is not guaranteed on architectures whose word size is less than + * @systime_t size. * * @return The system time in ticks. * - * @iclass + * @special */ -static inline systime_t chVTGetSystemTimeI(void) { - - chDbgCheckClassI(); +static inline systime_t chVTGetSystemTimeX(void) { #if CH_CFG_TIMEDELTA == 0 return vtlist.vt_systime; @@ -232,7 +233,7 @@ static inline systime_t chVTGetSystemTime(void) { systime_t systime; chSysLock(); - systime = chVTGetSystemTimeI(); + systime = chVTGetSystemTimeX(); chSysUnlock(); return systime; } @@ -252,7 +253,9 @@ static inline systime_t chVTGetSystemTime(void) { */ static inline bool chVTIsSystemTimeWithinI(systime_t start, systime_t end) { - return chVTIsTimeWithin(chVTGetSystemTimeI(), start, end); + chDbgCheckClassI(); + + return chVTIsTimeWithin(chVTGetSystemTimeX(), start, end); } /** @@ -395,7 +398,7 @@ static inline void chVTDoTickI(void) { } #else /* CH_CFG_TIMEDELTA > 0 */ virtual_timer_t *vtp; - systime_t now = chVTGetSystemTimeI(); + systime_t now = chVTGetSystemTimeX(); systime_t delta = now - vtlist.vt_lasttime; while ((vtp = vtlist.vt_next)->vt_delta <= delta) { diff --git a/os/kernel/kernel.mk b/os/kernel/kernel.mk index 3ebf2ed98..d0617e536 100644 --- a/os/kernel/kernel.mk +++ b/os/kernel/kernel.mk @@ -4,6 +4,7 @@ KERNSRC = ${CHIBIOS}/os/kernel/src/chsys.c \ ${CHIBIOS}/os/kernel/src/chdebug.c \ ${CHIBIOS}/os/kernel/src/chlists.c \ ${CHIBIOS}/os/kernel/src/chvt.c \ + ${CHIBIOS}/os/kernel/src/chrt.c \ ${CHIBIOS}/os/kernel/src/chschd.c \ ${CHIBIOS}/os/kernel/src/chthreads.c \ ${CHIBIOS}/os/kernel/src/chdynamic.c \ diff --git a/os/kernel/src/chrt.c b/os/kernel/src/chrt.c new file mode 100644 index 000000000..a63ce9e32 --- /dev/null +++ b/os/kernel/src/chrt.c @@ -0,0 +1,206 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012,2013 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file chvt.c + * @brief Real Time Counter and Measurement module code. + * + * @addtogroup realtime_counter + * @details Realtime Counter APIs and services. + * + *

Operation mode

+ * The realtime counter is a fast HW counter that counts upward at + * regular intervals. This counted can be used for small and accurate + * delays, time stamp and time measurement. + * + *

Notes

+ * On those architectures where such a counter is not implemented + * the system time counter is used instead. Of course the system + * time counter usually has a much lower resolution than a real + * HW counter. + * @{ + */ + +#include "ch.h" + +#if CH_CFG_USE_RT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module local variables. */ +/*===========================================================================*/ + +/** + * @brief Subsystem calibration value. + */ +static rtcnt_t measurement_offset; + +/*===========================================================================*/ +/* Module local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Initializes the realtime counter unit. + * + * @init + */ +void _rt_init(void) { + time_measurement_t tm; + + /* Time Measurement subsystem calibration, it does a null measurement + and calculates the call overhead which is subtracted to real + measurements.*/ + measurement_offset = 0; + chRTTimeMeasurementObjectInit(&tm); + chRTTimeMeasurementStartX(&tm); + chRTTimeMeasurementStopX(&tm); + measurement_offset = tm.last; +} + +/** + * @brief Realtime window test. + * @details This function verifies if the current realtime counter value + * lies within the specified range or not. The test takes care + * of the realtime counter wrapping to zero on overflow. + * @note When start==end then the function returns always true because the + * whole time range is specified. + * @note This function can be called from any context. + * + * @par Example 1 + * Example of a guarded loop using the realtime counter. The loop implements + * a timeout after one second. + * @code + * rtcnt_t start = chRTGetCounterValue(); + * rtcnt_t timeout = start + S2RTC(RTCCLK, 1); + * while (my_condition) { + * if (!chRTIsCounterWithin(start, timeout) + * return TIMEOUT; + * // Do something. + * } + * // Continue. + * @endcode + * + * @par Example 2 + * Example of a loop that lasts exactly 50 microseconds. + * @code + * rtcnt_t start = chRTGetCounterValue(); + * rtcnt_t timeout = start + US2RTC(RTCCLK, 50); + * while (chRTIsCounterWithin(start, timeout)) { + * // Do something. + * } + * // Continue. + * @endcode + * + * @param[in] start the start of the time window (inclusive) + * @param[in] end the end of the time window (non inclusive) + * @retval true current time within the specified time window. + * @retval false current time not within the specified time window. + * + * @special + */ +bool chRTIsCounterWithin(rtcnt_t start, rtcnt_t end) { + rtcnt_t now = chRTGetCounterValueX(); + + return end > start ? (now >= start) && (now < end) : + (now >= start) || (now < end); +} + +/** + * @brief Polled delay. + * @note The real delay is always few cycles in excess of the specified + * value. + * @note This function can be called from any context. + * + * @param[in] cycles number of cycles + * + * @special + */ +void chRTPolledDelay(rtcnt_t cycles) { + rtcnt_t start = chRTGetCounterValueX(); + rtcnt_t end = start + cycles; + while (chRTIsCounterWithin(start, end)) + ; +} + +/** + * @brief Initializes a @p TimeMeasurement object. + * + * @param[out] tmp pointer to a @p TimeMeasurement structure + * + * @init + */ +void chRTTimeMeasurementObjectInit(time_measurement_t *tmp) { + + tmp->last = (rtcnt_t)0; + tmp->worst = (rtcnt_t)0; + tmp->best = (rtcnt_t)-1; +} + +/** + * @brief Starts a measurement. + * @pre The @p time_measurement_t structure must be initialized. + * @note This function can be invoked from any context. + * + * @param[in,out] tmp pointer to a @p TimeMeasurement structure + * + * @special + */ +NOINLINE void chRTTimeMeasurementStartX(time_measurement_t *tmp) { + + tmp->last = chRTGetCounterValueX(); +} + +/** + * @brief Stops a measurement. + * @pre The @p time_measurement_t structure must be initialized. + * @note This function can be invoked from any context. + * + * @param[in,out] tmp pointer to a @p time_measurement_t structure + * + * @special + */ +NOINLINE void chRTTimeMeasurementStopX(time_measurement_t *tmp) { + + rtcnt_t now = chRTGetCounterValueX(); + tmp->last = now - tmp->last - measurement_offset; + if (tmp->last > tmp->worst) + tmp->worst = tmp->last; + else if (tmp->last < tmp->best) + tmp->best = tmp->last; +} + +#endif /* CH_CFG_USE_RT */ + +/** @} */ diff --git a/os/kernel/src/chsys.c b/os/kernel/src/chsys.c index 4a67c7042..91277dc60 100644 --- a/os/kernel/src/chsys.c +++ b/os/kernel/src/chsys.c @@ -105,6 +105,9 @@ void chSysInit(void) { port_init(); _scheduler_init(); _vt_init(); +#if CH_CFG_USE_RT + _rt_init(); +#endif #if CH_CFG_USE_MEMCORE _core_init(); #endif diff --git a/os/kernel/src/chthreads.c b/os/kernel/src/chthreads.c index 9017a59b7..b707b4562 100644 --- a/os/kernel/src/chthreads.c +++ b/os/kernel/src/chthreads.c @@ -327,7 +327,7 @@ void chThdSleep(systime_t time) { void chThdSleepUntil(systime_t time) { chSysLock(); - if ((time -= chVTGetSystemTimeI()) > 0) + if ((time -= chVTGetSystemTimeX()) > 0) chThdSleepS(time); chSysUnlock(); } diff --git a/os/ports/GCC/ARMCMx/chtypes.h b/os/ports/GCC/ARMCMx/chtypes.h index 65f8cafeb..6870fbd6e 100644 --- a/os/ports/GCC/ARMCMx/chtypes.h +++ b/os/ports/GCC/ARMCMx/chtypes.h @@ -54,6 +54,13 @@ typedef int32_t cnt_t; /**< Resources counter. */ */ #define ROMCONST const +/** + * @brief Makes functions not inlineable. + * @note If the compiler does not support such attribute then the + * realtime counter precision could be degraded. + */ +#define NOINLINE __attribute__((noinline)) + #endif /* _CHTYPES_H_ */ /** @} */ -- cgit v1.2.3