Skip to main content
JBond.1
Senior
February 8, 2025
Question

How to ensure interrupt handling before going to sleep/stop mode

  • February 8, 2025
  • 6 replies
  • 1141 views

Hi, I want to go to sleep/stop mode with STM32 and wake on interrupt. After last interrupt it should wait for 10sec and go back to sleep. But I see an edge case where interrupt could occur just before going to sleep/stop mode.
How do I handle interrupt just before going to sleep/stop mode (cancel sleep/stop mode)?
Basically force WAKE from sleep/stop mode even if STM32 is not yet in sleep/stop mode?

 

 

#define STAY_WAKE_FOR_TICK 10000
static volatile uint32_t GoToSleepAfterTick;

void main(void)
{
 //...

 while (1)
 {
 HAL_SuspendTick();
 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
 HAL_ResumeTick();

 while (HAL_GetTick() < GoToSleepAfterTick)
 {
 //...
 }
	
 // interupt could occure here???
 }
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == CALL_Pin)
	{
		GoToSleepAfterTick = HAL_GetTick() + STAY_WAKE_FOR_TICK;
	}
}

 

 

 

6 replies

ST Employee
February 20, 2025

Hello @JBond.1

You can check for pending interrupts before entering stop/sleep mode, check for pending bits, something like this: 

 if (__HAL_GPIO_EXTI_GET_IT(CALL_Pin) == RESET)
 {
 HAL_SuspendTick();
 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
 HAL_ResumeTick();
 }

 while (HAL_GetTick() < GoToSleepAfterTick)
 {
 //...
 }

 

JBond.1
JBond.1Author
Senior
February 20, 2025

But will it handle all cases?

 if (__HAL_GPIO_EXTI_GET_IT(CALL_Pin) == RESET)
 {
 // interupt could occure here???
 HAL_SuspendTick();
 // interupt could occure here???
 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
 HAL_ResumeTick();
 }

 while (HAL_GetTick() < GoToSleepAfterTick)
 {
 //...
 }


Also will interrupts even be "pending"? I think interrupts have higher priority than main loop?

I guess I could check if `GoToSleepAfterTick` have not been changed just before sleep. But interrupt could still occur just after check?

 while (1)
 {
 HAL_SuspendTick();

 if (HAL_GetTick() >= GoToSleepAfterTick)
 {
 // interupt could occure here???
 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
 }

 HAL_ResumeTick();

 while (HAL_GetTick() < GoToSleepAfterTick)
 {
 //...
 }
 }





January 8, 2026

@JBond.1 wrote:

But will it handle all cases?

 if (__HAL_GPIO_EXTI_GET_IT(CALL_Pin) == RESET)
 {
 // interupt could occure here???
 HAL_SuspendTick();
 // interupt could occure here???
 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
 HAL_ResumeTick();
 }

 while (HAL_GetTick() < GoToSleepAfterTick)
 {
 //...
 }


Also will interrupts even be "pending"? I think interrupts have higher priority than main loop?

I guess I could check if GoToSleepAfterTick has not been changed just before going to sleep, but an interrupt could still occur immediately after that check. It feels similar to how a Morse code translator has to deal with signal timing—if a pulse arrives right at the boundary between characters or words, the decoder must decide whether to treat it as part of the current signal or start a new one. You can visit this website as well. In both cases, handling these edge conditions correctly is key to avoiding missed or misinterpreted events.

 while (1)
 {
 HAL_SuspendTick();

 if (HAL_GetTick() >= GoToSleepAfterTick)
 {
 // interupt could occure here???
 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
 }

 HAL_ResumeTick();

 while (HAL_GetTick() < GoToSleepAfterTick)
 {
 //...
 }
 }






I’m actually wondering the same thing. I have a similar flow where the MCU should stay awake for a short period after an interrupt and then go back to sleep, and I’m also worried about that small window right before entering sleep/stop mode. If an interrupt fires just before the sleep instruction, it feels like the logic could miss it or still go to sleep unexpectedly. Curious how others handle this edge case cleanly or if there’s a recommended pattern to cancel sleep when an interrupt happens at the last moment.

gbm
Principal
February 20, 2025

Basically, the problem you describe does not exist at all.

If you consider standard sleep mode, all the peripheral blocks are active, so any enabled interrupt will wake up the MCU from sleep. If think of a deeper sleep, then when you put the MCU to sleep you agree to ignore most of events which are handled in normal operation state, so it makes no difference if the event is handled or not. No difference if the event occurred one microsecond before sleep or after it - it must be safe to ignore it.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
JBond.1
JBond.1Author
Senior
February 23, 2025

It does mater to handle all interrupt, for example if I am counting button presses for Morse code. If one button press happens just before sleep it wont wake-up because its not yet into sleep mode?


MM..1
Chief III
February 20, 2025

Primary your use haltick have mistake.

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == CALL_Pin)
	{
		GoToSleepAfterTick = HAL_GetTick() + STAY_WAKE_FOR_TICK;
	}
}

example GetTick isnt neverending increment value. On overrun your while fail ...

And better is leave callback empty and place code after wake...

 while (1)
 {
 HAL_SuspendTick();
 if(!ignoresleep)HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
 HAL_ResumeTick();
GoToSleepAfterTick= ...
 while (HAL_GetTick() != GoToSleepAfterTick) //right for overrun
 {
 //...
 }
	
 // interupt could occure here??? when yes place in callback bool ignoresleep
 }
JBond.1
JBond.1Author
Senior
February 23, 2025

Yes, I see the issue with uint32 overload, but I guess that's another story... It still can work for 49days until overload and if its awake only 10secs other time does not count into those 49days.

I cant remove code from callback, because it wont reset timer on each button click callback. I need to reset 10seconds countdown on each button click...

MM..1
Chief III
February 23, 2025

In normal code button do somethink and time update is place into this code, but can be in exti ...

You still ask unreal question, normal situation instruction asm go to sleep cant be interrupted, then ISR occurs before or after... before is your issue because if timeout then is skip. If this is issue in your app then set second wake source for example timer ... But if user is not android machine and pick nano second click = system no react simply repeat click wake.

JBond.1
JBond.1Author
Senior
February 23, 2025

I guess the solution would be to set "wake up on interrupt only", so it would listen to button press and button press would start/reset(if timer started) timer, but I guess I wont be able to go to "stop" mode if I need timer? Or I can go into "stop" mode after timer end in timer interrupt?

Basically on each button interrupt it should start/reset 10seconds timer and after 10seconds timer end (10seconds of button inactive) it should stop timer and go to "stop" mode and wait for button activity.

TDK
Super User
January 9, 2026

I agree with @gbm here, this is a non-issue.

If the interrupt happens before entering sleep, it will be handled before entering sleep in the interrupt routine. If it happens after, it'll wake up from sleep and be handled then.

In either case, it will be handled. It doesn't matter if it happens after suspend tick and before WFI, or after WFI, or anywhere. It will never be ignored. Total non-issue.

I don't see the point of checking for pending interrupts. If they are pending, they will happen regardless.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Visitor II
March 14, 2026

Your concern is absolutely valid.
Let's assume the code where we receive events in an interrupt, handle events in main loop and sleep if there are no events.

void myiSR() {
 events.Add();
}

void main() {
 while (1) {
 while (events.Available()) {
 HandleAndRemoveEvent(events);
 }
 if (!events.Available()) {
 // do something right before sleep
 Sleep();
 }
 }
}

We check for events in line 10 and go to Sleep in line 12, if interrupt happens between lines 10 and 12 it will be handled by myiSR and event will be added to the list BUT it will not prevent Sleep.
You can make this problem more obvious if you make transition from line 10 to 12 longer, put Hal_Delay() in line 11 for example.

To overcome the problem I usually use a one-shot timer to generate delayed interrupt. Timer period must be short enough but definitely longer than a time it takes to get from line 10 to 12.
I start timer in myiSR. If myiSR happens outside lines 10-12 event is handled in a normal way and timer interrupt is just ignored. It myiSR happens between lines 10-12, event is not handled and Sleep is initiated, but timer interrupt wakes MCU from sleep and makes it handle the event.

void myiSR() {
 events.Add();
 __HAL_TIM_ENABLE(timer_onetime_inst);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
 if (htim == timer_onetime_inst) {
 __HAL_TIM_DISABLE(htim);
 }
}

void main() {
 while (1) {
 while (events.Available()) {
 HandleAndRemoveEvent(events);
 }
 if (!events.Available()) {
 // do something right before sleep
 Sleep();
 }
 }
}
MM..1
Chief III
March 14, 2026

Absurd. Primary this is year old ticket. And your code is more absurd as @JBond.1 

Nobody eco based set code to do nothink 10s at max speed for waiting somethink...