| /* |
| * Copyright (c) 2023 STMicroelectronics |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/drivers/hwinfo.h> |
| #include <zephyr/kernel.h> |
| #include <zephyr/device.h> |
| #include <zephyr/devicetree.h> |
| #include <zephyr/drivers/gpio.h> |
| #include <zephyr/sys/printk.h> |
| #include <zephyr/pm/pm.h> |
| #include <zephyr/sys/poweroff.h> |
| #include <stm32_ll_pwr.h> |
| |
| #if !defined(CONFIG_SOC_SERIES_STM32L4X) |
| #error Not implemented for other series |
| #endif /* CONFIG_SOC_SERIES_STM32L4X */ |
| |
| #define STACKSIZE 1024 |
| #define PRIORITY 7 |
| #define SLEEP_TIME_MS 3000 |
| |
| #define SW0_NODE DT_ALIAS(sw0) |
| #if !DT_NODE_HAS_STATUS(SW0_NODE, okay) |
| #error "Unsupported board: sw0 devicetree alias is not defined" |
| #endif |
| |
| /* Semaphore used to control button pressed value */ |
| static struct k_sem button_sem; |
| |
| static int led_is_on; |
| |
| static const struct gpio_dt_spec button = |
| GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0}); |
| |
| static const struct gpio_dt_spec led = |
| GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); |
| |
| static struct gpio_callback button_cb_data; |
| |
| void config_wakeup_features(void) |
| { |
| /* Configure wake-up features */ |
| /* WKUP2(PC13) only , - active low, pull-up */ |
| /* Set pull-ups for standby modes */ |
| LL_PWR_EnableGPIOPullUp(LL_PWR_GPIO_C, LL_PWR_GPIO_BIT_13); |
| LL_PWR_IsWakeUpPinPolarityLow(LL_PWR_WAKEUP_PIN2); |
| /* Enable pin pull up configurations and wakeup pins */ |
| LL_PWR_EnablePUPDCfg(); |
| LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2); |
| /* Clear wakeup flags */ |
| LL_PWR_ClearFlag_WU(); |
| } |
| |
| void button_pressed(const struct device *dev, struct gpio_callback *cb, |
| uint32_t pins) |
| { |
| k_sem_give(&button_sem); |
| } |
| |
| void thread_poweroff_standby_mode(void) |
| { |
| k_sem_init(&button_sem, 0, 1); |
| k_sem_take(&button_sem, K_FOREVER); |
| gpio_pin_configure(led.port, led.pin, GPIO_DISCONNECTED); |
| printk("User button pressed\n"); |
| config_wakeup_features(); |
| if (led_is_on == false) { |
| printk("Powering off\n"); |
| printk("Release the user button to wake-up\n\n"); |
| #ifdef CONFIG_LOG |
| k_msleep(2000); |
| #endif /* CONFIG_LOG */ |
| sys_poweroff(); |
| /* powered off until wakeup line activated */ |
| } else { |
| printk("Standby Mode requested\n"); |
| printk("Release the user button to exit from Standby Mode\n\n"); |
| #ifdef CONFIG_LOG |
| k_msleep(2000); |
| #endif /* CONFIG_LOG */ |
| pm_state_force(0u, &(struct pm_state_info) {PM_STATE_STANDBY, 0, 0}); |
| /* stay in Standby mode until wakeup line activated */ |
| } |
| } |
| |
| K_THREAD_DEFINE(thread_poweroff_standby_mode_id, STACKSIZE, thread_poweroff_standby_mode, |
| NULL, NULL, NULL, PRIORITY, 0, 0); |
| |
| int main(void) |
| { |
| int ret; |
| uint32_t cause; |
| |
| hwinfo_get_reset_cause(&cause); |
| hwinfo_clear_reset_cause(); |
| |
| if (cause == RESET_LOW_POWER_WAKE) { |
| hwinfo_clear_reset_cause(); |
| printk("\nReset cause: Standby mode\n\n"); |
| } |
| |
| if (cause == (RESET_PIN | RESET_BROWNOUT)) { |
| printk("\nReset cause: Shutdown mode or power up\n\n"); |
| } |
| |
| if (cause == RESET_PIN) { |
| printk("\nReset cause: Reset pin\n\n"); |
| } |
| |
| |
| __ASSERT_NO_MSG(gpio_is_ready_dt(&led)); |
| if (!gpio_is_ready_dt(&button)) { |
| printk("Error: button device %s is not ready\n", |
| button.port->name); |
| return 0; |
| } |
| |
| ret = gpio_pin_configure_dt(&button, GPIO_INPUT); |
| if (ret != 0) { |
| printk("Error %d: failed to configure %s pin %d\n", |
| ret, button.port->name, button.pin); |
| return 0; |
| } |
| |
| ret = gpio_pin_interrupt_configure_dt(&button, |
| GPIO_INT_EDGE_TO_ACTIVE); |
| if (ret != 0) { |
| printk("Error %d: failed to configure interrupt on %s pin %d\n", |
| ret, button.port->name, button.pin); |
| return 0; |
| } |
| |
| gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); |
| gpio_add_callback(button.port, &button_cb_data); |
| |
| printk("Device ready: %s\n\n\n", CONFIG_BOARD); |
| |
| printk("Press and hold the user button:\n"); |
| printk(" when LED2 is OFF to power off\n"); |
| printk(" when LED2 is ON to enter to Standby Mode\n\n"); |
| |
| led_is_on = true; |
| while (true) { |
| gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); |
| gpio_pin_set(led.port, led.pin, (int)led_is_on); |
| k_msleep(SLEEP_TIME_MS); |
| led_is_on = !led_is_on; |
| } |
| |
| return 0; |
| } |