Threads not working after STM32F4 STOP Mode

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: RoccoMarco, barthess

philcrump
Posts: 2
Joined: Mon Jun 06, 2016 12:22 pm
Been thanked: 1 time

Threads not working after STM32F4 STOP Mode

Postby philcrump » Mon Jun 06, 2016 12:36 pm

Hi All,

I have code below that is intended to put an STM32F415 into STOP mode, and then wake it using the RTC Wakeup Interrupt 5 seconds later.

The result of running this code is that the STM32 boots (LED is Off, current is ~11mA), after 1 second enters STOP mode (LED goes On, current drops to ~5mA). 5 seconds later exits STOP mode (LED goes Off, a loop fast-toggling the LED also works here), however other threads do not run and any call to chThdSleep..() never completes. In addition the current does not rise above 7mA. (LED current is excluded from measurements.)
.
This happens in both ticked and tickless modes, I am wondering if the systick timer (or the virtual timer used in tickless) is not being started back up correctly?

Any help is greatly appreciated.

Thanks,
Phil

Code: Select all

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

static RTCWakeup wakeupspec;

static void ext_cb(EXTDriver *extp, expchannel_t channel);
static const EXTConfig extcfg = {
  {
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART, ext_cb},
  }
};

static void Chibi_DeepSleep(void)
{
    /* Clear RTC Interrupt flags */
    RTC->ISR &= ~(RTC_ISR_ALRBF | RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TAMP1F |
                RTC_ISR_TSOVF | RTC_ISR_TSF);

    /* Set regulator to low-power and clear wakeup flags */
    PWR->CR  |= (PWR_CR_LPDS | PWR_CR_CSBF | PWR_CR_CWUF);
   
    /* Set deep-sleep mode */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

    __WFI();
}

static void ext_cb(EXTDriver *extp, expchannel_t channel)
{
  (void)extp;
  (void)channel;
 
  chSysLockFromISR();
 
  stm32_clock_init();
 
  RTC->ISR &= ~RTC_ISR_WUTF;
  EXTI->PR &= ~(1 << 22);
 
  chSysUnlockFromISR();
}


int main(void)
{
    halInit();
    chSysInit();
   
    /* Set LED Off */
    palClearPad(GPIOA, GPIOA_STM_LED_DRIVE);
   
    extStart(&EXTD1, &extcfg);
   
    nvicEnableVector(RTC_WKUP_IRQn, STM32_EXT_EXTI22_IRQ_PRIORITY);
   
    /* set wakeup */
    wakeupspec.wutr = ((uint32_t)4) << 16;      /* select 1 Hz clock source */
    wakeupspec.wutr |= ((5));                 /* Period in seconds */
    rtcSTM32SetPeriodicWakeup(&RTCD1, &wakeupspec);
   
    chThdSleepMilliseconds(1000);
   
    /* Set LED On */
    palSetPad(GPIOA, GPIOA_STM_LED_DRIVE);
    Chibi_DeepSleep();   /* Sleep for 5s */
   
    halInit();
    chSysInit();
     
    while (true) {
        /* Toggle LED to indicate wakeup - this works */
        palTogglePad(GPIOA, GPIOA_STM_LED_DRIVE);
        /* Sleep - this never completes */
        chThdSleepMilliseconds(200);
    }
}

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: Threads not working after STM32F4 STOP Mode

Postby Giovanni » Mon Jun 06, 2016 1:56 pm

Hi,

Exiting from stop mode requires reinitialization of clocks and peripherals, see the STM32 RM.

I recommend:
1) Stop drivers before entering stop mode.
2) Go in stop mode.
3) Reinitialize clocks.
4) Restart drivers.

The ST driver does not have a stop function, you need to restart it at registers level. Alternatively try disabling the tickless mode and see if it works using Systick.

I need to look into the ST driver and define a procedure for this.

Giovanni

chrismerck
Posts: 21
Joined: Fri Mar 14, 2014 12:35 am
Been thanked: 4 times

Re: Threads not working after STM32F4 STOP Mode

Postby chrismerck » Sun Jan 22, 2017 9:47 pm

I have been battling ChibiOS + STM32 STOP mode for a while now, on an STM32L151.

I learned a few lessons on how to properly enter/exit STOP mode:

  • If you need RTC and pin change interrupt, don't use __WFE, you need __WFI.
  • You need to restore clocks after STOP using stm32_clock_init();
  • STOP works best with periodic SysTick mode (not tickless). This means you need to stop and restart the SysTick timer using the SysTick_CTRL_TICKINT_Msk bit.
  • To get lowest power, you need to shut off peripheral clocks, but don't forget to restore them to the same values!
  • Stop any ChibiOS drivers before STOP, and Start them again after resume.
  • hal_init() and friends don't like being run on resume, use lighter weight commands like palInit() if you have to.
  • To squeeze out the last few tens of uA, configure all pins as analog input during STOP!
  • I'm seeing 2uA in STOP mode, and recovering with the RAM still intact.
  • When measuring low power, remove ALL debuggers, debug serial ports, etc. from the board.
  • Remember that a microammeter is usually high resistance, and so you may only be able to switch to uA mode on your meter after starting up the board in mA mode. The board may also not recover from STOP in uA mode on the meter --- so use the meter only for a measurement of the STOP mode current, then take it out.
  • It's very helpful to have a benchtop power supply with a built in current meter, especially if it has <100uA resolution. That way you can tell during development if you have screwed up the low power mode (very easy to do). Recommendation on PSU is B&K Precision 9122A (meter has 50uA precision).
  • Get low-power working early in your project, then make sure it still works as you add each new feature.

Setup RTC and External Interrupt

Many applications need both a timed wakeup (RTC) and a user button or peripheral (like accelerometer) that can wake up the processor from deep sleep.

So you define EXTConfig like so:

Code: Select all

static const EXTConfig extcfg = {
  {
    {EXT_CH_MODE_FALLING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb},
   ...
    {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART, extcb}, /* 20 */
    ...
  }
};


You will also want to keep track of the "wakeup reason", which can be done in the callback function:

Code: Select all

void extcb(EXTDriver *extp, expchannel_t channel)
{
   (void) extp;
   (void) channel;

   switch(channel) {
     case 0:
       wake_reason |= WAKE_REASON_BUTTON;
       break;
     case 20:
       wake_reason |= WAKE_REASON_RTC;
       break;
     default:
       break;
   }
}



Enter STOP Mode

Here's my code for RTC and entering STOP mode:

Code: Select all

void RTC_Init()
{
  // enable backup and pwr clocks
  RCC->APB1ENR |= RCC_APB1ENR_PWREN;
  PWR->CR |= PWR_CR_DBP;

  // reset RTC
  RCC->CSR |= RCC_CSR_RTCRST;
  RCC->CSR &= ~RCC_CSR_RTCRST;

  /* enable LSE and wait for it to stabilize
  RCC->CSR |= RCC_CSR_LSION;
  while (!(RCC->CSR & RCC_CSR_LSIRDY))
  {
    OsSleepMs(100);
    i++;
    if (i>50)
    {
      SysError("LSI did not stabilize.");
      break;
    }
    if (i%5) SysInfo("Waiting for LSI to stabilize...");
  }
  SysInfo("LSI stable."); */

  // reset RTC
  RCC->CSR |= RCC_CSR_RTCRST;
  RCC->CSR &= ~RCC_CSR_RTCRST;

  // enable RTC with external 32kHz xtal
  RCC->CSR |= RCC_CSR_RTCSEL_LSI;
  RCC->CSR |= RCC_CSR_RTCEN;

  //RTC->CR &= (uint16_t)~0x0008;
  //while (!(RTC->CR & 0x8));
  //while (!(RTC->CR & 0x20));
  //RTC->CR |= RTC_CR_ALRAIE;
  //while (!(RTC->CR & 0x20));
}

static uint32_t RCC_AHBENR_bk;
static uint32_t RCC_APB2ENR_bk;
static uint32_t RCC_APB1ENR_bk;
static uint32_t RCC_AHBLPENR_bk;
static uint32_t RCC_APB2LPENR_bk;
static uint32_t RCC_APB1LPENR_bk;
static uint32_t ADC1_CR2_bk;
static uint32_t USART1_CR1_bk;
static uint32_t USART2_CR1_bk;
static uint32_t USART3_CR1_bk;
static uint32_t OPAMP_CSR_bk;


static void lp_backup() {
  /* backup clock & periph settings */
  RCC_AHBENR_bk = RCC->AHBENR;
  RCC_APB2ENR_bk = RCC->APB2ENR;
  RCC_APB1ENR_bk = RCC->APB1ENR;
  RCC_AHBLPENR_bk = RCC->AHBLPENR;
  RCC_APB2LPENR_bk = RCC->APB2LPENR;
  RCC_APB1LPENR_bk = RCC->APB1LPENR;
  ADC1_CR2_bk = ADC1->CR2;
  USART1_CR1_bk = USART1->CR1;
  USART2_CR1_bk = USART2->CR1;
  USART3_CR1_bk = USART3->CR1;
  OPAMP_CSR_bk = OPAMP->CSR;

  /* disable clocks and peripherals */
  RCC->AHBENR = 0;
  RCC->APB2ENR = 0;
  RCC->APB1ENR = RCC_APB1ENR_PWREN;
  RCC->AHBLPENR = 0;
  RCC->APB2LPENR = 0;
  RCC->APB1LPENR = RCC_APB1LPENR_PWRLPEN;
  ADC1->CR2 = 0;
  USART1->CR1 = 0;
  USART2->CR1 = 0;
  USART3->CR1 = 0;
  OPAMP->CSR = OPAMP_CSR_OPA1PD | OPAMP_CSR_OPA2PD | OPAMP_CSR_S5SEL2 | OPAMP_CSR_S4SEL2;
}

static void lp_restore() {
  /* restore clock & periph settings */
  RCC->AHBENR = RCC_AHBENR_bk;
  RCC->APB2ENR = RCC_APB2ENR_bk;
  RCC->APB1ENR = RCC_APB1ENR_bk;
  RCC->AHBLPENR = RCC_AHBLPENR_bk;
  RCC->APB2LPENR = RCC_APB2LPENR_bk;
  RCC->APB1LPENR = RCC_APB1LPENR_bk;
  ADC1->CR2 = ADC1_CR2_bk;
  USART1->CR1 = USART1_CR1_bk;
  USART2->CR1 = USART2_CR1_bk;
  USART3->CR1 = USART3_CR1_bk;
  OPAMP->CSR = OPAMP_CSR_bk;
}

void RTC_DeepSleep(uint32_t seconds, bool periph)
{
  ADC_Stop();
  DbgConsoleShutdown();
 
  //nvicDisableVector(HANDLER_SYSTICK);
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;

  if (periph) {
    for (int i = 0; i<16; i++) {
      modePinDirect(GPIOA,i,PAL_MODE_INPUT_ANALOG);
      modePinDirect(GPIOB,i,PAL_MODE_INPUT_ANALOG);
      modePinDirect(GPIOC,i,PAL_MODE_INPUT_ANALOG);
      modePinDirect(GPIOD,i,PAL_MODE_INPUT_ANALOG);
      modePinDirect(GPIOE,i,PAL_MODE_INPUT_ANALOG);
      modePinDirect(GPIOH,i,PAL_MODE_INPUT_ANALOG);
    }
    lp_backup();
  }

  /*
   * use ck_spre (1Hz internal clock)
   * WUCKSEL[2:1] = 10 (1s to 18h)
   * Clear WUTE in RTC_CR to disable wkup timer
   * Poll WUTWF until it is set in RTC_ISR to make sure the access
   *   to the wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
   *   This takes ~2RTCCLK cycles.
   * Program the wakeup auto-reload value WUT[15:0],
   *   and the wakeup clock selection (WUCKSEL[2:0] in RTC_CR).
   *   Set WUTE in RTC_CR to enable timer again.
   */

  // sleep up to 18h
  OsAssert(seconds < 65536,"RTC Assert");

  // unlock RTC regs
  RTC->WPR = 0xCA;
  RTC->WPR = 0x53;
 
  RTC->PRER |= RTC_PRER_PREDIV_A; // maximum async prediv
  RTC->PRER = (RTC->PRER & RTC_PRER_PREDIV_S) | 0x122; // 1Hz from 37kHz


  RTC->CR &= ~RTC_CR_WUTE;
  while (!(RTC->ISR & RTC_ISR_WUTWF)) {};
  RTC->WUTR = (RTC->WUTR & ~RTC_WUTR_WUT) | (seconds & RTC_WUTR_WUT);
  RTC->CR = (RTC->CR & ~RTC_CR_WUCKSEL) | (RTC_CR_WUCKSEL_2 /* 10x */);
  RTC->CR |= RTC_CR_WUTE;

  RTC->CR |= RTC_CR_WUTIE;

  // clear wakeup timer flag
  RTC->ISR &= ~(RTC_ISR_ALRBF | RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TAMP1F |
                      RTC_ISR_TSOVF | RTC_ISR_TSF);

  // lock RTC regs
  RTC->WPR = 0xFF;

  /* Enter low power mode */
  //PWR->CR |= PWR_CR_LPSDSR;
  //PWR->CR &= ~PWR_CR_PDDS; // stop (rather than standby)

  /* clear PDDS and LPDS bits */
  PWR->CR &= ~(PWR_CR_PDDS | PWR_CR_LPSDSR);

  /* set LPDS and clear  */
  PWR->CR |= (PWR_CR_LPSDSR | PWR_CR_CSBF | PWR_CR_CWUF);
  PWR->CR |= PWR_CR_ULP;

  /* enable wakeup pin */
  PWR->CSR |= PWR_CSR_EWUP1;

  for(int i = 0; i < 100; i++) {
    __NOP();
    __NOP();
    __NOP();
    __NOP();
    __NOP();
  }
  SCB->SCR |= SCB_SCR_SLEEPDEEP;
  for(int i = 0; i < 100; i++) {
    __NOP();
    __NOP();
    __NOP();
    __NOP();
    __NOP();
  }
  wake_reason = 0;
  __WFI();
  __disable_irq();
  SCB->SCR &= ~SCB_SCR_SLEEPDEEP;
  PWR->CR |= PWR_CR_CWUF;
  PWR->CR |= PWR_CR_CSBF;
  stm32_clock_init();
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
  __enable_irq();

  if (periph) {
    lp_restore();
    palInit(&pal_default_config);
  }

  RTC_Init();
  ADC_Reinit();
  DbgConsoleReInit();

}



Tabulous
Posts: 509
Joined: Fri May 03, 2013 12:02 pm
Has thanked: 7 times
Been thanked: 17 times

Re: Threads not working after STM32F4 STOP Mode

Postby Tabulous » Tue Apr 25, 2017 7:19 pm

hi all
am struggling to get RTC wakeup interrupt working again after entering WFI.


The device an F4, has the rtc setup to give wakeup interrupt every second this is using for general things when working normally.
When put to sleep i do the following :-

Code: Select all

    /* clear PDDS bit safety */
    PWR->CR &= ~( PWR_CR_PDDS );

    /* set LPDS, clear flags */
    PWR->CR |= ( PWR_CR_LPDS | \
                 PWR_CR_CSBF | \
                 PWR_CR_CWUF | \
                 PWR_CR_FPDS );

    /* Clear wakeup reason */
    lpm.wakeup = LPM_NULL_INTERRUPT;

    /* Set deep sleep mask bit */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;

    __WFI();
    __disable_irq();

    /* Clr deep sleep mask */
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;

    /* re-init system clock */
    stm32_clock_init();
    __enable_irq();


But after this the RTC does not function anymore i.e. no wakeup Interrupt.

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: Threads not working after STM32F4 STOP Mode

Postby Giovanni » Wed Apr 26, 2017 8:14 am

Hi,

I never tested this scenario, could you create a minimal project with the whole example? that would make things easier.

Giovanni

Tabulous
Posts: 509
Joined: Fri May 03, 2013 12:02 pm
Has thanked: 7 times
Been thanked: 17 times

Re: Threads not working after STM32F4 STOP Mode

Postby Tabulous » Wed Apr 26, 2017 10:40 am

working now

this was important
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_DBP;

along with this
RTC->ISR &= ~RTC_ISR_WUTF;
EXTI->PR = ( 1 << CLK_SECOND_EVENT );


Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 15 guests