64-bit ticks on Cortex-M3

philpem wrote on Wednesday, November 16, 2016:

We’ve had a code review issue raised that our code could potentially suffer issues when the RTOS tick counter wraps around; at a tick interval of 100Hz with 32-bit ticks, this would be every 2^32 ticks, or 497 days – or 248.55 days if ticks are being subtracted (used in a signed fashion).

I’d like to increase the size of TickType_t to 64 bits, i.e. “unsigned long long”. Is this likely to have any adverse side effects which would need to be addressed?


rtel wrote on Wednesday, November 16, 2016:

If the review says there is something wrong in FreeRTOS, then you need
to say what it is.

If the review says there is something wrong in your code, then I would
recommend fixing it.

heinbali01 wrote on Wednesday, November 16, 2016:

Increasing the width of TickType_t sounds like postponing the problem.

The tick count value is normally treated as unsigned, and taking an unsigned difference is safe:

	TickType_t xNow = xTaskGetTickCount();
	TickType_t xDifference = xNow - xThen;

Only if you need timers and time-outs that last longer that 497 days (using 100 HZ), I would consider increasing the width.

The FreeRTOS kernel and libraries are fully aware that the tick-counter will have overflows.

It has recently been proposed to have the tick-counter start at an unusual value like:

	/* Let xTickCount have the first overflow 5 minutes after booting. */

	#define	configINITIAL_TICK_COUNT_VALUE	( ( ( TickType_t )~0u ) - pdMS_TO_TICKS( 5ul * 60000ul ) )


This change might be usefull for testing your code. At least the overflow will occur quickly.


rtel wrote on Wednesday, November 16, 2016:

Only if you need timers and time-outs that last longer that 497 days
(using 100 HZ), I would consider increasing the width.

…and even then it is not necessary as waking unnecessarily every 497
days in not going to impact battery life in any measurable way. You
just wake, see that you timed out rather than woke due to an event, then
go back to sleep for another 497 days.

Using a 64-bit tick type on a 32-bit architecture is possible, but it
requires a very minor code change. That is not the point though - at
the moment I don’t know what the OP wishes to make this change, and if
we knew that, we could provide a helpful answer.

philpem wrote on Thursday, November 17, 2016:

The review stated there was an issue in our code, not FreeRTOS.

We use xTaskGetTickCount() in a few places, e.g. to find out if a set period has elapsed since the last time an event occurred, using a function called “isTimeAfter” which has been posted here previously.

The issue was that our implementation would fail roughly every 248.5 days, when the timer wrapped around.

While the correct fix is obviously to add some kind of background task to set a “timer has expired Y/N” flag which invalidates the event flag (or to rework the code to use FreeRTOS software timers – but there was a desire not to use these because it would involve enabling another FreeRTOS build option and there was a strong desire not to do this “just for one minor feature”).

The general air of the code review was that “by increasing the timer tick to 64 bits, we can avoid problems like this in the future.”

rtel wrote on Thursday, November 17, 2016:

If you change the tick type to 64-bits then you will also need to edit
the portmacro.h file for your port to set portTICK_TYPE_IS_ATOMIC to 0.
However I would not recommend it, the tick type is used all over the
place and making it twice the natural word size of the architecture will
have a performance impact.

Do these functions help your case?

The second link includes example code.

heinbali01 wrote on Thursday, November 17, 2016:

Philip, would you mind posting the source of isTimeAfter again? I can not find it.

philpem wrote on Tuesday, November 22, 2016:

It’s from way back in the archives:

Apparently it was originally called timeAfter – we converted it from a function-like macro to an inline function (type checking is quite important for us from a software reliability POV) and renamed it.

philpem wrote on Tuesday, November 22, 2016:

I should also clarify: the specific case of this going wrong is that we were advised against using FreeRTOS Software Timers as it would require an additional Third Party Review to be done on that part of FreeRTOS, and we already had “timeAfter” reviewed.

This was suggested and implemented:

  • A global variable is set to xTaskGetTickCount() + 5 minutes when event “A” occurs
  • It’s reset to five minutes when further "event A"s occur
  • It stops waiting completely (set to zero) when a different type of event (“B”) occurs
  • Other things can poll to see if the five minutes has elapsed – that is to say, event “A” has elapsed, and five minutes have elapsed without either an event “A” resetting the counter to 5 minutes again, or an event “B” to say “done waiting, too late”.

In the review, this came up:

timeAfter() will return an incorrect return value when xTaskGetTickCount reaches half of its range, but event “A” hasn’t occurred yet (the global timer is still zero).

If you look at it in terms of 16-bit ticks:

xTaskGetTickCount = 0x7FFF
GlobalTimer = 0

timeAfter = (GlobalTimer - 0x7FFF) = 0x8001 = TRUE
timeAfter = (GlobalTimer - 0x8000) = 0x8000 = TRUE
timeAfter = (GlobalTimer - 0x8001) = 0x7FFF = FALSE
timeAfter = (GlobalTimer - 0x8002) = 0x7FFE = FALSE

The same holds if this is extended to 32-bit ticks.