Search code examples
arminterruptcortex-m

ARM WFI won't sleep


I am trying to enter standby mode on a Cortex-M4. The normal behaviour is that the device wakes up about every 2 minutes but on my latest FW release, it seems that the code is "randomly" stuck.

After investigation it seems that the code passes the WFI instruction without going to standby (no standby => no reset => infinite loop => ... => 42).

So after many unclear spec reading my understanding is that the WFI may not go to sleep if there are pending interrupts.

  1. Can you confirm the last sentence
  2. How to ensure all pending interrupts are cleared before calling WFI ?

Solution

  • There are three conditions that cause the processor to wake up from a WFI instruction:

    1. a non-masked interrupt occurs and its priority is greater than the current execution priority (i.e. the interrupt is taken)
    2. an interrupt masked by PRIMASK becomes pending
    3. a Debug Entry request.

    If any of the wake up conditions are true when the WFI instruction executes, then it is effectively a NOP (i.e. you don't go to sleep).

    As for making sure that no interrupts are pending, that's your code that must do that. Usually it means making sure that the interrupt source is satisfied so that it does not assert its interrupt request and then clear the necessary pending bit. You can see what is pending by reading at the interrupt pending registers but interrupt handlers are usually tasked to make sure they leave things quiescent.

    Note that most systems have to do some work immediately before or after executing WFI. For example, there is often a test that must be done to determine if there is any additional work to be done before deciding to go to sleep with WFI. That test and the execution of WFI are then done in a critical section where PRIMASK is set to 1 (so we are exercising option #2 above). This will insure that no interrupts gets in between the test and the WFI and that after wakeup, no interrupt gets in case there are additional operations (usually involving clocking) that need to get done. After wake up, PRIMASK is set back to 0 (exiting the critical section) and any pending interrupt is taken.

    Also ARM recommends executing a DSB instruction immediately before WFI to insure that any data operations are finished before the processor goes to sleep. It may not be strictly necessary in all situations, but put it in just in case circumstances change and you overlook it.