cancel
Showing results for 
Search instead for 
Did you mean: 

WFI instruction causes system crash

Albert Claessen
Associate II
Posted on May 21, 2017 at 18:30

I am using a Nucleo L152RE for a simple interrupt driven application.

I am using an external interrupt (EXTI0) and tim6 interrupt.

Everything works fine but when I try to use HAL_PWR_EnterSLEEPMode (PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI) to save some power during non-activity, the system crashes, does not make it out of sleep mode.

The program counter ends up at  line 130 in startup_stm32l152xe.s line 130  b Infinite_Loop which seems to be the WWDG_IRQ handler. The watchdog is not enabled and what I have found so far indicates that this is caused by an interrupt that is not handled. I have not been able to find a cause. I cannot find any interrupts enabled other than the what I am intending to use.

I am probably making a rookie mistake but would appreciate any help/pointers.

#wfi-pwr_enterstopmode-interrupt
18 REPLIES 18
Adam Czapski
Associate II
Posted on August 06, 2017 at 20:48

Hello everyone, I just encountered the same problem on my Nucleo-L053R8. I'm using interrupts other than EXTI but basically the same thing happens. When debugging, the MCU enters HardFault_Handler once a wake-up event occurs. It may be useful to note that when this happens the MCU must be re-powered for the program to start working - disconnecting the debug session and a HW reset are not enough.

Recently at work I've worked on a project which uses an L152RD and I did not have any issues with it so maybe I'll try some configuration from that project and get back to you if I have any luck.

For now I'll just say that the L152 project uses V-reg on Range 3, no HSE and sleeps in stop mode while my test program on the Nucleo uses Vreg Range 1, HSE and LSE, and normal sleep (WFI with no other options)

I've also found this forum thread:

https://community.st.com/thread/41602-stm32l1-hardfault-when-returning-from-wfi-only-when-debugger-attached

which seems to describe the same issue.

Posted on August 06, 2017 at 21:08

Power-cycle-reset seems to be similar to some of the errata for the L0 part, you may want to review these in the context of your failure.

http://www.st.com/content/ccc/resource/technical/document/errata_sheet/d4/03/42/b0/b1/6c/4a/19/DM00114891.pdf/files/DM00114891.pdf/jcr:content/translations/en.DM00114891.pdf

 

Check DBGMCU settings, most current firmware/drivers. Not sure what tool-chain is being used here.

Generally I'd avoid using the debugger for low-power testing, as it is likely to more invasive and prone to disconnection.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on August 06, 2017 at 21:34

I think you're missing the point. The debugger does not disconnect and even if it did it's not the issue we're talking about. The problem is the MCU itself enters HardFault on a wake-up event if the debugger is connected;

However your suggestion yielded...well...something...

When LL_DBGMCU_EnableDBGSleepMode(); is used the program doesn't work even after a power cycle.

BTW, I'm using SW4STM32 (with GCC) but I don't think it should matter. As I said my project on L152 works flawlessly with and without debugging.
Adam Czapski
Associate II
Posted on August 07, 2017 at 00:43

Found it! And it ain't pretty...

Note: I don't currently know if it's the same issue on L152 as it is on my L

The code that wouldn't work for me was a FreeRTOS port on which I wanted to try the tickless idle mode.

Eventually I generated a new project with CubeMX that would toggle an LED in EXTI ISR after pushing a button and would enter sleep mode in the main loop. And there were no issues. I verified that both projects have all clocks and everything set and found no problems. So I returned to the FreeRTOS based project and set a breakpoint right after the WFI instruction and it did not crash. So it got me thinking... The way this FreeRTOS port enters sleep is:

__asm volatile( 'dsb' );
__asm volatile( 'wfi' );
__asm volatile( 'isb' );�?�?�?�?�?�?

In CubeMX-generated code I tried:

HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);�?�?

and then:

__disable_irq();
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
__enable_irq();�?�?�?�?�?�?

both worked so i replaced them with:

__asm volatile( 'cpsid i' );
__asm volatile( 'dsb' );
__asm volatile( 'wfi' );
__asm volatile( 'isb' );
__asm volatile( 'cpsie i' );�?�?�?�?�?�?�?�?�?�?

and the code would no longer work (HardFault on wake-up).

Because inserting a breakpoint on the ISB instruction caused the program to work (and halt every time the breakpoint was hit) i tried inserting a NOP instruction between WFI and ISB and it solved the problem! When I started writing this post I initially wrote (and thought) that you need to wait between executing WFI and allowing the core to enter Handler mode but it can't be it. I don't think I really understand what is going on. I think it may be related to the memory alignment of some instructions (check the examples below). Here are some examples of code that works:

// 1
__asm volatile( 'wfi' );�?�?�?
// 2
__asm volatile( 'cpsid i' );
__asm volatile( 'wfi' );
__asm volatile( 'nop' );
__asm volatile( 'nop' );
__asm volatile( 'cpsie i' );�?�?�?�?�?�?�?�?�?�?�?
// 3
__asm volatile( 'cpsid i' );
// This may be repeated an odd number of times (1, 3, 5 etc.)
__asm volatile( 'nop' );
__asm volatile( 'wfi' );
__asm volatile( 'cpsie i' );
// 4
__asm volatile( 'cpsid i' );
__asm volatile( 'dsb' );
__asm volatile( 'wfi' );
// Again it only works with odd number of NOPs
__asm volatile( 'nop' );
__asm volatile( 'isb' );
__asm volatile( 'cpsie i' );
// 5
__asm volatile( 'cpsid i' );
__asm volatile( 'dsb' );
// x1, 3, 5 etc.
__asm volatile( 'nop' );
__asm volatile( 'wfi' );
// If there's an odd number of NOPs before WFI, there can be any number of NOPs
// after WFI unlike in the previous example
__asm volatile( 'nop' );
__asm volatile( 'nop' );
__asm volatile( 'isb' );
__asm volatile( 'cpsie i' );�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

And here are some that don't work:

// 1
__asm volatile( 'cpsid i' );
__asm volatile( 'wfi' );
__asm volatile( 'cpsie i' );
// 2
__asm volatile( 'cpsid i' );
__asm volatile( 'wfi' );
__asm volatile( 'nop' );
__asm volatile( 'cpsie i' );�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
// 3
__asm volatile( 'cpsid i' );
// It doesn't work when there's an even number of NOPs (2, 4, etc.)
__asm volatile( 'nop' );
__asm volatile( 'nop' );
__asm volatile( 'wfi' );
__asm volatile( 'cpsie i' );
// 4
__asm volatile( 'cpsid i' );
__asm volatile( 'dsb' );
__asm volatile( 'wfi' );
__asm volatile( 'isb' );
__asm volatile( 'cpsie i' );�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Unfortunately this MCU doesn't have any fault status registers but when executing

__asm volatile( 'cpsid i' );
__asm volatile( 'dsb' );
__asm volatile( 'wfi' );
__asm volatile( 'isb' );
__asm volatile( 'cpsie i' );�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

the PC stored in the stack frame after entering HardFault_Handler points to the ISB instruction address.

Posted on August 07, 2017 at 02:36

>>I think you're missing the point.

Perhaps, but if conventional methods got you to a solution you wouldn't be here, so humour me a little.

>>The debugger does not disconnect and even if it did it's not the issue we're talking about.

Yes, but the debugger is far from ideal, and tends to distort what's happening. If you can take it out of the equation, you might better see what's really happening.

>>The problem is the MCU itself enters HardFault on a wake-up event if the debugger is connected;

Ok, and what does the fault handler tell you about the problem? Do you have any register content, or stack data? Does it fault in a consistent place?

There are definitely issues with the flash/prefetch with respect to this on one or more of the devices, this thread was for an L1 device, the L0 hopefully addressed some of the original issues, but they are entirely different parts, using a different core, and the compiler is going to generate different code. The debug interface is also rather different.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on August 07, 2017 at 06:21

Well, I've found a reliable way to replicate the problem and a possible workaround but my post is 'Currently being moderated'...

Edit: And I've just checked that disabling prefetch does not seem to make any difference.
Posted on August 08, 2017 at 23:14

I'm back with more bizarre news! I took one of the old prototypes from work that uses L152, compiled the same kind of code and even weirder things happen. At this point I'm thinking either the FreeRTOS's port.c file supplied with STM32 firmware packages is incorrect or something is seriously wrong with these micros. I don't have enough experience with Thumb assembly to determine that.

So again I added this code to the CubeMX-generated code:

__asm volatile( ''cpsid i'' );
__asm volatile( ''dsb'' );
__asm volatile( ''wfi'' );
__asm volatile( ''isb'' );
__asm volatile( ''cpsie i'' );�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

and I toggle a GPIO line in EXTI ISR to quickly determine whether it still works.

I put a breakpoint in the ISR which wakes the MCU up and found that the stacked PC is a nop instruction (padding) after ''main'' function. If I put a breakpoint on the instruction after WFI, press the button (which causes the breakpoint to be hit) and resume the program (with a breakpoint still present in the ISR) I can see that the stacked PC is correct.

0690X00000607kKQAQ.png Does anyone know what could possibly be happening? This could be problematic because as I said previously, on L0 it would stop working not only when the debugger was attached but also when debugging in sleep mode was simply enabled. E.g. by:

LL_DBGMCU_EnableDBGSleepMode();�?�?�?

I just realized that I might have screwed up my previous test on the L0 because I think I somehow forgot that CubeMX enables SysTick and additional interrupts might have skewed my view. I'll try again shortly. Maybe it's the same problem.

Edit: Nope, the L053 HardFaults even without any interrupts and as I said before the stacked PC points to the ISB instruction.

Update (for the L152): I uncommented the nop instruction (visible in the attached screenshot) and now it does not get to the EXTI ISR - it just HardFaults with: SHCSR == 0, CFSR == 0x8200 (which is BFARVALID | PRECISERR), HFSR == 0x40000000 (FORCED) DFSR == 0xb BFAR == 0xb005f851 But it still works when I put a breakpoint after WFI
Posted on December 08, 2017 at 16:16

Adam, do you have any updates on this issue?

We are also attempting to track down the cause of a hard fault on an STM32L476 that seems to occur on the exit of Stop Mode 1.  We have the WFI() wrapped by DSB() and ISB() instructions similar to the FreeRTOS implementation. Adding NOP(s) after the WFI() seems to prevent the problem.

Posted on January 25, 2018 at 09:23

Any comments from ST side?

I experience these issues with a STM32F429 using HAL_PWR_EnterSTOPMode()!