Tickless idle and interrupts which don't need scheduler service

mrazoun wrote on Friday, September 23, 2016:

Dears,
for my ultra low power application I need to find way how to quickly proceed interrupt which doesn’t need scheduler service and return immediately back into sleep mode. Routines fn_EnterSleepPRE() and fn_EnterSleepPOST() consume long time (I2C bus communication is necessary to achive ultra low consumption of board at the sleep mode) which takes battery energy. It’s the reason why it’s not suitable to do it by standard way through scheduler.

Any idea ? I don’t feel to be enough familiar with FreeRTOS to solve this phylosophic question myself.

In old one OS (cooperative) we are using code, see the following snippet. Main idea is to inform OS from interrupt handler’s through procesFlag. If procesFlag is set to “RUN” OS service will follow, if not it return’s into sleep mode immediately.

        procesFlag = SLEEP;
        fn_EnterSleepPRE ();

        do{
            /* Disable interrupts first to avoid interrupt executing between EM2 */
            INT_Disable();
            /* Enter energy mode */
            EMU_EnterEM2(true);
            /* ISR for any pending and enabled IRQs will be executed after this */
            INT_Enable();
        } while(procesFlag != RUN); /* if any interrupt routine need OS service, set procesFlag == RUN; if not, uP fall at once into sleep mode */

        fn_EnterSleepPOST ();

I’m using EFM32GG, Cortex-M3.
My solution is now based on \FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_EFM32_Giant_Gecko_Simplicity_Studio\Low_Power_Demo\low_power_tick_management_BURTC.c

Thank’s in advance.
Zdenek

davedoors wrote on Friday, September 23, 2016:

Are you using configUSE_TICKLESS_IDLE? If so can you use the pre and post sleep macros to add a loop around the code that goes into sleep if a context switch is not pending whn your efm wakes?

mrazoun wrote on Friday, September 23, 2016:

Hi Dave,
thank’s for your answer.
Yes, I’m using configUSE_TICKLESS_IDLE = 1, and special port of vPortSuppressTicksAndSleep() for EFM - see \FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_EFM32_Giant_Gecko_Simplicity_Studio\Low_Power_Demo\low_power_tick_management_BURTC.c.

I’m not able follow your advice, pls. can you explain it more precisely or write some snippet of code?
Thank’s.
Zdenek

rtel wrote on Friday, September 23, 2016:

The code in that file contains the following:

configPRE_SLEEP_PROCESSING( xModifiableIdleTime );

/* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING()
means the application defined code has already executed the WAIT
instruction. */
if( xModifiableIdleTime > 0 )
{
     __asm volatile( "dsb" );
     SLEEP_Sleep();
     __asm volatile( "isb" );
}

/* Allow the application to define some post sleep processing. */
configPOST_SLEEP_PROCESSING( xModifiableIdleTime );

configPRE_SLEEP_PROCESSING() and
configPOST_SLEEP_PROCESSING() can be defined in FreeRTOSConfig.h to
contain any code you want. I think the suggestion was to define them to
create a loop around the sleep function that is executed continuously
until the interrupt that woke your CPU from sleep attempts to perform a
context switch.

For example, something like this:

#define configPRE_SLEEP_PROCESSING() \
while( context switch not pending ) \
{

#define configPOST_SLEEP_PROCESSING() \
}

then you will re-enter sleep again immediately if the CPU woke because
of an interrupt that didn’t attempt a context switch.

mrazoun wrote on Monday, September 26, 2016:

Hi,
thank’s for your reply. I understood your idea. It’s a great tool - prepare hook’s via macros to modify code without attacking source…

But, it’s a problem in my case. When I prepare solution according your instructions, interrupts stay disabled inside of loop prepared via macros and nothing happen.

Explanation : sleep_SLEEP() function which I’m using from Silabs library (sleep.c) call INT_Disable() before going into EM2 sleep mode. INT_Disable() is also used before sleep_SLEEP(). There is used “lock level counter”. Value of this counter is 2, before falling into EM2. It means, that when uP wake up, call INT_Enable() from sleep_SLEEP() (value of counter = 1 and interrupt stays disabled) and return back into FreeRTOS code. Interrupts will be enabled on third line after “configPOST_SLEEP_PROCESSING( xModifiableIdleTime );” where you recommend me to put “while” bracket.
How to solve this ?
Thank’s in advance
Zdenek

<

SLEEP_EnergyMode_t SLEEP_Sleep(void)
{
  SLEEP_EnergyMode_t allowedEM;

  INT_Disable();

  allowedEM = SLEEP_LowestEnergyModeGet();

  if ((allowedEM >= sleepEM1) && (allowedEM <= sleepEM3))
  {
    SLEEP_EnterEMx(allowedEM);
  }
  else
  {
    allowedEM = sleepEM0;
  }

  INT_Enable();

  return(allowedEM);
}

rtel wrote on Monday, September 26, 2016:

I’m not sure I’m fully following, but how about editing the fucntion, or providing your own modified version of the function, rather than just using the library function exactly as it is.

mrazoun wrote on Tuesday, September 27, 2016:

The problem we face is associated with the order in which the instructions bellow are performed.

INT_Disable();

configPRE_SLEEP_PROCESSING();

SLEEP();

configPOST_SLEEP_PROCESSING();

INT_Enable();

So when the loop around the sleep function is made between configPRE_SLEEP_PROCESSING and configPOST_SLEEP_PROCESSING,

then no interrupt execution can be performed because of disabled INT.

It will only wake and sleep again.