diff --git a/demos/STM32/RT-STM32G474RE-NUCLEO64/Makefile b/demos/STM32/RT-STM32G474RE-NUCLEO64/Makefile index 636ed0cf4..e2b9c6eeb 100644 --- a/demos/STM32/RT-STM32G474RE-NUCLEO64/Makefile +++ b/demos/STM32/RT-STM32G474RE-NUCLEO64/Makefile @@ -5,7 +5,7 @@ # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 + USE_OPT = -Og -ggdb -fomit-frame-pointer -falign-functions=16 endif # C specific options here (added to USE_OPT). diff --git a/demos/STM32/RT-STM32G474RE-NUCLEO64/main.c b/demos/STM32/RT-STM32G474RE-NUCLEO64/main.c index 20d98a53d..341123b09 100644 --- a/demos/STM32/RT-STM32G474RE-NUCLEO64/main.c +++ b/demos/STM32/RT-STM32G474RE-NUCLEO64/main.c @@ -19,6 +19,7 @@ #include "rt_test_root.h" #include "oslib_test_root.h" +#if 0 /* * Green LED blinker thread, times are in milliseconds. */ @@ -34,6 +35,14 @@ static THD_FUNCTION(Thread1, arg) { chThdSleepMilliseconds(500); } } +#endif + +virtual_timer_t vt1; +void vtfunc(void *par) { + + (void)par; + palToggleLine(LINE_LED_GREEN); +} /* * Application entry point. @@ -60,7 +69,8 @@ int main(void) { /* * Creates the blinker thread. */ - chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); +// chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); + chVTSetContinuous(&vt1, TIME_MS2I(500), vtfunc, NULL); /* * Normal main() thread activity, in this demo it does nothing except diff --git a/os/rt/include/chobjects.h b/os/rt/include/chobjects.h index 647a492b3..86c140db4 100644 --- a/os/rt/include/chobjects.h +++ b/os/rt/include/chobjects.h @@ -98,6 +98,14 @@ typedef struct ch_virtual_timer { * @brief Timer callback function parameter. */ void *par; + /** + * @brief Time of the last activation. + */ + systime_t last; + /** + * @brief Current reload interval. + */ + sysinterval_t reload; } virtual_timer_t; /** diff --git a/os/rt/include/chobjects_alt.h b/os/rt/include/chobjects_alt.h deleted file mode 100644 index 86c140db4..000000000 --- a/os/rt/include/chobjects_alt.h +++ /dev/null @@ -1,520 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014, - 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio. - - This file is part of ChibiOS. - - ChibiOS 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 version 3 of the License. - - ChibiOS 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 chobjects.h - * @brief Operating System Objects macros and structures. - * - * @addtogroup os_structures - * @{ - */ - -#ifndef CHOBJECTS_H -#define CHOBJECTS_H - -/*===========================================================================*/ -/* Module constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module pre-compile time settings. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module data structures and types. */ -/*===========================================================================*/ - -/** - * @brief Global state of the operating system. - */ -typedef enum { - ch_sys_uninit = 0, - ch_sys_initializing = 1, - ch_sys_running = 2, - ch_sys_halted = 3 -} system_state_t; - -/** - * @brief Type of a Virtual Timer callback function. - */ -typedef void (*vtfunc_t)(void *p); - -/** - * @brief Type of a Virtual Timer structure. - */ -typedef struct ch_delta_list delta_list_t; - -/** - * @brief Virtual Timer delta list element and header structure. - */ -struct ch_delta_list { - /** - * @brief Next timer in the list. - */ - delta_list_t *next; - /** - * @brief Previous timer in the list. - */ - delta_list_t *prev; - /** - * @brief Time delta before timeout. - */ - sysinterval_t delta; -}; - -/** - * @brief Type of a Virtual Timer. - */ -typedef struct ch_virtual_timer { - /** - * @brief Delta list element. - */ - delta_list_t dlist; - /** - * @brief Timer callback function pointer. - */ - vtfunc_t func; - /** - * @brief Timer callback function parameter. - */ - void *par; - /** - * @brief Time of the last activation. - */ - systime_t last; - /** - * @brief Current reload interval. - */ - sysinterval_t reload; -} virtual_timer_t; - -/** - * @brief Type of virtual timers list header. - * @note The timers list is implemented as a double link bidirectional list - * in order to make the unlink time constant, the reset of a virtual - * timer is often used in the code. - */ -typedef struct ch_virtual_timers_list { - /** - * @brief Delta list header. - */ - delta_list_t dlist; -#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__) - /** - * @brief System Time counter. - */ - volatile systime_t systime; -#endif -#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__) - /** - * @brief System time of the last tick event. - */ - systime_t lasttime; -#endif -#if (CH_CFG_USE_TIMESTAMP == TRUE) || defined(__DOXYGEN__) - /** - * @brief Last generated time stamp. - */ - volatile uint64_t laststamp; -#endif -} virtual_timers_list_t; - -/** - * @brief Type of a registry structure. - */ -typedef struct ch_registry { - /** - * @brief Registry queue header. - */ - ch_queue_t queue; -} registry_t; - -/** - * @brief Type of a thread reference. - */ -typedef thread_t * thread_reference_t; - -/** - * @brief Type of a threads queue. - */ -typedef struct ch_threads_queue { - /** - * @brief Threads queue header. - */ - ch_queue_t queue; -} threads_queue_t; - -/** - * @brief Structure representing a thread. - * @note Not all the listed fields are always needed, by switching off some - * not needed ChibiOS/RT subsystems it is possible to save RAM space - * by shrinking this structure. - */ -struct ch_thread { - /** - * @brief Shared list headers. - */ - union { - /** - * @brief Threads lists element. - */ - ch_list_t list; - /** - * @brief Threads queues element. - */ - ch_queue_t queue; - /** - * @brief Threads ordered queues element. - */ - ch_priority_queue_t pqueue; - } hdr; - /** - * @brief Processor context. - */ - struct port_context ctx; -#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) - /** - * @brief Registry queue element. - */ - ch_queue_t rqueue; -#endif - /** - * @brief OS instance owner of this thread. - */ - os_instance_t *owner; -#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) - /** - * @brief Thread name or @p NULL. - */ - const char *name; -#endif -#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) || \ - defined(__DOXYGEN__) - /** - * @brief Working area base address. - * @note This pointer is used for stack overflow checks and for - * dynamic threading. - */ - stkalign_t *wabase; -#endif - /** - * @brief Current thread state. - */ - tstate_t state; - /** - * @brief Various thread flags. - */ - tmode_t flags; -#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__) - /** - * @brief References to this thread. - */ - trefs_t refs; -#endif - /** - * @brief Number of ticks remaining to this thread. - */ -#if (CH_CFG_TIME_QUANTUM > 0) || defined(__DOXYGEN__) - tslices_t ticks; -#endif -#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__) - /** - * @brief Thread consumed time in ticks. - * @note This field can overflow. - */ - volatile systime_t time; -#endif - /** - * @brief State-specific fields. - * @note All the fields declared in this union are only valid in the - * specified state or condition and are thus volatile. - */ - union { - /** - * @brief Thread wakeup code. - * @note This field contains the low level message sent to the thread - * by the waking thread or interrupt handler. The value is valid - * after exiting the @p chSchWakeupS() function. - */ - msg_t rdymsg; - /** - * @brief Thread exit code. - * @note The thread termination code is stored in this field in order - * to be retrieved by the thread performing a @p chThdWait() on - * this thread. - */ - msg_t exitcode; - /** - * @brief Pointer to a generic "wait" object. - * @note This field is used to get a generic pointer to a synchronization - * object and is valid when the thread is in one of the wait - * states. - */ - void *wtobjp; - /** - * @brief Pointer to a generic thread reference object. - * @note This field is used to get a pointer to a synchronization - * object and is valid when the thread is in @p CH_STATE_SUSPENDED - * state. - */ - thread_reference_t *wttrp; -#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) - /** - * @brief Thread sent message. - */ - msg_t sentmsg; -#endif -#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__) - /** - * @brief Pointer to a generic semaphore object. - * @note This field is used to get a pointer to a synchronization - * object and is valid when the thread is in @p CH_STATE_WTSEM - * state. - */ - struct ch_semaphore *wtsemp; -#endif -#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__) - /** - * @brief Pointer to a generic mutex object. - * @note This field is used to get a pointer to a synchronization - * object and is valid when the thread is in @p CH_STATE_WTMTX - * state. - */ - struct ch_mutex *wtmtxp; -#endif -#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) - /** - * @brief Enabled events mask. - * @note This field is only valid while the thread is in the - * @p CH_STATE_WTOREVT or @p CH_STATE_WTANDEVT states. - */ - eventmask_t ewmask; -#endif - } u; -#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__) - /** - * @brief Termination waiting list. - */ - ch_list_t waiting; -#endif -#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__) - /** - * @brief Messages queue. - */ - ch_queue_t msgqueue; -#endif -#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) - /** - * @brief Pending events mask. - */ - eventmask_t epending; -#endif -#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__) - /** - * @brief List of the mutexes owned by this thread. - * @note The list is terminated by a @p NULL in this field. - */ - struct ch_mutex *mtxlist; - /** - * @brief Thread's own, non-inherited, priority. - */ - tprio_t realprio; -#endif -#if ((CH_CFG_USE_DYNAMIC == TRUE) && (CH_CFG_USE_MEMPOOLS == TRUE)) || \ - defined(__DOXYGEN__) - /** - * @brief Memory Pool where the thread workspace is returned. - */ - void *mpool; -#endif -#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__) - /** - * @brief Thread statistics. - */ - time_measurement_t stats; -#endif -#if defined(CH_CFG_THREAD_EXTRA_FIELDS) - /* Extra fields defined in chconf.h.*/ - CH_CFG_THREAD_EXTRA_FIELDS -#endif -}; - -/** - * @brief Type of a ready list header. - */ -typedef struct ch_ready_list { - /** - * @brief Threads ordered queues header. - * @note The priority field must be initialized to zero. - */ - ch_priority_queue_t pqueue; - /** - * @brief The currently running thread. - */ - thread_t *current; -} ready_list_t; - -/** - * @brief Type of an system instance configuration. - */ -typedef struct ch_os_instance_config { - /** - * @brief Instance name. - */ - const char *name; -#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) || \ - defined(__DOXYGEN__) - /** - * @brief Lower limit of the main function thread stack. - */ - stkalign_t *mainthread_base; - /** - * @brief Upper limit of the main function thread stack. - */ - stkalign_t *mainthread_end; -#endif -#if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__) - /** - * @brief Lower limit of the dedicated idle thread stack. - */ - stkalign_t *idlethread_base; - /** - * @brief Upper limit of the dedicated idle thread stack. - */ - stkalign_t *idlethread_end; -#endif -} os_instance_config_t; - -/** - * @brief System instance data structure. - */ -struct ch_os_instance { - /** - * @brief Ready list header. - */ - ready_list_t rlist; - /** - * @brief Virtual timers delta list header. - */ - virtual_timers_list_t vtlist; -#if ((CH_CFG_USE_REGISTRY == TRUE) && (CH_CFG_SMP_MODE == FALSE)) || \ - defined(__DOXYGEN__) - /** - * @brief Registry header. - * @note This field is present only if the SMP mode is disabled. - */ - registry_t reglist; -#endif - /** - * @brief Core associated to this instance. - */ - core_id_t core_id; - /** - * @brief Pointer to the instance configuration data. - */ - const os_instance_config_t *config; - /** - * @brief Main thread descriptor. - */ - thread_t mainthread; - /** - * @brief System debug. - */ - system_debug_t dbg; -#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_DISABLED) || defined(__DOXYGEN__) - /** - * @brief Trace buffer. - */ - trace_buffer_t trace_buffer; -#endif -#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__) - /** - * @brief Global kernel statistics. - */ - kernel_stats_t kernel_stats; -#endif -#if defined(PORT_INSTANCE_EXTRA_FIELDS) || defined(__DOXYGEN__) - /* Extra fields from port layer.*/ - PORT_INSTANCE_EXTRA_FIELDS -#endif - /* Extra fields from configuration.*/ - CH_CFG_OS_INSTANCE_EXTRA_FIELDS -}; - -/** - * @brief Type of system data structure. - */ -typedef struct ch_system { - /** - * @brief Operating system state. - */ - system_state_t state; - /** - * @brief Initialized OS instances or @p NULL. - */ - os_instance_t *instances[PORT_CORES_NUMBER]; -#if (CH_CFG_USE_TM == TRUE) || defined(__DOXYGEN__) - /** - * @brief Time measurement calibration data. - */ - tm_calibration_t tmc; -#endif -#if ((CH_CFG_USE_REGISTRY == TRUE) && (CH_CFG_SMP_MODE == TRUE)) || \ - defined(__DOXYGEN__) - /** - * @brief Registry header. - * @note This field is present only if the SMP mode is enabled. - */ - registry_t reglist; -#endif -#if defined(PORT_SYSTEM_EXTRA_FIELDS) || defined(__DOXYGEN__) - /* Extra fields from port layer.*/ - PORT_SYSTEM_EXTRA_FIELDS -#endif - /* Extra fields from configuration.*/ - CH_CFG_SYSTEM_EXTRA_FIELDS -} ch_system_t; - -/*===========================================================================*/ -/* Module macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -/*===========================================================================*/ -/* Module inline functions. */ -/*===========================================================================*/ - -#endif /* CHOBJECTS_H */ - -/** @} */ diff --git a/os/rt/include/chvt.h b/os/rt/include/chvt.h index 2193faf3d..4f2e79722 100644 --- a/os/rt/include/chvt.h +++ b/os/rt/include/chvt.h @@ -73,6 +73,8 @@ extern "C" { #endif void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, vtfunc_t vtfunc, void *par); + void chVTDoSetContinuousI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par); void chVTDoResetI(virtual_timer_t *vtp); void chVTDoTickI(void); #if CH_CFG_USE_TIMESTAMP == TRUE @@ -100,7 +102,7 @@ extern "C" { */ static inline void chVTObjectInit(virtual_timer_t *vtp) { - vtp->func = NULL; + vtp->dlist.next = NULL; } /** @@ -246,7 +248,7 @@ static inline bool chVTIsArmedI(const virtual_timer_t *vtp) { chDbgCheckClassI(); - return (bool)(vtp->func != NULL); + return (bool)(vtp->dlist.next != NULL); } /** @@ -304,7 +306,7 @@ static inline void chVTReset(virtual_timer_t *vtp) { } /** - * @brief Enables a virtual timer. + * @brief Enables a one-shot virtual timer. * @details If the virtual timer was already enabled then it is re-enabled * using the new parameters. * @pre The timer must have been initialized using @p chVTObjectInit() @@ -333,7 +335,7 @@ static inline void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay, } /** - * @brief Enables a virtual timer. + * @brief Enables a one-shot virtual timer. * @details If the virtual timer was already enabled then it is re-enabled * using the new parameters. * @pre The timer must have been initialized using @p chVTObjectInit() @@ -362,6 +364,121 @@ static inline void chVTSet(virtual_timer_t *vtp, sysinterval_t delay, chSysUnlock(); } +/** + * @brief Enables a continuous virtual timer. + * @details If the virtual timer was already enabled then it is re-enabled + * using the new parameters. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @param[in] delay the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE is allowed but interpreted as a + * normal time specification. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @param[in] vtfunc the timer callback function. After invoking the + * callback the timer is disabled and the structure can + * be disposed or reused. + * @param[in] par a parameter that will be passed to the callback + * function + * + * @iclass + */ +static inline void chVTSetContinuousI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + + chVTResetI(vtp); + chVTDoSetContinuousI(vtp, delay, vtfunc, par); +} + +/** + * @brief Enables a continuous virtual timer. + * @details If the virtual timer was already enabled then it is re-enabled + * using the new parameters. + * @pre The timer must have been initialized using @p chVTObjectInit() + * or @p chVTDoSetI(). + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @param[in] delay the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE is allowed but interpreted as a + * normal time specification. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @param[in] vtfunc the timer callback function. After invoking the + * callback the timer is disabled and the structure can + * be disposed or reused. + * @param[in] par a parameter that will be passed to the callback + * function + * + * @api + */ +static inline void chVTSetContinuous(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + + chSysLock(); + chVTSetContinuousI(vtp, delay, vtfunc, par); + chSysUnlock(); +} + +/** + * @brief Returns the current reload value. + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @return The reload value. + * + * @xclass + */ +static inline sysinterval_t chVTGetReloadIntervalX(virtual_timer_t *vtp) { + + return vtp->reload; +} + +/** + * @brief Changes a timer reload time interval. + * @note This function is meant to be called from a timer callback, it + * does nothing in any other context. + * @note Calling this function from a one-shot timer callback turns it + * into a continuous timer. + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @param[in] reload the new reload value, zero means no reload + * + * @xclass + */ +static inline void chVTSetReloadIntervalX(virtual_timer_t *vtp, + sysinterval_t reload) { + + vtp->reload = reload; +} + +/** + * @brief Returns the remaining time interval before next timer trigger. + * @note This function can be called while the timer is active or + * after stopping it. + * + * @param[in] vtp the @p virtual_timer_t structure pointer + * @return The remaining time interval. + * + * @xclass + */ +static inline sysinterval_t chVTGetRemainingIntervalX(virtual_timer_t *vtp) { + sysinterval_t elapsed_time; + + /* Time elapsed since last triggering or 1st activation.*/ + elapsed_time = chTimeDiffX(vtp->last, chVTGetSystemTimeX()); + + /* Current time could have slipped past the next deadline, compensating.*/ + if (elapsed_time > vtp->reload) { + elapsed_time = vtp->reload; + } + + /* Returning the remaining time interval.*/ + return vtp->reload - elapsed_time; +} + #if (CH_CFG_USE_TIMESTAMP == TRUE) || defined(__DOXYGEN__) /** * @brief Generates a monotonic time stamp. diff --git a/os/rt/include/chvt_alt.h b/os/rt/include/chvt_alt.h deleted file mode 100644 index 1c0d7d904..000000000 --- a/os/rt/include/chvt_alt.h +++ /dev/null @@ -1,519 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014, - 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio. - - This file is part of ChibiOS. - - ChibiOS 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 version 3 of the License. - - ChibiOS 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 rt/include/chvt.h - * @brief Time and Virtual Timers module macros and structures. - * - * @addtogroup time - * @{ - */ - -#ifndef CHVT_H -#define CHVT_H - -/*===========================================================================*/ -/* Module constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module pre-compile time settings. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if (CH_CFG_ST_TIMEDELTA < 0) || (CH_CFG_ST_TIMEDELTA == 1) -#error "invalid CH_CFG_ST_TIMEDELTA specified, must " \ - "be zero or greater than one" -#endif - -#if (CH_CFG_ST_TIMEDELTA > 0) && (CH_CFG_TIME_QUANTUM > 0) -#error "CH_CFG_TIME_QUANTUM not supported in tickless mode" -#endif - -#if (CH_CFG_ST_TIMEDELTA > 0) && (CH_DBG_THREADS_PROFILING == TRUE) -#error "CH_DBG_THREADS_PROFILING not supported in tickless mode" -#endif - -/*===========================================================================*/ -/* Module data structures and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -/* - * Virtual Timers APIs. - */ -#ifdef __cplusplus -extern "C" { -#endif - void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par); - void chVTDoSetContinuousI(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par); - void chVTDoResetI(virtual_timer_t *vtp); - void chVTDoTickI(void); -#if CH_CFG_USE_TIMESTAMP == TRUE - systimestamp_t chVTGetTimeStampI(void); - void chVTResetTimeStampI(void); -#endif -#ifdef __cplusplus -} -#endif - -/*===========================================================================*/ -/* Module inline functions. */ -/*===========================================================================*/ - -/** - * @brief Initializes a @p virtual_timer_t object. - * @note Initializing a timer object is not strictly required because - * the function @p chVTSetI() initializes the object too. This - * function is only useful if you need to perform a @p chVTIsArmed() - * check before calling @p chVTSetI(). - * - * @param[out] vtp the @p virtual_timer_t structure pointer - * - * @init - */ -static inline void chVTObjectInit(virtual_timer_t *vtp) { - - vtp->dlist.next = NULL; -} - -/** - * @brief Current system time. - * @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 - * @p systime_t size. - * - * @return The system time in ticks. - * - * @xclass - */ -static inline systime_t chVTGetSystemTimeX(void) { - -#if CH_CFG_ST_TIMEDELTA == 0 - return currcore->vtlist.systime; -#else /* CH_CFG_ST_TIMEDELTA > 0 */ - return port_timer_get_time(); -#endif /* CH_CFG_ST_TIMEDELTA > 0 */ -} - -/** - * @brief Current system time. - * @details Returns the number of system ticks since the @p chSysInit() - * invocation. - * @note The counter can reach its maximum and then restart from zero. - * - * @return The system time in ticks. - * - * @api - */ -static inline systime_t chVTGetSystemTime(void) { - systime_t systime; - - chSysLock(); - systime = chVTGetSystemTimeX(); - chSysUnlock(); - - return systime; -} - -/** - * @brief Returns the elapsed time since the specified start time. - * - * @param[in] start start time - * @return The elapsed time. - * - * @xclass - */ -static inline sysinterval_t chVTTimeElapsedSinceX(systime_t start) { - - return chTimeDiffX(start, chVTGetSystemTimeX()); -} - -/** - * @brief Checks if the current system time is within the specified time - * window. - * @note When start==end then the function returns always false because the - * time window has zero size. - * - * @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. - * - * @xclass - */ -static inline bool chVTIsSystemTimeWithinX(systime_t start, systime_t end) { - - return chTimeIsInRangeX(chVTGetSystemTimeX(), start, end); -} - -/** - * @brief Checks if the current system time is within the specified time - * window. - * @note When start==end then the function returns always false because the - * time window has zero size. - * - * @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. - * - * @api - */ -static inline bool chVTIsSystemTimeWithin(systime_t start, systime_t end) { - - return chTimeIsInRangeX(chVTGetSystemTime(), start, end); -} - -/** - * @brief Returns the time interval until the next timer event. - * @note The return value is not perfectly accurate and can report values - * in excess of @p CH_CFG_ST_TIMEDELTA ticks. - * @note The interval returned by this function is only meaningful if - * more timers are not added to the list until the returned time. - * - * @param[out] timep pointer to a variable that will contain the time - * interval until the next timer elapses. This pointer - * can be @p NULL if the information is not required. - * @return The time, in ticks, until next time event. - * @retval false if the timers list is empty. - * @retval true if the timers list contains at least one timer. - * - * @iclass - */ -static inline bool chVTGetTimersStateI(sysinterval_t *timep) { - virtual_timers_list_t *vtlp = &currcore->vtlist; - delta_list_t *dlp = &vtlp->dlist; - - chDbgCheckClassI(); - - if (dlp == dlp->next) { - return false; - } - - if (timep != NULL) { -#if CH_CFG_ST_TIMEDELTA == 0 - *timep = dlp->next->delta; -#else - *timep = (dlp->next->delta + (sysinterval_t)CH_CFG_ST_TIMEDELTA) - - chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()); -#endif - } - - return true; -} - -/** - * @brief Returns @p true if the specified timer is armed. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * @return true if the timer is armed. - * - * @iclass - */ -static inline bool chVTIsArmedI(const virtual_timer_t *vtp) { - - chDbgCheckClassI(); - - return (bool)(vtp->dlist.next != NULL); -} - -/** - * @brief Returns @p true if the specified timer is armed. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * @return true if the timer is armed. - * - * @api - */ -static inline bool chVTIsArmed(const virtual_timer_t *vtp) { - bool b; - - chSysLock(); - b = chVTIsArmedI(vtp); - chSysUnlock(); - - return b; -} - -/** - * @brief Disables a Virtual Timer. - * @note The timer is first checked and disabled only if armed. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * - * @iclass - */ -static inline void chVTResetI(virtual_timer_t *vtp) { - - if (chVTIsArmedI(vtp)) { - chVTDoResetI(vtp); - } -} - -/** - * @brief Disables a Virtual Timer. - * @note The timer is first checked and disabled only if armed. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * - * @api - */ -static inline void chVTReset(virtual_timer_t *vtp) { - - chSysLock(); - chVTResetI(vtp); - chSysUnlock(); -} - -/** - * @brief Enables a one-shot virtual timer. - * @details If the virtual timer was already enabled then it is re-enabled - * using the new parameters. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * @param[in] delay the number of ticks before the operation timeouts, the - * special values are handled as follow: - * - @a TIME_INFINITE is allowed but interpreted as a - * normal time specification. - * - @a TIME_IMMEDIATE this value is not allowed. - * . - * @param[in] vtfunc the timer callback function. After invoking the - * callback the timer is disabled and the structure can - * be disposed or reused. - * @param[in] par a parameter that will be passed to the callback - * function - * - * @iclass - */ -static inline void chVTSetI(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par) { - - chVTResetI(vtp); - chVTDoSetI(vtp, delay, vtfunc, par); -} - -/** - * @brief Enables a one-shot virtual timer. - * @details If the virtual timer was already enabled then it is re-enabled - * using the new parameters. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * @param[in] delay the number of ticks before the operation timeouts, the - * special values are handled as follow: - * - @a TIME_INFINITE is allowed but interpreted as a - * normal time specification. - * - @a TIME_IMMEDIATE this value is not allowed. - * . - * @param[in] vtfunc the timer callback function. After invoking the - * callback the timer is disabled and the structure can - * be disposed or reused. - * @param[in] par a parameter that will be passed to the callback - * function - * - * @api - */ -static inline void chVTSet(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par) { - - chSysLock(); - chVTSetI(vtp, delay, vtfunc, par); - chSysUnlock(); -} - -/** - * @brief Enables a continuous virtual timer. - * @details If the virtual timer was already enabled then it is re-enabled - * using the new parameters. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * @param[in] delay the number of ticks before the operation timeouts, the - * special values are handled as follow: - * - @a TIME_INFINITE is allowed but interpreted as a - * normal time specification. - * - @a TIME_IMMEDIATE this value is not allowed. - * . - * @param[in] vtfunc the timer callback function. After invoking the - * callback the timer is disabled and the structure can - * be disposed or reused. - * @param[in] par a parameter that will be passed to the callback - * function - * - * @iclass - */ -static inline void chVTSetContinuousI(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par) { - - chVTResetI(vtp); - chVTDoSetContinuousI(vtp, delay, vtfunc, par); -} - -/** - * @brief Enables a continuous virtual timer. - * @details If the virtual timer was already enabled then it is re-enabled - * using the new parameters. - * @pre The timer must have been initialized using @p chVTObjectInit() - * or @p chVTDoSetI(). - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * @param[in] delay the number of ticks before the operation timeouts, the - * special values are handled as follow: - * - @a TIME_INFINITE is allowed but interpreted as a - * normal time specification. - * - @a TIME_IMMEDIATE this value is not allowed. - * . - * @param[in] vtfunc the timer callback function. After invoking the - * callback the timer is disabled and the structure can - * be disposed or reused. - * @param[in] par a parameter that will be passed to the callback - * function - * - * @api - */ -static inline void chVTContinuousSet(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par) { - - chSysLock(); - chVTSetContinuousI(vtp, delay, vtfunc, par); - chSysUnlock(); -} - -/** - * @brief Changes a timer reload time interval. - * @note This function is meant to be called from a timer callback, it - * does nothing in any other context. - * @note Calling this function from a one-shot timer callback turns it - * into a continuous timer. - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * @param[in] reload the new reload value, zero means no reload - * @return The previous reload value - * - * @special - */ -static inline sysinterval_t chVTSetReload(virtual_timer_t *vtp, - sysinterval_t reload) { - sysinterval_t old_reload; - - old_reload = vtp->reload; - vtp->reload = reload; - - return old_reload; -} - -#if (CH_CFG_USE_TIMESTAMP == TRUE) || defined(__DOXYGEN__) -/** - * @brief Generates a monotonic time stamp. - * @details This function generates a monotonic time stamp synchronized with - * the system time. The time stamp has the same resolution of - * system time. - * @note There is an assumption, this function must be called at - * least once before the system time wraps back to zero or - * synchronization is lost. You may use a periodic virtual timer with - * a very large interval in order to keep time stamps synchronized - * by calling this function. - * - * @return The time stamp. - * - * @api - */ -static inline systimestamp_t chVTGetTimeStamp(void) { - systimestamp_t stamp; - - chSysLock(); - - stamp = chVTGetTimeStampI(); - - chSysUnlock(); - - return stamp; -} - -/** - * @brief Resets and re-synchronizes the time stamps monotonic counter. - * - * @api - */ -static inline void chVTResetTimeStamp(void) { - - chDbgCheckClassI(); - - chSysLock(); - - chVTResetTimeStampI(); - - chSysUnlock(); -} -#endif /* CH_CFG_USE_TIMESTAMP == TRUE */ - -/** - * @brief Virtual Timers instance initialization. - * @note Internal use only. - * - * @param[out] vtlp pointer to the @p virtual_timers_list_t structure - * - * @notapi - */ -static inline void __vt_object_init(virtual_timers_list_t *vtlp) { - - vtlp->dlist.next = &vtlp->dlist; - vtlp->dlist.prev = &vtlp->dlist; - vtlp->dlist.delta = (sysinterval_t)-1; -#if CH_CFG_ST_TIMEDELTA == 0 - vtlp->systime = (systime_t)0; -#else /* CH_CFG_ST_TIMEDELTA > 0 */ - vtlp->lasttime = (systime_t)0; -#endif /* CH_CFG_ST_TIMEDELTA > 0 */ -#if CH_CFG_USE_TIMESTAMP == TRUE - currcore->vtlist.laststamp = (systimestamp_t)chVTGetSystemTimeX(); -#endif -} - -#endif /* CHVT_H */ - -/** @} */ diff --git a/os/rt/src/chvt.c b/os/rt/src/chvt.c index c95c8c4a2..2aa160481 100644 --- a/os/rt/src/chvt.c +++ b/os/rt/src/chvt.c @@ -129,47 +129,18 @@ static void vt_list_compress(virtual_timers_list_t *vtlp, } #endif -/*===========================================================================*/ -/* Module exported functions. */ -/*===========================================================================*/ - /** - * @brief Enables a virtual timer. - * @details The timer is enabled and programmed to trigger after the delay - * specified as parameter. - * @pre The timer must not be already armed before calling this function. - * @note The callback function is invoked from interrupt context. - * - * @param[out] vtp the @p virtual_timer_t structure pointer - * @param[in] delay the number of ticks before the operation timeouts, the - * special values are handled as follow: - * - @a TIME_INFINITE is allowed but interpreted as a - * normal time specification. - * - @a TIME_IMMEDIATE this value is not allowed. - * . - * @param[in] vtfunc the timer callback function. After invoking the - * callback the timer is disabled and the structure can - * be disposed or reused. - * @param[in] par a parameter that will be passed to the callback - * function - * - * @iclass + * @brief Enqueues a virtual timer in a virtual timers list. */ -void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par) { - virtual_timers_list_t *vtlp = &currcore->vtlist; +static void vt_enqueue(virtual_timers_list_t *vtlp, + virtual_timer_t *vtp, + systime_t now, + sysinterval_t delay) { delta_list_t *dlp; sysinterval_t delta; - chDbgCheckClassI(); - chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); - - vtp->par = par; - vtp->func = vtfunc; - #if CH_CFG_ST_TIMEDELTA > 0 { - systime_t now = chVTGetSystemTimeX(); sysinterval_t deltanow; /* If the requested delay is lower than the minimum safe delta then it @@ -260,6 +231,96 @@ void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, vtlp->dlist.delta = (sysinterval_t)-1; } +/*===========================================================================*/ +/* Module exported functions. */ +/*===========================================================================*/ + +/** + * @brief Enables a one-shot virtual timer. + * @details The timer is enabled and programmed to trigger after the delay + * specified as parameter. + * @pre The timer must not be already armed before calling this function. + * @note The callback function is invoked from interrupt context. + * + * @param[out] vtp the @p virtual_timer_t structure pointer + * @param[in] delay the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE is allowed but interpreted as a + * normal time specification. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @param[in] vtfunc the timer callback function. After invoking the + * callback the timer is disabled and the structure can + * be disposed or reused. + * @param[in] par a parameter that will be passed to the callback + * function + * + * @iclass + */ +void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + virtual_timers_list_t *vtlp = &currcore->vtlist; + systime_t now; + + chDbgCheckClassI(); + chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); + + /* Current system time.*/ + now = chVTGetSystemTimeX(); + + /* Timer initialization.*/ + vtp->par = par; + vtp->func = vtfunc; + vtp->last = now; + vtp->reload = (sysinterval_t)0; + + /* Inserting the timer in the delta list.*/ + vt_enqueue(vtlp, vtp, vtp->last, delay); +} + +/** + * @brief Enables a continuous virtual timer. + * @details The timer is enabled and programmed to trigger after the delay + * specified as parameter. + * @pre The timer must not be already armed before calling this function. + * @note The callback function is invoked from interrupt context. + * + * @param[out] vtp the @p virtual_timer_t structure pointer + * @param[in] delay the number of ticks before the operation timeouts, the + * special values are handled as follow: + * - @a TIME_INFINITE is allowed but interpreted as a + * normal time specification. + * - @a TIME_IMMEDIATE this value is not allowed. + * . + * @param[in] vtfunc the timer callback function. After invoking the + * callback the timer is disabled and the structure can + * be disposed or reused. + * @param[in] par a parameter that will be passed to the callback + * function + * + * @iclass + */ +void chVTDoSetContinuousI(virtual_timer_t *vtp, sysinterval_t delay, + vtfunc_t vtfunc, void *par) { + virtual_timers_list_t *vtlp = &currcore->vtlist; + systime_t now; + + chDbgCheckClassI(); + chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); + + /* Current system time.*/ + now = chVTGetSystemTimeX(); + + /* Timer initialization.*/ + vtp->par = par; + vtp->func = vtfunc; + vtp->last = now; + vtp->reload = delay; + + /* Inserting the timer in the delta list.*/ + vt_enqueue(vtlp, vtp, vtp->last, delay); +} + /** * @brief Disables a Virtual Timer. * @pre The timer must be in armed state before calling this function. @@ -273,17 +334,17 @@ void chVTDoResetI(virtual_timer_t *vtp) { chDbgCheckClassI(); chDbgCheck(vtp != NULL); - chDbgAssert(vtp->func != NULL, "timer not set or already triggered"); + chDbgAssert(chVTIsArmedI(vtp), "timer not armed"); #if CH_CFG_ST_TIMEDELTA == 0 /* The delta of the timer is added to the next timer.*/ vtp->dlist.next->delta += vtp->dlist.delta; - /* Removing the element from the delta list.*/ + /* Removing the element from the delta list, marking it as not armed.*/ vtp->dlist.prev->next = vtp->dlist.next; vtp->dlist.next->prev = vtp->dlist.prev; - vtp->func = NULL; + vtp->dlist.next = NULL; /* The above code changes the value in the header when the removed element is the last of the list, restoring it.*/ @@ -297,19 +358,21 @@ void chVTDoResetI(virtual_timer_t *vtp) { /* Removing the element from the delta list.*/ vtp->dlist.prev->next = vtp->dlist.next; vtp->dlist.next->prev = vtp->dlist.prev; - vtp->func = NULL; /* Adding delta to the next element, if it is not the last one.*/ if (is_timer(&vtlp->dlist, vtp->dlist.next)) vtp->dlist.next->delta += vtp->dlist.delta; + /* Marking timer as not armed.*/ + vtp->dlist.next = NULL; + return; } - /* Removing the first timer from the list.*/ + /* Removing the first timer from the list, marking it as not armed.*/ vtlp->dlist.next = vtp->dlist.next; vtlp->dlist.next->prev = &vtlp->dlist; - vtp->func = NULL; + vtp->dlist.next = NULL; /* If the list become empty then the alarm timer is stopped and done.*/ if (is_vtlist_empty(&vtlp->dlist)) { @@ -378,29 +441,30 @@ void chVTDoTickI(void) { --vtlp->dlist.next->delta; while (vtlp->dlist.next->delta == (sysinterval_t)0) { virtual_timer_t *vtp; - vtfunc_t fn; + /* Triggered timer.*/ vtp = (virtual_timer_t *)vtlp->dlist.next; - fn = vtp->func; - vtp->func = NULL; + + /* Removing the element from the delta list, marking it as not armed.*/ vtp->dlist.next->prev = &vtlp->dlist; vtlp->dlist.next = vtp->dlist.next; + vtp->dlist.next = NULL; + chSysUnlockFromISR(); - fn(vtp->par); + vtp->func(vtp->par); chSysLockFromISR(); } } #else /* CH_CFG_ST_TIMEDELTA > 0 */ delta_list_t *dlp; - systime_t now; sysinterval_t delta, nowdelta; + systime_t now = chVTGetSystemTimeX(); /* Looping through timers.*/ dlp = vtlp->dlist.next; while (true) { - /* Getting the system time as reference.*/ - now = chVTGetSystemTimeX(); + /* Delta between current time and last execution time.*/ nowdelta = chTimeDiffX(vtlp->lasttime, now); /* The list scan is limited by the timers header having @@ -412,32 +476,51 @@ void chVTDoTickI(void) { /* Consuming all timers between "vtp->lasttime" and now.*/ do { - vtfunc_t fn; virtual_timer_t *vtp = (virtual_timer_t *)dlp; /* The "last time" becomes this timer's expiration time.*/ vtlp->lasttime += dlp->delta; nowdelta -= dlp->delta; - /* Removing the timer from the list.*/ + /* Removing the timer from the list, marking it as not armed.*/ dlp->next->prev = &vtlp->dlist; vtlp->dlist.next = dlp->next; - - /* Calling the associated function and then marking the timer as - non active.*/ - fn = vtp->func; - vtp->func = NULL; + dlp->next = NULL; /* If the list becomes empty then the timer is stopped.*/ if (is_vtlist_empty(&vtlp->dlist)) { port_timer_stop_alarm(); } + /* Now "last" marks the current deadline based on the stored + reload value. It is done before calling the callback because + the reload value could change. Note that "reload" could be + zero, no harm.*/ + vtp->last = chTimeAddX(vtp->last, vtp->reload); + /* The callback is invoked outside the kernel critical zone.*/ chSysUnlockFromISR(); - fn(vtp->par); + vtp->func(vtp->par); chSysLockFromISR(); + /* Getting again the system time after executing the callback in + order to reduce error.*/ + now = chVTGetSystemTimeX(); + + /* If a reload is defined the timer needs to be restarted.*/ + if (vtp->reload > (sysinterval_t)0) { + sysinterval_t skipped_delta; + + /* Calculating how much the real current time skipped past the + hypothetical current deadline.*/ + skipped_delta = chTimeDiffX(vtp->last, now); + + chDbgAssert(skipped_delta < vtp->reload, "skipped deadline"); + + /* Enqueuing the timer again using the calculated delta.*/ + vt_enqueue(vtlp, vtp, now, vtp->reload - skipped_delta); + } + /* Next element in the list.*/ dlp = vtlp->dlist.next; } @@ -451,7 +534,8 @@ void chVTDoTickI(void) { /* The "unprocessed nowdelta" time slice is added to "last time" and subtracted to next timer's delta.*/ - vtlp->lasttime += nowdelta; +// vtlp->lasttime += nowdelta; + vtlp->lasttime = chTimeAddX(vtlp->lasttime, nowdelta); vtlp->dlist.next->delta -= nowdelta; /* Recalculating the next alarm time.*/ diff --git a/os/rt/src/chvt_alt.c b/os/rt/src/chvt_alt.c deleted file mode 100644 index 2aa160481..000000000 --- a/os/rt/src/chvt_alt.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014, - 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio. - - This file is part of ChibiOS. - - ChibiOS 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 version 3 of the License. - - ChibiOS 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 rt/src/chvt.c - * @brief Time and Virtual Timers module code. - * - * @addtogroup time - * @details Time and Virtual Timers related APIs and services. - * @{ - */ - -#include "ch.h" - -/*===========================================================================*/ -/* Module local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module local types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module local variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module local functions. */ -/*===========================================================================*/ - -/** - * @brief List empty check. - * - * @param[in] dlhp pointer to the delta list header - * - * @notapi - */ -static inline bool is_vtlist_empty(delta_list_t *dlhp) { - - return (bool)(dlhp == dlhp->next); -} - -#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__) -/** - * @brief Last timer in the list check. - * - * @param[in] dlhp pointer to the delta list header - * @param[in] dlp pointer to the delta list element - * - * @notapi - */ -static inline bool is_last_timer(delta_list_t *dlhp, delta_list_t *dlp) { - - return (bool)(dlp->next == dlhp); -} - -/** - * @brief Fist timer in the list check. - * - * @param[in] dlhp pointer to the delta list header - * @param[in] dlp pointer to the delta list element - * - * @notapi - */ -static inline bool is_first_timer(delta_list_t *dlhp, delta_list_t *dlp) { - - return (bool)(dlhp->next == dlp); -} - -/** - * @brief Timer check. - * - * @param[in] dlhp pointer to the delta list header - * @param[in] dlp pointer to the delta list element - * - * @notapi - */ -static inline bool is_timer(delta_list_t *dlhp, delta_list_t *dlp) { - - return (bool)(dlp != dlhp); -} - -/** - * @brief Delta list compression. - * - * @param[in] vtlp pointer to the delta list to be compressed - * @param[in] deltanow interval to be compacted starting from "lasttime" - * - * @notapi - */ -static void vt_list_compress(virtual_timers_list_t *vtlp, - sysinterval_t deltanow) { - delta_list_t *dlp = vtlp->dlist.next; - - /* The loop is bounded because the delta list header has the delta field - set to (sysinterval_t)-1 which is larger than all deltas.*/ - while (dlp->delta < deltanow) { - deltanow -= dlp->delta; - dlp->delta = (sysinterval_t)0; - dlp = dlp->next; - } - - vtlp->lasttime = vtlp->lasttime + deltanow; - - /* Adjusting next timer in the list, if any.*/ - if (is_timer(&vtlp->dlist, dlp)) { - dlp->delta -= deltanow; - } -} -#endif - -/** - * @brief Enqueues a virtual timer in a virtual timers list. - */ -static void vt_enqueue(virtual_timers_list_t *vtlp, - virtual_timer_t *vtp, - systime_t now, - sysinterval_t delay) { - delta_list_t *dlp; - sysinterval_t delta; - -#if CH_CFG_ST_TIMEDELTA > 0 - { - sysinterval_t deltanow; - - /* If the requested delay is lower than the minimum safe delta then it - is raised to the minimum safe value.*/ - if (delay < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { - delay = (sysinterval_t)CH_CFG_ST_TIMEDELTA; - } - - /* Special case where the timers list is empty.*/ - if (is_vtlist_empty(&vtlp->dlist)) { - - /* The delta list is empty, the current time becomes the new - delta list base time, the timer is inserted.*/ - vtlp->lasttime = now; - vtlp->dlist.next = &vtp->dlist; - vtlp->dlist.prev = &vtp->dlist; - vtp->dlist.next = &vtlp->dlist; - vtp->dlist.prev = &vtlp->dlist; - vtp->dlist.delta = delay; - -#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION - /* The delta could be too large for the physical timer to handle.*/ - if (delay > (sysinterval_t)TIME_MAX_SYSTIME) { - delay = (sysinterval_t)TIME_MAX_SYSTIME; - } -#endif - - /* Being the first element in the list the alarm timer is started.*/ - port_timer_start_alarm(chTimeAddX(vtlp->lasttime, delay)); - - return; - } - - /* Delay as delta from 'lasttime'. Note, it can overflow and the value - becomes lower than 'deltanow'.*/ - deltanow = chTimeDiffX(vtlp->lasttime, now); - delta = deltanow + delay; - - /* Scenario where a very large delay exceeded the numeric range, it - requires a special handling, the compression procedure.*/ - if (delta < deltanow) { - vt_list_compress(vtlp, deltanow); - delta -= deltanow; - } - else if (delta < vtlp->dlist.next->delta) { - sysinterval_t deadline_delta; - - /* A small delay that will become the first element in the delta list - and next deadline.*/ - deadline_delta = delta; -#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION - /* The delta could be too large for the physical timer to handle.*/ - if (deadline_delta > (sysinterval_t)TIME_MAX_SYSTIME) { - deadline_delta = (sysinterval_t)TIME_MAX_SYSTIME; - } -#endif - port_timer_set_alarm(chTimeAddX(vtlp->lasttime, deadline_delta)); - } - } -#else /* CH_CFG_ST_TIMEDELTA == 0 */ - /* Delta is initially equal to the specified delay.*/ - delta = delay; -#endif /* CH_CFG_ST_TIMEDELTA == 0 */ - - /* The delta list is scanned in order to find the correct position for - this timer. */ - dlp = vtlp->dlist.next; - while (dlp->delta < delta) { - /* Debug assert if the timer is already in the list.*/ - chDbgAssert(dlp != &vtp->dlist, "timer already armed"); - - delta -= dlp->delta; - dlp = dlp->next; - } - - /* The timer is inserted in the delta list.*/ - vtp->dlist.next = dlp; - vtp->dlist.prev = vtp->dlist.next->prev; - vtp->dlist.prev->next = &vtp->dlist; - dlp->prev = &vtp->dlist; - vtp->dlist.delta = delta; - - /* Calculate new delta for the following entry.*/ - dlp->delta -= delta; - - /* Special case when the timer is in last position in the list, the - value in the header must be restored.*/ - vtlp->dlist.delta = (sysinterval_t)-1; -} - -/*===========================================================================*/ -/* Module exported functions. */ -/*===========================================================================*/ - -/** - * @brief Enables a one-shot virtual timer. - * @details The timer is enabled and programmed to trigger after the delay - * specified as parameter. - * @pre The timer must not be already armed before calling this function. - * @note The callback function is invoked from interrupt context. - * - * @param[out] vtp the @p virtual_timer_t structure pointer - * @param[in] delay the number of ticks before the operation timeouts, the - * special values are handled as follow: - * - @a TIME_INFINITE is allowed but interpreted as a - * normal time specification. - * - @a TIME_IMMEDIATE this value is not allowed. - * . - * @param[in] vtfunc the timer callback function. After invoking the - * callback the timer is disabled and the structure can - * be disposed or reused. - * @param[in] par a parameter that will be passed to the callback - * function - * - * @iclass - */ -void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par) { - virtual_timers_list_t *vtlp = &currcore->vtlist; - systime_t now; - - chDbgCheckClassI(); - chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); - - /* Current system time.*/ - now = chVTGetSystemTimeX(); - - /* Timer initialization.*/ - vtp->par = par; - vtp->func = vtfunc; - vtp->last = now; - vtp->reload = (sysinterval_t)0; - - /* Inserting the timer in the delta list.*/ - vt_enqueue(vtlp, vtp, vtp->last, delay); -} - -/** - * @brief Enables a continuous virtual timer. - * @details The timer is enabled and programmed to trigger after the delay - * specified as parameter. - * @pre The timer must not be already armed before calling this function. - * @note The callback function is invoked from interrupt context. - * - * @param[out] vtp the @p virtual_timer_t structure pointer - * @param[in] delay the number of ticks before the operation timeouts, the - * special values are handled as follow: - * - @a TIME_INFINITE is allowed but interpreted as a - * normal time specification. - * - @a TIME_IMMEDIATE this value is not allowed. - * . - * @param[in] vtfunc the timer callback function. After invoking the - * callback the timer is disabled and the structure can - * be disposed or reused. - * @param[in] par a parameter that will be passed to the callback - * function - * - * @iclass - */ -void chVTDoSetContinuousI(virtual_timer_t *vtp, sysinterval_t delay, - vtfunc_t vtfunc, void *par) { - virtual_timers_list_t *vtlp = &currcore->vtlist; - systime_t now; - - chDbgCheckClassI(); - chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); - - /* Current system time.*/ - now = chVTGetSystemTimeX(); - - /* Timer initialization.*/ - vtp->par = par; - vtp->func = vtfunc; - vtp->last = now; - vtp->reload = delay; - - /* Inserting the timer in the delta list.*/ - vt_enqueue(vtlp, vtp, vtp->last, delay); -} - -/** - * @brief Disables a Virtual Timer. - * @pre The timer must be in armed state before calling this function. - * - * @param[in] vtp the @p virtual_timer_t structure pointer - * - * @iclass - */ -void chVTDoResetI(virtual_timer_t *vtp) { - virtual_timers_list_t *vtlp = &currcore->vtlist; - - chDbgCheckClassI(); - chDbgCheck(vtp != NULL); - chDbgAssert(chVTIsArmedI(vtp), "timer not armed"); - -#if CH_CFG_ST_TIMEDELTA == 0 - - /* The delta of the timer is added to the next timer.*/ - vtp->dlist.next->delta += vtp->dlist.delta; - - /* Removing the element from the delta list, marking it as not armed.*/ - vtp->dlist.prev->next = vtp->dlist.next; - vtp->dlist.next->prev = vtp->dlist.prev; - vtp->dlist.next = NULL; - - /* The above code changes the value in the header when the removed element - is the last of the list, restoring it.*/ - vtlp->dlist.delta = (sysinterval_t)-1; -#else /* CH_CFG_ST_TIMEDELTA > 0 */ - sysinterval_t nowdelta, delta; - - /* If the timer is not the first of the list then it is simply unlinked - else the operation is more complex.*/ - if (!is_first_timer(&vtlp->dlist, &vtp->dlist)) { - /* Removing the element from the delta list.*/ - vtp->dlist.prev->next = vtp->dlist.next; - vtp->dlist.next->prev = vtp->dlist.prev; - - /* Adding delta to the next element, if it is not the last one.*/ - if (is_timer(&vtlp->dlist, vtp->dlist.next)) - vtp->dlist.next->delta += vtp->dlist.delta; - - /* Marking timer as not armed.*/ - vtp->dlist.next = NULL; - - return; - } - - /* Removing the first timer from the list, marking it as not armed.*/ - vtlp->dlist.next = vtp->dlist.next; - vtlp->dlist.next->prev = &vtlp->dlist; - vtp->dlist.next = NULL; - - /* If the list become empty then the alarm timer is stopped and done.*/ - if (is_vtlist_empty(&vtlp->dlist)) { - port_timer_stop_alarm(); - - return; - } - - /* The delta of the removed timer is added to the new first timer.*/ - vtlp->dlist.next->delta += vtp->dlist.delta; - - /* If the new first timer has a delta of zero then the alarm is not - modified, the already programmed alarm will serve it.*/ -/* if (vtlp->dlist.next->delta == 0) { - return; - }*/ - - /* Distance in ticks between the last alarm event and current time.*/ - nowdelta = chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()); - - /* If the current time surpassed the time of the next element in list - then the event interrupt is already pending, just return.*/ - if (nowdelta >= vtlp->dlist.next->delta) { - return; - } - - /* Distance from the next scheduled event and now.*/ - delta = vtlp->dlist.next->delta - nowdelta; - - /* Making sure to not schedule an event closer than CH_CFG_ST_TIMEDELTA - ticks from now.*/ - if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { - delta = nowdelta + (sysinterval_t)CH_CFG_ST_TIMEDELTA; - } - else { - delta = nowdelta + delta; -#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION - /* The delta could be too large for the physical timer to handle.*/ - if (delta > (sysinterval_t)TIME_MAX_SYSTIME) { - delta = (sysinterval_t)TIME_MAX_SYSTIME; - } -#endif - } - port_timer_set_alarm(chTimeAddX(vtlp->lasttime, delta)); -#endif /* CH_CFG_ST_TIMEDELTA > 0 */ -} - -/** - * @brief Virtual timers ticker. - * @note The system lock is released before entering the callback and - * re-acquired immediately after. It is callback's responsibility - * to acquire the lock if needed. This is done in order to reduce - * interrupts jitter when many timers are in use. - * - * @iclass - */ -void chVTDoTickI(void) { - virtual_timers_list_t *vtlp = &currcore->vtlist; - - chDbgCheckClassI(); - -#if CH_CFG_ST_TIMEDELTA == 0 - vtlp->systime++; - if (!is_vtlist_empty(&vtlp->dlist)) { - /* The list is not empty, processing elements on top.*/ - --vtlp->dlist.next->delta; - while (vtlp->dlist.next->delta == (sysinterval_t)0) { - virtual_timer_t *vtp; - - /* Triggered timer.*/ - vtp = (virtual_timer_t *)vtlp->dlist.next; - - /* Removing the element from the delta list, marking it as not armed.*/ - vtp->dlist.next->prev = &vtlp->dlist; - vtlp->dlist.next = vtp->dlist.next; - vtp->dlist.next = NULL; - - chSysUnlockFromISR(); - vtp->func(vtp->par); - chSysLockFromISR(); - } - } -#else /* CH_CFG_ST_TIMEDELTA > 0 */ - delta_list_t *dlp; - sysinterval_t delta, nowdelta; - systime_t now = chVTGetSystemTimeX(); - - /* Looping through timers.*/ - dlp = vtlp->dlist.next; - while (true) { - - /* Delta between current time and last execution time.*/ - nowdelta = chTimeDiffX(vtlp->lasttime, now); - - /* The list scan is limited by the timers header having - "vtlp->dlist.delta == (sysinterval_t)-1" which is - greater than all deltas.*/ - if (nowdelta < dlp->delta) { - break; - } - - /* Consuming all timers between "vtp->lasttime" and now.*/ - do { - virtual_timer_t *vtp = (virtual_timer_t *)dlp; - - /* The "last time" becomes this timer's expiration time.*/ - vtlp->lasttime += dlp->delta; - nowdelta -= dlp->delta; - - /* Removing the timer from the list, marking it as not armed.*/ - dlp->next->prev = &vtlp->dlist; - vtlp->dlist.next = dlp->next; - dlp->next = NULL; - - /* If the list becomes empty then the timer is stopped.*/ - if (is_vtlist_empty(&vtlp->dlist)) { - port_timer_stop_alarm(); - } - - /* Now "last" marks the current deadline based on the stored - reload value. It is done before calling the callback because - the reload value could change. Note that "reload" could be - zero, no harm.*/ - vtp->last = chTimeAddX(vtp->last, vtp->reload); - - /* The callback is invoked outside the kernel critical zone.*/ - chSysUnlockFromISR(); - vtp->func(vtp->par); - chSysLockFromISR(); - - /* Getting again the system time after executing the callback in - order to reduce error.*/ - now = chVTGetSystemTimeX(); - - /* If a reload is defined the timer needs to be restarted.*/ - if (vtp->reload > (sysinterval_t)0) { - sysinterval_t skipped_delta; - - /* Calculating how much the real current time skipped past the - hypothetical current deadline.*/ - skipped_delta = chTimeDiffX(vtp->last, now); - - chDbgAssert(skipped_delta < vtp->reload, "skipped deadline"); - - /* Enqueuing the timer again using the calculated delta.*/ - vt_enqueue(vtlp, vtp, now, vtp->reload - skipped_delta); - } - - /* Next element in the list.*/ - dlp = vtlp->dlist.next; - } - while (dlp->delta <= nowdelta); - } - - /* If the list is empty, nothing else to do.*/ - if (is_vtlist_empty(&vtlp->dlist)) { - return; - } - - /* The "unprocessed nowdelta" time slice is added to "last time" - and subtracted to next timer's delta.*/ -// vtlp->lasttime += nowdelta; - vtlp->lasttime = chTimeAddX(vtlp->lasttime, nowdelta); - vtlp->dlist.next->delta -= nowdelta; - - /* Recalculating the next alarm time.*/ - delta = dlp->delta - chTimeDiffX(vtlp->lasttime, now); - if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { - delta = (sysinterval_t)CH_CFG_ST_TIMEDELTA; - } -#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION - /* The delta could be too large for the physical timer to handle.*/ - else if (delta > (sysinterval_t)TIME_MAX_SYSTIME) { - delta = (sysinterval_t)TIME_MAX_SYSTIME; - } -#endif - port_timer_set_alarm(chTimeAddX(now, delta)); - - chDbgAssert(chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()) <= - chTimeDiffX(vtlp->lasttime, chTimeAddX(now, delta)), - "exceeding delta"); -#endif /* CH_CFG_ST_TIMEDELTA > 0 */ -} - -#if (CH_CFG_USE_TIMESTAMP == TRUE) || defined(__DOXYGEN__) -/** - * @brief Generates a monotonic time stamp. - * @details This function generates a monotonic time stamp synchronized with - * the system time. The time stamp has the same resolution of - * system time. - * @note There is an assumption, this function must be called at - * least once before the system time wraps back to zero or - * synchronization is lost. You may use a periodic virtual timer with - * a very large interval in order to keep time stamps synchronized - * by calling this function. - * - * @return The time stamp. - * - * @iclass - */ -systimestamp_t chVTGetTimeStampI(void) { - os_instance_t * oip = currcore; - systimestamp_t last, stamp; - systime_t now; - - chDbgCheckClassI(); - - /* Current system time.*/ - now = chVTGetSystemTimeX(); - - /* Last time stamp generated.*/ - last = oip->vtlist.laststamp; - - /* Interval between the last time stamp and current time used for a new - time stamp. Note that this fails if the interval is larger than a - systime_t type.*/ - stamp = last + (systimestamp_t)chTimeDiffX((systime_t)last, now); - - chDbgAssert(oip->vtlist.laststamp <= stamp, "wrapped"); - - /* Storing the new stamp.*/ - oip->vtlist.laststamp = stamp; - - return stamp; -} - -/** - * @brief Resets and re-synchronizes the time stamps monotonic counter. - * - * @iclass - */ -void chVTResetTimeStampI(void) { - - chDbgCheckClassI(); - - currcore->vtlist.laststamp = (systimestamp_t)chVTGetSystemTimeX(); -} - -#endif /* CH_CFG_USE_TIMESTAMP == TRUE */ - -/** @} */ diff --git a/readme.txt b/readme.txt index f82413003..36c6f2277 100644 --- a/readme.txt +++ b/readme.txt @@ -74,6 +74,7 @@ ***************************************************************************** *** Next *** +- NEW: Reload feature added to RT virtual timers. - NEW: Upgraded the clock initialization for STM32G0, STM32L4 and STM32L4++ to the new standard (started with STM32G4). - NEW: Added support for STM32L422. diff --git a/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Flash and Run).launch b/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Flash and Run).launch index b66442fc0..73496f85f 100644 --- a/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Flash and Run).launch +++ b/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Flash and Run).launch @@ -1,49 +1,42 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Just Run).launch b/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Just Run).launch index 5b5f68d54..998e73c46 100644 --- a/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Just Run).launch +++ b/testrt/VT_STORM/debug/TEST-RT-VT_STORM (build-stm32g474re_nucleo64-ch.elf)(OpenOCD, Just Run).launch @@ -3,7 +3,7 @@ - + @@ -17,12 +17,12 @@ - + - - - - + + + + @@ -31,18 +31,11 @@ - + - - - - - - -