64 bit system time using 32bit TickCount

jarni wrote on Sunday, June 30, 2019:


uint64_t GetSysTime64()
{
	static uint64_t systime = 0;
	static uint32_t maxticktime = 0;
	static uint32_t overflow = 0;
	uint32_t ticktime;
	
	ticktime = xTaskGetTickCount();
	
	if (ticktime < maxticktime) overflow++;
	maxticktime = ticktime;
	
	systime = overflow;
	systime <<= 32;
	systime += ticktime;
	return systime;
}

heinbali01 wrote on Sunday, June 30, 2019:

systime” doesn’t have to be static :slight_smile:

If you do not call your function GetSysTime64() for a long time, you might miss an overflow.
With a 1000 Hz clock, the tick time overflows after 49 days, which is quiet a long time.

But mind you, there is a time tick hook, in which you can update your own tick counter:

#if(  configUSE_TICK_HOOK != 0 )
    volatile uint64_t tickCount64;
    void vApplicationTickHook( void )
    {
        tickCount64++;
    }
#endif /* configUSE_TICK_HOOK */

The above code won’t miss a single clock tick

jarni wrote on Sunday, June 30, 2019:

I didn’t remember configUSE_TICK_HOOK…
Anyway you need a mutex to read/write tickCount64, or:

uint64_t GetTickCount64()
{
    uint64_ tick;
    taskENTER_CRITICAL();
    tick = tickCount64;
    taskEXIT_CRITICAL();
    return tick;
}

heinbali01 wrote on Sunday, June 30, 2019:

In your example code, it would be more correct to use TickType_t in stead of uint32_t.

You’re right about the critical section, unless you have you’re on a 64-bit machine. And in that case, you wouldn’t need the extra code at all, because xTaskGetTickCount() will return a 64-bit count.

rtel wrote on Sunday, June 30, 2019:

Not sure what is trying to be achieved here, but the kernel code already
keeps a count of the number of overflows if that is helpful:

https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Source/tasks.c#l373

If you want access to it you can add your own code into tasks.c using
the c additions header file:

https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Source/tasks.c#l5203

heinbali01 wrote on Sunday, June 30, 2019:

One more addition about the atomical copy of TickType_t:

TickType_t xTaskGetTickCount( void )
{
TickType_t xTicks;

    /* Critical section required if running on a 16 bit processor. */
    portTICK_TYPE_ENTER_CRITICAL();
    {
        xTicks = xTickCount;
    }
    portTICK_TYPE_EXIT_CRITICAL();

    return xTicks;
}

With the above code, a critical section will be entered only if needed.

jarni wrote on Sunday, June 30, 2019:

On 32bit systems reading/modifying TickType_t variables is atomic:

/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
#if (portTICK_TYPE_IS_ATOMIC == 0)
/* Either variables of tick type cannot be read atomically, or
portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
the tick count is returned to the standard critical section macros. */
#define portTICK_TYPE_ENTER_CRITICAL() portENTER_CRITICAL()
#define portTICK_TYPE_EXIT_CRITICAL() portEXIT_CRITICAL()
#define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK_FROM_ISR((x))
#else
/* The tick type can be read atomically, so critical sections used when the
tick count is returned can be defined away. */
#define portTICK_TYPE_ENTER_CRITICAL()
#define portTICK_TYPE_EXIT_CRITICAL()
#define portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR() 0
#define portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR(x) (void)x
#endif

jarni wrote on Sunday, June 30, 2019:

I’m on a 32bit system, and I need to read system time many times per second, but I need a time counter that covers more than 49 days.
So the function of my first post is perfect.

jarni wrote on Sunday, June 30, 2019:

Yes, but this overflow count is more for internal use, and I prefer not to modify FreeRTOS source files.

rtel wrote on Sunday, June 30, 2019:

The point of the C inclusions header file is that you can add code into
the task.c file WITHOUT modifying the kernel code.

richarddamon wrote on Sunday, June 30, 2019:

FreeRTOS already keeps track of the number of times the tick has overflowed in xNumOfOverflows, and the vTaskSetTimeOutState function will fetch the current tick count and the current overflow state, so the data is already available. The details of what vTaskSetTimeOutState gets isn’t well documented.

It also wouldn’t be hard to use the freertos_tasks_c_additions.h hook to add a function to fetch the pair as a 64 bit number.

jarni wrote on Sunday, June 30, 2019:

For my apllication I nedd an absolute 64bit time counter.
vTaskSetTimeOutState doesn’t work well for me.

richarddamon wrote on Sunday, June 30, 2019:

But the values returned by it can easily be converted into the 64 bit value you want. The xNumOfOverflows is exactly what you overflow counter is, and kept by FreeRTOS in a way to prevent races.

Your function has the issue that it isn’t thread safe, and has a data race (If the first task that is calling it gets preempted after detecting the roll over but before resetting the maxTickTime, or after getting the current tick count and before testing against maxTickCount, and a tick increment occurs before some preempting task calls the function.

jarni wrote on Sunday, June 30, 2019:

I don’t need thread safe, only one task calls this function.
Anyway I can use taskENTER_CRITICAL.