1 tick delayed task start after portSUPPRESS_TICKS_AND_SLEEP

bernatikv wrote on Wednesday, April 05, 2017:

Hello,
I got nRF52 port of FreeRtos and there were tick bug. They called correctly vTaskStepTick(diff); but then they did not clear RTC->Compare Event flag. Thus they effectively jumped into RTC ISR and added extra tick. And thus effectively after every portSUPPRESS_TICKS_AND_SLEEP system tick was 1 tick faster and timing was wrong. I did fix that by clearing RTC Compare Event Flag. That fixed frequency when in my test code I was calling function vTaskDelayUntil( &xLastWakeTime, xFrequency ); . But I noticed another problem. I noticed there is one tick delay - between CPU wake up #define configPOST_SLEEP_PROCESSING( x ) nrf_gpio_pin_set(CPU_RUN_PIN); and actually starting the task. I find out it is due to fact that adding delayed task from pxDelayedTaskList is happenning only in xTaskIncrementTick(). I assume that is not correct. I assume that it shall also happen in vTaskStepTick(). So I assume it is bug in FreeRTOS. I’m actually having old version FreeRTOS V8.2.1, but I downloaded later FreeRTOS V9.0.0 and I saw there is same vTaskStepTick(). I know how to workaround it. I just call vTaskStepTick() with update value 1 tick lower than should be and I keep RTC compare event flag. So I let xTaskIncrementTick() to count last tick and it is working fine. It just seems like bug that many people may not notice and could have 1 tick of CPU being in zombie mode where task is still in pxDelayedTaskList although it shall be running already. What do you think? Can vTaskStepTick() be updated with delayed task timeout expire check?

rtel wrote on Wednesday, April 05, 2017:

It is not clear, are you saying you can replicate this in the code
provided by us? As I recall in the default tickless mode the step tick
function is passed one less than the expected idle time because when it
executes there is already a tick interrupt pending.

bernatikv wrote on Monday, April 10, 2017:

I have no platform to test your original distro. I’m observing the bug on Nordic SDK 12.0 and 13.0. I hate those Nordic guys for giving me buggy SDK so I’m biased against them. But frankly I think FreeRTOS is partially in fault here. If you look into documentation http://www.freertos.org/vTaskStepTick.html
freeRTOS just say call this function and correct time. There shall be some warning (ideally with big red letters) that this function is not rescheduling tasks. And task are rescheduled only after xTaskIncrementTick() is actually called. So what you want to do is correct the time -1 and call xTaskIncrementTick(). This bug is hard to find because it only delays starting the task 1 tick. But if you do low power design and you let CPU run wait loop for one tick then it is not such banality as it may sound…

bernatikv wrote on Monday, April 10, 2017:

I think free rtos shall modify documentation into this way: into documentation http://www.freertos.org/vTaskStepTick.html

...
/* Determine how long the microcontroller was actually in a low power state
    for, which will be less than xExpectedIdleTime if the microcontroller was
    brought out of low power mode by an interrupt other than that configured by
    the vSetWakeTimeInterrupt() call.  Note that the scheduler is suspended
    before portSUPPRESS_TICKS_AND_SLEEP() is called, and resumed when
    portSUPPRESS_TICKS_AND_SLEEP() returns.  Therefore no other tasks will
    execute until this function completes. */
    ulLowPowerTimeAfterSleep = ulGetExternalTime();

    /* Correct the kernels tick count to account for the time the microcontroller
    spent in its low power state. 
    Subtract one as it will be counted by xTaskIncrementTick() later*/
    vTaskStepTick( ulLowPowerTimeAfterSleep – ulLowPowerTimeBeforeSleep -1);
    
    // call once tick so rescheduling is forced when xTaskResumeAll() is 
    //   called - otherwise task start one tick later,
    // and there is one tick of useless CPU consumption
    xTaskIncrementTick();

    /* Restart the timer that is generating the tick interrupt. */
    prvStartTickInterruptTimer();
    ...

rtel wrote on Monday, April 10, 2017:

I’m still not really following what the problem is. I know Nordic had a
bug in their implementation as it is mentioned on their forum some times

  • at which time they also point the poster’s to the fix they provided.

vTaskStepTick() is not something the application writer should be
calling directly. It is only for use by tickless low power implementations.

The tickless idle implementation does not switch to another task. It
stops the tick, places the system into a low power state, correct the
time when it starts running again, and restarts the tick. It is brought
out of low power mode by an interrupt. If the interrupt handler (which
may be the timer interrupt set to mark the end of the idle period)
requests a context switch then the context switch will be held pending
until the ‘suppress ticks and sleep’ function exits. The ‘suppress
ticks and sleep’ function is called with the scheduler suspended, so
when it exits the scheduler is unsuspended, and at which point any
pending context switches will occur.

For the tickless idle function to perform a context switch itself would
be a logical error - besides which - it is called with the scheduler
suspended so it couldn’t even if it tried. The context switch would
just pend until the scheduler was restarted.

It sounds like you are describing what might be subtle bug, and maybe
you are right, but I’m afraid I don’t understand what it is you are
describing. You say the suppress ticks and sleep function is not
switching tasks - which is right - it definitely should not.

So please clearly describe the scenario where you think there is a
problem, something like this:

  1. The clock is programmed to wake in 10000 clock counts.
  2. Interrupts are disabled.
  3. Low power mode is entered.
  4. TBD interrupt occurs, bringing the MCU out of low power mode after
    5000 clock counts.
  5. Etc.

until I see the bit that you think is wrong.

bernatikv wrote on Monday, April 10, 2017:

Ok let’s go step by step:

  1. expect there is one task and that task will call vTaskDelayUntil( ...);
  2. FreeRTOS starts idle task portTASK_FUNCTION( prvIdleTask, pvParameters )
  3. Idle tasks calls vTaskSuspendAll();
  4. Then it put CPU to sleep calling: portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
  5. When CPU wakes up it will just correct time as is in free rtos help: vTaskStepTick(diff);
  6. Then it returns to idle task and it will call: ( void ) xTaskResumeAll();
    But here is a problem. Nor vTaskStepTick() nor xTaskResumeAll() checks if tasks is unblocked. Someone has to call BaseType_t xTaskIncrementTick( void ) which would place the task on ready list: prvAddTaskToReadyList( pxTCB );. Since no-one did that what is hapenning? CPU is in forever loop in idle task. Consumes energy and doing nothing for whole 1 tick. After tick finally happen ISR void xPortSysTickHandler( void ) calls xTaskIncrementTick(); and it will unblock task and put it to ready list. But 1 tick late!.

How to fix it? In step 5 you can call instead of vTaskStepTick(diff); follwoing sequence:

vTaskStepTick(diff-1); // -1 because we will call tick event just in next command
xTaskIncrementTick(); // this will actually use ++uxPendedTicks; because task sheduler is suspended

Now if you move to step 6 everything is going fine. xTaskResumeAll(); restart scheduler, detects uxPendedTicks, thus calls xTaskIncrementTick() which will add task to prvAddTaskToReadyList( pxTCB ); and retrun true so xTaskResumeAll(); will call taskYIELD_IF_USING_PREEMPTION(); and task is switched to right after CPU waking up Hurray! everything works now :slight_smile:

So what I think you shall do - either document this into vTaskStepTick() that it is developer responsibility to call xTaskIncrementTick(); or better rewrite vTaskStepTick() to do:

xTickCount += xTicksToJump-1;
xTaskIncrementTick();

Did I made myself clear enough this time??

rtel wrote on Tuesday, April 11, 2017:

Ok let’s go step by step:

This is good…

  1. expect there is one task and that task will call |vTaskDelayUntil( …);|

Lets say the call is vTaskDelay( 10 ), and to make it easy, that 10
means 10 milliseconds (1KHz tick).

  1. FreeRTOS starts idle task |portTASK_FUNCTION( prvIdleTask,
    pvParameters )|
  2. Idle tasks calls |vTaskSuspendAll();|

That will prevent context switches occurring, but will keep any
requested context switches pending.

  1. Then it put CPU to sleep calling: |portSUPPRESS_TICKS_AND_SLEEP(
    xExpectedIdleTime );|

Lets say the MCU slept for the full 10ms, so it is the timer interrupt
(SysTick interrupt) that brings the CPU out of sleep mode.

When the CPU comes out of sleep mode interrupts become enabled for a
short while, at which point the SysTick interrupt executes. The SysTick
handler calls xTaskIncrementTick() - but the scheduler is suspended so
xTaskIncrementTick() just increments the uxPendedTicks variable to hold
the tick pending.

  1. When CPU wakes up it will just correct time as is in free rtos help:
    |vTaskStepTick(diff);|

vTaskStepTick() should now be called with 9 as its parameter. That is,
9 ticks are going to be stepped, one tick is already pending, making the
total of 10 ticks. Therefore the tick count should be stepped forward
to the time the task that called vTaskDelay( 10 ) should unblock.

  1. Then it returns to idle task and it will call: |( void )
    xTaskResumeAll();|

xTaskResumeAll() calls xTaskIncrementTick() once per count held pending
in the uxPendedTicks variable. The tick count has already been stepped
forward 9, calling xTaskIncrementTick() increments the tick for the 10th
time, so the time reaches the time at which the task that called
vTaskDelay() should leave the blocked state, and the task is unblocked,
and a context switch pended. The context switch will execute before
xTaskResumeAll() exits - as soon as xTaskResumeAll() exits its critical
section.

But here is a problem. Nor |vTaskStepTick()| nor |xTaskResumeAll()|
checks if tasks is unblocked.

In the scenario above xTaskResumeAll() unblocks the task when it calls
xTaskIncrementTick().

Someone has to call |BaseType_t
xTaskIncrementTick( void )| which would place the task on ready list:
|prvAddTaskToReadyList( pxTCB );|. Since no-one did that what is
hapenning? CPU is in forever loop in idle task. Consumes energy and
doing nothing for whole 1 tick.

It sounds like there is something else wrong in your code. Do you have
the fixed code from Nordic?

How to fix it? In step 5 you can call instead of |vTaskStepTick(diff);|
follwoing sequence:

vTaskStepTick(diff-1); // -1 because we will call tick event just in next command
xTaskIncrementTick(); // this will actually use ++uxPendedTicks; because task sheduler is suspended

That will result in the tick count being one ahead of where it should be.

So what I think you shall do - either document this into
|vTaskStepTick()| that it is developer responsibility to call
|xTaskIncrementTick();| or better rewrite |vTaskStepTick()| to do:

xTickCount += xTicksToJump-1;
xTaskIncrementTick();

Did I made myself clear enough this time??

Yes, understood this time, thanks, but the scenario you describe is not
the scenario I see in the code. Can you determine where your observed
behaviour differs from the sequence I have described above?

The sequence I describe above assumes it is the tick that brings the MCU
out of sleep mode. If another interrupt brings the CPU out of sleep
mode then it is up to that interrupt to pend a context switch if one is
necessary - but that is true of all interrupts that perform an action
that brings a task out of the Blocked state. Make sure your interrupt
handlers are doing that correctly if you have something other than the
tick bringing your CPU out of sleep mode.

bernatikv wrote on Tuesday, April 11, 2017:

Hello your sentence:

“When the CPU comes out of sleep mode interrupts become enabled for a
short while, at which point the SysTick interrupt executes.”

is not correct. Nordic goes to sleep with global interrupt disabled. The CPU is woken up on interrupts but would not go to ISR.

Also such behavior might be quite dangerous from other point of view. Imagine that CPU is woken by other event. And imagine that ISR of that other even would ask to get sysTick from ISR. It might be very imprecise before correction is done. The CPU could have slept for minute and thus timestamp of event stored by such ISR would be totaly old and incorect.

Also nordic quite reasonably after correcting time using function vTaskStepTick() clears the RTC IRQ Flags, because they already fixed the time. And there was not written in documentation that vTaskStepTick() won’t reschedule delayed tasks into ready tasks (what in my opinion would be expectable and nice from that function).

You can see what they do in port_cmsis_systick.c:

void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
    /*
     * Implementation note:
     *
     * To help debugging the option configUSE_TICKLESS_IDLE_SIMPLE_DEBUG was presented.
     * This option would make sure that even if program execution was stopped inside
     * this function no more than expected number of ticks would be skipped.
     *
     * Normally RTC works all the time even if firmware execution was stopped
     * and that may lead to skipping too much of ticks.
     */
    TickType_t enterTime;

    /* Make sure the SysTick reload value does not overflow the counter. */
    if ( xExpectedIdleTime > portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
    {
        xExpectedIdleTime = portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP;
    }
    /* Block all the interrupts globally */
#ifdef SOFTDEVICE_PRESENT
    do{
        uint8_t dummy = 0;
        uint32_t err_code = sd_nvic_critical_region_enter(&dummy);
        APP_ERROR_CHECK(err_code);
    }while(0);
#else
    __disable_irq();
#endif

    enterTime = nrf_rtc_counter_get(portNRF_RTC_REG);

    if ( eTaskConfirmSleepModeStatus() != eAbortSleep )
    {
        TickType_t xModifiableIdleTime;
        TickType_t wakeupTime = (enterTime + xExpectedIdleTime) & portNRF_RTC_MAXTICKS;

        /* Stop tick events */
        nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);

        /* Configure CTC interrupt */
        nrf_rtc_cc_set(portNRF_RTC_REG, 0, wakeupTime);
        nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);
        nrf_rtc_int_enable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);

        __DSB();

        /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
         * set its parameter to 0 to indicate that its implementation contains
         * its own wait for interrupt or wait for event instruction, and so wfi
         * should not be executed again.  However, the original expected idle
         * time variable must remain unmodified, so a copy is taken. */
        xModifiableIdleTime = xExpectedIdleTime;
        configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
        if ( xModifiableIdleTime > 0 )
        {
#ifdef SOFTDEVICE_PRESENT
            if (softdevice_handler_is_enabled())
            {
                uint32_t err_code = sd_app_evt_wait();
                APP_ERROR_CHECK(err_code);
            }
            else
#endif
            {
                /* No SD -  we would just block interrupts globally.
                * BASEPRI cannot be used for that because it would prevent WFE from wake up.
                */
                do{
                    __WFE();
                } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1]));
            }
        }
        configPOST_SLEEP_PROCESSING( xExpectedIdleTime );

        nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);
        nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);

        /* Correct the system ticks */
        {
            TickType_t diff;

            nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_TICK);
            nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);

            /* check for overflow in TICK counter */
            if(nrf_rtc_event_pending(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW))
            {
                nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW);
                m_tick_overflow_count++;
            }

            diff = ((m_tick_overflow_count << portNRF_RTC_BITWIDTH) + nrf_rtc_counter_get(portNRF_RTC_REG)) - xTaskGetTickCount();

            /* It is important that we clear pending here so that our corrections are latest and in sync with tick_interrupt handler */
            NVIC_ClearPendingIRQ(portNRF_RTC_IRQn);

            if((configUSE_TICKLESS_IDLE_SIMPLE_DEBUG) && (diff > xExpectedIdleTime))
            {
                diff = xExpectedIdleTime;
            }

            if (diff > 0)
            {
                vTaskStepTick(diff);
            }
        }
    }
#ifdef SOFTDEVICE_PRESENT
    uint32_t err_code = sd_nvic_critical_region_exit(0);
    APP_ERROR_CHECK(err_code);
#else
    __enable_irq();
#endif
}

rtel wrote on Tuesday, April 11, 2017:

“When the CPU comes out of sleep mode interrupts become enabled for
a short while, at which point the SysTick interrupt executes.”

is not correct.

Umm, yes it is. I can point to the lines of code that do it if you like.

Nordic goes to sleep with global interrupt disabled.
The CPU is woken up on interrupts but would not go to ISR.

I am confused here. I thought we had established that we were relating
to the FreeRTOS code, not code provided by a third party that we cannot
be expected to support or otherwise influence. You seem to be looking
at Nordic code, but saying there are bugs in and suggesting updates to
the FreeRTOS mainline code.

You can see what they do in port_cmsis_systick.c:

I don’t want to see what they do. I just focus on what we do. As I
told you before, there were bugs in their implementation, which they
claim to have fixed. I asked you a couple of times if you have their
fixed code.

bernatikv wrote on Tuesday, April 11, 2017:

I have latest code from Nordic (From 2017 W11). There is nothing newer as far as I know. But obviously that code is not fixed. So no I have no fixed code, and I doubt such code exists.

I think we have reached an impasse.

I told you that big company (claiming #1 at Bluetooth low energy) partialy fucked up porting of your OS. And as unbiased I’m telling you how you can improve your OS documentation or function to minimize chance that ppl will port it wrongly. For nordic it would help if vTaskStepTick() is actually checking if some task needs to be actually moved into ready queue, and architecturally it seems to me as a good thing that function which adjust time also checks if time is good for some task to be moved into ready queue. But I might be wrong because I’m totally newbee with FreeRtos. There might be good reason not to do it…

Also I can not influence much Nordic to do better job, and implement port of FreeRTOS correctly. Which is possible and easy even with current state of FreeRTOS. And I admit it is more Nordic fault than yours…

Now it is up to you and Nordic. I’m in no position to tell either of you what to do. I reported to both of you what is not working I give you both working solutions how to solve it. The current situation is that port of FreeRTOS on Nordic has 1 tick idle loop every wakeup, so it is not much low power. If you are OK with it then be it. If you are not ok with it you can solve it actually only with nordic not with me :frowning: I can do my own fix, for my own product, and I will have competitive advantage to other developers who would not apply my fix… So for me it is actually best if there is bug for others, and I have it fixed inhouse… I just wanted be good guy and improve things… I have no reason to be pushy or in stress… And like I said it is mostly Nordic shit anyway so you can be calm also.
So have a nice day

rtel wrote on Tuesday, April 11, 2017:

For nordic it would help if
vTaskStepTick() is actually checking if some task needs to be actually
moved into ready queue,

…but it would be a logical error if it was to do that, as it is done
when the scheduler is unsuspended. Even if vTaskStepTick() did do that
it is called with the scheduler suspended so the switch to the new task
would not occur until the scheduler was unsuspended - which is exactly
what it is doing now.

Now it is up to you and Nordic. I’m in no position to tell either of you
what to do. I reported to both of you what is not working I give you
both working solutions how to solve it.

Please, understand, the FreeRTOS code is working. I can’t comment on
the Nordic code as I’ve not looked at it, but as I have already
described the problem does NOT exist in the official FreeRTOS code.

bernatikv wrote on Tuesday, April 18, 2017:

Hello,
Please understand that even FeeRTOS code is not working. As you explained me above how freertos original port works I told you that I’m afraid that there will be problem with geting xTick from ISR. And unfortunatelly I was right. I just got my hands on F767ZI which is using original FreeRTOS port for ARM M7 and the code does not work. It has correct sleep period and correct wakup time, but when you have for example interrupt from GPIO and ISR will call xTaskGetTickCountFromISR() then it will return wrong time. It will return the time when CPU went to sleep. But current time may be many hundreds of ticks different. The problem is that port.c is calling enable_irq(); before vTaskStepTick() compensate for sleep time. I’m little bit frustrated to work with such libraries :frowning: Could you please fix your RTOS?

rtel wrote on Tuesday, April 18, 2017:

You are right of course. If you stop the tick, then read the tick count, the value you read is the value it had when you stopped it. Then, after you have stepped the value forward to account for the time the tick was stopped, when you read the tick value the value you read is the value the tick would have had if it had never been stopped. I take it from your post you now agree with me the values read are as expected.

bernatikv wrote on Wednesday, April 19, 2017:

No - value read is not as expected. So once again try to hear me. I did simple app. It sleeps in loop for 1 second. The code can be also woken up by IRQ from GPIO. When I ask for tick in ISR triggered by GPIO toggle I get wrong time. So of course it is wrong. And it should not behave like that. I expect function get tick to give me always correct time. I do not care how you do your port and where you stop timer and where you compensate. I expect simply that kernel will works. And function for returning ticks will give me correct time - always. In your own specification is written that xTaskGetTickCountFromISR() returns: “The count of ticks since vTaskStartScheduler was called.” and it does not do that! So it is very wrong and devfinitelly not correct. Do you understand now?? The fix seems to be easy to me you can just call enable_irq(); after vTaskStepTick( ulCompleteTickPeriods ); compensation.

rtel wrote on Wednesday, April 19, 2017:

No - value read is not as expected. So once again try to hear me.

This will be my last post on this thread, unless you can provide me a
clear sequence of events, step by step, with no ambiguity so I know
exactly the sequence you are describing, that shows there is a problem
that needs investigating:

I did
simple app. It sleeps in loop for 1 second. The code can be also woken
up by IRQ from GPIO. When I ask for tick in ISR triggered by GPIO toggle
I get wrong time.

You get the wrong time? Or you get the time at which the tick interrupt
was stopped? As per my last post, if you read the tick count while it
is stopped then the EXPECTED value will be the value the tick count had
when you stopped it. After you have stepped the tick count forward to
take into account the time it was stopped for then the value read will
be as if the tick hadn’t been stopped - and not before. To state again,
if a value is incrementing, and you [deliberately] stop it incrementing,
then read the value, the value you read will be the value the variable
had at the time it stopped being updated.

So of course it is wrong. And it should not behave
like that. I expect function get tick to give me always correct time.

The tick has been stopped. It doesn’t change while it is stopped. It
starts changing after you start it again. Otherwise what would it mean
to stop it?

I
do not care how you do your port and where you stop timer and where you
compensate. I expect simply that kernel will works. And function for
returning ticks will give me correct time - always.

Always…other than when you have stopped it.

In your own

specification is written that |xTaskGetTickCountFromISR()| returns: “The
count of ticks since vTaskStartScheduler was called.”

I could update the documentation to say “unless you have done something
to stop it”, but I think the tickless idle documentation probably says
that while the tick is not incrementing its value does not change.

and it does not do

that! So it is very wrong and devfinitelly not correct. Do you
understand now?? The fix seems to be easy to me you can just call
enable_irq(); after vTaskStepTick( ulCompleteTickPeriods ); compensation.

Please re-read all this thread. I have already stated why that would be
wrong.

bernatikv wrote on Thursday, April 20, 2017:

We shall clear one thing. I do not do anything with tick. I’m user of your FreeRTOS. I’m using your original port “FreeRTOSv9.0.0\FreeRTOS\Source\portable\RVDS\ARM_CM7\r0p1\port.c”.
I only wrote simple user code:

while (1)  {
   vTaskDelayUntil( &xLastWakeTime, xFrequency );
   chNum = sprintf(txt,"%d\r\n", xTaskGetTickCount());
    HAL_UART_Transmit(&huart2, (uint8_t*)txt, chNum, 1000);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	uint32_t chNum;
	chNum = sprintf(txt,"btn: %d\r\n", xTaskGetTickCountFromISR( ));
    HAL_UART_Transmit(&huart2, (uint8_t*)txt, chNum, 1000);
 }

Frequency is 1 second tick is every 1ms. When I configure my FreeRTOS to not be power saving:
#define configUSE_TICKLESS_IDLE 0
and run the code my test is working well it prints time every second and then it prints time when button was pressed:
9001
10001
btn: 10611
11001
12001

I see the time when I pressed button.

When my only change is to confiogure FreeRTOS to be more power efficient and use tickless sleep
#define configUSE_TICKLESS_IDLE 1
my code stops working - because I do not see whn I pressed button but I see only last time that was printed by task:
9001
10001
btn: 10001
11001
12001

You see that I do not see true time when I pressed button, but time when FreeRTOS went to sleep.

To me power saving feature shall ideally not have impact on code behavior.

I nowhere see in documentation some note about the fact that tick is not reported correctly under some system configuration - please point me to the documentation where such information is written.

I looked here:
http://www.freertos.org/a00021.html#xTaskGetTickCountFromISR
here:
http://www.freertos.org/a00110.html#configUSE_TICKLESS_IDLE
and here:
http://www.freertos.org/low-power-tickless-rtos.html
and nowhere is information that xTaskGetTickCountFromISR() can under certain situation report other time than time passed since vTaskStartScheduler() was called.

If you insist on claim that this behavior is “AS EXPECTED”. Then to me it sounds crazy - but we have saying: “there can not be arguing about anyone taste”. I just hope that you are consistent in your opinions. I have personal question - when you go to sleep and set your alarm clock next to your bed to go off after 8 hours. Then when you wake up - do you prefer your alarm clock to show you time when you fall asleep? Or rather (as rest of the world) you like your alarm clock to show you current time? Another parallel would be - do you want your alarm clock next to your bed to show different times when you run it from power outlet and when you run it from battery? Or do you want it (as rest of the world) to show same times no mather what is the power source?

davedoors wrote on Thursday, April 20, 2017:

This thread is boring and stopped being useful to other FreeRTOs users after a few posts - is it just trolling? Can we lock the thread?

I have a question for you. If you stop the tick, then read the value back while it is stopped, what value would you expect it to be? You seem to argue it should not be any different as if it hadnt been stopp, so then my question to you is what do you think stopping the tick does?

If you really must read the time from an interrupt when you know the tick is not running then read a time you know is running. A hardware timer is still running, only the interrupt is stopped, so read the hardware timer to work out what the time is. Another way is to just unblock a task in the interrupt, then read the time in the task. The task will not read the time until after the tick has been corrected for the sleep time.

bernatikv wrote on Thursday, April 20, 2017:

To me stopping the tick is power saving feature. RTOS should and partially does compensate ticks after wake up. The only problem is that it enables ISR sooner befgore it does the compensation. To me it seems as just a matter of enabling ISR few instruciotn later after the time compensation is done. Why not to do that if it seems easy? When I rewrite port.c and move __enable_irq(); to the end of vPortSuppressTicksAndSleep() then everything works as expected.

You are rgiht there is multiple other ways how to solve it, but those are workaround of wrong desing.

I would have accepted that they do not want to change port.c code for some reason. But at least I would like to force them to update documentation so users know that xTaskGetTickCountFromISR() is not working well sometimes when tickless mode is enabled.

And no I’m not trolling I’m offering working solution. And I’m open to hear arguemtns why on earth first ISR shall report wrong time?

davedoors wrote on Thursday, April 20, 2017:

Interrupts get enabled as soon as possible to maximize responsiveness. Coming out of a low power mode can take the hardware a long time and most people want the interrupt that woke the chip to execute as soon as physically possible. The latest version in SVN goes further, enabling interrupts so they can execute asap, then disabling them again while the catch up is done.

bernatikv wrote on Thursday, April 20, 2017:

Dave thank you! now you said first reasonable response in this long and exhausting thread! If we prefer speed over correct tick reporting then it is understandable. But still we need to write in big red letters in documentation that we made this choice and that time reporting under this and that condition is not correct because we prefer speed. On my ARM M7 at 16MHz the time compensation takes around 1.5ms. Which is trully quite long… Perhaps this can be added as configurable option - if we prefer fast wake up from deep sleep or if we prefer code to work same as if tickless mode is disabled. I can imagine if some chip is anyway waking up 10ms from deep sleep the extra 1.5 ms is acceptable for user…