Skip to content

Commit 51ad6cf

Browse files
committed
feat(esp32h21): support RTC_IO and hysteresis on ESP32H21
1 parent d3acbe1 commit 51ad6cf

File tree

14 files changed

+328
-53
lines changed

14 files changed

+328
-53
lines changed

components/esp_driver_gpio/test_apps/.build-test-rules.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,6 @@
33
components/esp_driver_gpio/test_apps:
44
depends_components:
55
- esp_driver_gpio
6-
disable:
7-
- if: IDF_TARGET in ["esp32h21"]
8-
temporary: true
9-
reason: not support yet # TODO: [esp32h21] IDF-11611
10-
116
components/esp_driver_gpio/test_apps/gpio_extensions:
127
enable:
138
- if: SOC_DEDICATED_GPIO_SUPPORTED == 1
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
2-
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
1+
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
2+
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- |
Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,77 @@
11

22
/*
3-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
44
*
55
* SPDX-License-Identifier: Apache-2.0
66
*/
77

8-
//TODO: [ESP32H21] IDF-11611
8+
#include "freertos/FreeRTOS.h"
9+
#include "esp_private/io_mux.h"
10+
#include "esp_private/periph_ctrl.h"
11+
#include "hal/gpio_ll.h"
12+
#include "hal/rtc_io_ll.h"
13+
14+
#define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
15+
16+
static portMUX_TYPE s_io_mux_spinlock = portMUX_INITIALIZER_UNLOCKED;
17+
static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter)
18+
static uint8_t s_rtc_io_enabled_cnt[MAX_RTC_GPIO_NUM] = { 0 };
19+
static uint32_t s_rtc_io_using_mask = 0;
20+
21+
esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src)
22+
{
23+
bool clk_conflict = false;
24+
// check is the IO MUX has been set to another clock source
25+
portENTER_CRITICAL(&s_io_mux_spinlock);
26+
if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) {
27+
clk_conflict = true;
28+
} else {
29+
s_io_mux_clk_src = clk_src;
30+
}
31+
portEXIT_CRITICAL(&s_io_mux_spinlock);
32+
33+
if (clk_conflict) {
34+
return ESP_ERR_INVALID_STATE;
35+
}
36+
37+
gpio_ll_iomux_set_clk_src(clk_src);
38+
39+
return ESP_OK;
40+
}
41+
42+
void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable)
43+
{
44+
portENTER_CRITICAL(&s_io_mux_spinlock);
45+
if (enable) {
46+
if (s_rtc_io_enabled_cnt[gpio_num] == 0) {
47+
s_rtc_io_using_mask |= (1ULL << gpio_num);
48+
}
49+
s_rtc_io_enabled_cnt[gpio_num]++;
50+
} else if (!enable && (s_rtc_io_enabled_cnt[gpio_num] > 0)) {
51+
s_rtc_io_enabled_cnt[gpio_num]--;
52+
if (s_rtc_io_enabled_cnt[gpio_num] == 0) {
53+
s_rtc_io_using_mask &= ~(1ULL << gpio_num);
54+
}
55+
}
56+
RTCIO_RCC_ATOMIC() {
57+
if (s_rtc_io_using_mask == 0) {
58+
rtcio_ll_enable_io_clock(false);
59+
} else {
60+
rtcio_ll_enable_io_clock(true);
61+
}
62+
}
63+
portEXIT_CRITICAL(&s_io_mux_spinlock);
64+
}
65+
66+
void io_mux_force_disable_lp_io_clock(gpio_num_t gpio_num)
67+
{
68+
portENTER_CRITICAL(&s_io_mux_spinlock);
69+
s_rtc_io_enabled_cnt[gpio_num] = 0;
70+
s_rtc_io_using_mask &= ~(1ULL << gpio_num);
71+
if (s_rtc_io_using_mask == 0) {
72+
RTCIO_RCC_ATOMIC() {
73+
rtcio_ll_enable_io_clock(false);
74+
}
75+
}
76+
portEXIT_CRITICAL(&s_io_mux_spinlock);
77+
}

components/hal/esp32h21/include/hal/gpio_ll.h

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,9 @@ static inline void gpio_ll_iomux_set_clk_src(soc_module_clk_t src)
544544
*/
545545
static inline int gpio_ll_get_in_signal_connected_io(gpio_dev_t *hw, uint32_t in_sig_idx)
546546
{
547-
uint32_t val = REG_GET_BIT(GPIO_FUNC0_IN_SEL_CFG_REG + in_sig_idx * 4, GPIO_SIG0_IN_SEL);
548-
return (val ? val : -1);
547+
gpio_func_in_sel_cfg_reg_t reg;
548+
reg.val = hw->func_in_sel_cfg[in_sig_idx].val;
549+
return (reg.sig_in_sel ? reg.func_in_sel : -1);
549550
}
550551

551552
/**
@@ -689,21 +690,21 @@ static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, gpio_num_t gpio_n
689690
*/
690691
static inline void gpio_ll_deepsleep_wakeup_enable(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type)
691692
{
692-
HAL_ASSERT((gpio_num >= GPIO_NUM_7 && gpio_num <= GPIO_NUM_14) &&
693-
"only gpio7~14 support deep sleep wake-up function");
693+
HAL_ASSERT((gpio_num >= GPIO_NUM_5 && gpio_num <= GPIO_NUM_11) &&
694+
"only gpio5~11 support deep sleep wake-up function");
694695

695696
LP_AON.ext_wakeup_cntl.aon_ext_wakeup_filter = 1;
696697

697698
uint32_t wakeup_sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, aon_ext_wakeup_sel);
698-
wakeup_sel_mask |= BIT(gpio_num - 7);
699+
wakeup_sel_mask |= BIT(gpio_num - 5);
699700
HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, aon_ext_wakeup_sel, wakeup_sel_mask);
700701

701702
bool trigger_level = (intr_type == GPIO_INTR_LOW_LEVEL) ? 0 : 1;
702703
uint32_t wakeup_level_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, aon_ext_wakeup_lv);
703704
if (trigger_level) {
704-
wakeup_level_mask |= BIT(gpio_num - 7);
705+
wakeup_level_mask |= BIT(gpio_num - 5);
705706
} else {
706-
wakeup_level_mask &= ~BIT(gpio_num - 7);
707+
wakeup_level_mask &= ~BIT(gpio_num - 5);
707708
}
708709
HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, aon_ext_wakeup_lv, wakeup_level_mask);
709710
}
@@ -716,11 +717,11 @@ static inline void gpio_ll_deepsleep_wakeup_enable(gpio_dev_t *hw, gpio_num_t gp
716717
*/
717718
static inline void gpio_ll_deepsleep_wakeup_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
718719
{
719-
HAL_ASSERT((gpio_num >= GPIO_NUM_7 && gpio_num <= GPIO_NUM_14) &&
720-
"only gpio7~14 support deep sleep wake-up function");
720+
HAL_ASSERT((gpio_num >= GPIO_NUM_5 && gpio_num <= GPIO_NUM_11) &&
721+
"only gpio5~11 support deep sleep wake-up function");
721722

722723
uint32_t wakeup_sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, aon_ext_wakeup_sel);
723-
wakeup_sel_mask &= ~BIT(gpio_num - 7);
724+
wakeup_sel_mask &= ~BIT(gpio_num - 5);
724725
HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, aon_ext_wakeup_sel, wakeup_sel_mask);
725726
}
726727

@@ -733,11 +734,11 @@ static inline void gpio_ll_deepsleep_wakeup_disable(gpio_dev_t *hw, gpio_num_t g
733734
*/
734735
static inline bool gpio_ll_deepsleep_wakeup_is_enabled(gpio_dev_t *hw, uint32_t gpio_num)
735736
{
736-
HAL_ASSERT((gpio_num >= GPIO_NUM_7 && gpio_num <= GPIO_NUM_14) &&
737-
"only gpio7~14 support deep sleep wake-up function");
737+
HAL_ASSERT((gpio_num >= GPIO_NUM_5 && gpio_num <= GPIO_NUM_11) &&
738+
"only gpio5~11 support deep sleep wake-up function");
738739

739740
uint32_t wakeup_sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.ext_wakeup_cntl, aon_ext_wakeup_sel);
740-
return wakeup_sel_mask & BIT(gpio_num - 7);
741+
return wakeup_sel_mask & BIT(gpio_num - 5);
741742
}
742743

743744
#ifdef __cplusplus
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/*******************************************************************************
8+
* NOTICE
9+
* The ll is not public api, don't use in application code.
10+
* See readme.md in hal/readme.md
11+
******************************************************************************/
12+
13+
#pragma once
14+
15+
#include <stdbool.h>
16+
#include "soc/soc_caps.h"
17+
#include "soc/lp_aon_struct.h"
18+
#include "soc/lpperi_struct.h"
19+
#include "soc/pmu_struct.h"
20+
#include "hal/misc.h"
21+
22+
#ifdef __cplusplus
23+
extern "C" {
24+
#endif
25+
26+
#define RTCIO_LL_GPIO_NUM_OFFSET 5 // rtcio 0-6 correspond to gpio 5-11
27+
28+
typedef enum {
29+
RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */
30+
RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */
31+
} rtcio_ll_func_t;
32+
33+
34+
/**
35+
* @brief Enable/Disable LP_IO peripheral clock.
36+
*
37+
* @param enable true to enable the clock / false to disable the clock
38+
*/
39+
static inline void _rtcio_ll_enable_io_clock(bool enable)
40+
{
41+
LPPERI.clk_en.lp_io_ck_en = enable;
42+
while (LPPERI.clk_en.lp_io_ck_en != enable) {
43+
;
44+
}
45+
}
46+
47+
#define rtcio_ll_enable_io_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _rtcio_ll_enable_io_clock(__VA_ARGS__)
48+
49+
/**
50+
* @brief Select the rtcio function.
51+
*
52+
* @note The RTC function must be selected before the pad analog function is enabled.
53+
*
54+
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
55+
* @param func Select pin function.
56+
*/
57+
static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func)
58+
{
59+
if (func == RTCIO_LL_FUNC_RTC) {
60+
// 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module.
61+
uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, aon_gpio_mux_sel);
62+
sel_mask |= BIT(rtcio_num);
63+
HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, aon_gpio_mux_sel, sel_mask);
64+
} else if (func == RTCIO_LL_FUNC_DIGITAL) {
65+
// Clear the bit to use digital GPIO module
66+
uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, aon_gpio_mux_sel);
67+
sel_mask &= ~BIT(rtcio_num);
68+
HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, aon_gpio_mux_sel, sel_mask);
69+
}
70+
}
71+
72+
/**
73+
* Enable force hold function for an RTC IO pad.
74+
*
75+
* Enabling HOLD function will cause the pad to lock current status, such as,
76+
* input/output enable, input/output value, function, drive strength values.
77+
* This function is useful when going into light or deep sleep mode to prevent
78+
* the pin configuration from changing.
79+
*
80+
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
81+
*/
82+
static inline void rtcio_ll_force_hold_enable(int rtcio_num)
83+
{
84+
LP_AON.gpio_hold0.gpio_hold0 |= BIT(rtcio_num + RTCIO_LL_GPIO_NUM_OFFSET);
85+
}
86+
87+
/**
88+
* Disable hold function on an RTC IO pad
89+
*
90+
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
91+
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
92+
*/
93+
static inline void rtcio_ll_force_hold_disable(int rtcio_num)
94+
{
95+
LP_AON.gpio_hold0.gpio_hold0 &= ~BIT(rtcio_num + RTCIO_LL_GPIO_NUM_OFFSET);
96+
}
97+
98+
/**
99+
* Enable force hold function for all RTC IO pads
100+
*
101+
* Enabling HOLD function will cause the pad to lock current status, such as,
102+
* input/output enable, input/output value, function, drive strength values.
103+
* This function is useful when going into light or deep sleep mode to prevent
104+
* the pin configuration from changing.
105+
*/
106+
static inline void rtcio_ll_force_hold_all(void)
107+
{
108+
PMU.imm.pad_hold_all.tie_high_lp_pad_hold_all = 1;
109+
}
110+
111+
/**
112+
* Disable hold function fon all RTC IO pads
113+
*
114+
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
115+
*/
116+
static inline void rtcio_ll_force_unhold_all(void)
117+
{
118+
PMU.imm.pad_hold_all.tie_low_lp_pad_hold_all = 1;
119+
}
120+
121+
#ifdef __cplusplus
122+
}
123+
#endif

components/soc/esp32h21/include/soc/Kconfig.soc_caps.in

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ config SOC_GPIO_PIN_COUNT
235235
int
236236
default 26
237237

238+
config SOC_GPIO_SUPPORT_PIN_HYS_FILTER
239+
bool
240+
default y
241+
238242
config SOC_GPIO_SUPPORT_RTC_INDEPENDENT
239243
bool
240244
default y
@@ -259,6 +263,22 @@ config SOC_GPIO_SUPPORT_FORCE_HOLD
259263
bool
260264
default y
261265

266+
config SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP
267+
bool
268+
default y
269+
270+
config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
271+
bool
272+
default y
273+
274+
config SOC_RTCIO_PIN_COUNT
275+
int
276+
default 7
277+
278+
config SOC_RTCIO_HOLD_SUPPORTED
279+
bool
280+
default y
281+
262282
config SOC_DEDIC_GPIO_OUT_CHANNELS_NUM
263283
int
264284
default 8
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#define RTCIO_GPIO5_CHANNEL 0 //RTCIO_CHANNEL_0
10+
#define RTCIO_CHANNEL_0_GPIO_NUM 5
11+
12+
#define RTCIO_GPIO6_CHANNEL 1 //RTCIO_CHANNEL_1
13+
#define RTCIO_CHANNEL_1_GPIO_NUM 6
14+
15+
#define RTCIO_GPIO7_CHANNEL 2 //RTCIO_CHANNEL_2
16+
#define RTCIO_CHANNEL_2_GPIO_NUM 7
17+
18+
#define RTCIO_GPIO8_CHANNEL 3 //RTCIO_CHANNEL_3
19+
#define RTCIO_CHANNEL_3_GPIO_NUM 8
20+
21+
#define RTCIO_GPIO9_CHANNEL 4 //RTCIO_CHANNEL_4
22+
#define RTCIO_CHANNEL_4_GPIO_NUM 9
23+
24+
#define RTCIO_GPIO10_CHANNEL 5 //RTCIO_CHANNEL_5
25+
#define RTCIO_CHANNEL_5_GPIO_NUM 10
26+
27+
#define RTCIO_GPIO11_CHANNEL 6 //RTCIO_CHANNEL_6
28+
#define RTCIO_CHANNEL_6_GPIO_NUM 11

components/soc/esp32h21/include/soc/soc_caps.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@
192192
#define SOC_GPIO_PIN_COUNT 26
193193
// #define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1
194194
// #define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8
195-
// #define SOC_GPIO_SUPPORT_PIN_HYS_FILTER 1
195+
#define SOC_GPIO_SUPPORT_PIN_HYS_FILTER 1
196196

197197
// GPIO peripheral has the ETM extension
198198
// #define SOC_GPIO_SUPPORT_ETM 1
@@ -216,8 +216,10 @@
216216

217217
// Support to force hold all IOs
218218
#define SOC_GPIO_SUPPORT_FORCE_HOLD (1)
219+
// LP_IOs and DIG_IOs can be hold during deep sleep and after waking up
220+
#define SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP (1)
219221
// Support to hold a single digital I/O when the digital domain is powered off
220-
// #define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1)
222+
#define SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP (1)
221223

222224
// The Clock Out signal is route to the pin by GPIO matrix
223225
// #define SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX (1)
@@ -227,9 +229,8 @@
227229
/*-------------------------- RTCIO CAPS --------------------------------------*/
228230
/* No dedicated LP_IOMUX subsystem on ESP32-H2. LP functions are still supported
229231
* for hold, wake & 32kHz crystal functions - via LP_AON registers */
230-
// #define SOC_RTCIO_PIN_COUNT (8U)
231-
// #define SOC_RTCIO_HOLD_SUPPORTED (1)
232-
// #define SOC_RTCIO_VALID_RTCIO_MASK (0x7F80)
232+
#define SOC_RTCIO_PIN_COUNT (7U)
233+
#define SOC_RTCIO_HOLD_SUPPORTED (1)
233234

234235
/*-------------------------- Dedicated GPIO CAPS -----------------------------*/
235236
#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */

components/soc/esp32h21/register/soc/gpio_struct.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ typedef struct {
352352
uint32_t reserved_0c8[3];
353353
volatile gpio_pinn_reg_t pinn[30];
354354
uint32_t reserved_14c[98];
355-
volatile gpio_func_in_sel_cfg_reg_t func_in_sel_cfg[128]; //0-128. reserved: 0-6, 17-19, 19-28, 35-40, 42-45, 56-6, 73-77, 82-87, 95-97, 124-128;
356-
uint32_t reserved_4ac[384];
355+
volatile gpio_func_in_sel_cfg_reg_t func_in_sel_cfg[256]; //0-255. reserved: 0-6, 17-19, 19-28, 35-40, 42-45, 56-6, 73-77, 82-87, 95-97, 162-255;
356+
uint32_t reserved_4ac[256];
357357
volatile gpio_funcn_out_sel_cfg_reg_t funcn_out_sel_cfg[30];
358358
uint32_t reserved_b4c[171];
359359
volatile gpio_clock_gate_reg_t clock_gate;

0 commit comments

Comments
 (0)