AnsweredAssumed Answered

freeRTOS tickless feature on K27

Question asked by Maneesh Singh on Apr 18, 2017
Latest reply on Jul 13, 2017 by Evgeny Erlihman

Hi Sir,

I am using -

FreeRTOS V8.2.3,

Kinetis Design Studio Version: 3.2.0, and

KL27 Processor 

( Note : - I am not using processor Expert in feature in my project )

in my application, and I am now trying to lower the power consumption by implementing tickless mode feature.

 

But, I am facing some issues regarding the implementation of tickless mode feature.

 

I did the same steps as mentioned on FreeRTOS  - Tickless Low power features in FreeRTOS 

 

STEP 1 :-  Built in tickless idle functionality is enabled by defining configUSE_TICKLESS_IDLE as 1 in FreeRTOSConfig.h

 

/* For Tickless Mode */
#define xIdleTime 1000
#define configUSE_TICKLESS_IDLE 1 //added for tickless mode

 

 

/* First define the portSUPPRESS_TICKS_AND_SLEEP() macro. The parameter is the
time, in ticks, until the kernel next needs to execute. */
#define portSUPPRESS_TICKS_AND_SLEEP( xIdleTime ) vPortSuppressTicksAndSleep( xIdleTime )

 

 

STEP 2:- Using the Default Implementation of vPortSuppressTicksAndSleep(  ) fn defined in port.c

 

#if configUSE_TICKLESS_IDLE == 1


__attribute__(( weak )) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{

 

uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL;
TickType_t xModifiableIdleTime;

 

/* Make sure the SysTick reload value does not overflow the counter. */
if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
{
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
if (xExpectedIdleTime == 0) return;
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
*(portNVIC_SYSTICK_CTRL) &= ~portNVIC_SYSTICK_ENABLE_BIT;

/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation )
{
ulReloadValue -= ulStoppedTimerCompensation;
}

/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__asm volatile( "cpsid i" );

/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{
/* Restart from whatever is left in the count register to complete
this tick period. */
*(portNVIC_SYSTICK_LOAD) = portNVIC_SYSTICK_CURRENT_VALUE_REG;

/* Restart SysTick. */
*(portNVIC_SYSTICK_CTRL) |= portNVIC_SYSTICK_ENABLE_BIT;

/* Reset the reload register to the value required for normal tick
periods. */
*(portNVIC_SYSTICK_LOAD) = ulTimerCountsForOneTick - 1UL;

/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm volatile( "cpsie i" );
}
else
{
/* Set the new reload value. */
*(portNVIC_SYSTICK_LOAD) = ulReloadValue;

/* Clear the SysTick count flag and set the count value back to
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;

/* Restart SysTick. */
*(portNVIC_SYSTICK_CTRL) |= portNVIC_SYSTICK_ENABLE_BIT;

/* 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 )
{
__asm volatile( "dsb" );
__asm volatile( "wfi" );
__asm volatile( "isb" );
}
configPOST_SLEEP_PROCESSING( xExpectedIdleTime );

/* Stop SysTick. Again, the time the SysTick is stopped for is
accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
ulSysTickCTRL = *(portNVIC_SYSTICK_CTRL);
*(portNVIC_SYSTICK_CTRL) = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );

/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm volatile( "cpsie i" );

if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{
uint32_t ulCalculatedLoadValue;

/* The tick interrupt has already executed, and the SysTick
count reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );

/* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something
that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
}

*(portNVIC_SYSTICK_LOAD) = ulCalculatedLoadValue;

/* The tick interrupt handler will already have pended the tick
processing in the kernel. As the pending tick will be
processed as soon as this function exits, the tick value
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
}
else
{
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;

/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;

/* The reload value is set to whatever fraction of a single tick
period remains. */
*(portNVIC_SYSTICK_LOAD) = ( ( ulCompleteTickPeriods + 1 ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
}

/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. The critical section is used to ensure the tick interrupt
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
*(portNVIC_SYSTICK_CTRL) |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods );
*(portNVIC_SYSTICK_LOAD) = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL();

 

}
}
#endif /* #if configUSE_TICKLESS_IDLE */

#endif

 

 

My Observation :- 

1) Now when i suspended all my task then Idle Task is getting priority to run is internally

     calling vPortSuppressTicksAndSleep(). and system is able to go into tickless mode. but tick timer timeout is

    happening very fast and the system is entering and exiting the sleep mode very frequently.

 

2) i even try to disable the tickless timer by removing reload value and by not restarting the sys-tick timer in

   vPortSuppressTicksAndSleep() fn. so i noticed that system enter's into sleep mode but since no timer, no timeout

   so it remains in that state......    and i need to restart the system to wake up from the sleep.

 

My Problem :- 

1) The current saving provided from above mentioned method is very minimal and it doesn't serve my purpose of keeping

    CPU in deep Sleep Mode.

 

2) So It looks like the framework for tickless mode that is provided by FreeRTOS is focused on eliminating the handling of “idle” ticks by the operating system. So it saves some code execution cycles. But it does not seem to address the deeper issues, like shutting down clock/power domains for sleeping peripherals.

Also, even in tickless mode there is a counter running and some sort of comparison logic that knows to generate an interrupt after the ExpectedIdleTime is reached so that a scheduled task can run.

So the current we measure in “sleep” may represent a fair amount of non-sleeping hardware functionality inside the chip.

 

My Requirement :- 

I want to keep my system into very low power state i.e very deep sleep mode and it should be in that state until any external interrupt occurred... or after every 30 min only.

 

Now please help me to solve this issue.

1) How can put KL27 into deep sleep mode ?

2) I am using FreeRTOS V8.2.3  and i tried tickless mode feature as mention by FreeRTOS, but it is not serving my

    purpose so what else i need to  do in FreeRTOS to avoid very fast sleep enter and exit and how can i keep the

    system in sleep mode for longer time.

 

 

It would be great if someone could have a look at this and help me to solve this issue.

 

Any help will be Appreciated.

 

 

Thanks & Regards,

Maneesh 

Outcomes