diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 45e2104f80..d11b128bbd 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -58,7 +58,7 @@ typedef enum { UART_PARITY_ERR, /*!< UART RX parity event*/ UART_DATA_BREAK, /*!< UART TX data and break event*/ UART_PATTERN_DET, /*!< UART pattern detected */ -#if SOC_UART_SUPPORT_WAKEUP +#if SOC_UART_SUPPORT_WAKEUP_INT UART_WAKEUP, /*!< UART wakeup event */ #endif UART_EVENT_MAX, /*!< UART event max index*/ diff --git a/components/driver/uart.c b/components/driver/uart.c index 22bc7fa81e..bc14748b96 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,7 +47,7 @@ static const char *UART_TAG = "uart"; #define UART_PATTERN_DET_QLEN_DEFAULT (10) #define UART_MIN_WAKEUP_THRESH (UART_LL_MIN_WAKEUP_THRESH) -#if SOC_UART_SUPPORT_WAKEUP +#if SOC_UART_SUPPORT_WAKEUP_INT #define UART_INTR_CONFIG_FLAG ((UART_INTR_RXFIFO_FULL) \ | (UART_INTR_RXFIFO_TOUT) \ | (UART_INTR_RXFIFO_OVF) \ @@ -1091,7 +1091,7 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); } } - #if SOC_UART_SUPPORT_WAKEUP + #if SOC_UART_SUPPORT_WAKEUP_INT else if (uart_intr_status & UART_INTR_WAKEUP) { uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_WAKEUP); uart_event.type = UART_WAKEUP; diff --git a/components/hal/esp32c2/include/hal/uart_ll.h b/components/hal/esp32c2/include/hal/uart_ll.h index 1123afbbfb..7bd37d81fd 100644 --- a/components/hal/esp32c2/include/hal/uart_ll.h +++ b/components/hal/esp32c2/include/hal/uart_ll.h @@ -48,6 +48,7 @@ typedef enum { UART_INTR_RS485_FRM_ERR = (0x1 << 16), UART_INTR_RS485_CLASH = (0x1 << 17), UART_INTR_CMD_CHAR_DET = (0x1 << 18), + UART_INTR_WAKEUP = (0x1 << 19), } uart_intr_t; static inline void uart_ll_reset_core(uart_dev_t *hw) { diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h index e4ba839b1a..aeecd0aabc 100644 --- a/components/hal/esp32h2/include/hal/uart_ll.h +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -51,6 +51,7 @@ typedef enum { UART_INTR_RS485_FRM_ERR = (0x1 << 16), UART_INTR_RS485_CLASH = (0x1 << 17), UART_INTR_CMD_CHAR_DET = (0x1 << 18), + UART_INTR_WAKEUP = (0x1 << 19), } uart_intr_t; static inline void uart_ll_set_reset_core(uart_dev_t *hw, bool core_rst_en) { diff --git a/components/hal/esp32s2/include/hal/uart_ll.h b/components/hal/esp32s2/include/hal/uart_ll.h index 9309d3b8f2..b5e27a37bd 100644 --- a/components/hal/esp32s2/include/hal/uart_ll.h +++ b/components/hal/esp32s2/include/hal/uart_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for UART register operations. // Note that most of the register operations in this layer are non-atomic operations. @@ -57,6 +49,7 @@ typedef enum { UART_INTR_RS485_FRM_ERR = (0x1<<16), UART_INTR_RS485_CLASH = (0x1<<17), UART_INTR_CMD_CHAR_DET = (0x1<<18), + UART_INTR_WAKEUP = (0x1 << 19), } uart_intr_t; /** diff --git a/components/hal/esp32s3/include/hal/uart_ll.h b/components/hal/esp32s3/include/hal/uart_ll.h index f437c502e0..e9da9c3ae2 100644 --- a/components/hal/esp32s3/include/hal/uart_ll.h +++ b/components/hal/esp32s3/include/hal/uart_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ // The LL layer for UART register operations. // Note that most of the register operations in this layer are non-atomic operations. @@ -60,6 +52,7 @@ typedef enum { UART_INTR_RS485_FRM_ERR = (0x1 << 16), UART_INTR_RS485_CLASH = (0x1 << 17), UART_INTR_CMD_CHAR_DET = (0x1 << 18), + UART_INTR_WAKEUP = (0x1 << 19), } uart_intr_t; diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index 8969ec7393..b57c639b89 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -455,6 +455,10 @@ config SOC_UART_BITRATE_MAX int default 5000000 +config SOC_UART_SUPPORT_WAKEUP_INT + bool + default y + config SOC_UART_SUPPORT_RTC_CLK bool default y diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 37e94fe626..29a2eb10d6 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -247,7 +247,7 @@ #define SOC_UART_NUM (2) #define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ #define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ - +#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_SUPPORT_RTC_CLK (1) #define SOC_UART_SUPPORT_XTAL_CLK (1) diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index d61e5c5779..7bbdbd82f6 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -583,7 +583,7 @@ config SOC_UART_SUPPORT_XTAL_CLK bool default y -config SOC_UART_SUPPORT_WAKEUP +config SOC_UART_SUPPORT_WAKEUP_INT bool default y diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 30a5369c10..f0d548e845 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -288,7 +288,7 @@ #define SOC_UART_SUPPORT_RTC_CLK (1) #define SOC_UART_SUPPORT_XTAL_CLK (1) -#define SOC_UART_SUPPORT_WAKEUP (1) +#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_REQUIRE_CORE_RESET (1) // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index e7454d936e..4cf06863a8 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -555,6 +555,10 @@ config SOC_UART_BITRATE_MAX int default 5000000 +config SOC_UART_SUPPORT_WAKEUP_INT + bool + default y + config SOC_UART_SUPPORT_RTC_CLK bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index c4d4de7b4c..1346119cf0 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -279,7 +279,7 @@ #define SOC_UART_NUM (2) #define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ #define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ - +#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_SUPPORT_RTC_CLK (1) #define SOC_UART_SUPPORT_XTAL_CLK (1) diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index e14c8500cb..5d78edd73a 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -575,6 +575,10 @@ config SOC_UART_NUM int default 2 +config SOC_UART_SUPPORT_WAKEUP_INT + bool + default y + config SOC_UART_SUPPORT_REF_TICK bool default y diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 9374d84e37..16c75869a5 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -275,6 +275,7 @@ /*-------------------------- UART CAPS ---------------------------------------*/ // ESP32-S2 has 2 UART. #define SOC_UART_NUM (2) +#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_SUPPORT_REF_TICK (1) /*!< Support REF_TICK as the clock source */ #define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ #define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 2eb054b0fc..c8c4f64a0f 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -659,6 +659,26 @@ config SOC_TOUCH_PAD_MEASURE_WAIT_MAX hex default 0xFF +config SOC_UART_NUM + int + default 3 + +config SOC_UART_FIFO_LEN + int + default 128 + +config SOC_UART_BITRATE_MAX + int + default 5000000 + +config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND + bool + default y + +config SOC_UART_SUPPORT_WAKEUP_INT + bool + default y + config SOC_UART_SUPPORT_RTC_CLK bool default y @@ -838,19 +858,3 @@ config SOC_TWAI_BRP_MAX config SOC_TWAI_SUPPORTS_RX_STATUS bool default y - -config SOC_UART_FIFO_LEN - int - default 128 - -config SOC_UART_BITRATE_MAX - int - default 5000000 - -config SOC_UART_NUM - int - default 3 - -config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND - bool - default y diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index b3be1edabf..78dbc86f64 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -252,8 +252,13 @@ #include "twai_caps.h" /*-------------------------- UART CAPS ---------------------------------------*/ -#include "uart_caps.h" - +// ESP32-S3 has 3 UARTs +#define SOC_UART_NUM (3) +#define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ +#define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ +// UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled +#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) +#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_SUPPORT_RTC_CLK (1) /*!< Support RTC clock as the clock source */ #define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */ diff --git a/components/soc/esp32s3/include/soc/uart_caps.h b/components/soc/esp32s3/include/soc/uart_caps.h deleted file mode 100644 index 30d219baac..0000000000 --- a/components/soc/esp32s3/include/soc/uart_caps.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ -#define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ - -#define SOC_UART_NUM (3) - -// UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled -#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) - -#ifdef __cplusplus -} -#endif diff --git a/examples/system/light_sleep/README.md b/examples/system/light_sleep/README.md index 4ae642df2e..63d99b084b 100644 --- a/examples/system/light_sleep/README.md +++ b/examples/system/light_sleep/README.md @@ -1,5 +1,3 @@ -| Supported Targets | ESP32-C3 | -| ----------------- | -------- | # Light Sleep Example (See the README.md file in the upper level 'examples' directory for more information about examples.) @@ -10,6 +8,7 @@ The example enables the following wakeup sources: - Timer: wake up the chip in 2 seconds - EXT0: wake up the chip if a button attached to GPIO0 is pressed (i.e. if GPIO0 goes low) +- UART0: wake up the chip when the uart rx pin (default GPIO6) receive more than 3 edges. The example also prints time spent in light sleep mode to illustrate that timekeeping continues while the chip is in light sleep. @@ -41,19 +40,47 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui ## Example Output +### Wake-up by Timer + +If do nothing to the example, the chip will wake-up every 2000 ms by timer, and fall into light sleep again after print some logs. We can see the wake-up reason is `timer` in this case. + +### Wake-up by GPIO + +For this example, the wake-up GPIO is bound to the 'BOOT' button on the board, we can wake-up the chip from light sleep by pressing the 'BOOT' button, the chip will wake-up immediately after we pressed the button. We can see the wake-up reason is `pin` in this case and the chip will fall into light sleep again if we release the button. + +### Wake-up by UART + +For this example, the wake-up UART is bound to the default console port (UART_NUM_0), we can wake-up the chip from light sleep by inputting some keys on the key board. We can see the wake-up reason is `uart` in this case. + +Note #1: the UART wake-up threshould is set to 3 in this example, which means the ascii code of the input character should has at least 3 edges, for example, the ascii code of character `0` is `0011 0000` in binary, which only contains 2 edges, so the character `0` is not enough to wakeup the chip. + +Note #2: only UART0 and UART1 (if has) are supported to be configured as wake up source. And for ESP32, we have to use iomux pin for RX signal (i.e. GPIO3 for UART0 & GPIO9 for UART1), otherwise it won't success. + +Note #3: due to limitation of the HW, the bytes that received during light sleep is only used for waking up, and it will not be received by UART peripheral or passed to the driver. + ``` Entering light sleep -Returned from light sleep, reason: timer, t=2014 ms, slept for 2000 ms +Returned from light sleep, reason: timer, t=2713 ms, slept for 1999 ms Entering light sleep -Returned from light sleep, reason: timer, t=4023 ms, slept for 2000 ms +Returned from light sleep, reason: timer, t=4722 ms, slept for 2000 ms Entering light sleep -Returned from light sleep, reason: pin, t=5297 ms, slept for 1266 ms -Waiting for GPIO0 to go high... +Returned from light sleep, reason: uart, t=5148 ms, slept for 418 ms Entering light sleep -Returned from light sleep, reason: timer, t=10072 ms, slept for 2000 ms +Returned from light sleep, reason: uart, t=6178 ms, slept for 1022 ms Entering light sleep -Returned from light sleep, reason: timer, t=12080 ms, slept for 2000 ms +Returned from light sleep, reason: timer, t=8187 ms, slept for 2000 ms Entering light sleep +Returned from light sleep, reason: timer, t=10195 ms, slept for 2000 ms +Entering light sleep +Returned from light sleep, reason: timer, t=12203 ms, slept for 2000 ms +Entering light sleep +Returned from light sleep, reason: pin, t=12555 ms, slept for 342 ms +Waiting for GPIO9 to go high... +Entering light sleep +Returned from light sleep, reason: pin, t=12564 ms, slept for 1 ms +Waiting for GPIO9 to go high... +Entering light sleep +... ``` In the scenario above, the button attached to GPIO0 was pressed and held for about 3 seconds, after the 2nd wakeup from light sleep. The program has indicated the wakeup reason after each sleep iteration. diff --git a/examples/system/light_sleep/example_test.py b/examples/system/light_sleep/example_test.py index 5a6d3e1e0c..4a1306d8e9 100644 --- a/examples/system/light_sleep/example_test.py +++ b/examples/system/light_sleep/example_test.py @@ -12,7 +12,7 @@ WAITING_FOR_GPIO_STR = re.compile(r'Waiting for GPIO\d to go high...') WAKEUP_INTERVAL_MS = 2000 -@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32c3']) +@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3', 'esp32s3']) def test_examples_system_light_sleep(env, extra_data): dut = env.get_dut('light_sleep_example', 'examples/system/light_sleep') dut.start_app() @@ -32,7 +32,7 @@ def test_examples_system_light_sleep(env, extra_data): groups = dut.expect(EXIT_SLEEP_REGEX) print('Got second sleep period, wakeup from {}, slept for {}'.format(groups[0], groups[2])) # sleep time error should be less than 1ms - assert(groups[0] == 'timer' and int(groups[2]) == WAKEUP_INTERVAL_MS) + assert(groups[0] == 'timer' and int(groups[2]) >= WAKEUP_INTERVAL_MS - 1 and int(groups[2]) <= WAKEUP_INTERVAL_MS + 1) # this time we'll test gpio wakeup dut.expect(ENTERING_SLEEP_STR) @@ -49,8 +49,17 @@ def test_examples_system_light_sleep(env, extra_data): dut.port_inst.setDTR(False) dut.expect(ENTERING_SLEEP_STR) print('Went to sleep again') + + # Write 'U' to uart, 'U' in ascii is 0x55 which contains 8 edges in total + dut.write('U') + time.sleep(1) groups = dut.expect(EXIT_SLEEP_REGEX) - assert(groups[0] == 'timer' and int(groups[2]) == WAKEUP_INTERVAL_MS) + print('Got third sleep period, wakeup from {}, slept for {}'.format(groups[0], groups[2])) + assert(groups[0] == 'uart' and int(groups[2]) < WAKEUP_INTERVAL_MS) + print('Went to sleep again') + + groups = dut.expect(EXIT_SLEEP_REGEX) + assert(groups[0] == 'timer' and int(groups[2]) >= WAKEUP_INTERVAL_MS - 1 and int(groups[2]) <= WAKEUP_INTERVAL_MS + 1) print('Woke up from timer again') diff --git a/examples/system/light_sleep/main/CMakeLists.txt b/examples/system/light_sleep/main/CMakeLists.txt index b22f1089dc..d5b05c298c 100644 --- a/examples/system/light_sleep/main/CMakeLists.txt +++ b/examples/system/light_sleep/main/CMakeLists.txt @@ -1,2 +1,7 @@ -idf_component_register(SRCS "light_sleep_example_main.c" - INCLUDE_DIRS ".") +set(srcs "light_sleep_example_main.c" + "gpio_wakeup.c" + "timer_wakeup.c" + "uart_wakeup.c") + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ".") diff --git a/examples/system/light_sleep/main/gpio_wakeup.c b/examples/system/light_sleep/main/gpio_wakeup.c new file mode 100644 index 0000000000..b7a945ef05 --- /dev/null +++ b/examples/system/light_sleep/main/gpio_wakeup.c @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_check.h" +#include "esp_sleep.h" +#include "driver/gpio.h" + +/* Most development boards have "boot" button attached to GPIO0. + * You can also change this to another pin. + */ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H2 +#define BOOT_BUTTON_NUM 9 +#else +#define BOOT_BUTTON_NUM 0 +#endif + +/* Use boot button as gpio input */ +#define GPIO_WAKEUP_NUM BOOT_BUTTON_NUM +/* "Boot" button is active low */ +#define GPIO_WAKEUP_LEVEL 0 + +static const char *TAG = "gpio_wakeup"; + +void example_wait_gpio_inactive(void) +{ + printf("Waiting for GPIO%d to go high...\n", GPIO_WAKEUP_NUM); + while (gpio_get_level(GPIO_WAKEUP_NUM) == GPIO_WAKEUP_LEVEL) { + vTaskDelay(pdMS_TO_TICKS(10)); + } +} + +esp_err_t example_register_gpio_wakeup(void) +{ + /* Initialize GPIO */ + gpio_config_t config = { + .pin_bit_mask = BIT64(GPIO_WAKEUP_NUM), + .mode = GPIO_MODE_INPUT, + .pull_down_en = false, + .pull_up_en = false, + .intr_type = GPIO_INTR_DISABLE + }; + ESP_RETURN_ON_ERROR(gpio_config(&config), TAG, "Initialize GPIO%d failed", GPIO_WAKEUP_NUM); + + /* Enable wake up from GPIO */ + ESP_RETURN_ON_ERROR(gpio_wakeup_enable(GPIO_WAKEUP_NUM, GPIO_WAKEUP_LEVEL == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL), + TAG, "Enable gpio wakeup failed"); + ESP_RETURN_ON_ERROR(esp_sleep_enable_gpio_wakeup(), TAG, "Configure gpio as wakeup source failed"); + + /* Make sure the GPIO is inactive and it won't trigger wakeup immediately */ + example_wait_gpio_inactive(); + ESP_LOGI(TAG, "gpio wakeup source is ready"); + + return ESP_OK; +} diff --git a/examples/system/light_sleep/main/light_sleep_example.h b/examples/system/light_sleep/main/light_sleep_example.h new file mode 100644 index 0000000000..b3faf43f57 --- /dev/null +++ b/examples/system/light_sleep/main/light_sleep_example.h @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void example_wait_gpio_inactive(void); + +esp_err_t example_register_gpio_wakeup(void); + +esp_err_t example_register_timer_wakeup(void); + +esp_err_t example_register_uart_wakeup(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/system/light_sleep/main/light_sleep_example_main.c b/examples/system/light_sleep/main/light_sleep_example_main.c index 7643f4a88e..f42f17e06a 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ -/* Light sleep example */ - #include #include #include @@ -13,112 +11,53 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/uart.h" #include "esp_sleep.h" #include "esp_log.h" -#include "driver/uart.h" -#include "driver/gpio.h" -#include "esp_timer.h" -#include "soc/uart_struct.h" -#include "soc/rtc.h" -#include "esp_pm.h" -#include "esp32c3/pm.h" +#include "light_sleep_example.h" -#define TAG "UART" -#define TEST_UART_NUM 1 -#define TEST_BUF_SIZE 1024 - -static QueueHandle_t uart0_queue; - -void light_sleep_wakeup_config(void) +static void light_sleep_task(void *args) { - ESP_ERROR_CHECK(gpio_sleep_set_direction(6, GPIO_MODE_INPUT)); - ESP_ERROR_CHECK(gpio_sleep_set_pull_mode(6, GPIO_PULLUP_ONLY)); + while (true) { + printf("Entering light sleep\n"); + /* To make sure the complete line is printed before entering sleep mode, + * need to wait until UART TX FIFO is empty: + */ + uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); - if (uart_set_wakeup_threshold(TEST_UART_NUM, 3) != ESP_OK) { - ESP_LOGE(TAG, "set uart1 wakeup threshold failed"); - } - if (esp_sleep_enable_uart_wakeup(TEST_UART_NUM) != ESP_OK) { - ESP_LOGE(TAG, "set uart1 wakeup failed"); - } - ESP_LOGI(TAG, "set_light_sleep_wakeup ok"); -} + /* Get timestamp before entering sleep */ + int64_t t_before_us = esp_timer_get_time(); -void light_sleep_setup(void) -{ - light_sleep_wakeup_config(); + /* Enter sleep mode */ + esp_light_sleep_start(); - esp_pm_config_esp32c3_t pm_config = { - .max_freq_mhz = CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ, - .min_freq_mhz = (int) rtc_clk_xtal_freq_get(), - .light_sleep_enable = true - }; - ESP_ERROR_CHECK(esp_pm_configure(&pm_config)); -} + /* Get timestamp after waking up from sleep */ + int64_t t_after_us = esp_timer_get_time(); -#define RD_BUF_SIZE 1024 - -static void uart_wakeup_task(void *arg) -{ - uart_event_t event; - // esp_light_sleep_start(); - - esp_pm_lock_handle_t lock = ((struct { esp_pm_lock_handle_t lock; } *)arg)->lock; - light_sleep_setup(); - - uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE); - - for(;;) { - //Waiting for UART event. - if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) { - - esp_pm_lock_acquire(lock); - - ESP_LOGI(TAG, "uar%d recved event:%d (wk:%d)", TEST_UART_NUM, event.type, UART_WAKEUP); - switch(event.type) { - case UART_DATA: - ESP_LOGI(TAG, "[UART DATA]: %d", event.size); - uart_read_bytes(TEST_UART_NUM, dtmp, event.size, portMAX_DELAY); - ESP_LOGI(TAG, "[DATA EVT]:"); - uart_write_bytes(TEST_UART_NUM, (const char *)dtmp, event.size); - break; - //Event of HW FIFO overflow detected - case UART_FIFO_OVF: - ESP_LOGI(TAG, "hw fifo overflow"); - // If fifo overflow happened, you should consider adding flow control for your application. - // The ISR has already reset the rx FIFO, - // As an example, we directly flush the rx buffer here in order to read more data. - uart_flush_input(TEST_UART_NUM); - xQueueReset(uart0_queue); - break; - //Event of UART ring buffer full - case UART_BUFFER_FULL: - ESP_LOGI(TAG, "ring buffer full"); - // If buffer full happened, you should consider encreasing your buffer size - // As an example, we directly flush the rx buffer here in order to read more data. - uart_flush_input(TEST_UART_NUM); - xQueueReset(uart0_queue); - break; - //Event of UART RX break detected - case UART_BREAK: - ESP_LOGI(TAG, "uart rx break"); - break; - //Event of UART parity check error - case UART_PARITY_ERR: - ESP_LOGI(TAG, "uart parity error"); - break; - //Event of UART frame error - case UART_FRAME_ERR: - ESP_LOGI(TAG, "uart frame error"); - break; - case UART_WAKEUP: - ESP_LOGI(TAG, "uart uart wakeup"); - break; - default: - ESP_LOGI(TAG, "uart event type: %d", event.type); - break; - } - ESP_LOGI(TAG, "uart[%d] esp_pm_lock_release()", TEST_UART_NUM); - esp_pm_lock_release(lock); + /* Determine wake up reason */ + const char* wakeup_reason; + switch (esp_sleep_get_wakeup_cause()) { + case ESP_SLEEP_WAKEUP_TIMER: + wakeup_reason = "timer"; + break; + case ESP_SLEEP_WAKEUP_GPIO: + wakeup_reason = "pin"; + break; + case ESP_SLEEP_WAKEUP_UART: + wakeup_reason = "uart"; + /* Hang-up for a while to switch and execuse the uart task + * Otherwise the chip may fall sleep again before running uart task */ + vTaskDelay(1); + break; + default: + wakeup_reason = "other"; + break; + } + printf("Returned from light sleep, reason: %s, t=%lld ms, slept for %lld ms\n", + wakeup_reason, t_after_us / 1000, (t_after_us - t_before_us) / 1000); + if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_GPIO) { + /* Waiting for the gpio inactive, or the chip will continously trigger wakeup*/ + example_wait_gpio_inactive(); } } vTaskDelete(NULL); @@ -126,22 +65,12 @@ static void uart_wakeup_task(void *arg) void app_main(void) { - uart_config_t uart_config = { - .baud_rate = 115200, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .source_clk = UART_SCLK_XTAL, - }; - //Install UART driver, and get the queue. - uart_driver_install(TEST_UART_NUM, TEST_BUF_SIZE * 2, TEST_BUF_SIZE * 2, 20, &uart0_queue, 0); - uart_param_config(TEST_UART_NUM, &uart_config); - uart_set_pin(TEST_UART_NUM, 7, 6, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - light_sleep_wakeup_config(); + /* Enable wakeup from light sleep by gpio */ + example_register_gpio_wakeup(); + /* Enable wakeup from light sleep by timer */ + example_register_timer_wakeup(); + /* Enable wakeup from light sleep by uart */ + example_register_uart_wakeup(); - static esp_pm_lock_handle_t uart_event_lock; - ESP_ERROR_CHECK(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "uart_evt", &uart_event_lock)); - struct { esp_pm_lock_handle_t lock; } args = { .lock = uart_event_lock }; - xTaskCreate(uart_wakeup_task, "uart_wakeup_task", 2048, &args, 12, NULL); + xTaskCreate(light_sleep_task, "light_sleep_task", 4096, NULL, 6, NULL); } diff --git a/examples/system/light_sleep/main/timer_wakeup.c b/examples/system/light_sleep/main/timer_wakeup.c new file mode 100644 index 0000000000..5d9ffa5b9f --- /dev/null +++ b/examples/system/light_sleep/main/timer_wakeup.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "esp_check.h" +#include "esp_sleep.h" + +#define TIMER_WAKEUP_TIME_US (2 * 1000 * 1000) + +static const char *TAG = "timer_wakeup"; + +esp_err_t example_register_timer_wakeup(void) +{ + ESP_RETURN_ON_ERROR(esp_sleep_enable_timer_wakeup(TIMER_WAKEUP_TIME_US), TAG, "Configure timer as wakeup source failed"); + ESP_LOGI(TAG, "timer wakeup source is ready"); + return ESP_OK; +} diff --git a/examples/system/light_sleep/main/uart_wakeup.c b/examples/system/light_sleep/main/uart_wakeup.c new file mode 100644 index 0000000000..7ed8bb4288 --- /dev/null +++ b/examples/system/light_sleep/main/uart_wakeup.c @@ -0,0 +1,139 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_check.h" +#include "esp_sleep.h" +#include "soc/uart_pins.h" +#include "driver/uart.h" +#include "driver/gpio.h" + +#define EXAMPLE_UART_NUM 0 +/* Notice that ESP32 has to use the iomux input to configure uart as wakeup source + * Please use 'UxRXD_GPIO_NUM' as uart rx pin. No limitation to the other target */ +#define EXAMPLE_UART_TX_IO_NUM U0TXD_GPIO_NUM +#define EXAMPLE_UART_RX_IO_NUM U0RXD_GPIO_NUM + +#define EXAMPLE_UART_WAKEUP_THRESHOLD 3 + +#define EXAMPLE_READ_BUF_SIZE 1024 +#define EXAMPLE_UART_BUF_SIZE (EXAMPLE_READ_BUF_SIZE * 2) + +static const char *TAG = "uart_wakeup"; + +static QueueHandle_t uart_evt_que = NULL; + +static void uart_wakeup_task(void *arg) +{ + uart_event_t event; + if (uart_evt_que == NULL) { + ESP_LOGE(TAG, "uart_evt_que is NULL"); + abort(); + } + + uint8_t* dtmp = (uint8_t*) malloc(EXAMPLE_READ_BUF_SIZE); + + while(1) { + // Waiting for UART event. + if(xQueueReceive(uart_evt_que, (void * )&event, (portTickType)portMAX_DELAY)) { + ESP_LOGI(TAG, "uart%d recved event:%d", EXAMPLE_UART_NUM, event.type); + switch(event.type) { + case UART_DATA: + ESP_LOGI(TAG, "[UART DATA]: %d", event.size); + uart_read_bytes(EXAMPLE_UART_NUM, dtmp, event.size, portMAX_DELAY); + ESP_LOGI(TAG, "[DATA EVT]:"); + uart_write_bytes(EXAMPLE_UART_NUM, (const char *)dtmp, event.size); + break; + // Event of HW FIFO overflow detected + case UART_FIFO_OVF: + ESP_LOGI(TAG, "hw fifo overflow"); + // If fifo overflow happened, you should consider adding flow control for your application. + // The ISR has already reset the rx FIFO, + // As an example, we directly flush the rx buffer here in order to read more data. + uart_flush_input(EXAMPLE_UART_NUM); + xQueueReset(uart_evt_que); + break; + // Event of UART ring buffer full + case UART_BUFFER_FULL: + ESP_LOGI(TAG, "ring buffer full"); + // If buffer full happened, you should consider encreasing your buffer size + // As an example, we directly flush the rx buffer here in order to read more data. + uart_flush_input(EXAMPLE_UART_NUM); + xQueueReset(uart_evt_que); + break; + // Event of UART RX break detected + case UART_BREAK: + ESP_LOGI(TAG, "uart rx break"); + break; + // Event of UART parity check error + case UART_PARITY_ERR: + ESP_LOGI(TAG, "uart parity error"); + break; + // Event of UART frame error + case UART_FRAME_ERR: + ESP_LOGI(TAG, "uart frame error"); + break; + // ESP32 can wakeup by uart but there is no wake up interrupt +#if SOC_UART_SUPPORT_WAKEUP_INT + // Event of waking up by UART + case UART_WAKEUP: + ESP_LOGI(TAG, "uart wakeup"); + break; +#endif + default: + ESP_LOGI(TAG, "uart event type: %d", event.type); + break; + } + } + } + free(dtmp); + vTaskDelete(NULL); +} + +static esp_err_t uart_initialization(void) +{ + uart_config_t uart_cfg = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, + }; + //Install UART driver, and get the queue. + ESP_RETURN_ON_ERROR(uart_driver_install(EXAMPLE_UART_NUM, EXAMPLE_UART_BUF_SIZE, EXAMPLE_UART_BUF_SIZE, 20, &uart_evt_que, 0), + TAG, "Install uart failed"); + ESP_RETURN_ON_ERROR(uart_param_config(EXAMPLE_UART_NUM, &uart_cfg), TAG, "Configure uart param failed"); + ESP_RETURN_ON_ERROR(uart_set_pin(EXAMPLE_UART_NUM, EXAMPLE_UART_TX_IO_NUM, EXAMPLE_UART_RX_IO_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE), + TAG, "Configure uart gpio pins failed"); + return ESP_OK; +} + +static esp_err_t uart_wakeup_config(void) +{ + /* UART will wakeup the chip up from light sleep if the edges that RX pin received has reached the threshold + * Besides, the Rx pin need extra configuration to enable it can work during light sleep */ + ESP_RETURN_ON_ERROR(gpio_sleep_set_direction(EXAMPLE_UART_RX_IO_NUM, GPIO_MODE_INPUT), TAG, "Set uart sleep gpio failed"); + ESP_RETURN_ON_ERROR(gpio_sleep_set_pull_mode(EXAMPLE_UART_RX_IO_NUM, GPIO_PULLUP_ONLY), TAG, "Set uart sleep gpio failed"); + ESP_RETURN_ON_ERROR(uart_set_wakeup_threshold(EXAMPLE_UART_NUM, EXAMPLE_UART_WAKEUP_THRESHOLD), + TAG, "Set uart wakeup threshold failed"); + /* Only uart0 and uart1 (if has) support to be configured as wakeup source */ + ESP_RETURN_ON_ERROR(esp_sleep_enable_uart_wakeup(EXAMPLE_UART_NUM), + TAG, "Configure uart as wakeup source failed"); + return ESP_OK; +} + +esp_err_t example_register_uart_wakeup(void) +{ + /* Initialize uart1 */ + ESP_RETURN_ON_ERROR(uart_initialization(), TAG, "Initialize uart%d failed", EXAMPLE_UART_NUM); + /* Enable wakeup from uart */ + ESP_RETURN_ON_ERROR(uart_wakeup_config(), TAG, "Configure uart as wakeup source failed"); + + xTaskCreate(uart_wakeup_task, "uart_wakeup_task", 4096, NULL, 5, NULL); + ESP_LOGI(TAG, "uart wakeup source is ready"); + return ESP_OK; +} diff --git a/examples/system/light_sleep/sdkconfig.defaults b/examples/system/light_sleep/sdkconfig.defaults index e8945648db..8e2af8cd2c 100644 --- a/examples/system/light_sleep/sdkconfig.defaults +++ b/examples/system/light_sleep/sdkconfig.defaults @@ -1,2 +1 @@ -CONFIG_PM_ENABLE=y -CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_80=y diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 9b6d52eb72..58ba8bae05 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1061,7 +1061,6 @@ components/hal/esp32s2/include/hal/touch_sensor_hal.h components/hal/esp32s2/include/hal/touch_sensor_ll.h components/hal/esp32s2/include/hal/trace_ll.h components/hal/esp32s2/include/hal/twai_ll.h -components/hal/esp32s2/include/hal/uart_ll.h components/hal/esp32s2/include/hal/usb_ll.h components/hal/esp32s2/interrupt_descriptor_table.c components/hal/esp32s2/touch_sensor_hal.c @@ -1085,7 +1084,6 @@ components/hal/esp32s3/include/hal/spi_flash_ll.h components/hal/esp32s3/include/hal/spimem_flash_ll.h components/hal/esp32s3/include/hal/systimer_ll.h components/hal/esp32s3/include/hal/twai_ll.h -components/hal/esp32s3/include/hal/uart_ll.h components/hal/esp32s3/include/hal/uhci_ll.h components/hal/esp32s3/include/hal/usb_ll.h components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h