cancel
Showing results for 
Search instead for 
Did you mean: 

WFI call inside IRQ handler

bogusz
Associate II
Posted on September 08, 2017 at 09:58

Hello,

I'm using STM32L100R8T6A.

The problem I'm facing is that I do a Low Power Battery Powered Project, where it's necessary to detect that battery has been removed and I have backup capacitor for this case but with limited charge to hold MCU alive.

The problem is that I 

detect Falling edge by EXTI if battery is removed at pin PC.13 (Wakeup 2). 

When this interrupt is called I do this:

HAL_GPIO_EXTI_IRQHandler(PTB_DEF_BATT_PRESENT_PIN); // PC13

__HAL_RTC_WAKEUPTIMER_DISABLE(&T_hrtc);

__HAL_RCC_CLEAR_RESET_FLAGS();

__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2); // Batt detection

RCC->APB1ENR |= RCC_APB1ENR_PWREN; // To be able to write to PWR registers, you have first to enable PWR's clock by setting RCC_APB1ENR.PWREN.

SCB->SCR |= SCB_SCR_SLEEPDEEP; // enter deepsleep mode

PWR->CR |= PWR_CR_PDDS; // enter standby in deepsleep

PWR->CR |= PWR_CR_CWUF; // clear wakeup flag

__WFI(); 

 

 

After this I enter Standby mode but it's never wokenup, not by rising edge at PC13 and event not by IWDG which is also running.

When I call same code within the mainloop, it enters StandBy corectly and can be woken uop by both IWDG and PC13 rising edge.

Is the problem that I call WFI within IRQ handler? If so is there some workarounf? I have to enter StandBy as Soon as battery is removed so it's time critical task which I can't handle within main loop, it's too slow.

And then I have to detect Rising edge at PC.13 when battery is put back and wake up the system.
3 REPLIES 3
Ben K
Senior III
Posted on September 08, 2017 at 16:40

I imagine that the WFI instruction is halting the further execution of code, therefore the ISR does not return, and is not able to be started again, which might be the cause of the problem.

In any case I would suggest setting the SCB_SCR_SLEEPONEXIT bit in the ISR, in that way entering the Thread mode (main()) is redirected to sleep mode. See description in

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/BABHHGEB.html

.
Alan Chambers
Associate II
Posted on September 08, 2017 at 17:30

Could it be interrupt priorities? Since the interrupt has not returned, it can only be interrupted by a higher priority request. According to Joseph Yiu's book, the device will only wake up if the new interrupt priority is greater than the current level, and the ISR will then only be executed if interrupts are enabled. Suggest you sleep in the lowest priority interrupt, or don't do it in an ISR.

bogusz
Associate II
Posted on September 11, 2017 at 15:14

Thanks guys,

well it seems I have these strange states due to JTAG.

When I did a flash, JTAG performs SW reset automatically, then I have disconnected JTAG, put out/in the battery and made a tests.

But the backup Capacitor hold the voltage so actually removing battery didn't performe voltage reset but it stays in state made by JTAG reset and call the EXTI IRQ, which behaves really strange what about consumption but also the problems I mentioned above.

What happend is this:

1. JTAG flash new firmware and perform software reset

2. I put out the battery (thinking the voltage reset was made), but actually EXTI IRQ was called and Standby __WFI executed.

3. I'm in strange StandBy mode

And here comes the strange behavior, StandBy mode made after JTAG SW Reset (even if JTAG is disconnected) cause the problems. But if EXTI IRQ is called after real power reset it behaves exactly as supposed.

Anyway I made an experiments with priority and reslult is that even if RTC WAKEUP IT has lower priority than EXTI where I call __WFI, it will wake up even so.

SLEEPONEXIT - well thats a nice solution and works perfectly also, but it's safe when you call __DSB() after setting SLEEPONEXIT bit due to note from SIlab forum:

The DSB ensures that any ongoing data manipulations are completed before continuing (i.e., before exiting the ISR).  The DSB will finish in one cycle if you count from the cycle where the SLEEPONEXIT write has finished (remember, it is a 3 stage pipeline).  The reason you found that two NOPs were needed is that the first NOP was executed in the data phase of the write to SLEEPONEXIT.

Eventually it seems it's ok to call __WFI() inside ISR and it will not affect wakeup condition from the wakeup pin nor wakeup timer interrupt.

Only problem is that if IWDG is running I can't stop it, thus reset will occur and I have to put the system to the standy again after the reset and check that the reset was made by IWDG in standby mode:

__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)

__HAL_PWR_GET_FLAG(PWR_FLAG_SB)

This reset cycle drain the backup capacitor and shorten backup time.