cancel
Showing results for 
Search instead for 
Did you mean: 

Clarification of Entering, Leaving and Remaining in Sleep

DRobe.4
Senior

Suppose that my system consists of 3 modules

  1. main... at the end of the while loop, I want the system to enter sleep mode, so at the end of the while, I put wfi(); or possibly I put DSB(); after that. Other examples replace wfi() with HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); Another example used HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
  2. EXTI... which is an edge triggered ISR; when this interrupt is triggered, I want to exit sleep. At the end of this ISR, I put HAL_PwrDisableSleepOnExit(); or possibly follow that with DSB(); Or possibly if I don't put anything, it will wake the system.
  3. function1... which is an interrupt triggered by a timer; when this interrupt is finished, I want the system to go back to its previous mode, whether sleeping or awake. There are actually several ISRs like function1 in my system. This routine is the thorny point... I cannot say sleep_on_exit, because if it ran before the main loop ended, I want the main loop to continue to the point where the sleep command is invoked. If this ISR ran after the main loop ended, I want it to return to sleep after finishing.

5 REPLIES 5
DRobe.4
Senior

On more thing... I use the LTDC and don't understand all the BSP code. There may be SysTick handlers or other interrupts. I don't want them to interfere with sleeping/waking.

TDK
Guru

Use a global variable to indicate if the function should go to sleep at the end before returning. Note that you can't go to sleep between when a function ends and execution returns to where the function was called. Either go to sleep at the end of the function, or after it's returned.

Edit: Manual says entry to sleep is "WFI or Return from ISR" so possible the above is incorrect in that regard.

If you feel a post has answered your question, please click "Accept as Solution".

I had thought of a global variable, but then I need an "if" statement, so the SCB instruction is not last statement in ISR... the if is still being processed.That is

   if (endmain == true)

   {                                                                                    // don't go to sleep if main loop has not ended

      SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;                    // Enable sleep on exit from ISR

   }

   __DSB();                                                // Ensure that waking up starts immediately upon exiting

Is it OK to have this structure? What works?

DRobe.4
Senior

I have decided what to do.

Default setup onCPU is for ISRs to be awake on exit (due to SLEEPONEXIT bit in SCB=0. SCB is a system register.).... no other global variable is needed.

At end of main program, put

__wfi():

This sets the SLEEPONEXIT bit in SCB telling ISRs to continue in sleep upon exit, no other global is needed.

__wfi(); is equivalent to SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;

In the EXTI program, put the following at the end

SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;

__DSB();

This clears the SLEEPONEXIT bit in the SCB. All of the other ISRs need no code to decide whether to sleep or be awake on exit for the scenario that I described in my initial question.

DRobe.4
Senior

I noticed that TDK's post can avoid SLEEPONEXIT altogether, and this is what I implemented, but haven't verified that it works yet. The idea is to let interrupts return to execution in the main program before or after sleep was initiated. If they return to main before sleep was initiated, the program continues executing normally. If they return to main after sleep was initiated, the main program puts the system to sleep again.

Program structure of main

int main(void)

{

initialize

while (1)

{

if (runloop == true)

{

most of code in main

runloop = false;

} // END of if(runloop== true)

__wfi();

} // END of main

no interrupt routines contain code relating to sleep

one interrupt routine, an EXTI which wakes up the system, contains the following

runloop = true

Note that if, in addition to wfi, it is desired to alter power regulator settings, that can be coded along with __wfi();