Esempio n. 1
0
static void stm32_idlepm(void)
{
  static enum pm_state_e oldstate = PM_NORMAL;
  enum pm_state_e newstate;
  int ret;

  /* The following is logic that is done after the wake-up from PM_STANDBY
   * state.  It decides whether to go back to the PM_NORMAL or to the deeper
   * power-saving mode PM_SLEEP:  If the alarm expired with no "normal"
   * wake-up event, then PM_SLEEP is entered.
   *
   * Logically, this code belongs at the end of the PM_STANDBY case below,
   * does not work in the position for some unkown reason.
   */

  if (oldstate == PM_STANDBY)
    {
      /* Were we awakened by the alarm? */

#ifdef CONFIG_RTC_ALARM
      if (g_alarmwakeup)
        {
          /* Yes.. Go to SLEEP mode */

          newstate = PM_SLEEP;
        }
      else
#endif
        {
          /* Resume normal operation */

          newstate = PM_NORMAL;
        }
    }
  else
    {
      /* Let the PM system decide, which power saving level can be obtained */

      newstate = pm_checkstate();
    }

  /* Check for state changes */

  if (newstate != oldstate)
    {
      llvdbg("newstate= %d oldstate=%d\n", newstate, oldstate);

      sched_lock();

      /* Force the global state change */

      ret = pm_changestate(newstate);
      if (ret < 0)
        {
          /* The new state change failed, revert to the preceding state */

          (void)pm_changestate(oldstate);

          /* No state change... */

          goto errout;
        }

      /* Then perform board-specific, state-dependent logic here */

      switch (newstate)
        {
        case PM_NORMAL:
          {
            /* If we just awakened from PM_STANDBY mode, then reconfigure
             * clocking.
             */

            if (oldstate == PM_STANDBY)
              {
                /* Re-enable clocking */

                stm32_clockenable();

                /* The system timer was disabled while in PM_STANDBY or
                 * PM_SLEEP modes.  But the RTC has still be running:  Reset
                 * the system time the current RTC time.
                 */

#ifdef CONFIG_RTC
                clock_synchronize();
#endif
              }
          }
          break;

        case PM_IDLE:
          {
          }
          break;

        case PM_STANDBY:
          {
            /* Set the alarm as an EXTI Line */

#ifdef CONFIG_RTC_ALARM
            stm32_rtc_alarm(CONFIG_PM_ALARM_SEC, CONFIG_PM_ALARM_NSEC, true);
#endif
            /* Wait 10ms */

            up_mdelay(10);

            /* Enter the STM32 stop mode */

            (void)stm32_pmstop(false);

            /* We have been re-awakened by some even:  A button press?
             * An alarm?  Cancel any pending alarm and resume the normal
             * operation.
             */

#ifdef CONFIG_RTC_ALARM
            stm32_exti_cancel();
            ret = stm32_rtc_cancelalarm();
            if (ret < 0)
              {
                lldbg("Warning: Cancel alarm failed\n");
              }
#endif
            /* Note:  See the additional PM_STANDBY related logic at the
             * beginning of this function.  That logic is executed after
             * this point.
             */
          }
          break;

        case PM_SLEEP:
          {
            /* We should not return from standby mode.  The only way out
             * of standby is via the reset path.
             */

            /* Configure the RTC alarm to Auto Reset the system */

#ifdef CONFIG_PM_SLEEP_WAKEUP
            stm32_rtc_alarm(CONFIG_PM_SLEEP_WAKEUP_SEC, CONFIG_PM_SLEEP_WAKEUP_NSEC, false);
#endif
            /* Wait 10ms */

            up_mdelay(10);

            /* Enter the STM32 standby mode */

            (void)stm32_pmstandby();
          }
          break;

        default:
          break;
        }

      /* Save the new state */

      oldstate = newstate;

errout:
      sched_unlock();
    }
}
Esempio n. 2
0
static void up_idlepm(void)
{
#ifdef CONFIG_RTC_ALARM
  struct timespec alarmtime;
#endif
  static enum pm_state_e oldstate = PM_NORMAL;
  enum pm_state_e newstate;
  irqstate_t flags;
  int ret;

  /* Decide, which power saving level can be obtained */

  newstate = pm_checkstate();

  /* Check for state changes */

  if (newstate != oldstate)
    {
      lldbg("newstate= %d oldstate=%d\n", newstate, oldstate);

      flags = irqsave();

      /* Force the global state change */

      ret = pm_changestate(newstate);
      if (ret < 0)
        {
          /* The new state change failed, revert to the preceding state */

          (void)pm_changestate(oldstate);

          /* No state change... */

          goto errout;
        }

      /* Then perform board-specific, state-dependent logic here */

      switch (newstate)
        {
        case PM_NORMAL:
          {
          }
          break;

        case PM_IDLE:
          {
          }
          break;

        case PM_STANDBY:
          {
#ifdef CONFIG_RTC_ALARM
            /* Disable RTC Alarm interrupt */

#warning "missing logic"

            /* Configure the RTC alarm to Auto Wake the system */

#warning "missing logic"

            /* The tv_nsec value must not exceed 1,000,000,000. That
             * would be an invalid time.
             */

#warning "missing logic"

            /* Set the alarm */

#warning "missing logic"
#endif
            /* Call the STM32 stop mode */

            stm32_pmstop(true);

            /* We have been re-awakened by some even:  A button press?
             * An alarm?  Cancel any pending alarm and resume the normal
             * operation.
             */

#ifdef CONFIG_RTC_ALARM
#warning "missing logic"
#endif
            /* Resume normal operation */

            pm_changestate(PM_NORMAL);
            newstate = PM_NORMAL;
          }
          break;

        case PM_SLEEP:
          {
            /* We should not return from standby mode.  The only way out
             * of standby is via the reset path.
             */

            (void)stm32_pmstandby();
          }
          break;

        default:
          break;
        }

      /* Save the new state */

      oldstate = newstate;

errout:
      irqrestore(flags);
    }
}
Esempio n. 3
0
void board_deepsleep_with_stopmode(uint32_t secs)
{
#if defined(CONFIG_RTC) && defined(CONFIG_RTC_DATETIME)
  struct tm t;
  struct timespec ts;
  struct timespec rtc_start_ts;
  struct timespec rtc_end_ts;
#endif
#ifdef CONFIG_BOARD_DEEPSLEEP_RECONFIGURE_GPIOS
  uint32_t gpio_off_mask;
  bool sdcard_enabled;
#endif
  uint32_t regval;
  int ret;
#ifdef DEEPSLEEP_WAKETIME_DEBUG
  static struct timespec wake_ts;
#endif
#ifdef DEEPSLEEP_SLEEPTIME_DEBUG
  bool slept = false;
#endif

  /* Do not allow other tasks to takeover (for example, by wake-up with semaphore
   * from EXTI interrupt) before we have restored MCU functionalities. */

  sched_lock();

#ifdef DEEPSLEEP_SLEEPTIME_DEBUG
  lldbg("sleep for %d\n", secs);
#endif

#ifdef CONFIG_BOARD_DEEPSLEEP_RECONFIGURE_GPIOS

  /* Special support for SDcard. */

  if (stm32_gpioread(GPIO_CHIP_SELECT_SDCARD) == false)
    {
      lldbg("ERROR! SDcard communication active while trying deep-sleep!\n");

      goto skip_deepsleep;
    }

  /* Following devices do not have proper GPIO reconfigure recovery yet (and
   * some cannot work with deep-sleep at all). Abort deep-sleep instead of
   * introducing hard-to-diagnose bugs and general instability.
   */

  if (stm32_gpioread(GPIO_REGULATOR_WLAN))
    {
      lldbg("ERROR! Trying to deep-sleep when WLAN active!\n");

      goto skip_deepsleep;
    }

  if (stm32_gpioread(GPIO_PWR_SWITCH_MODEM))
    {
      lldbg("ERROR! Trying to deep-sleep when Modem active!\n");

      goto skip_deepsleep;
    }

  if (stm32_gpioread(GPIO_REGULATOR_GPS))
    {
      lldbg("ERROR! Trying to deep-sleep when GPS active!\n");

      goto skip_deepsleep;
    }

  if (stm32_gpioread(GPIO_REGULATOR_BLUETOOTH))
    {
      lldbg("ERROR! Trying to deep-sleep when Bluetooth active!\n");

      goto skip_deepsleep;
    }

  if (stm32_gpioread(GPIO_REGULATOR_DISPLAY))
    {
      lldbg("ERROR! Trying to deep-sleep when Display active!\n");

      goto skip_deepsleep;
    }
#endif /* CONFIG_BOARD_DEEPSLEEP_RECONFIGURE_GPIOS */

#if defined(CONFIG_RTC) && defined(CONFIG_RTC_DATETIME)
  /* Get RTC clock before STOP. */

  stm32_rtc_getdatetime_with_subseconds(&t, &rtc_start_ts.tv_nsec);
  rtc_start_ts.tv_sec = mktime(&t);

  /* Get current time. */

  ret = clock_gettime(CLOCK_REALTIME, &ts);
  DEBUGASSERT(ret != ERROR);

  /* Add nanoseconds to entropy pool. */

  add_time_randomness(ts.tv_nsec);

#endif

#ifdef DEEPSLEEP_WAKETIME_DEBUG
  if (wake_ts.tv_nsec || wake_ts.tv_sec)
    {
      struct timespec curr_ts;
      int64_t msecs;

      clock_gettime(CLOCK_REALTIME, &curr_ts);

      msecs = ((int64_t)curr_ts.tv_sec - wake_ts.tv_sec) * 1000;
      msecs += ((int64_t)curr_ts.tv_nsec - wake_ts.tv_nsec) / (1000 * 1000);

      lldbg("sleep to sleep time: %d msecs\n", (int)msecs);
    }
  else
    {
      lldbg("first sleep (for %u secs)\n", secs);
    }
#endif

#ifdef CONFIG_RTC_PERIODIC_AUTORELOAD_WAKEUP
  if (secs > 0)
    {
      /* Prepare RTC for wake-up. */

      ret = up_rtc_setperiodicwakeup(secs, NULL);
      DEBUGASSERT(ret == OK);
    }
#else
  DEBUGASSERT(secs == 0);
#endif

  /* Prevent USART interrupt activity, make sure that last transmission has
   * completed. */

  stm32_serial_set_suspend(true);

#ifdef CONFIG_BOARD_DEEPSLEEP_RECONFIGURE_GPIOS

  /* Read control state of SDCard regulator (TODO: add proper pwrctl api) */

  sdcard_enabled = stm32_gpioread(GPIO_REGULATOR_SDCARD);
  if (sdcard_enabled)
    {
      /* Mark SDcard as disconnected for block driver. */

      mmcsd_slot_pm_suspend(CONFIG_BOARD_MMCSDSLOTNO);
    }

  /* Force SDcard off. */

  stm32_gpiowrite(GPIO_REGULATOR_SDCARD, false);

  /* SDcard is off, and does not react on GPIOs. Force GPIOs low to avoid leak
   * current.
   */

  gpio_off_mask = ~(GPIO_PUPD_MASK | GPIO_MODE_MASK | GPIO_OUTPUT_SET);
  stm32_configgpio((GPIO_SPI3_MOSI & gpio_off_mask) | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT);
  stm32_configgpio((GPIO_SPI3_MISO & gpio_off_mask) | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT);
  stm32_configgpio((GPIO_SPI3_SCK & gpio_off_mask) | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT);
  stm32_configgpio((GPIO_CHIP_SELECT_SDCARD & gpio_off_mask) | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT);

  /* Reconfigure GPIO's for stop mode (most pins are setup as analog input). */

  up_reconfigure_gpios_for_pmstop();

#endif

#if defined(CONFIG_USBDEV) && defined (CONFIG_STM32_USB)
  /* Reset USB peripheral */

  regval = getreg32(STM32_RCC_APB1RSTR);
  putreg32(regval | RCC_APB1RSTR_USBRST, STM32_RCC_APB1RSTR);
  putreg32(regval, STM32_RCC_APB1RSTR);
#endif

#if defined(CONFIG_STM32_PWR)
  /* Disable PVD during sleep because I_DD (PVD/BOR) consumes 2.6 uA,
     and because there is nothing better to do than die while sleeping
     if lose power in stop-mode. */

  stm32_pwr_disablepvd();
#endif

#ifndef CONFIG_BOARD_DEEPSLEEP_SKIP_PMSTOP
  /* Enter stop-mode with MCU internal regulator in low-power mode. */

  ret = stm32_pmstop(true);
#endif

#ifdef DEEPSLEEP_SLEEPTIME_DEBUG
  slept = true;
#endif

#if defined(CONFIG_STM32_PWR)
  /* Re-enable PVD and check if voltage has dropped too much
     while we slept. We might have enough power for MCU, but not
     for SD card or other peripherals. */

  stm32_pwr_enablepvd();
  board_pwr_checkpvd();
#endif

#ifdef CONFIG_RTC_PERIODIC_AUTORELOAD_WAKEUP
  if (secs > 0)
    {
      /* Prevent more wake-ups. */

      (void)up_rtc_cancelperiodicwakeup();
    }
#endif

#if defined(CONFIG_RTC) && defined(CONFIG_RTC_DATETIME)
  /* Get RTC clock after STOP. */

  stm32_rtc_getdatetime_with_subseconds(&t, &rtc_end_ts.tv_nsec);
  rtc_end_ts.tv_sec = mktime(&t);

  /* Advance time by RTC. */

  ts.tv_sec += rtc_end_ts.tv_sec - rtc_start_ts.tv_sec;
  ts.tv_nsec += rtc_end_ts.tv_nsec - rtc_start_ts.tv_nsec;
  if (ts.tv_nsec < 0)
    {
      ts.tv_nsec += 1000 * 1000 * 1000;
      ts.tv_sec--;
    }
  if (ts.tv_nsec >= 1000 * 1000 * 1000)
    {
      ts.tv_nsec -= 1000 * 1000 * 1000;
      ts.tv_sec++;
    }

  /* Set current time / date */

  ret = clock_settime(CLOCK_REALTIME, &ts);
  DEBUGASSERT(ret != ERROR);

#ifdef DEEPSLEEP_WAKETIME_DEBUG
  wake_ts = ts;
#endif

#if defined(CONFIG_CLOCK_MONOTONIC) && defined(CONFIG_CLOCK_MONOTONIC_OFFSET_TIME)

  /* Get amount of time adjusted by RTC. */

  ts.tv_sec = rtc_end_ts.tv_sec - rtc_start_ts.tv_sec;
  ts.tv_nsec = rtc_end_ts.tv_nsec - rtc_start_ts.tv_nsec;
  if (ts.tv_nsec < 0)
    {
      ts.tv_nsec += 1000 * 1000 * 1000;
      ts.tv_sec--;
    }
  if (ts.tv_nsec >= 1000 * 1000 * 1000)
    {
      ts.tv_nsec -= 1000 * 1000 * 1000;
      ts.tv_sec++;
    }

  /* Adjust CLOCK_MONOTONIC offset. */

  clock_increase_monotonic_offset(&ts);
#endif

#endif

  /* Stop mode disables HSE/HSI/PLL and wake happens with default system
   * clock (MSI, 2Mhz). So reconfigure clocks early on. RTC is however
   * handled before this for accurate time keeping.
   */

  stm32_clockconfig();

#ifdef CONFIG_BOARD_DEEPSLEEP_RECONFIGURE_GPIOS
  /* Restore pin configuration */

  up_restore_gpios_after_pmstop();
#endif

#if defined(CONFIG_USBDEV) && defined (CONFIG_STM32_USB)
  /* Initialize USB */
  /* TODO initialize USB properly, up_usbinitialize() call alone is not sufficient */

  up_usbinitialize();

#endif

  /* Resume serial ports after setting up system clock, as USART baud rate is
   * configured relative to system clock. */

  stm32_serial_set_suspend(false);

  /* Check that we have enough battery left, just in case
     PVD detection missed it. */

  board_pwr_checkvbat(false);

#ifdef CONFIG_BOARD_DEEPSLEEP_RECONFIGURE_GPIOS
  /* Special support for SD card. */

  /* Restore SDcard GPIOs */

  stm32_configgpio(GPIO_SPI3_MOSI);
  stm32_configgpio(GPIO_SPI3_MISO);
  stm32_configgpio(GPIO_SPI3_SCK);
  stm32_configgpio(GPIO_CHIP_SELECT_SDCARD);

  if (sdcard_enabled)
    {
      /* Re-enable power now that GPIOs are in correct state. */

      stm32_gpiowrite(GPIO_REGULATOR_SDCARD, true);

      /* Mark SDcard as reconnected for block driver, will reinitialize/reconfigure
       * SDcard. Apparently, block driver works fine without additional delay
       * for regulator. Might be because plug-in nature of SDcards require
       * block driver to keep retrying initialization until card stabilizes.
       */

      mmcsd_slot_pm_resume(CONFIG_BOARD_MMCSDSLOTNO);
    }

skip_deepsleep:
#endif

  /* Allow scheduler to switch tasks. */

  sched_unlock();

#ifdef DEEPSLEEP_SLEEPTIME_DEBUG
  if (slept)
    {
      /* Get amount of time adjusted by RTC. */

      ts.tv_sec = rtc_end_ts.tv_sec - rtc_start_ts.tv_sec;
      ts.tv_nsec = rtc_end_ts.tv_nsec - rtc_start_ts.tv_nsec;
      if (ts.tv_nsec < 0)
        {
          ts.tv_nsec += 1000 * 1000 * 1000;
          ts.tv_sec--;
        }
      if (ts.tv_nsec >= 1000 * 1000 * 1000)
        {
          ts.tv_nsec -= 1000 * 1000 * 1000;
          ts.tv_sec++;
        }

      lldbg("slept for %u.%03u\n", ts.tv_sec, ts.tv_nsec / (1000 * 1000));
    }
#endif
}
Esempio n. 4
0
void up_boot_standby_mode(void)
{
  uint32_t gpio_off_mask;
  uint32_t regval;
  int i;

  DEBUGASSERT((getreg32(STM32_PWR_CR) & PWR_CR_DBP) != 0);

  /*
   * This function is called from up_boot.c, stm32_boardinitialize(). OS is not
   * running yet. Regulators and chip-selects have been initialized. IWDG not
   * enabled. If board has HWWDG, we must enable it from this function before
   * going to standby mode.
   */

  regval = getreg32(CONFIG_STANDBYMODE_MAGIC_BKREG);
  if (regval != CONFIG_STANDBYMODE_MAGIC)
    {
      g_board_wakeup_from_standby = (regval == CONFIG_STANDBYMODE_MAGIC + 1);

      /* Standby mode was not requested, continue with regular boot. */

      putreg32(0, CONFIG_STANDBYMODE_MAGIC_BKREG);

      for (i = 0; i < 4; i++)
        up_lowputc('r');

      return;
    }

#if defined(CONFIG_STM32_DFU) || defined (CONFIG_BOARD_HALTIAN_HWWDG)
  up_irqinitialize();
#endif

  /* Go into standby mode. */

  putreg32(CONFIG_STANDBYMODE_MAGIC + 1, CONFIG_STANDBYMODE_MAGIC_BKREG);

  for (i = 0; i < 4; i++)
    up_lowputc('s');

  /* Setup bootloader to jump directly to firmware. */

  putreg32(BOARD_FIRMWARE_BASE_ADDR, CONFIG_BOOTLOADER_ADDR_BKREG);

  /* Now disable backup register access. If following interrupt handlers
   * access backup registers, they need to make sure to re-enable access. */

  stm32_pwr_enablebkp(false);

  while (true)
    {
      /* Configure SDcard pins. */

      gpio_initialize_sdcard_pins();

      /* Configure display GPIOs. */

      gpio_off_mask = ~(GPIO_PUPD_MASK | GPIO_MODE_MASK | GPIO_OUTPUT_SET);
      stm32_configgpio(GPIO_CHIP_SELECT_DISPLAY);
      stm32_configgpio(GPIO_LCD_SSD1309_CMDDATA);
      stm32_configgpio(GPIO_LCD_SSD1309_RESET);
      stm32_configgpio((GPIO_SPI2_MOSI & gpio_off_mask) | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT);
      stm32_configgpio((GPIO_SPI2_SCK & gpio_off_mask) | GPIO_OUTPUT_CLEAR | GPIO_OUTPUT);

      /* Reconfigure GPIO's for stop mode (most pins are setup as analog input). */

      up_reconfigure_gpios_for_pmstop();

      /* We must kick HWWDG even from standby mode, else it resets device. */

      board_wdginitialize_autokick(hwwdg_irq_in_standby);

      /* Setup 'power'-button as EXTI for wake-up. */

      stm32_configgpio(GPIO_BTN_POWERKEY);
      stm32_gpiosetevent(GPIO_BTN_POWERKEY, true, false, true,
                         button_pressed_down_handler);

      /* Our standby-mode is really ARM core's stop-mode.
         Enter stop-mode with MCU internal regulator in low-power mode. */

      (void)stm32_pmstop(true);

      standby_do_trace('p');
    }
}
Esempio n. 5
0
static void up_idlepm(void)
{
  static enum pm_state_e oldstate = PM_NORMAL;
  enum pm_state_e newstate;
  irqstate_t flags;
  int ret;
  
  /* Decide, which power saving level can be obtained */

  newstate = pm_checkstate();

  /* Check for state changes */

  if (newstate != oldstate)
    {
      flags = irqsave();

      /* Perform board-specific, state-dependent logic here */

      llvdbg("newstate= %d oldstate=%d\n", newstate, oldstate);

      /* Then force the global state change */

      ret = pm_changestate(newstate);
      if (ret < 0)
        {
          /* The new state change failed, revert to the preceding state */

          (void)pm_changestate(oldstate);
        }
      else
        {
          /* Save the new state */

          oldstate = newstate;
        }

      /* MCU-specific power management logic */

      switch (newstate)
        {
        case PM_NORMAL:
          break;

        case PM_IDLE:
          break;

        case PM_STANDBY:
          stm32_pmstop(true);
          break;

        case PM_SLEEP:
          (void)stm32_pmstandby();
          break;

        default:
          break;
        }

      irqrestore(flags);
    }
}