STM32L1 HardFault after wakeup from sleep mode + fix
I would like to share a bug I encountered and how to fix it:
I am using an STM32L151, the goal is to set it into SLEEP mode and wake it up using a UART receive interrupt while debugging. All configurations to pins, registers and interrupts are made correctly.
The problem:
MCU goes to sleep just fine. When sending data over UART, the MCU wakes up, but doesnt enter the UART RX ISR. Instead it enters the HardFaultHandler. Readout of the Bus Fault Status Register (BFSR) of the Configurable Fault Status Registers (CFSR) shows that bit 0 is set, indicating an Instruction bus error.
The fix:
Full credit goes to https://web.archive.org/web/20210625090753/https://lists.riot-os.org/pipermail/devel/2016-September/004534.html.
The fix states, before entering wait-for-interrupt instruction, one must disable interrupts (they will still trigger wakeup and be registered), then entering wait-for-interrupt, then issuing a nop-instruction, then re-enabling interrupts.
The fix requires to modify the HAL/SPL, so be careful when using CubeMX code generation. In my case I am using the old Standard Preipheral Library, so in the file "stm32l1xx_pwr.c" in function "PWR_EnterSleepMode" i changed
if(PWR_SLEEPEntry == PWR_SLEEPEntry_WFI)
{
/* Request Wait For Interrupt */
__DSB();
__WFI();
__NOP();
__ISB();
}to
if(PWR_SLEEPEntry == PWR_SLEEPEntry_WFI)
{
/* Request Wait For Interrupt */
__DSB();
__disable_irq();
asm ("DMB");
__WFI();
asm ("nop");
__enable_irq();
__NOP();
__ISB();
}This solves the problem. It might be necessary in some cases to insert more than one nop-Instruction after the wfi instruction.
