Hi. Maybe this is a common topic, but I can't find an answer. I set interrupt callback on some pin, configure wake up time and go SAMD21 to sleep. As expected MCU awake in set time. If interrupt occurs MCU also wake up. OK.
BUT.
What if interrupt comes some small time before interrupt? For example just before __WFI instruction? How to handle this situation?
I have idea that MCU must not go to sleep if interrupt occurs just before __WFI. I guessed that if disable interrupt then MCU will awake immidiatly if interrupt occurs just before sleep. I disabled interrupts via __disable_irq function, then check if interrupt occured, and if not -> MCU go to sleep. But it failed: MCU do not go to sleep mode if __disable_irq was called.
So, I need some help in such situation. Is there some special requirements for standby mode if __disable_irq was called? Or if there is some other solution for such problem?
//1. some code here
//2. check if interrupt occurred (bool variable that is set to true in interrupt handler)
//3. go to sleep
//4. awake and check if interrupt occurred (check variable and set it to false if it was true).
What if interrupt occurs between step 2 and 3? If variable will be set after step 2 but before step 3, then MCU will go to standby mode. And I need that it continue works in such case.
No variable can change while the controller is sleeping.
Interrupts can occur during sleep, then wake up the MCU and the handler is called only after waking up.
you would do the flag testing in a critical code section with interrupts disabled and activate the interrupts just before calling sleep. Usually, the intruction right after the SEI is guaranteed to be executed before an interrupt could trigger.
set sleep mode
disable interrupts
if (flag test ok) {
Enable sleep
Activate interrupts
sleep
Disable sleep
}
Activate interrupts
Well, thanks, as I understood it will be something like this:
__disable_irg();
if (!f_interrupt)
{
__enable_irq();
__WFI();
}
__enable_irq();
But in such case the problem remains: interrupt can occurs between __enable_irq() and __WFI()
I think I found a workaround for this problem, but it is a bit complicated.
It will be something like this:
bool f_interrupt; //set to true in interrupt handler
bool f_go_to_sleep; //set to true before go to sleep and before f_interrupt check
//Global interruption handler on SAMD21
void EIC_Handler(void)
{
//... some code to get callback function for specific interrupt
//in this code callback function must return true if interrupt active state must be reset
if (callback())
{
EIC->INTFLAG.reg = <reset mask>
}
else
{
//not reset interruption but disable calling EIC_Handler
__disable_irq();
}
}
//callback function that is called from EIC_Handler
bool interrupt_callback()
{
f_interrupt = true;
if (f_go_to_sleep) return false;
return true;
}
void some_sleep_function()
{
f_go_to_sleep = true;
if (f_interrupt)
{
f_go_to_sleep = false;
__enable_irq();
//if interrupt flag was not reset in register
//then it will be called here
return;
}
//some additional code before sleep
__WFI();
//some additional code after sleep
//reset sleep flag and enable interrupts
f_go_to_sleep = false;
__enable_irq();
//here interrupt callback will be called again, but it is no problem in my case
}
But when interrupts is disabled delay() stop working, so after __disable_irq()delay() function make no sense. it is OK for me. But can there still be pitfalls with this code?
As I said, in many architecture there is a hardware guarantee that when you set the flag to activate the interrupts, they actually won’t go live before the next instruction which would be the instruction sleeping the processor.
But really you are discussing micro/nanoseconds differences on when the interrupt would happen (which I suppose would wake from sleep anyway) and you want a different behavior that does not make much sense IMHO