Stuck in idle_thread after wake from STOP

Discussions and support about ChibiOS/RT, the free embedded RTOS.
chrismerck
Posts: 21
Joined: Fri Mar 14, 2014 12:35 am
Been thanked: 4 times

Stuck in idle_thread after wake from STOP

Postby chrismerck » Mon Jan 02, 2017 8:20 pm

I'm trying to get wake from SLEEP/STOP mode working on STM32L151CC, with ChibiOS 16.1.0.

We first initialize the project, including starting debug serial port and setting EXTI 20 (for RTC wakeup event):

Code: Select all

void extcb(EXTDriver *extp, expchannel_t channel)
{
   (void) extp;
   (void) channel;
   
   /* Reset SLEEPDEEP bit of Cortex System Control Register */
   SCB->SCR &= (uint32_t) ~((uint32_t) SCB_SCR_SLEEPDEEP_Msk);
   /* switch off wakeup */
   rtcSTM32SetPeriodicWakeup(&RTCD1, NULL);

   chSysLockFromISR();
   /* we must reinit clocks after waking up ESPECIALLY if use HSE or HSI+PLL */
   stm32_clock_init();
   chSysUnlockFromISR();

}

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_BOTH_EDGES | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOB, extcb_enc}, // example interrupt
    {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, extcb}, /* 20 */
    {EXT_CH_MODE_DISABLED, NULL},
    {EXT_CH_MODE_DISABLED, NULL}
  }
};

int main(void) {


  /*
   * Real-Time Operating System Initialization
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
  halInit();
  chSysInit();

  /*
   * Activates the EXT driver 1.
   */
  extStart(&EXTD1, &extcfg);
 
  ...
 


Next we initialize the RTC:

Code: Select all


void RTC_Init()
{
  int i = 0;
  // 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));
}



And then set a 3 sec timer with RTC_DeepSleep(3):

Code: Select all


void RTC_DeepSleep(uint32_t seconds)
{
  /*
   * 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;
}


And finally call WFI:

Code: Select all

    /* ADC1->CR2 = 0; // ADC off
    USART1->CR1 = 0;
    USART2->CR1 = 0;
    USART3->CR1 = 0;*/
    PWR->CR |= PWR_CR_ULP;
    PWR->CR |= PWR_CR_LPSDSR;
    //PWR->CR |= PWR_CR_PDDS; // standby
    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();
    }
    __WFI();


Then three seconds later, the system wakes, we are able to print to the debug serial port, but then a call to OsSleepMs (chThdSleepMilliseconds) never returns. Debugger shows system enters but never leaves idle thread.

What might need to be re-initialized in ChibiOS to allow normal operation after waking from STOP?

Koen
Posts: 35
Joined: Mon Dec 21, 2015 12:15 am
Been thanked: 5 times

Re: Stuck in idle_thread after wake from STOP

Postby Koen » Mon Jan 02, 2017 8:41 pm

Hello, it might be easier with Idle thread hooks (chconf.h) :

Code: Select all

#define CORTEX_ENABLE_WFI_IDLE              TRUE

/**
 * @brief   Idle thread enter hook.
 * @note    This hook is invoked within a critical zone, no OS functions
 *          should be invoked from here.
 * @note    This macro can be used to activate a power saving mode.
 */
#ifndef  _FROM_ASM_
#define CH_CFG_IDLE_ENTER_HOOK() {                                          \
  extern bool stop_mode;                                                  \
  if(stop_mode) {                                                         \
       uint32_t   tmpreg  = PWR->CR1;                                     \
                  tmpreg &= (uint32_t) ~(PWR_CR1_PDDS | PWR_CR1_LPDS);    \
                  tmpreg |= PWR_CR1_LPDS;                                 \
    PWR->CR1  = tmpreg;                                                 \
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;                                  \
  }                                                                       \
}
#endif

/**
 * @brief   Idle thread leave hook.
 * @note    This hook is invoked within a critical zone, no OS functions
 *          should be invoked from here.
 * @note    This macro can be used to deactivate a power saving mode.
 */
#ifndef  _FROM_ASM_
  #define CH_CFG_IDLE_LEAVE_HOOK() {                                      \
    SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);           \
  }
#endif


This example does not contain clocks reinitialization. Declare bool stop_mode somewhere and assign it true/false depending on your wish to enter STOP or SLEEP mode.

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

Re: Stuck in idle_thread after wake from STOP

Postby chrismerck » Mon Jan 02, 2017 8:55 pm

Hi Koen,

Thanks for the reply. Indeed the idlethread hooks are a nice feature, however I will likely not be able to use them because I plan to take extreme steps to lower power consumption during STOP mode, including setting all GPIOs to analog inputs. But I would not want GPIOs modified every time the idle thread runs.

Does that make sense, or am I missing your point?

-Chris

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: Stuck in idle_thread after wake from STOP

Postby Giovanni » Mon Jan 02, 2017 9:15 pm

Hi,

Leaving the idle thread is done by serving interrupts that cause other threads to become ready, are interrupts enabled at that point? especially the systick timer.

Giovanni

Koen
Posts: 35
Joined: Mon Dec 21, 2015 12:15 am
Been thanked: 5 times

Re: Stuck in idle_thread after wake from STOP

Postby Koen » Mon Jan 02, 2017 10:29 pm

The example above (with more logic of course) works great to always be in the lowest consumption configuration possible.


Return to “ChibiOS/RT”

Who is online

Users browsing this forum: No registered users and 5 guests