[En-Nut-Discussion] Possible problem with timers

Holger Mai mai at gemac.info
Thu Feb 25 11:10:14 CET 2016


ok, Mea Culpa.

I ignored, that the time for the timers is an int.

And, indeed, 64bit operations on an 8bit MCU are horrible. But any operation
greater than 16bit on an 8bit system ist horrible, more or less. 32bit is less,
64bit is more. To prevent this, there are enough options available. Best is to
compile such (additional) codeblocks only if MCU can handle it. AVR can not good
handle, also compile it only, if MCU is not an AVR. Symbols for those things are
available and well used in other librarys of the NutOS-framework.

So, please, rollback the timer code i posted.

But i think it is still a good idea, to have (additional) functions to get
Milliseconds and Ticks as 64bit value.

This is my additional code (Note that the original 32bit result function is
named "NutGetMillis()" ):


#ifndef __AVR__

uint64_t NutGetMilliseconds(void)
{
uint64_t ticks;

#ifdef NUT_USE_OLD_TIME_API
    // carefully stay within 32 bit values
    ticks   = NutGetFullTickCount();
    uint64_t seconds = ticks / NutGetTickClock();
    ticks -= seconds * NutGetTickClock();
    ticks = seconds * 1000 + (ticks * 1000 ) / NutGetTickClock();
#else
    NutEnterCritical();
    ticks = system_time.tv_sec * 1000 + system_time.tv_usec / 1000;
    NutExitCritical();
#endif
    return ticks;
}

uint64_t NutGetFullTickCount(void)
{
    uint64_t rc;

#ifdef __NUT_EMULATION__
    struct timeval   timeNow;
    gettimeofday( &timeNow, NULL );
    rc = (timeNow.tv_sec - timeStart.tv_sec) * 1000;
    rc += (timeNow.tv_usec - timeStart.tv_usec) / 1000;
#else
#ifndef __CORTEX__
    NutEnterCritical();
    rc = nut_ticks;
    NutExitCritical();
#else
    /* 64bit value readings needs more than one op, therefore encapsulate as
critical section     */
    NutEnterCritical();
    rc = nut_ticks;
    NutExitCritical();
#endif
#endif

    return rc;
}

#endif



for timer.h:

/*
 * extended (64bit) API (do not use for 8bit AVR Machines)
 */
#ifndef __AVR__
extern uint64_t NutGetFullTickCount(void);
extern uint64_t NutGetMilliseconds(void);
#endif



now this funtions can be used in 32bit systems for timestamps, own timing
functions and so on, without the risc of overflows all 49 days for the
milliseconds function. For 32bit-Ticks the overflow time is dependent to the
Ticktime and may be longer (>1ms), equal (=1ms) or shorter (<1ms Ticktime)

Holger



Nathan Moore wrote:

With a system time that rolls over it is fairly easily handle rollovers as
long as
timers are never created with durations greater than 1/2 that of
unsigned_ticks_max (0xFFFFFFFF, for a 32 bit tick counter).

To do this rather than:

 if (expire_time <= current_time)

do:

 if (0<= (expire_time - current_time)

Oh, and you have to make sure that you service your timers often enough that
you never let anything sit in the timer queue longer than 1/2 of
unsigned_ticks_max because if things in the queue get old enough they will
cease to be expired and become unexpired again. Likewise, a time that it
too
far into the future will appear to be already expired, but this could be
caught
by the timer creation routine.

This will avoid introducing 64 bit values, which were horrible on AVR the
last
time that I looked, and also avoid having to worry about what happens to
timers
after 584558050 years of continuous operation of a Nut/OS system.

Nathan
_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion


More information about the En-Nut-Discussion mailing list