【问题标题】:How to setup the standby mode on a STM32F4 MCU running an RTOS and waking it up after?如何在运行 RTOS 的 STM32F4 MCU 上设置待机模式并在之后将其唤醒?
【发布时间】:2019-10-03 15:58:47
【问题描述】:

我喜欢让我的 STM32F412 进入深度睡眠模式,然后按下按钮将其唤醒。此代码应与 RTOS(Zephyr) 一起运行。所以在执行代码时,为了让设备进入深度睡眠,其他任务等都处于活动状态。

所以我正在寻找一种防弹方法,以确保 STM32F412 进入待机状态并在之后唤醒。

到目前为止我的(不工作的代码):

#define POWER_WAKEUP_PIN LL_PWR_WAKEUP_PIN2

// set PC0 as input gpio
LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_0, LL_GPIO_PULL_NO);
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_0, LL_GPIO_MODE_INPUT);

// activate EXTI line 0
LL_EXTI_InitTypeDef EXTI_InitStruct = {0};

LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_ALL_0_31);

EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_0;
EXTI_InitStruct.LineCommand = ENABLE;
EXTI_InitStruct.Mode = LL_EXTI_MODE_EVENT;
EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING;
LL_EXTI_Init(&EXTI_InitStruct);

// put to standby
LL_PWR_DisableWakeUpPin(POWER_WAKEUP_PIN);
LL_PWR_ClearFlag_WU();
LL_PWR_EnableWakeUpPin(POWER_WAKEUP_PIN);

LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
LL_LPM_EnableDeepSleep();
__WFI();

它使用 stm32 LL HAL。任何想法缺少什么

【问题讨论】:

  • 你的问题是?什么不工作?设备不退出待机?不进入深度睡眠?
  • 谢谢@GuillaumePetitjean。目前我不确定是否应该使用事件等待(WFE)或等待中断(WFI)。我也不确定我的 PIN 设置是否正确。也许您可以提供一些反馈
  • 使用 WFE,您将被中断或事件唤醒。事件主要用于多核系统,但不仅限于此。还有更多(棘手的)差异,STM32参考手册对此主题相当清楚。如果您想通过 GPIO 中断唤醒,我想您可以使用 WFI,而不必担心 WFE 的细微差别。
  • 我不知道这个特殊的STM32,所以我不会评论PIN设置。请记住,某些外围设备将在停止模式下停止,因此显然无法唤醒您。管理待机也可能非常棘手。例如,您应该在执行 WFI 之前添加一条 DSB 指令。看看HAL_PWR_EnterSTOPMode
  • 你还是没有说什么不行。

标签: stm32 standby


【解决方案1】:

我找到了一个可行的解决方案。它由两部分组成:

  1. 添加一个调用“__WFI()”的空闲线程。在我的例子中,我使用 Zephyr 的主线程并将其 prio 设置为系统线程的最低值。如果对系统无事可做,则此线程处于活动状态,并且除了休眠之外什么都不做。
  2. 设置启用 RTC 的功能,该功能会在一段时间后触发唤醒事件(在我的情况下为 1 秒)。使用 将 MCU 置于睡眠模式。通过 RTC Clk 唤醒电路。在唤醒事件检查之后,检查唤醒条件。就我而言,我检查唤醒引脚和另一个引脚的状态。如果条件已满,则会生成重置。

以下是 ZephyrRTOS 的一些代码截图:

void rtc_setupDeepsleepWakeUp(bool on) {
    if (true == on) {
        /*
        Programming the wakeup timer
        The following sequence is required to configure or change the wakeup timer auto-reload
        value (WUT[15:0] in RTC_WUTR):
        1. Clear WUTE in RTC_CR to disable the wakeup timer.
        2. Poll WUTWF until it is set in RTC_ISR to make sure the access to wakeup auto-reload
        counter and to WUCKSEL[2:0] bits is allowed. It takes 1 to 2 RTCCLK clock cycles
        (due to clock synchronization).
        3. Program the wakeup auto-reload value WUT[15:0] and the wakeup clock selection
        (WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR to enable the timer again.
        The wakeup timer restarts down-counting. Due to clock synchronization, the WUTWF
        bit is cleared up to 2 RTCCLK clocks cycles after WUTE is cleared.

        note on step 3:
        32768Hz -> 32768 decrements per second
        now calc the value for the timer
        32768/ 16 = 0x800
        0x800 -> counter -> 1sec
        */
        LL_RCC_EnableRTC();
        HAL_RTCEx_SetWakeUpTimer_IT(&rtc.hrtc, 0x800, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
        irq_enable(RTC_WKUP_IRQn);
    } else {
        HAL_RTCEx_DeactivateWakeUpTimer(&rtc.hrtc);
        irq_disable(RTC_WKUP_IRQn);
    }
}

void power_sleep(void) {
    __WFI();
}

#define THREAD_PRIO_idle 12

void power_deepSleep(void) {
    unsigned int key;

    LOG_INF("preparing device to deep sleep");

    power_disableAllPeriphals();
    power_clearAllInterrupts();
    gpio_enableWakeupButton();

    rtc_setupDeepsleepWakeUp(true);
    for (;;) {
        HAL_SuspendTick();
        HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
        HAL_ResumeTick();
        // break condition of low power mode
        // button pressed or usb insert
        if (
            (0 == gpio_get_powerButton_state()) ||
            (1 == gpio_get_vbus_state())
            ) {
            rtc_setupDeepsleepWakeUp(false);
            sys_reboot(SYS_REBOOT_COLD);
        }
    }
    rtc_setupDeepsleepWakeUp(false);

    sys_reboot(SYS_REBOOT_COLD);

    LOG_ERR("ahhhh something went wrong");
}


void main(void)
{
    power_recoverFromDeepSleep();
    LOG_INF("start");
...
    LOG_INF("start completed");

    LOG_DBG("set main prio to lowest(idle)");
    k_thread_priority_set(k_current_get(), THREAD_PRIO_idle);

    while(1) {
        power_sleep();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-06
    • 2021-11-04
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-28
    相关资源
    最近更新 更多