[stm32l1] [lpm_arch] Hard Fault after wake-up

Hello everyone!

I have started to introducing a support of Low Power Mode into current STM32L1 code base and I faced a problem which is hard to resolve alone with my current experience level at the RIOT.

Firstly, I have implemented some low power modes in corresponding lpm_arch.c: https://github.com/Cr0s/RIOT/blob/stm32l1-lpm/cpu/stm32l1/lpm_arch.c

The code seems to be correct just because I took corresponding code pieces from the SPL’s stm32l1xx_pwr.c source file.

After that I created a small application to test:

  1. Low Power Mode entrance

  2. RTC wake-up by alarm

  3. Measure actual power consumption

https://github.com/Cr0s/RIOT/blob/stm32l1-lpm/tests/lpm_test/main.c

And there’s a issue that I faced: after entering SLEEP mode and when MCU is woken up by the RTC alarm the HardFault condition happens immediately and no other instruction after _WFI() seems to be executed.

After HardFault thanks to DEVELHELP flag I can observe the HardFault handler message:

Context before hardfault: r0: 0x20000c04 r1: 0x0000000a r2: 0xe000ed00 r3: 0x00000010 r12: 0x00000000 lr: 0x08002027 pc: 0x20000c04 psr: 0x20000044

FSR/FAR: CFSR: 0x00040000 HFSR: 0x40000000 DFSR: 0x00000000 AFSR: 0x00000000 Misc EXC_RET: 0xfffffffd Attempting to reconstruct state for debugging… In GDB: set $pc=0x20000c04 frame 0 bt

ISR stack overflowed by at least 80 bytes.

So the only idea that it gives is that I should inspect CFSR/HFSR registers to see which condition leads to the HF.

I’m asking about any idea to resolve this issue: what to check first, which conditions I should check before and after entering into the LPM, etc.

Any help and response is much appreciated!

Best regards,

Anon

Dear Anon, First of all, good to hear that someone is working on LPM!

Does your program work correctly if you remove the lpm_set() line from your main or does it still crash when the RTC alarm occurs?

Normally, the idle thread will call lpm_set to go to a low power mode when the system is idle, I did not examine the implementation of lpm_set so I don’t know what will happen if you call it like that. To go to SLEEP mode from the idle thread, uncomment https://github.com/Cr0s/RIOT/blob/stm32l1-lpm/core/kernel_init.c#L74 and comment out the line above it.

To let your thread sleep and allow the idle thread to switch to low power mode, use the xtimer module (include xtimer.h), and xtimer_sleep(x).

I think there might be a bug in the stm32l1 RTC implementation with callback = NULL: https://github.com/Cr0s/RIOT/blob/stm32l1-lpm/cpu/stm32l1/periph/rtc.c#L236 The ISR flag is only cleared if cb is not null. I don’t have the reference manual for the CPU nor any experience with it so I wouldn’t know what is correct here. Feel free to open a PR on the RIOT master for any mistakes you fix in this code.

Your crash message suggests that the ISR stack is overflowing, this is most of the time caused by performing complex tasks in an ISR which might be better suited for a thread, or (accidentally) making recursive function calls in an ISR. Also, printf is a real stack-consumer and will easily take a couple 100 bytes for any kind of debugging output. The ISR_STACKSIZE definition can be changed to increase the size of the ISR stack while debugging. https://github.com/Cr0s/RIOT/blob/stm32l1-lpm/cpu/cortexm_common/include/cpu_conf_common.h#L55

You can define it in your cpu_conf.h or add it to CFLAGS (CFLAGS+=-DISR_STACKSIZE=2048 in your Makefile)

I hope this helps you on the way a bit.

Best regards, Joakim

Hi!

It seems I have found the solution for this and I believe it might be helpful for someone with the same problem . The solution is to replace plain _WFI() command with following code: __disable_irq(); asm (“DMB”); __WFI(); asm (“nop”); __enable_irq();

After that, the device is successfully wakes up by interrupt without any hard faults. Don’t know actually what the root cause of the problem, but it seems like kind of L151 silicon problem.

Best regards,

Anon