Skip to content

Commit 5f37de2

Browse files
author
Igor Udot
committed
Merge branch 'feat/lp-uart-wakeup-mode3' into 'master'
Added support for UART wakeup modes Closes IDF-10202 See merge request espressif/esp-idf!31965
2 parents f9d5802 + f742a05 commit 5f37de2

File tree

70 files changed

+1830
-99
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1830
-99
lines changed

components/esp_driver_uart/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ idf_build_get_property(target IDF_TARGET)
33
set(srcs)
44
set(public_include "include")
55
if(CONFIG_SOC_UART_SUPPORTED)
6-
list(APPEND srcs "src/uart.c")
6+
list(APPEND srcs "src/uart.c" "src/uart_wakeup.c")
77
endif()
88

99
if(${target} STREQUAL "linux")
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include "esp_err.h"
10+
#include "soc/soc_caps.h"
11+
#include "hal/uart_types.h"
12+
13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
17+
/**
18+
* @brief Structure that holds configuration for UART wakeup.
19+
*
20+
* This structure is used to configure the wakeup behavior for a UART port. The wakeup mode can be
21+
* selected from several options, such as active threshold, FIFO threshold, start bit detection, and
22+
* character sequence detection. The availability of different wakeup modes depends on the SOC capabilities.
23+
*/
24+
typedef struct {
25+
/** Wakeup mode selection */
26+
uart_wakeup_mode_t wakeup_mode;
27+
28+
#if SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE
29+
/** Used in Active threshold wake-up;
30+
related: UART_WK_MODE_ACTIVE_THRESH;
31+
Configures the number of RXD edge changes to wake up the chip.*/
32+
uint16_t rx_edge_threshold;
33+
#endif
34+
35+
#if SOC_UART_WAKEUP_SUPPORT_FIFO_THRESH_MODE
36+
/** Used in Bytes received in RX FIFO wake-up;
37+
related: UART_WK_MODE_FIFO_THRESH;
38+
Configures the number of received data bytes to wake up the chip.*/
39+
uint16_t rx_fifo_threshold;
40+
#endif
41+
42+
#if SOC_UART_WAKEUP_SUPPORT_CHAR_SEQ_MODE
43+
/** Used in Character sequence detection(Trigger phrase) wake-up;
44+
related: UART_WK_MODE_CHAR_SEQ;
45+
'*' represents any symbol.
46+
The end character cannot be '*'.
47+
Example: "he**o" matches hello, heyyo. */
48+
char wake_chars_seq[SOC_UART_WAKEUP_CHARS_SEQ_MAX_LEN];
49+
#endif
50+
51+
} uart_wakeup_cfg_t;
52+
53+
/**
54+
* @brief Initializes the UART wakeup functionality.
55+
*
56+
* This function configures the wakeup behavior for a specified UART port based on the provided configuration.
57+
* The behavior depends on the selected wakeup mode and additional parameters such as active threshold or
58+
* character sequence, if applicable. It is important that the provided configuration matches the capabilities
59+
* of the SOC to ensure proper operation.
60+
*
61+
* @param uart_num The UART port to initialize for wakeup (e.g., UART_NUM_0, UART_NUM_1, etc.).
62+
* @param cfg Pointer to the `uart_wakeup_cfg_t` structure that contains the wakeup configuration settings.
63+
*
64+
* @return
65+
* - `ESP_OK` if the wakeup configuration was successfully applied.
66+
* - `ESP_ERR_INVALID_ARG` if the provided configuration is invalid (e.g., threshold values out of range).
67+
*/
68+
esp_err_t uart_wakeup_setup(uart_port_t uart_num, const uart_wakeup_cfg_t *cfg);
69+
70+
#ifdef __cplusplus
71+
}
72+
#endif

components/esp_driver_uart/src/uart.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static const char *UART_TAG = "uart";
7070
#define UART_CLKDIV_FRAG_BIT_WIDTH (3)
7171
#define UART_TX_IDLE_NUM_DEFAULT (0)
7272
#define UART_PATTERN_DET_QLEN_DEFAULT (10)
73-
#define UART_MIN_WAKEUP_THRESH (UART_LL_MIN_WAKEUP_THRESH)
73+
#define UART_MIN_WAKEUP_THRESH (UART_LL_WAKEUP_EDGE_THRED_MIN)
7474

7575
#if (SOC_UART_LP_NUM >= 1)
7676
#define UART_THRESHOLD_NUM(uart_num, field_name) ((uart_num < SOC_UART_HP_NUM) ? field_name : LP_##field_name)
@@ -1945,7 +1945,7 @@ esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold)
19451945
ESP_RETURN_ON_FALSE((wakeup_threshold <= UART_THRESHOLD_NUM(uart_num, UART_ACTIVE_THRESHOLD_V) && wakeup_threshold >= UART_MIN_WAKEUP_THRESH), ESP_ERR_INVALID_ARG, UART_TAG,
19461946
"wakeup_threshold out of bounds");
19471947
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
1948-
uart_hal_set_wakeup_thrd(&(uart_context[uart_num].hal), wakeup_threshold);
1948+
uart_hal_set_wakeup_edge_thrd(&(uart_context[uart_num].hal), wakeup_threshold);
19491949
HP_UART_PAD_CLK_ATOMIC() {
19501950
uart_ll_enable_pad_sleep_clock(uart_context[uart_num].hal.dev, true);
19511951
}
@@ -1957,7 +1957,7 @@ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int *out_wakeup_thresh
19571957
{
19581958
ESP_RETURN_ON_FALSE((uart_num < UART_NUM_MAX), ESP_ERR_INVALID_ARG, UART_TAG, "uart_num error");
19591959
ESP_RETURN_ON_FALSE((out_wakeup_threshold != NULL), ESP_ERR_INVALID_ARG, UART_TAG, "argument is NULL");
1960-
uart_hal_get_wakeup_thrd(&(uart_context[uart_num].hal), (uint32_t *)out_wakeup_threshold);
1960+
uart_hal_get_wakeup_edge_thrd(&(uart_context[uart_num].hal), (uint32_t *)out_wakeup_threshold);
19611961
return ESP_OK;
19621962
}
19631963

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*
8+
* WARNING:
9+
*
10+
* This file is shared between the HP and LP cores.
11+
* Updates to this file should be made carefully and should not include FreeRTOS APIs or other IDF-specific functionalities, such as the interrupt allocator.
12+
*/
13+
14+
#include "driver/uart_wakeup.h"
15+
#include "hal/uart_hal.h"
16+
17+
#if SOC_UART_WAKEUP_SUPPORT_CHAR_SEQ_MODE
18+
static esp_err_t uart_char_seq_wk_configure(uart_dev_t *hw, const char* phrase)
19+
{
20+
if (phrase == NULL || phrase[0] == '\0') {
21+
return ESP_ERR_INVALID_ARG;
22+
}
23+
esp_err_t ret = ESP_OK;
24+
25+
uint32_t mask = 0;
26+
uint32_t index = 0;
27+
28+
while (index < SOC_UART_WAKEUP_CHARS_SEQ_MAX_LEN && phrase[index] != '\0') {
29+
if (phrase[index] == '*') {
30+
mask |= 1 << index;
31+
} else {
32+
uart_ll_set_char_seq_wk_char(hw, index, phrase[index]);
33+
}
34+
index++;
35+
}
36+
37+
if (
38+
index == 0 ||
39+
phrase[index - 1] == '*' ||
40+
mask > 0xF
41+
) {
42+
return ESP_ERR_INVALID_ARG;
43+
}
44+
uart_ll_set_wakeup_char_seq_mask(hw, mask);
45+
uart_ll_set_wakeup_char_seq_char_num(hw, index - 1);
46+
47+
return ret;
48+
}
49+
#endif
50+
51+
esp_err_t uart_wakeup_setup(uart_port_t uart_num, const uart_wakeup_cfg_t *cfg)
52+
{
53+
54+
if (cfg == NULL) {
55+
return ESP_ERR_INVALID_ARG;
56+
}
57+
uart_dev_t *hw = UART_LL_GET_HW(uart_num);
58+
59+
// This should be mocked at ll level if the selection of the UART wakeup mode is not supported by this SOC.
60+
uart_ll_set_wakeup_mode(hw, cfg->wakeup_mode);
61+
62+
switch (cfg->wakeup_mode) {
63+
#if SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE
64+
case UART_WK_MODE_ACTIVE_THRESH:
65+
// UART_ACTIVE_THRESHOLD register has only 10 bits, and the min value is 3.
66+
if (cfg->rx_edge_threshold < UART_LL_WAKEUP_EDGE_THRED_MIN || cfg->rx_edge_threshold > UART_LL_WAKEUP_EDGE_THRED_MAX(hw)) {
67+
return ESP_ERR_INVALID_ARG;
68+
}
69+
uart_ll_set_wakeup_edge_thrd(hw, cfg->rx_edge_threshold);
70+
return ESP_OK;
71+
#endif
72+
#if SOC_UART_WAKEUP_SUPPORT_FIFO_THRESH_MODE
73+
case UART_WK_MODE_FIFO_THRESH:
74+
if (cfg->rx_fifo_threshold > UART_LL_WAKEUP_FIFO_THRED_MAX(hw)) {
75+
return ESP_ERR_INVALID_ARG;
76+
}
77+
uart_ll_set_wakeup_fifo_thrd(hw, cfg->rx_fifo_threshold);
78+
return ESP_OK;
79+
#endif
80+
#if SOC_UART_WAKEUP_SUPPORT_START_BIT_MODE
81+
case UART_WK_MODE_START_BIT:
82+
return ESP_OK;
83+
#endif
84+
#if SOC_UART_WAKEUP_SUPPORT_CHAR_SEQ_MODE
85+
case UART_WK_MODE_CHAR_SEQ:
86+
return uart_char_seq_wk_configure(hw, cfg->wake_chars_seq);
87+
#endif
88+
}
89+
90+
return ESP_ERR_INVALID_ARG;
91+
}

components/hal/esp32/include/hal/uart_ll.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -30,8 +30,10 @@ extern "C" {
3030
// The timeout calibration factor when using ref_tick
3131
#define UART_LL_TOUT_REF_FACTOR_DEFAULT (8)
3232

33-
#define UART_LL_MIN_WAKEUP_THRESH (3)
33+
#define UART_LL_WAKEUP_EDGE_THRED_MIN (3)
3434
#define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask
35+
#define UART_LL_WAKEUP_EDGE_THRED_MAX(hw) UART_ACTIVE_THRESHOLD_V
36+
3537

3638
// Define UART interrupts
3739
typedef enum {
@@ -710,13 +712,19 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level)
710712
*
711713
* @return None.
712714
*/
713-
FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
715+
FORCE_INLINE_ATTR void uart_ll_set_wakeup_edge_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
714716
{
715717
// System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+2)
716718
// Note: On ESP32, the minimum UART wakeup threshold is 2 + 1 = 3 (UART_ACTIVE_THRESHOLD set to 0 leads to consecutive triggering wakeup)
717-
hw->sleep_conf.active_threshold = wakeup_thrd - (UART_LL_MIN_WAKEUP_THRESH - 1);
719+
hw->sleep_conf.active_threshold = wakeup_thrd - (UART_LL_WAKEUP_EDGE_THRED_MIN - 1);
718720
}
719721

722+
/**
723+
* @brief Mocking the selection of the UART wakeup mode, as it is not supported by this SOC.
724+
*/
725+
FORCE_INLINE_ATTR void uart_ll_set_wakeup_mode(uart_dev_t *hw, uart_wakeup_mode_t mode)
726+
{}
727+
720728
/**
721729
* @brief Enable/disable the UART pad clock in sleep_state
722730
*
@@ -867,9 +875,9 @@ FORCE_INLINE_ATTR void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char
867875
*
868876
* @return The UART wakeup threshold value.
869877
*/
870-
FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw)
878+
FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_edge_thrd(uart_dev_t *hw)
871879
{
872-
return hw->sleep_conf.active_threshold + (UART_LL_MIN_WAKEUP_THRESH - 1);
880+
return hw->sleep_conf.active_threshold + (UART_LL_WAKEUP_EDGE_THRED_MIN - 1);
873881
}
874882

875883
/**

components/hal/esp32c2/include/hal/uart_ll.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -29,8 +29,9 @@ extern "C" {
2929
// Get UART hardware instance with giving uart num
3030
#define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (&UART1))
3131

32-
#define UART_LL_MIN_WAKEUP_THRESH (3)
32+
#define UART_LL_WAKEUP_EDGE_THRED_MIN (3)
3333
#define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask
34+
#define UART_LL_WAKEUP_EDGE_THRED_MAX(hw) UART_ACTIVE_THRESHOLD_V
3435

3536
#define UART_LL_FSM_IDLE (0x0)
3637
#define UART_LL_FSM_TX_WAIT_SEND (0xf)
@@ -673,12 +674,18 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level)
673674
*
674675
* @return None.
675676
*/
676-
FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
677+
FORCE_INLINE_ATTR void uart_ll_set_wakeup_edge_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
677678
{
678679
// System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3)
679-
hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH;
680+
hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_WAKEUP_EDGE_THRED_MIN;
680681
}
681682

683+
/**
684+
* @brief Mocking the selection of the UART wakeup mode, as it is not supported by this SOC.
685+
*/
686+
FORCE_INLINE_ATTR void uart_ll_set_wakeup_mode(uart_dev_t *hw, uart_wakeup_mode_t mode)
687+
{}
688+
682689
/**
683690
* @brief Enable/disable the UART pad clock in sleep_state
684691
*
@@ -836,9 +843,9 @@ FORCE_INLINE_ATTR void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char
836843
*
837844
* @return The UART wakeup threshold value.
838845
*/
839-
FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw)
846+
FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_edge_thrd(uart_dev_t *hw)
840847
{
841-
return hw->sleep_conf.active_threshold + UART_LL_MIN_WAKEUP_THRESH;
848+
return hw->sleep_conf.active_threshold + UART_LL_WAKEUP_EDGE_THRED_MIN;
842849
}
843850

844851
/**

components/hal/esp32c3/include/hal/uart_ll.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -29,8 +29,9 @@ extern "C" {
2929
// Get UART hardware instance with giving uart num
3030
#define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (&UART1))
3131

32-
#define UART_LL_MIN_WAKEUP_THRESH (3)
32+
#define UART_LL_WAKEUP_EDGE_THRED_MIN (3)
3333
#define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask
34+
#define UART_LL_WAKEUP_EDGE_THRED_MAX(hw) UART_ACTIVE_THRESHOLD_V
3435

3536
#define UART_LL_FSM_IDLE (0x0)
3637
#define UART_LL_FSM_TX_WAIT_SEND (0xf)
@@ -676,12 +677,18 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level)
676677
*
677678
* @return None.
678679
*/
679-
FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
680+
FORCE_INLINE_ATTR void uart_ll_set_wakeup_edge_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
680681
{
681682
// System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3)
682-
hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH;
683+
hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_WAKEUP_EDGE_THRED_MIN;
683684
}
684685

686+
/**
687+
* @brief Mocking the selection of the UART wakeup mode, as it is not supported by this SOC.
688+
*/
689+
FORCE_INLINE_ATTR void uart_ll_set_wakeup_mode(uart_dev_t *hw, uart_wakeup_mode_t mode)
690+
{}
691+
685692
/**
686693
* @brief Enable/disable the UART pad clock in sleep_state
687694
*
@@ -839,9 +846,9 @@ FORCE_INLINE_ATTR void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char
839846
*
840847
* @return The UART wakeup threshold value.
841848
*/
842-
FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw)
849+
FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_edge_thrd(uart_dev_t *hw)
843850
{
844-
return hw->sleep_conf.active_threshold + UART_LL_MIN_WAKEUP_THRESH;
851+
return hw->sleep_conf.active_threshold + UART_LL_WAKEUP_EDGE_THRED_MIN;
845852
}
846853

847854
/**

components/hal/esp32c5/include/hal/lp_core_ll.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ static inline uint8_t lp_core_ll_get_triggered_interrupt_srcs(void)
131131
return LPPERI.interrupt_source.lp_interrupt_source;
132132
}
133133

134+
/**
135+
* @brief Enable wakeup from LP UART.
136+
*/
137+
static inline void lp_core_ll_enable_lp_uart_wakeup(bool enable)
138+
{
139+
LPPERI.mem_ctrl.uart_wakeup_en = enable;
140+
}
141+
134142
/**
135143
* @brief Get the flag that marks whether LP CPU is awakened by ETM
136144
*

0 commit comments

Comments
 (0)