1 /*
2 * Copyright (c) 2023 STMicroelectronics
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/hwinfo.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/device.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/sys/printk.h>
13 #include <zephyr/pm/pm.h>
14 #include <zephyr/sys/poweroff.h>
15 #include <stm32_ll_pwr.h>
16
17 #if !defined(CONFIG_SOC_SERIES_STM32L4X)
18 #error Not implemented for other series
19 #endif /* CONFIG_SOC_SERIES_STM32L4X */
20
21 #define STACKSIZE 1024
22 #define PRIORITY 7
23 #define SLEEP_TIME_MS 3000
24
25 #define SW0_NODE DT_ALIAS(sw0)
26 #if !DT_NODE_HAS_STATUS_OKAY(SW0_NODE)
27 #error "Unsupported board: sw0 devicetree alias is not defined"
28 #endif
29
30 /* Semaphore used to control button pressed value */
31 static struct k_sem button_sem;
32
33 static int led_is_on;
34
35 static const struct gpio_dt_spec button =
36 GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, {0});
37
38 static const struct gpio_dt_spec led =
39 GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
40
41 static struct gpio_callback button_cb_data;
42
config_wakeup_features(void)43 void config_wakeup_features(void)
44 {
45 /* Configure wake-up features */
46 /* WKUP2(PC13) only , - active low, pull-up */
47 /* Set pull-ups for standby modes */
48 LL_PWR_EnableGPIOPullUp(LL_PWR_GPIO_C, LL_PWR_GPIO_BIT_13);
49 LL_PWR_IsWakeUpPinPolarityLow(LL_PWR_WAKEUP_PIN2);
50 /* Enable pin pull up configurations and wakeup pins */
51 LL_PWR_EnablePUPDCfg();
52 LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2);
53 /* Clear wakeup flags */
54 LL_PWR_ClearFlag_WU();
55 }
56
button_pressed(const struct device * dev,struct gpio_callback * cb,uint32_t pins)57 void button_pressed(const struct device *dev, struct gpio_callback *cb,
58 uint32_t pins)
59 {
60 k_sem_give(&button_sem);
61 }
62
thread_poweroff_standby_mode(void)63 void thread_poweroff_standby_mode(void)
64 {
65 k_sem_init(&button_sem, 0, 1);
66 k_sem_take(&button_sem, K_FOREVER);
67 gpio_pin_configure(led.port, led.pin, GPIO_DISCONNECTED);
68 printk("User button pressed\n");
69 config_wakeup_features();
70 if (led_is_on == false) {
71 printk("Powering off\n");
72 printk("Release the user button to wake-up\n\n");
73 #ifdef CONFIG_LOG
74 k_msleep(2000);
75 #endif /* CONFIG_LOG */
76 sys_poweroff();
77 /* powered off until wakeup line activated */
78 } else {
79 printk("Standby Mode requested\n");
80 printk("Release the user button to exit from Standby Mode\n\n");
81 #ifdef CONFIG_LOG
82 k_msleep(2000);
83 #endif /* CONFIG_LOG */
84 pm_state_force(0u, &(struct pm_state_info) {PM_STATE_STANDBY, 0, 0});
85 /* stay in Standby mode until wakeup line activated */
86 }
87 }
88
89 K_THREAD_DEFINE(thread_poweroff_standby_mode_id, STACKSIZE, thread_poweroff_standby_mode,
90 NULL, NULL, NULL, PRIORITY, 0, 0);
91
main(void)92 int main(void)
93 {
94 int ret;
95 uint32_t cause;
96
97 hwinfo_get_reset_cause(&cause);
98 hwinfo_clear_reset_cause();
99
100 if (cause == RESET_LOW_POWER_WAKE) {
101 hwinfo_clear_reset_cause();
102 printk("\nReset cause: Standby mode\n\n");
103 }
104
105 if (cause == (RESET_PIN | RESET_BROWNOUT)) {
106 printk("\nReset cause: Shutdown mode or power up\n\n");
107 }
108
109 if (cause == RESET_PIN) {
110 printk("\nReset cause: Reset pin\n\n");
111 }
112
113
114 __ASSERT_NO_MSG(gpio_is_ready_dt(&led));
115 if (!gpio_is_ready_dt(&button)) {
116 printk("Error: button device %s is not ready\n",
117 button.port->name);
118 return 0;
119 }
120
121 ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
122 if (ret != 0) {
123 printk("Error %d: failed to configure %s pin %d\n",
124 ret, button.port->name, button.pin);
125 return 0;
126 }
127
128 ret = gpio_pin_interrupt_configure_dt(&button,
129 GPIO_INT_EDGE_TO_ACTIVE);
130 if (ret != 0) {
131 printk("Error %d: failed to configure interrupt on %s pin %d\n",
132 ret, button.port->name, button.pin);
133 return 0;
134 }
135
136 gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
137 gpio_add_callback(button.port, &button_cb_data);
138
139 printk("Device ready: %s\n\n\n", CONFIG_BOARD);
140
141 printk("Press and hold the user button:\n");
142 printk(" when LED2 is OFF to power off\n");
143 printk(" when LED2 is ON to enter to Standby Mode\n\n");
144
145 led_is_on = true;
146 while (true) {
147 gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
148 gpio_pin_set(led.port, led.pin, (int)led_is_on);
149 k_msleep(SLEEP_TIME_MS);
150 led_is_on = !led_is_on;
151 }
152
153 return 0;
154 }
155