mirror of https://github.com/rusefi/ChibiOS.git
Virtual timers tolerance to insufficient delta, experimental.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@14727 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
parent
0980d3af53
commit
3407139cf6
158
os/rt/src/chvt.c
158
os/rt/src/chvt.c
|
@ -49,6 +49,91 @@
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
|
#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
|
||||||
|
#if 1
|
||||||
|
static systime_t vt_set_alarm(systime_t basetime, sysinterval_t delta) {
|
||||||
|
sysinterval_t mindelta;
|
||||||
|
systime_t next_alarm;
|
||||||
|
|
||||||
|
/* Initial delta is what is configured statically.*/
|
||||||
|
mindelta = (sysinterval_t)CH_CFG_ST_TIMEDELTA;
|
||||||
|
|
||||||
|
if (delta < mindelta) {
|
||||||
|
/* We need to avoid that the system time goes past the alarm we are
|
||||||
|
going to set before the alarm is actually set.*/
|
||||||
|
delta = mindelta;
|
||||||
|
}
|
||||||
|
#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION
|
||||||
|
else if (delta > (sysinterval_t)TIME_MAX_SYSTIME) {
|
||||||
|
/* The delta could be too large for the physical timer to handle
|
||||||
|
this can happen when: sizeof (systime_t) < sizeof (sysinterval_t).*/
|
||||||
|
delta = (sysinterval_t)TIME_MAX_SYSTIME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
sysinterval_t nowdelta;
|
||||||
|
systime_t now;
|
||||||
|
|
||||||
|
/* Absolute time for next alarm.*/
|
||||||
|
next_alarm = chTimeAddX(basetime, delta);
|
||||||
|
|
||||||
|
/* Setting up the alarm on the next deadline.*/
|
||||||
|
port_timer_set_alarm(next_alarm);
|
||||||
|
|
||||||
|
/* Check on current time, we need to detect the error condition where
|
||||||
|
current time skipped past the calculated deadline.*/
|
||||||
|
now = chVTGetSystemTimeX();
|
||||||
|
nowdelta = chTimeDiffX(basetime, now);
|
||||||
|
if (nowdelta < delta) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trying again with a more relaxed minimum delta.*/
|
||||||
|
mindelta += (sysinterval_t)1;
|
||||||
|
|
||||||
|
/* Current time becomes the new "base" time.*/
|
||||||
|
basetime = now;
|
||||||
|
delta = mindelta;
|
||||||
|
|
||||||
|
#if !defined(CH_VT_RFCU_DISABLED)
|
||||||
|
chRFCUCollectFaultsI(CH_RFCU_VT_INSUFFICIENT_DELTA);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_alarm;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static systime_t vt_set_alarm(systime_t basetime, sysinterval_t delta) {
|
||||||
|
sysinterval_t mindelta;
|
||||||
|
systime_t next_alarm;
|
||||||
|
|
||||||
|
/* Initial delta is what is configured statically.*/
|
||||||
|
mindelta = (sysinterval_t)CH_CFG_ST_TIMEDELTA;
|
||||||
|
|
||||||
|
if (delta < mindelta) {
|
||||||
|
/* We need to avoid that the system time goes past the alarm we are
|
||||||
|
going to set before the alarm is actually set.*/
|
||||||
|
delta = mindelta;
|
||||||
|
}
|
||||||
|
#if CH_CFG_INTERVALS_SIZE > CH_CFG_ST_RESOLUTION
|
||||||
|
else if (delta > (sysinterval_t)TIME_MAX_SYSTIME) {
|
||||||
|
/* The delta could be too large for the physical timer to handle
|
||||||
|
this can happen when: sizeof (systime_t) < sizeof (sysinterval_t).*/
|
||||||
|
delta = (sysinterval_t)TIME_MAX_SYSTIME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Absolute time for next alarm.*/
|
||||||
|
next_alarm = chTimeAddX(basetime, delta);
|
||||||
|
|
||||||
|
/* Setting up the alarm on the next deadline.*/
|
||||||
|
port_timer_set_alarm(next_alarm);
|
||||||
|
|
||||||
|
return next_alarm;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Inserts a timer as first element in a delta list.
|
* @brief Inserts a timer as first element in a delta list.
|
||||||
* @note This is the special case when the delta list is initially empty.
|
* @note This is the special case when the delta list is initially empty.
|
||||||
|
@ -120,24 +205,8 @@ static void vt_enqueue(virtual_timers_list_t *vtlp,
|
||||||
/* Checking if this timer would become the first in the delta list, this
|
/* Checking if this timer would become the first in the delta list, this
|
||||||
requires changing the current alarm setting.*/
|
requires changing the current alarm setting.*/
|
||||||
if (delta < vtlp->dlist.next->delta) {
|
if (delta < vtlp->dlist.next->delta) {
|
||||||
sysinterval_t deadline_delta;
|
|
||||||
|
|
||||||
/* A small delay that will become the first element in the delta list
|
(void) vt_set_alarm(vtlp->lasttime, delta);
|
||||||
and next deadline.*/
|
|
||||||
deadline_delta = delta;
|
|
||||||
|
|
||||||
/* Limit delta to CH_CFG_ST_TIMEDELTA.*/
|
|
||||||
if (deadline_delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {
|
|
||||||
deadline_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
|
|
||||||
this can happen when: sizeof (systime_t) < sizeof (sysinterval_t).*/
|
|
||||||
else 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 */
|
#else /* CH_CFG_ST_TIMEDELTA == 0 */
|
||||||
|
@ -258,6 +327,7 @@ void chVTDoResetI(virtual_timer_t *vtp) {
|
||||||
is the last of the list, restoring it.*/
|
is the last of the list, restoring it.*/
|
||||||
vtlp->dlist.delta = (sysinterval_t)-1;
|
vtlp->dlist.delta = (sysinterval_t)-1;
|
||||||
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||||
|
systime_t now;
|
||||||
sysinterval_t nowdelta, delta;
|
sysinterval_t nowdelta, delta;
|
||||||
|
|
||||||
/* If the timer is not the first of the list then it is simply unlinked
|
/* If the timer is not the first of the list then it is simply unlinked
|
||||||
|
@ -296,7 +366,8 @@ void chVTDoResetI(virtual_timer_t *vtp) {
|
||||||
vtlp->dlist.next->delta += vtp->dlist.delta;
|
vtlp->dlist.next->delta += vtp->dlist.delta;
|
||||||
|
|
||||||
/* Distance in ticks between the last alarm event and current time.*/
|
/* Distance in ticks between the last alarm event and current time.*/
|
||||||
nowdelta = chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX());
|
now = chVTGetSystemTimeX();
|
||||||
|
nowdelta = chTimeDiffX(vtlp->lasttime, now);
|
||||||
|
|
||||||
/* If the current time surpassed the time of the next element in list
|
/* If the current time surpassed the time of the next element in list
|
||||||
then the event interrupt is already pending, just return.*/
|
then the event interrupt is already pending, just return.*/
|
||||||
|
@ -307,21 +378,8 @@ void chVTDoResetI(virtual_timer_t *vtp) {
|
||||||
/* Distance from the next scheduled event and now.*/
|
/* Distance from the next scheduled event and now.*/
|
||||||
delta = vtlp->dlist.next->delta - nowdelta;
|
delta = vtlp->dlist.next->delta - nowdelta;
|
||||||
|
|
||||||
/* Making sure to not schedule an event closer than CH_CFG_ST_TIMEDELTA
|
/* Setting up the alarm.*/
|
||||||
ticks from now.*/
|
(void) vt_set_alarm(now, delta);
|
||||||
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 */
|
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +465,7 @@ void chVTDoTickI(void) {
|
||||||
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||||
virtual_timer_t *vtp;
|
virtual_timer_t *vtp;
|
||||||
sysinterval_t delta, nowdelta;
|
sysinterval_t delta, nowdelta;
|
||||||
systime_t now;
|
systime_t now, next_alarm;
|
||||||
|
|
||||||
/* Looping through timers consuming all timers with deltas lower or equal
|
/* Looping through timers consuming all timers with deltas lower or equal
|
||||||
than the interval between "now" and "lasttime".*/
|
than the interval between "now" and "lasttime".*/
|
||||||
|
@ -510,36 +568,12 @@ void chVTDoTickI(void) {
|
||||||
/* Calculating the delta to the next alarm time.*/
|
/* Calculating the delta to the next alarm time.*/
|
||||||
delta = vtp->dlist.delta - nowdelta;
|
delta = vtp->dlist.delta - nowdelta;
|
||||||
|
|
||||||
/* Limit delta to CH_CFG_ST_TIMEDELTA.*/
|
|
||||||
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
|
|
||||||
|
|
||||||
/* Update alarm time to next timer.*/
|
/* Update alarm time to next timer.*/
|
||||||
{
|
next_alarm = vt_set_alarm(now, delta);
|
||||||
sysinterval_t next_alarm = chTimeAddX(now, delta);
|
|
||||||
|
|
||||||
port_timer_set_alarm(next_alarm);
|
chDbgAssert(chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()) <=
|
||||||
|
chTimeDiffX(vtlp->lasttime, next_alarm),
|
||||||
#if !defined(CH_VT_RFCU_DISABLED)
|
"insufficient delta");
|
||||||
if (chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()) >
|
|
||||||
chTimeDiffX(vtlp->lasttime, next_alarm)) {
|
|
||||||
|
|
||||||
chDbgAssert(false, "insufficient delta");
|
|
||||||
chRFCUCollectFaultsI(CH_RFCU_VT_INSUFFICIENT_DELTA);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
chDbgAssert(chTimeDiffX(vtlp->lasttime, chVTGetSystemTimeX()) <=
|
|
||||||
chTimeDiffX(vtlp->lasttime, next_alarm),
|
|
||||||
"insufficient delta");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
# Compiler options here.
|
# Compiler options here.
|
||||||
ifeq ($(USE_OPT),)
|
ifeq ($(USE_OPT),)
|
||||||
USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
|
USE_OPT = -Og -ggdb -fomit-frame-pointer -falign-functions=16
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# C specific options here (added to USE_OPT).
|
# C specific options here (added to USE_OPT).
|
||||||
|
|
|
@ -277,6 +277,7 @@ void vt_storm_execute(const vt_storm_config_t *cfg) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 1; i <= VT_STORM_CFG_ITERATIONS; i++) {
|
for (i = 1; i <= VT_STORM_CFG_ITERATIONS; i++) {
|
||||||
|
bool dw;
|
||||||
|
|
||||||
chprintf(cfg->out, "Iteration %d\r\n", i);
|
chprintf(cfg->out, "Iteration %d\r\n", i);
|
||||||
chThdSleepS(TIME_MS2I(10));
|
chThdSleepS(TIME_MS2I(10));
|
||||||
|
@ -305,7 +306,7 @@ void vt_storm_execute(const vt_storm_config_t *cfg) {
|
||||||
chVTSetI(&guard2, TIME_MS2I(250) + (CH_CFG_TIME_QUANTUM + 1), guard_cb, NULL);
|
chVTSetI(&guard2, TIME_MS2I(250) + (CH_CFG_TIME_QUANTUM + 1), guard_cb, NULL);
|
||||||
chVTSetI(&guard3, TIME_MS2I(250) + (CH_CFG_TIME_QUANTUM * 2), guard_cb, NULL);
|
chVTSetI(&guard3, TIME_MS2I(250) + (CH_CFG_TIME_QUANTUM * 2), guard_cb, NULL);
|
||||||
|
|
||||||
/* Letting them run for half second.*/
|
/* Letting them run for a while.*/
|
||||||
chThdSleepS(TIME_MS2I(100));
|
chThdSleepS(TIME_MS2I(100));
|
||||||
|
|
||||||
/* Stopping everything.*/
|
/* Stopping everything.*/
|
||||||
|
@ -323,21 +324,23 @@ void vt_storm_execute(const vt_storm_config_t *cfg) {
|
||||||
chVTResetI(&guard3);
|
chVTResetI(&guard3);
|
||||||
|
|
||||||
/* Check for relevant RFCU events.*/
|
/* Check for relevant RFCU events.*/
|
||||||
delta_warning = chRFCUGetAndClearFaultsI(CH_RFCU_VT_INSUFFICIENT_DELTA |
|
dw = chRFCUGetAndClearFaultsI(CH_RFCU_VT_INSUFFICIENT_DELTA |
|
||||||
CH_RFCU_VT_SKIPPED_DEADLINE) != (rfcu_mask_t)0;
|
CH_RFCU_VT_SKIPPED_DEADLINE) != (rfcu_mask_t)0;
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
|
|
||||||
if (saturated) {
|
if (saturated) {
|
||||||
chprintf(cfg->out, "#");
|
chprintf(cfg->out, "#");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (delta_warning) {
|
else if (dw) {
|
||||||
|
palToggleLine(config->line);
|
||||||
chprintf(cfg->out, "+");
|
chprintf(cfg->out, "+");
|
||||||
break;
|
delta_warning = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
palToggleLine(config->line);
|
||||||
|
chprintf(cfg->out, ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
palToggleLine(config->line);
|
|
||||||
chprintf(cfg->out, ".");
|
|
||||||
// if (delay >= TIME_US2I(1)) {
|
// if (delay >= TIME_US2I(1)) {
|
||||||
// delay -= TIME_US2I(1);
|
// delay -= TIME_US2I(1);
|
||||||
// }
|
// }
|
||||||
|
|
Loading…
Reference in New Issue