This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

IDLE task behaviour of FreeRTOS

Hi,

I use FreeRTOS for ble application on nRF52840.

To save current consumption, I want to add __WFE() to portTASK_FUNCTION().

There is a comment in the function as below.

/* It is not desirable to suspend then resume the scheduler on
each iteration of the idle task. Therefore, a preliminary
test of the expected idle time is performed without the
scheduler suspended. The result here is not necessarily
valid. */

Then I want to ask you check adding __WFE() like below is safe or not.

The line number is 114.

static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
    /* Stop warnings. */
    ( void ) pvParameters;

    /** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
    SCHEDULER IS STARTED. **/

    /* In case a task that has a secure context deletes itself, in which case
    the idle task is responsible for deleting the task's secure context, if
    any. */
    portTASK_CALLS_SECURE_FUNCTIONS();

    #if defined(DBGMON_ENABLE) && defined(DBGMON_TASK_COMMAND)
    xStartTickCount = xTickCount;
    xSleepTickCount = 0;
    #endif
    for( ;; )
    {
        /* See if any tasks have deleted themselves - if so then the idle task
        is responsible for freeing the deleted task's TCB and stack. */
        prvCheckTasksWaitingTermination();

        #if ( configUSE_PREEMPTION == 0 )
        {
            /* If we are not using preemption we keep forcing a task switch to
            see if any other task has become available.  If we are using
            preemption we don't need to do this as any task becoming available
            will automatically get the processor anyway. */
            taskYIELD();
        }
        #endif /* configUSE_PREEMPTION */

        #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
        {
            /* When using preemption tasks of equal priority will be
            timesliced.  If a task that is sharing the idle priority is ready
            to run then the idle task should yield before the end of the
            timeslice.

            A critical region is not required here as we are just reading from
            the list, and an occasional incorrect value will not matter.  If
            the ready list at the idle priority contains more than one task
            then a task other than the idle task is ready to execute. */
            if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
            {
                taskYIELD();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */

        #if ( configUSE_IDLE_HOOK == 1 )
        {
            extern void vApplicationIdleHook( void );

            /* Call the user defined function from within the idle task.  This
            allows the application designer to add background functionality
            without the overhead of a separate task.
            NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
            CALL A FUNCTION THAT MIGHT BLOCK. */
            vApplicationIdleHook();
        }
        #endif /* configUSE_IDLE_HOOK */

        /* This conditional compilation should use inequality to 0, not equality
        to 1.  This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when
        user defined low power mode implementations require
        configUSE_TICKLESS_IDLE to be set to a value other than 1. */
        #if ( configUSE_TICKLESS_IDLE != 0 )
        {
        TickType_t xExpectedIdleTime;

            /* It is not desirable to suspend then resume the scheduler on
            each iteration of the idle task.  Therefore, a preliminary
            test of the expected idle time is performed without the
            scheduler suspended.  The result here is not necessarily
            valid. */
            xExpectedIdleTime = prvGetExpectedIdleTime();

            if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
            {
                vTaskSuspendAll();
                {
                    /* Now the scheduler is suspended, the expected idle
                    time can be sampled again, and this time its value can
                    be used. */
                    configASSERT( xNextTaskUnblockTime >= xTickCount );
                    xExpectedIdleTime = prvGetExpectedIdleTime();

                    /* Define the following macro to set xExpectedIdleTime to 0
                    if the application does not want
                    portSUPPRESS_TICKS_AND_SLEEP() to be called. */
                    configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );

                    if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
                    {
                        traceLOW_POWER_IDLE_BEGIN();
                        portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
                        traceLOW_POWER_IDLE_END();
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                ( void ) xTaskResumeAll();
            }
            else
            {
                __WFE();
                mtCOVERAGE_TEST_MARKER();
            }
        }
        #endif /* configUSE_TICKLESS_IDLE */
    }
}

Thank you.

Parents Reply
  • It means that the calculation of the expected idle time is re calculated without the scheduler being suspended. The results are not necessarily valid since the scheduler was not suspended and it can preempt this context after the calculation and they estimated time will not be correct. But it will not create any bad side effects apart from that the device will wake little early if that happens. So not to worry too much about this.

Children
No Data
Related