[En-Nut-Discussion] Possible problem with timers
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()" ):
// carefully stay within 32 bit values
ticks = NutGetFullTickCount();
uint64_t seconds = ticks / NutGetTickClock();
ticks -= seconds * NutGetTickClock();
ticks = seconds * 1000 + (ticks * 1000 ) / NutGetTickClock();
ticks = system_time.tv_sec * 1000 + system_time.tv_usec / 1000;
struct timeval timeNow;
gettimeofday( &timeNow, NULL );
rc = (timeNow.tv_sec - timeStart.tv_sec) * 1000;
rc += (timeNow.tv_usec - timeStart.tv_usec) / 1000;
rc = nut_ticks;
/* 64bit value readings needs more than one op, therefore encapsulate as
critical section */
rc = nut_ticks;
* extended (64bit) API (do not use for 8bit AVR Machines)
extern uint64_t NutGetFullTickCount(void);
extern uint64_t NutGetMilliseconds(void);
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)
Nathan Moore wrote:
With a system time that rolls over it is fairly easily handle rollovers 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)
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
far into the future will appear to be already expired, but this could be
by the timer creation routine.
This will avoid introducing 64 bit values, which were horrible on AVR the
time that I looked, and also avoid having to worry about what happens to
after 584558050 years of continuous operation of a Nut/OS system.
More information about the En-Nut-Discussion