Improved and fixed tickless mode.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@7842 35acf78f-673a-0410-8e92-d51de3d6d3f4master
parent
9366ed77a6
commit
56d0fdc011
|
@ -339,6 +339,26 @@ static inline bool chVTIsArmedI(virtual_timer_t *vtp) {
|
||||||
return (bool)(vtp->vt_func != NULL);
|
return (bool)(vtp->vt_func != 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(virtual_timer_t *vtp) {
|
||||||
|
bool b;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
b = chVTIsArmedI(vtp);
|
||||||
|
chSysUnlock();
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Disables a Virtual Timer.
|
* @brief Disables a Virtual Timer.
|
||||||
* @note The timer is first checked and disabled only if armed.
|
* @note The timer is first checked and disabled only if armed.
|
||||||
|
@ -466,35 +486,43 @@ static inline void chVTDoTickI(void) {
|
||||||
}
|
}
|
||||||
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||||
virtual_timer_t *vtp;
|
virtual_timer_t *vtp;
|
||||||
|
systime_t now, delta;
|
||||||
|
|
||||||
|
/* First timer to be processed.*/
|
||||||
|
vtp = ch.vtlist.vt_next;
|
||||||
|
now = chVTGetSystemTimeX();
|
||||||
|
|
||||||
/* The list is assumed to be non-empty because an tick interrupt just
|
/* The list is assumed to be non-empty because an tick interrupt just
|
||||||
occurred.*/
|
occurred.*/
|
||||||
chDbgAssert(&ch.vtlist != (virtual_timers_list_t *)ch.vtlist.vt_next,
|
chDbgAssert(&ch.vtlist != (virtual_timers_list_t *)vtp,
|
||||||
"timers list empty");
|
"timers list empty");
|
||||||
|
|
||||||
/* First timer to be processed, its time is assumed to be between
|
/* The timer time is assumed to be between "vt_lasttime" and "now".*/
|
||||||
"vt_lasttime" and "now".*/
|
|
||||||
vtp = ch.vtlist.vt_next;
|
|
||||||
|
|
||||||
chDbgAssert(chVTIsTimeWithinX(ch.vtlist.vt_lasttime + vtp->vt_delta,
|
chDbgAssert(chVTIsTimeWithinX(ch.vtlist.vt_lasttime + vtp->vt_delta,
|
||||||
ch.vtlist.vt_lasttime,
|
ch.vtlist.vt_lasttime,
|
||||||
chVTGetSystemTimeX() + 1),
|
now + 1),
|
||||||
"out of time window");
|
"out of time window");
|
||||||
|
|
||||||
/* Timers processing loop.*/
|
/* All timers within the time window are triggered and removed,
|
||||||
while (true) {
|
note that the loop is stopped by the timers header having
|
||||||
systime_t now;
|
"ch.vtlist.vt_delta == (systime_t)-1" which is greater than
|
||||||
|
all deltas.*/
|
||||||
|
while (vtp->vt_delta <= now - ch.vtlist.vt_lasttime) {
|
||||||
vtfunc_t fn;
|
vtfunc_t fn;
|
||||||
|
|
||||||
/* The "last time" becomes this timer's expiration time.*/
|
/* The "last time" becomes this timer's expiration time.*/
|
||||||
ch.vtlist.vt_lasttime += vtp->vt_delta;
|
ch.vtlist.vt_lasttime += vtp->vt_delta;
|
||||||
|
|
||||||
/* The timer is removed from the list and marked as non-armed.*/
|
|
||||||
vtp->vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist;
|
vtp->vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist;
|
||||||
ch.vtlist.vt_next = vtp->vt_next;
|
ch.vtlist.vt_next = vtp->vt_next;
|
||||||
fn = vtp->vt_func;
|
fn = vtp->vt_func;
|
||||||
vtp->vt_func = NULL;
|
vtp->vt_func = NULL;
|
||||||
|
|
||||||
|
/* if the list becomes empty then the timer is stopped.*/
|
||||||
|
if (ch.vtlist.vt_next == (virtual_timer_t *)&ch.vtlist) {
|
||||||
|
port_timer_stop_alarm();
|
||||||
|
}
|
||||||
|
|
||||||
/* Leaving the system critical zone in order to execute the callback
|
/* Leaving the system critical zone in order to execute the callback
|
||||||
and in order to give a preemption chance to higher priority
|
and in order to give a preemption chance to higher priority
|
||||||
interrupts.*/
|
interrupts.*/
|
||||||
|
@ -507,37 +535,27 @@ static inline void chVTDoTickI(void) {
|
||||||
of the list.*/
|
of the list.*/
|
||||||
chSysLockFromISR();
|
chSysLockFromISR();
|
||||||
|
|
||||||
/* If the list is empty then ending the loop, the list has to be
|
/* Next element in the list, the current time could have advanced so
|
||||||
re-checked because new timers could have been added/removed from
|
recalculating the time window.*/
|
||||||
within the callback or other ISRs.*/
|
|
||||||
vtp = ch.vtlist.vt_next;
|
vtp = ch.vtlist.vt_next;
|
||||||
if (&ch.vtlist == (virtual_timers_list_t *)vtp) {
|
|
||||||
/* Timers list empty, stopping alarms.*/
|
|
||||||
port_timer_stop_alarm();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Getting the current system time and calculating the time window since
|
|
||||||
the last time has expired.*/
|
|
||||||
now = chVTGetSystemTimeX();
|
now = chVTGetSystemTimeX();
|
||||||
|
|
||||||
/* The next element is outside the current time window, the loop
|
|
||||||
is stopped here.*/
|
|
||||||
if (vtp->vt_delta > now - ch.vtlist.vt_lasttime) {
|
|
||||||
/* Updating the alarm to the next deadline, deadline that must not be
|
|
||||||
closer in time than the minimum time delta.*/
|
|
||||||
systime_t delta = ch.vtlist.vt_lasttime + vtp->vt_delta - now;
|
|
||||||
if (delta < (systime_t)CH_CFG_ST_TIMEDELTA) {
|
|
||||||
delta = (systime_t)CH_CFG_ST_TIMEDELTA;
|
|
||||||
}
|
|
||||||
port_timer_set_alarm(now + delta);
|
|
||||||
|
|
||||||
chDbgAssert((chVTGetSystemTimeX() - ch.vtlist.vt_lasttime) < delta,
|
|
||||||
"exceeding delta");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if the list is empty, nothing else to do.*/
|
||||||
|
if (ch.vtlist.vt_next == (virtual_timer_t *)&ch.vtlist) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recalculating the next alarm time.*/
|
||||||
|
delta = ch.vtlist.vt_lasttime + vtp->vt_delta - now;
|
||||||
|
if (delta < (systime_t)CH_CFG_ST_TIMEDELTA) {
|
||||||
|
delta = (systime_t)CH_CFG_ST_TIMEDELTA;
|
||||||
|
}
|
||||||
|
port_timer_set_alarm(now + delta);
|
||||||
|
|
||||||
|
chDbgAssert((chVTGetSystemTimeX() - ch.vtlist.vt_lasttime) <=
|
||||||
|
(now + delta - ch.vtlist.vt_lasttime),
|
||||||
|
"exceeding delta");
|
||||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,40 +101,56 @@ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay,
|
||||||
|
|
||||||
vtp->vt_par = par;
|
vtp->vt_par = par;
|
||||||
vtp->vt_func = vtfunc;
|
vtp->vt_func = vtfunc;
|
||||||
p = ch.vtlist.vt_next;
|
|
||||||
|
|
||||||
#if CH_CFG_ST_TIMEDELTA > 0
|
#if CH_CFG_ST_TIMEDELTA > 0
|
||||||
{
|
{
|
||||||
systime_t now = chVTGetSystemTimeX();
|
systime_t now = chVTGetSystemTimeX();
|
||||||
|
|
||||||
/* If the requested delay is lower than the minimum safe delta then it
|
/* Special case where the timers list is empty.*/
|
||||||
is raised to the minimum safe value.*/
|
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) {
|
||||||
if (delay < (systime_t)CH_CFG_ST_TIMEDELTA) {
|
/* If the requested delay is lower than the minimum safe delta then it
|
||||||
delay = (systime_t)CH_CFG_ST_TIMEDELTA;
|
is raised to the minimum safe value.*/
|
||||||
|
if (delay < (systime_t)CH_CFG_ST_TIMEDELTA) {
|
||||||
|
delay = (systime_t)CH_CFG_ST_TIMEDELTA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The delta list is empty, the current time becomes the new
|
||||||
|
delta list base time, the timer is inserted.*/
|
||||||
|
ch.vtlist.vt_lasttime = now;
|
||||||
|
ch.vtlist.vt_next = vtp;
|
||||||
|
ch.vtlist.vt_prev = vtp;
|
||||||
|
vtp->vt_next = (virtual_timer_t *)&ch.vtlist;
|
||||||
|
vtp->vt_prev = (virtual_timer_t *)&ch.vtlist;
|
||||||
|
vtp->vt_delta = delay;
|
||||||
|
|
||||||
|
/* Being the first element in the list the alarm timer is started.*/
|
||||||
|
port_timer_start_alarm(ch.vtlist.vt_lasttime + delay);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (&ch.vtlist == (virtual_timers_list_t *)p) {
|
/* Special case where the timer will be placed as first element in a
|
||||||
/* The delta list is empty, the current time becomes the new
|
non-empty list, the alarm needs to be recalculated.*/
|
||||||
delta list base time.*/
|
if ((now + delay) < (ch.vtlist.vt_lasttime + ch.vtlist.vt_next->vt_delta)) {
|
||||||
ch.vtlist.vt_lasttime = now;
|
/* If the requested delay is lower than the minimum safe delta then it
|
||||||
port_timer_start_alarm(ch.vtlist.vt_lasttime + delay);
|
is raised to the minimum safe value.*/
|
||||||
}
|
if (delay < (systime_t)CH_CFG_ST_TIMEDELTA) {
|
||||||
else {
|
delay = (systime_t)CH_CFG_ST_TIMEDELTA;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now the delay is calculated as delta from the last tick interrupt
|
/* Now the delay is calculated as delta from the last tick interrupt
|
||||||
time.*/
|
time.*/
|
||||||
delay += now - ch.vtlist.vt_lasttime;
|
delay += now - ch.vtlist.vt_lasttime;
|
||||||
|
|
||||||
/* If the specified delay is closer in time than the first element
|
/* New alarm deadline.*/
|
||||||
in the delta list then it becomes the next alarm event in time.*/
|
port_timer_set_alarm(ch.vtlist.vt_lasttime + delay);
|
||||||
if (delay < p->vt_delta) {
|
|
||||||
port_timer_set_alarm(ch.vtlist.vt_lasttime + delay);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||||
|
|
||||||
/* The delta list is scanned in order to find the correct position for
|
/* The delta list is scanned in order to find the correct position for
|
||||||
this timer. */
|
this timer. */
|
||||||
|
p = ch.vtlist.vt_next;
|
||||||
while (p->vt_delta < delay) {
|
while (p->vt_delta < delay) {
|
||||||
delay -= p->vt_delta;
|
delay -= p->vt_delta;
|
||||||
p = p->vt_next;
|
p = p->vt_next;
|
||||||
|
|
Loading…
Reference in New Issue