From 176f44c15f8ba201b3ee7c0c5b30d01b2c13f173 Mon Sep 17 00:00:00 2001 From: Chen Yi Qun Date: Thu, 22 Jul 2021 18:10:30 +0800 Subject: [PATCH 1/4] uart: add wakeup event for esp32c3 --- components/driver/include/driver/uart.h | 3 +++ components/driver/uart.c | 18 +++++++++++++++++- components/hal/esp32c3/include/hal/uart_ll.h | 1 + components/soc/esp32c3/include/soc/soc_caps.h | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index f0c2ae1013..4fa41930d9 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -58,6 +58,9 @@ 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 + UART_WAKEUP, /*!< UART wakeup event */ +#endif UART_EVENT_MAX, /*!< UART event max index*/ } uart_event_type_t; diff --git a/components/driver/uart.c b/components/driver/uart.c index 57a27e0e50..32040a6f29 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -59,11 +59,20 @@ 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 +#define UART_INTR_CONFIG_FLAG ((UART_INTR_RXFIFO_FULL) \ + | (UART_INTR_RXFIFO_TOUT) \ + | (UART_INTR_RXFIFO_OVF) \ + | (UART_INTR_BRK_DET) \ + | (UART_INTR_PARITY_ERR)) \ + | (UART_INTR_WAKEUP) +#else #define UART_INTR_CONFIG_FLAG ((UART_INTR_RXFIFO_FULL) \ | (UART_INTR_RXFIFO_TOUT) \ | (UART_INTR_RXFIFO_OVF) \ | (UART_INTR_BRK_DET) \ | (UART_INTR_PARITY_ERR)) +#endif #define UART_ENTER_CRITICAL_SAFE(mux) portENTER_CRITICAL_SAFE(mux) @@ -1111,7 +1120,14 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); } - } else { + } + #if SOC_UART_SUPPORT_WAKEUP + 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; + } + #endif + else { uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), uart_intr_status); /*simply clear all other intr status*/ uart_event.type = UART_EVENT_MAX; } diff --git a/components/hal/esp32c3/include/hal/uart_ll.h b/components/hal/esp32c3/include/hal/uart_ll.h index 1fe368dad6..a494e7b259 100644 --- a/components/hal/esp32c3/include/hal/uart_ll.h +++ b/components/hal/esp32c3/include/hal/uart_ll.h @@ -59,6 +59,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/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 520a6be6ef..09cf69a6a6 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -279,6 +279,7 @@ #define SOC_UART_SUPPORT_RTC_CLK (1) #define SOC_UART_SUPPORT_XTAL_CLK (1) +#define SOC_UART_SUPPORT_WAKEUP (1) #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 From ea837e3a5ee8b7ff67df17ae34f1c7c52acde44c Mon Sep 17 00:00:00 2001 From: Chen Yi Qun Date: Tue, 27 Jul 2021 12:18:56 +0800 Subject: [PATCH 2/4] simple test for uart wakeup --- .../main/light_sleep_example_main.c | 155 ++++++++++-------- 1 file changed, 88 insertions(+), 67 deletions(-) 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 4e979b1ece..4696b4b83f 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -19,77 +19,98 @@ #include "driver/uart.h" #include "driver/gpio.h" #include "esp_timer.h" +#include "soc/uart_struct.h" -/* Most development boards have "boot" button attached to GPIO0. - * You can also change this to another pin. - */ -#if CONFIG_IDF_TARGET_ESP32C3 -#define BUTTON_GPIO_NUM_DEFAULT 9 -#else -#define BUTTON_GPIO_NUM_DEFAULT 0 -#endif +#define TAG "UART" +#define TEST_UART_NUM 1 +#define TEST_BUF_SIZE 1024 -/* "Boot" button is active low */ -#define BUTTON_WAKEUP_LEVEL_DEFAULT 0 +static QueueHandle_t uart0_queue; + +void light_sleep_wakeup_config(void) +{ + ESP_ERROR_CHECK(gpio_sleep_set_direction(6, GPIO_MODE_INPUT)); + ESP_ERROR_CHECK(gpio_sleep_set_pull_mode(6, GPIO_PULLUP_ONLY)); + + 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"); +} + +static void uart_wakeup_task(void *arg) +{ + uart_event_t event; + esp_light_sleep_start(); + for(;;) { + //Waiting for UART event. + if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) { + ESP_LOGI(TAG, "uart[%d] event:", TEST_UART_NUM); + 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; + } + } + } + vTaskDelete(NULL); +} void app_main(void) { - /* Configure the button GPIO as input, enable wakeup */ - const int button_gpio_num = BUTTON_GPIO_NUM_DEFAULT; - const int wakeup_level = BUTTON_WAKEUP_LEVEL_DEFAULT; - gpio_config_t config = { - .pin_bit_mask = BIT64(button_gpio_num), - .mode = GPIO_MODE_INPUT + 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, }; - ESP_ERROR_CHECK(gpio_config(&config)); - gpio_wakeup_enable(button_gpio_num, - wakeup_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL); - - while (true) { - /* Wake up in 2 seconds, or when button is pressed */ - esp_sleep_enable_timer_wakeup(2000000); - esp_sleep_enable_gpio_wakeup(); - - /* Wait until GPIO goes high */ - if (gpio_get_level(button_gpio_num) == wakeup_level) { - printf("Waiting for GPIO%d to go high...\n", button_gpio_num); - do { - vTaskDelay(pdMS_TO_TICKS(10)); - } while (gpio_get_level(button_gpio_num) == wakeup_level); - } - - 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); - - /* Get timestamp before entering sleep */ - int64_t t_before_us = esp_timer_get_time(); - - /* Enter sleep mode */ - esp_light_sleep_start(); - /* Execution continues here after wakeup */ - - /* Get timestamp after waking up from sleep */ - int64_t t_after_us = esp_timer_get_time(); - - /* 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; - 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); - } - + //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(); + xTaskCreate(uart_wakeup_task, "uart_wakeup_task", 2048, NULL, 12, NULL); } From 1d31a493e4000ae748db3ef7a4caf70b9dd3e6e8 Mon Sep 17 00:00:00 2001 From: Chen Wu Date: Tue, 27 Jul 2021 15:46:23 +0800 Subject: [PATCH 3/4] debug: esp32c3 uart1 wakeup --- components/hal/esp32c3/include/hal/uart_ll.h | 18 ++---- examples/system/light_sleep/README.md | 2 + .../main/light_sleep_example_main.c | 57 ++++++++++++++----- .../system/light_sleep/sdkconfig.defaults | 3 +- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/components/hal/esp32c3/include/hal/uart_ll.h b/components/hal/esp32c3/include/hal/uart_ll.h index a494e7b259..f4a21e90e8 100644 --- a/components/hal/esp32c3/include/hal/uart_ll.h +++ b/components/hal/esp32c3/include/hal/uart_ll.h @@ -1,16 +1,8 @@ -// Copyright 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: 2021-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. diff --git a/examples/system/light_sleep/README.md b/examples/system/light_sleep/README.md index c9212067c6..4ae642df2e 100644 --- a/examples/system/light_sleep/README.md +++ b/examples/system/light_sleep/README.md @@ -1,3 +1,5 @@ +| Supported Targets | ESP32-C3 | +| ----------------- | -------- | # Light Sleep Example (See the README.md file in the upper level 'examples' directory for more information about examples.) 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 4696b4b83f..7643f4a88e 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -1,11 +1,10 @@ -/* Light sleep example +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ +/* Light sleep example */ #include #include @@ -20,6 +19,9 @@ #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" #define TAG "UART" #define TEST_UART_NUM 1 @@ -41,20 +43,43 @@ void light_sleep_wakeup_config(void) ESP_LOGI(TAG, "set_light_sleep_wakeup ok"); } +void light_sleep_setup(void) +{ + light_sleep_wakeup_config(); + + 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)); +} + +#define RD_BUF_SIZE 1024 + static void uart_wakeup_task(void *arg) { uart_event_t event; - esp_light_sleep_start(); + // 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_LOGI(TAG, "uart[%d] event:", TEST_UART_NUM); + + 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); + 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: @@ -92,6 +117,8 @@ static void uart_wakeup_task(void *arg) 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); } } vTaskDelete(NULL); @@ -112,5 +139,9 @@ void app_main(void) 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(); - xTaskCreate(uart_wakeup_task, "uart_wakeup_task", 2048, NULL, 12, NULL); + + 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); } diff --git a/examples/system/light_sleep/sdkconfig.defaults b/examples/system/light_sleep/sdkconfig.defaults index 8e2af8cd2c..e8945648db 100644 --- a/examples/system/light_sleep/sdkconfig.defaults +++ b/examples/system/light_sleep/sdkconfig.defaults @@ -1 +1,2 @@ -CONFIG_ESP32_DEFAULT_CPU_FREQ_80=y +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y From ac67d5dd355e7eabfd885fa9e0b0be2311f0f634 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 12 Jan 2022 11:03:38 +0800 Subject: [PATCH 4/4] uart: support light sleep on esp32s3 --- components/driver/include/driver/uart.h | 4 +- components/driver/uart.c | 6 +- components/hal/esp32c3/include/hal/uart_ll.h | 2 +- components/hal/esp32h2/include/hal/uart_ll.h | 1 + components/hal/esp32s2/include/hal/uart_ll.h | 19 +- components/hal/esp32s3/include/hal/uart_ll.h | 19 +- components/soc/esp32c3/include/soc/soc_caps.h | 4 +- components/soc/esp32h2/include/soc/soc_caps.h | 2 +- components/soc/esp32s2/include/soc/soc_caps.h | 3 +- components/soc/esp32s3/include/soc/soc_caps.h | 11 +- .../soc/esp32s3/include/soc/uart_caps.h | 31 --- examples/system/light_sleep/README.md | 2 - .../main/light_sleep_example_main.c | 198 +++++++----------- .../system/light_sleep/sdkconfig.defaults | 3 +- 14 files changed, 106 insertions(+), 199 deletions(-) delete mode 100644 components/soc/esp32s3/include/soc/uart_caps.h diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 4fa41930d9..2e98fa2bf5 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-2023 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 32040a6f29..b351eb722e 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-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -59,7 +59,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) \ @@ -1121,7 +1121,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/esp32c3/include/hal/uart_ll.h b/components/hal/esp32c3/include/hal/uart_ll.h index f4a21e90e8..ff82c0327b 100644 --- a/components/hal/esp32c3/include/hal/uart_ll.h +++ b/components/hal/esp32c3/include/hal/uart_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h index 0b93f8f9a9..5d6cc2c193 100644 --- a/components/hal/esp32h2/include/hal/uart_ll.h +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -59,6 +59,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 5596ab71e2..e39d2ff559 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-2023 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 87a90145c7..39bc439f3f 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-2023 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/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 09cf69a6a6..9bf28ad29a 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-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -279,7 +279,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/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 964f18cd27..b6eccf97ab 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -260,7 +260,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/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index a01cf422a9..182dce0999 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -262,6 +262,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/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index d34b39bf27..6aa71dd579 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -260,8 +260,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 */ #define SOC_UART_REQUIRE_CORE_RESET (1) 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..c9212067c6 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.) 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..4e979b1ece 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -1,10 +1,11 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 - */ +/* Light sleep example -/* Light sleep example */ + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ #include #include @@ -18,130 +19,77 @@ #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" -#define TAG "UART" -#define TEST_UART_NUM 1 -#define TEST_BUF_SIZE 1024 +/* Most development boards have "boot" button attached to GPIO0. + * You can also change this to another pin. + */ +#if CONFIG_IDF_TARGET_ESP32C3 +#define BUTTON_GPIO_NUM_DEFAULT 9 +#else +#define BUTTON_GPIO_NUM_DEFAULT 0 +#endif -static QueueHandle_t uart0_queue; - -void light_sleep_wakeup_config(void) -{ - ESP_ERROR_CHECK(gpio_sleep_set_direction(6, GPIO_MODE_INPUT)); - ESP_ERROR_CHECK(gpio_sleep_set_pull_mode(6, GPIO_PULLUP_ONLY)); - - 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"); -} - -void light_sleep_setup(void) -{ - light_sleep_wakeup_config(); - - 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)); -} - -#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); - } - } - vTaskDelete(NULL); -} +/* "Boot" button is active low */ +#define BUTTON_WAKEUP_LEVEL_DEFAULT 0 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, + /* Configure the button GPIO as input, enable wakeup */ + const int button_gpio_num = BUTTON_GPIO_NUM_DEFAULT; + const int wakeup_level = BUTTON_WAKEUP_LEVEL_DEFAULT; + gpio_config_t config = { + .pin_bit_mask = BIT64(button_gpio_num), + .mode = GPIO_MODE_INPUT }; - //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(); + ESP_ERROR_CHECK(gpio_config(&config)); + gpio_wakeup_enable(button_gpio_num, + wakeup_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL); + + while (true) { + /* Wake up in 2 seconds, or when button is pressed */ + esp_sleep_enable_timer_wakeup(2000000); + esp_sleep_enable_gpio_wakeup(); + + /* Wait until GPIO goes high */ + if (gpio_get_level(button_gpio_num) == wakeup_level) { + printf("Waiting for GPIO%d to go high...\n", button_gpio_num); + do { + vTaskDelay(pdMS_TO_TICKS(10)); + } while (gpio_get_level(button_gpio_num) == wakeup_level); + } + + 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); + + /* Get timestamp before entering sleep */ + int64_t t_before_us = esp_timer_get_time(); + + /* Enter sleep mode */ + esp_light_sleep_start(); + /* Execution continues here after wakeup */ + + /* Get timestamp after waking up from sleep */ + int64_t t_after_us = esp_timer_get_time(); + + /* 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; + 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); + } - 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); } 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