Page 1 of 2

Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Thu Sep 05, 2019 11:01 pm
by storzinc
Hi, I am trying to write a function that will enter the stop mode for a specified time and then return, but I keep getting hard faults. Can someone look what's going on there? Here is my code:

Code: Select all

#include "ch.h"
#include "hal.h"


void HardFault_Handler(void)
{
  while(1)
  {
  }
}

volatile bool lexit=false;

void alarmcb(RTCDriver *rtcp, rtcevent_t event)
{
  (void)rtcp;
  (void)event;

  lexit=true;
}


__attribute__((always_inline)) inline void nop(void)
{
  asm volatile("nop");
}

void RTC_Wait(int tms)
{
  rtcSetCallback(&RTCD1, alarmcb);

nop();
nop();
//nop();
//nop();

  RTC->CR&=~RTC_CR_ALRAE; // disable Alarm A
  while(!(RTC->ISR&RTC_ISR_ALRAWF));

  RTC->ALRMAR=RTC_ALRMAR_MSK4|RTC_ALRMAR_MSK3|RTC_ALRMAR_MSK2|RTC_ALRMAR_MSK1; // do not use ALRMAR

  int ms=RTC->SSR; // get current value from sub second register and add delta
  ms-=tms;         //
  if(ms<0)         //
    ms+=1000;      //

  RTC->ALRMASSR=ms|RTC_ALRMASSR_MASKSS; // match all bits in sub second register

  RTC->CR=RTC_CR_ALRAE|RTC_CR_ALRAIE; // enable Alarm A, enable Alarm A interrupt


  PWR->CR|=(/*PWR_CR_PDDS|*/PWR_CR_LPDS|PWR_CR_CSBF|PWR_CR_CWUF); // configure stop mode
  SCB->SCR|=SCB_SCR_SLEEPDEEP_Msk;                                //
  while(1)
  {
    syssts_t status=osalSysGetStatusAndLockX();
    if(lexit)
    {
      osalSysRestoreStatusX(status);
      break;
    }
    __WFI();
nop();
//nop();
    osalSysRestoreStatusX(status);
  }
  SCB->SCR&=~SCB_SCR_SLEEPDEEP_Msk;
  stm32_clock_init();
}

int main(void)
{
  DBGMCU->CR |= DBGMCU_CR_DBG_STOP; // enable debugging in stop mode

  halInit();
  chSysInit();

  RTC_Wait(100); // enter stop mode

  while(1)
  {
  }
}


The backtrace after a crash looks like this:

Code: Select all

#0  0x08001540 in HardFault_Handler [HardFault] () at main.c:6
#1  0x080015aa in nop () at main.c:25
#2  0x080015aa in RTC_Wait (tms=tms@entry=100) at main.c:63
#3  0x0800161a in main () at main.c:78                         


And here is assemly code from where the program is crashing:

Code: Select all

 80015a6:   bf30         wfi
 80015a8:   46c0         nop         ; (mov r8, r8)
 80015aa:   f7ff fc69    bl   8000e80 <chSysRestoreStatusX>
 80015b2:   7823         ldrb   r3, [r4, #0]


I am using gcc-arm-none-eabi-5_4-2016q3 as a compiler, and using RT-STM32F051-DISCOVERY demo from ChibiOS_19.1.3 as a template for my project, the only changes are:

Code: Select all

#define HAL_USE_RTC                         TRUE

in halconf.h and

Code: Select all

  USE_LTO = no

in the Makefile. It is also possible to reproduce with USE_LTO = yes, just a little harder.
The problem itself is timing dependent, depending on the number of nops in two places the program can work as intended, crash with hard fault or stuck in the infinite loop in RTC_Wait
The program is also usualy works without crashing the first time after the power up, but starts chashing after reset.
Right now I am testing this on the STM32F0discovery board, but I originaly encountered the problem on a different board with STM32F051K6U6 mcu, and also tested on the third board with STM32F051C8T6

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Sun Sep 08, 2019 9:23 pm
by storzinc
I have modified my program a little and now the results looks even stranger. Here is the modified code:

Code: Select all

#include "ch.h"
#include "hal.h"


void HardFault_Handler(void)
{
  while(1)
  {
  }
}

volatile bool lexit=false;

void alarmcb(RTCDriver *rtcp, rtcevent_t event)
{
  (void)rtcp;
  (void)event;

  lexit=true;
}


__attribute__((always_inline)) inline void nop(void)
{
  asm volatile("nop");
}


__attribute__((noinline)) void disableIRQ(void)
{
  __disable_irq();
}

void RTC_Wait(int tms)
{
  rtcSetCallback(&RTCD1, alarmcb);

nop();
nop();
nop();
nop();
//nop();
//nop();

  RTC->CR&=~RTC_CR_ALRAE; // disable Alarm A
  while(!(RTC->ISR&RTC_ISR_ALRAWF));

  RTC->ALRMAR=RTC_ALRMAR_MSK4|RTC_ALRMAR_MSK3|RTC_ALRMAR_MSK2|RTC_ALRMAR_MSK1; // do not use ALRMAR

  int ms=RTC->SSR; // get current value from sub second register register and add delta
  ms-=tms;
  if(ms<0)
    ms+=1000;

  RTC->ALRMASSR=ms|RTC_ALRMASSR_MASKSS; // match all bits in sub second register

  RTC->CR=RTC_CR_ALRAE|RTC_CR_ALRAIE; // enable Alarm A, enable Alarm A interrupt


  PWR->CR|=PWR_CR_LPDS;              // enter stop mode
  SCB->SCR|=SCB_SCR_SLEEPDEEP_Msk;   //
  while(1)
  {
    disableIRQ();
    if(lexit)
    {
      __enable_irq();
      break;
    }
    __WFI();
nop();
//nop();
      __enable_irq();
  }
  SCB->SCR&=~SCB_SCR_SLEEPDEEP_Msk;
  stm32_clock_init();
}

int main(void)
{
  DBGMCU->CR |= DBGMCU_CR_DBG_STOP; // enable debugging in stop mode

  halInit();
  chSysInit();

  RTC_Wait(100); // enter stop mode for 100 milliseconds

  while(1)
  {
  }
}


And here is stack trace and assembly listing from where hard fault is happening:

Code: Select all

#0  0x08000c80 in HardFault_Handler [HardFault] () at main.c:6
#1  0x08000d02 in RTC_Wait (tms=tms@entry=100) at main.c:64
#2  0x08000d6a in main () at main.c:86

Code: Select all

 8000cfa:   bf30         wfi
 8000cfc:   46c0         nop         ; (mov r8, r8)
 8000cfe:   b662         cpsie   i
 8000d00:   f7ff ffc6    bl   8000c90 <LockX>
 8000d04:   7823         ldrb   r3, [r4, #0]


This looks like the hard fault happened in the middle of the instruction! Is it possible that the bug is in the MCU itself? I can not come up with what else could have caused this...

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Sun Sep 08, 2019 9:40 pm
by steved
Often hard faults turn out to be the result of a stack overflow (not always on the thread which generates the hard fault). Or sometimes a bad pointer, so a write goes to somewhere it shouldn't. So you could look in detail at the offending instruction - check register values, and what they mean in that context.
I've not used stop mode, but a bug in the hardware seems pretty unlikely - the 32F051 has been around for a few years now. I believe that sometimes a specific sequence is used to enter and leave stop mode - check you've got that right.

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Mon Sep 09, 2019 5:36 pm
by storzinc
This does not look like a stack overflow, msp and psp are near the bottom of the stack and the memory fill pattern at the top is undisturbed.
I also don't see anything out of place amongst the registers:

Code: Select all

r0             0xf00000d           251658253
r1             0x0                 0
r2             0xe000ed00          -536810240
r3             0x0                 0
r4             0x200005c0          536872384
r5             0x80000c0           134217920
r6             0xffffffff          -1
r7             0xffffffff          -1
r8             0xffffffff          -1
r9             0xffffffff          -1
r10            0xffffffff          -1
r11            0xffffffff          -1
r12            0xe000e100          -536813312
sp             0x20000200          0x20000200
lr             0xfffffffd          -3
pc             0x8000c80           0x8000c80 <HardFault_Handler>
xPSR           0x21000003          553648131
msp            0x20000200          0x20000200
psp            0x200003d0          0x200003d0

And I really do not understand how `bl` instruction could cause a hard fault, especially for it to happen in the middle of the instruction...
The stop mode entry/exit sequence looks right to me. But maybe I am missing something, I will try to replicate this on something other than STM32F051 series, maybe that will help to understand what's going on.

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Mon Sep 09, 2019 5:44 pm
by Giovanni
Are you stepping through that "bl" in asm mode? it should not cause an exception in itself.

Giovanni

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Mon Sep 09, 2019 7:00 pm
by storzinc
No, I am attaching the debugger after the program have already crashed and analyzing the stack, the stack frame there looks like this:

Code: Select all

(gdb) x/8xw $psp
0x200003d0:     0x0f000122      0x00000000      0xe000ed00      0x00000000
0x200003e0:     0xe000e100      0x08000d05      0x08000d02      0x21000000

So it seems that "pc" was 0x08000d02 at the time of the hard fault, but it should have never been at that address, because the instruction at the address 8000d00 is 4 bytes long:

Code: Select all

 8000d00:   f7ff ffc6    bl   8000c90 <disableIRQ>

If I try to set a breakpoint at 8000d00 and then step through the "bl" or just continue the program then everything works as expected, without hard faults.

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Mon Sep 09, 2019 7:41 pm
by Giovanni
That is an even address (0x08000d02), addresses on Cortex-M must be odd because it is thumb code. LSb in PC must always be one.

Giovanni

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Mon Sep 09, 2019 9:45 pm
by storzinc
Maybe the rules for the exception stacking are different? I have made a program that is deliberately causing exceptions:

Code: Select all

  volatile char *ptr=(char *)4;
  *ptr=42;

And here is how the stack looks in the hard fault handler:

Code: Select all

(gdb) x/8xw $psp
0x200003d8:     0x00000000      0x08000e30      0x0000002a      0x00000004
0x200003e8:     0x08000df8      0x0800013f      0x08000d56      0x21000000

pc is 0x08000d56 here, also even, but now it points to the correct address:

Code: Select all

 8000d50:   222a         movs   r2, #42   ; 0x2a
 8000d52:   2304         movs   r3, #4
 8000d54:   b510         push   {r4, lr}
 8000d56:   701a         strb   r2, [r3, #0]

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Tue Sep 10, 2019 2:16 pm
by storzinc
Reproduced this on another two boards, with STM32F030K6T6 and with STM32F042K6T6, the results are the same. So it seems that the problem is not localized on the STM32F051 series.

Re: Hard fault when exiting stop mode with RTC alarm on STM32F051

Posted: Tue Sep 10, 2019 4:08 pm
by Giovanni
Try putting multiple asm("nop") after the wfi(), where does it crash? still in bl or in the very first instruction encountered?

Giovanni