The usage of pdMS_TO_TICKS

yuguangworld wrote on Tuesday, November 13, 2018:

In the API references for xTimerCreate, it is said that "pdMS_TO_TICKS() can only be used if configTICK_RATE_HZ is less than or equal to 1000. " Why we can’t use this function when configTICK_RATE_HZ is larger than 1000?

I checked the source code, the function is as follows, TickType_t is uint64_t. I don’t see any limit that is regarding the configTICK_RATE_HZ.

#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) )

I would appreciate if anyone could point out the reason. Thanks in advance!

rtel wrote on Tuesday, November 13, 2018:

pcMS_TO_TICKS() is macro that has a default implementation, but can be overwritten to do whatever you want simply by defining the macro again in FreeRTOSConfig.h. TickType_t can be 16-bits, 32-bits or 64-bits, depending on the architecture and FreeRTOSConfig.h settings.

The docs say it only works with tick rates at or below 1KHz as the results are stored in integers that cannot store fractions of a millisecond.

It is unusual to want a tick rate at 1KHz, let alone faster, so needing a faster tick could be a sign that something is not optimal in the run-time design.

yuguangworld wrote on Tuesday, November 13, 2018:

Thanks Richard!

If I understand correctly, to make the results are integers, we need tick rate at or larger than 1kHz. For example, if it is 100Hz, and we set xTimeInMs to be 1, and the result is not integer, as follows,

( ( TickType_t ) ( ( ( TickType_t ) ( 1 ) * ( TickType_t ) 100 ) / ( TickType_t ) 1000 ) )= 0.1, which is not integer.

Please let me know if I misunderstood something.

rtel wrote on Wednesday, November 14, 2018:

Hmm, I wondering if the comment you referenced in your original post is
actually for the portTICK_PERIOD_MS constant, which is defined as:

#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )

ldb wrote on Wednesday, November 14, 2018:

I think moreover he is confused if your tick rate is 100Hz then you can’t ask for any period shorter than 10ms, the answer for anything less is 0 ticks. He did the calc above 1ms = 0.1 but since the macro does all integer maths the return is 0 which is absolutely correct.

The basic answer is you can’t do a 1ms delay on a 100Hz timer tick.

If you want more accurate delays than timertick itself on a task switcher you need to go into tickless operation if FreeRTOS supports it?

Alternatively setup the delay in a way not utilizing the task switcher like just loop reading a high speed free running clock after turning off the interrupts to stop preemption. The period is way smaller than a context switch period so worst you do is jitter the task switch by the delay period.

The worst case for the above is if you called the delay just as a timer tick is due. You end up with an 11ms (10ms + 1ms hard loop delay) before you allow the next switch and the next slice ends up at 9ms. Is that acceptable is a depends situation on what you are doing and in many situations you would not even notice it.