blob: 6610f01f955f7b52d98435ecccba8e38adbd1c4d [file] [log] [blame]
/*
* 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;
}