Tentative fix for VTs and various improvements.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@14340 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
Giovanni Di Sirio 2021-05-06 11:26:08 +00:00
parent 84c18f04a5
commit f506bdca05
1 changed files with 49 additions and 72 deletions

View File

@ -461,32 +461,32 @@ void chVTDoTickI(void) {
#else /* CH_CFG_ST_TIMEDELTA > 0 */ #else /* CH_CFG_ST_TIMEDELTA > 0 */
delta_list_t *dlp; delta_list_t *dlp;
sysinterval_t delta, nowdelta; sysinterval_t delta, nowdelta;
systime_t now = chVTGetSystemTimeX(); systime_t now;
/* Delta between current time and last execution time.*/
now = chVTGetSystemTimeX();
nowdelta = chTimeDiffX(vtlp->lasttime, now);
/* Looping through timers.*/ /* Looping through timers.*/
dlp = vtlp->dlist.next; dlp = vtlp->dlist.next;
while (true) { while (true) {
virtual_timer_t *vtp = (virtual_timer_t *)dlp;
/* Delta between current time and last execution time.*/ /* Checking if the next timer in the list is within the current
nowdelta = chTimeDiffX(vtlp->lasttime, now); time delta. Note that the list scan is limited by the timers
header having "vtlp->dlist.delta == (sysinterval_t)-1" which is
/* The list scan is limited by the timers header having
"vtlp->dlist.delta == (sysinterval_t)-1" which is
greater than all deltas.*/ greater than all deltas.*/
if (nowdelta < dlp->delta) { if (nowdelta < dlp->delta) {
break; break;
} }
/* Consuming all timers between "vtp->lasttime" and now.*/ /* Last time deadline is updated to the next timer's time.*/
do {
virtual_timer_t *vtp = (virtual_timer_t *)dlp;
/* The "last time" becomes this timer's expiration time.*/
// vtlp->lasttime += dlp->delta;
vtlp->lasttime = chTimeAddX(vtlp->lasttime, dlp->delta); vtlp->lasttime = chTimeAddX(vtlp->lasttime, dlp->delta);
nowdelta -= dlp->delta; vtp->last = vtlp->lasttime;
/* Removing the timer from the list, marking it as not armed.*/ chDbgAssert((int)chTimeDiffX(vtlp->lasttime, now) >= 0, "back in time");
/* Removing the next timer from the list, marking it as not armed.*/
dlp->next->prev = &vtlp->dlist; dlp->next->prev = &vtlp->dlist;
vtlp->dlist.next = dlp->next; vtlp->dlist.next = dlp->next;
dlp->next = NULL; dlp->next = NULL;
@ -496,64 +496,41 @@ void chVTDoTickI(void) {
port_timer_stop_alarm(); port_timer_stop_alarm();
} }
/* Now "last" marks the current deadline based on the stored /* The callback is invoked outside the kernel critical section, it
reload value. It is done before calling the callback because is re-entered on the callback return. Note that "lasttime" can
the reload value could change. Note that "reload" could be be modified within the callback if some timer function is
zero, no harm.*/ called.*/
vtp->last = chTimeAddX(vtp->last, vtp->reload);
/* The callback is invoked outside the kernel critical zone.*/
chSysUnlockFromISR(); chSysUnlockFromISR();
vtp->func(vtp->par); vtp->func(vtp->par);
chSysLockFromISR(); chSysLockFromISR();
/* Getting again the system time after executing the callback in /* Delta between current time and last execution time.*/
order to reduce error.*/
now = chVTGetSystemTimeX(); now = chVTGetSystemTimeX();
nowdelta = chTimeDiffX(vtlp->lasttime, now);
// chDbgAssert((int)chTimeDiffX(vtp->last, now) >= 0, "back in time");
/* If a reload is defined the timer needs to be restarted.*/ /* If a reload is defined the timer needs to be restarted.*/
if (vtp->reload > (sysinterval_t)0) { if (vtp->reload > (sysinterval_t)0) {
sysinterval_t skipped_delta; sysinterval_t skipped_delta;
#if 1
/* Calculating how much the actual current time skipped past the /* Calculating how much the actual current time skipped past the
predicted current deadline.*/ current deadline.*/
skipped_delta = chTimeDiffX(vtp->last, now); skipped_delta = chTimeDiffX(vtp->last, now);
// if (vtp->reload == 121) {
// chTraceWriteI(vtp, (void *)now);
// chTraceWriteI(vtp, (void *)vtp->last);
// chTraceWriteI(vtp, (void *)skipped_delta);
// }
chDbgAssert(skipped_delta <= vtp->reload, "skipped deadline"); chDbgAssert(skipped_delta <= vtp->reload, "skipped deadline");
/* Enqueuing the timer again using the calculated delta.*/ /* Enqueuing the timer again using the calculated delta.*/
vt_enqueue(vtlp, vtp, now, vtp->reload - skipped_delta); vt_enqueue(vtlp, vtp, now, vtp->reload - skipped_delta);
#else
chVTDoSetI(vtp, vtp->reload, vtp->func, vtp->par);
#endif
} }
/* Next element in the list.*/ /* Next element in the list.*/
dlp = vtlp->dlist.next; dlp = vtlp->dlist.next;
} }
while (dlp->delta <= nowdelta);
}
/* If the list is empty, nothing else to do.*/ /* If the list is empty, nothing else to do.*/
if (is_vtlist_empty(&vtlp->dlist)) { if (is_vtlist_empty(&vtlp->dlist)) {
return; 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.*/ /* Recalculating the next alarm time.*/
delta = dlp->delta - chTimeDiffX(vtlp->lasttime, now); delta = dlp->delta - chTimeDiffX(vtlp->lasttime, now);
if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) { if (delta < (sysinterval_t)CH_CFG_ST_TIMEDELTA) {