Как настроить режим ожидания на микроконтроллере STM32F4, работающем с ОСРВ и просыпающемся после него? - PullRequest
0 голосов
/ 03 октября 2019

Мне нравится переводить мой 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. Есть идеи, чего не хватает

1 Ответ

0 голосов
/ 21 октября 2019

Я нашел рабочее решение. Он состоит из 2 частей:

  1. добавить свободный поток, который вызывает "__WFI ()". В моем случае я использую основной поток Zephyr и устанавливаю его prio на самый низкий из системных потоков. Если ничего не делать для системы, этот поток активен, и он не делает ничего, кроме режима сна.
  2. устанавливает функцию, которая включает RTC, который запускает событие пробуждения через некоторое время (в моем случае 1сек). Переведите MCU в спящий режим с помощью. Нажмите на пробуждение по RTC. После проверки события пробуждения проверяется условие пробуждения. В моем случае я проверяю состояние булавки пробуждения и другой булавки. Если условие полностью заполнено, создается сброс.

После некоторых фрагментов кода для 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();
    }
}
...