From ad5bdc83a73397a25edb04dc06c762d5f808eda1 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Tue, 26 Aug 2025 16:40:14 +0800 Subject: [PATCH] feat(pcnt): support pcnt on esp32h4 --- .../include/driver/pulse_cnt.h | 1 + components/esp_driver_pcnt/src/pulse_cnt.c | 69 ++- .../test_apps/pulse_cnt/README.md | 4 +- components/hal/esp32/include/hal/pcnt_ll.h | 18 +- components/hal/esp32c5/include/hal/pcnt_ll.h | 16 +- components/hal/esp32c6/include/hal/pcnt_ll.h | 18 +- components/hal/esp32h2/include/hal/pcnt_ll.h | 24 +- components/hal/esp32h21/include/hal/pcnt_ll.h | 16 +- components/hal/esp32h4/include/hal/pcnt_ll.h | 527 ++++++++++++++++++ components/hal/esp32p4/include/hal/pcnt_ll.h | 23 +- components/hal/esp32s2/include/hal/pcnt_ll.h | 16 +- components/hal/esp32s3/include/hal/pcnt_ll.h | 16 +- components/hal/include/hal/pcnt_types.h | 16 + .../soc/esp32/include/soc/clk_tree_defs.h | 15 + .../soc/esp32c5/include/soc/clk_tree_defs.h | 16 + .../soc/esp32c6/include/soc/clk_tree_defs.h | 16 + .../soc/esp32h2/include/soc/clk_tree_defs.h | 16 + .../soc/esp32h21/include/soc/clk_tree_defs.h | 16 + .../esp32h4/include/soc/Kconfig.soc_caps.in | 16 + .../soc/esp32h4/include/soc/clk_tree_defs.h | 17 + components/soc/esp32h4/include/soc/soc_caps.h | 10 +- .../soc/esp32h4/include/soc/soc_caps_full.h | 6 + components/soc/esp32h4/pcnt_periph.c | 70 +++ .../soc/esp32h4/register/soc/pcnt_struct.h | 97 +--- .../soc/esp32p4/include/soc/clk_tree_defs.h | 16 + .../soc/esp32s2/include/soc/clk_tree_defs.h | 15 + .../soc/esp32s3/include/soc/clk_tree_defs.h | 15 + components/soc/include/soc/pcnt_periph.h | 2 +- docs/docs_not_updated/esp32h4.txt | 1 - .../peripherals/pcnt/rotary_encoder/README.md | 4 +- 30 files changed, 997 insertions(+), 115 deletions(-) create mode 100644 components/hal/esp32h4/include/hal/pcnt_ll.h create mode 100644 components/soc/esp32h4/pcnt_periph.c diff --git a/components/esp_driver_pcnt/include/driver/pulse_cnt.h b/components/esp_driver_pcnt/include/driver/pulse_cnt.h index 98accc1be3..b12b201fe1 100644 --- a/components/esp_driver_pcnt/include/driver/pulse_cnt.h +++ b/components/esp_driver_pcnt/include/driver/pulse_cnt.h @@ -59,6 +59,7 @@ typedef struct { * @brief PCNT unit configuration */ typedef struct { + pcnt_clock_source_t clk_src; /*!< Clock source for PCNT unit */ int low_limit; /*!< Low limitation of the count unit, should be lower than 0 */ int high_limit; /*!< High limitation of the count unit, should be higher than 0 */ int intr_priority; /*!< PCNT interrupt priority, diff --git a/components/esp_driver_pcnt/src/pulse_cnt.c b/components/esp_driver_pcnt/src/pulse_cnt.c index 0858c496bd..b9daab3090 100644 --- a/components/esp_driver_pcnt/src/pulse_cnt.c +++ b/components/esp_driver_pcnt/src/pulse_cnt.c @@ -25,12 +25,13 @@ #include "soc/gpio_pins.h" #include "hal/pcnt_hal.h" #include "hal/pcnt_ll.h" +#include "driver/gpio.h" +#include "driver/pulse_cnt.h" #include "esp_private/esp_clk.h" #include "esp_private/periph_ctrl.h" #include "esp_private/sleep_retention.h" -#include "driver/gpio.h" #include "esp_private/gpio.h" -#include "driver/pulse_cnt.h" +#include "esp_private/esp_clk_tree_common.h" #include "esp_memory_utils.h" // If ISR handler is allowed to run whilst cache is disabled, @@ -49,6 +50,12 @@ #define PCNT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED +#if SOC_PERIPH_CLK_CTRL_SHARED +#define PCNT_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define PCNT_CLOCK_SRC_ATOMIC() +#endif + #if !SOC_RCC_IS_INDEPENDENT #define PCNT_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #else @@ -75,6 +82,7 @@ struct pcnt_platform_t { struct pcnt_group_t { int group_id; // Group ID, index from 0 int intr_priority; // PCNT interrupt priority + pcnt_clock_source_t clk_src; // PCNT clock source portMUX_TYPE spinlock; // to protect per-group register level concurrent access pcnt_hal_context_t hal; pcnt_unit_t *units[SOC_PCNT_ATTR(UNITS_PER_INST)]; // array of PCNT units @@ -140,6 +148,7 @@ static pcnt_platform_t s_platform; static pcnt_group_t *pcnt_acquire_group_handle(int group_id); static void pcnt_release_group_handle(pcnt_group_t *group); static void pcnt_default_isr(void *args); +static esp_err_t pcnt_select_periph_clock(pcnt_unit_t *unit, pcnt_clock_source_t clk_src); static esp_err_t pcnt_register_to_group(pcnt_unit_t *unit) { @@ -222,6 +231,10 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re int group_id = group->group_id; int unit_id = unit->unit_id; + pcnt_clock_source_t pcnt_clk_src = config->clk_src ? config->clk_src : PCNT_CLK_SRC_DEFAULT; + ESP_GOTO_ON_ERROR(pcnt_select_periph_clock(unit, pcnt_clk_src), err, TAG, "select periph clock failed"); + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)group->clk_src, true), err, TAG, "clock source enable failed"); + // if interrupt priority specified before, it cannot be changed until the group is released // check if the new priority specified consistents with the old one bool intr_priority_conflict = false; @@ -323,6 +336,8 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit) #endif // SOC_PCNT_SUPPORT_CLEAR_SIGNAL ESP_LOGD(TAG, "del unit (%d,%d)", group_id, unit_id); + // disable clock source + ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)group->clk_src, false), TAG, "clock source disable failed"); // recycle memory resource ESP_RETURN_ON_ERROR(pcnt_destroy(unit), TAG, "destroy pcnt unit failed"); return ESP_OK; @@ -930,14 +945,6 @@ static pcnt_group_t *pcnt_acquire_group_handle(int group_id) _lock_release(&s_platform.mutex); if (new_group) { -#if CONFIG_PM_ENABLE - // PCNT uses the APB as its function clock, - // and its filter module is sensitive to the clock frequency - // thus we choose the APM_MAX lock to prevent the function clock from being changed - if (esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, pcnt_periph_signals.groups[group_id].module_name, &group->pm_lock) != ESP_OK) { - ESP_LOGW(TAG, "create pm lock failed"); - } -#endif ESP_LOGD(TAG, "new group (%d) at %p", group_id, group); } @@ -975,6 +982,48 @@ static void pcnt_release_group_handle(pcnt_group_t *group) } } +static esp_err_t pcnt_select_periph_clock(pcnt_unit_t *unit, pcnt_clock_source_t clk_src) +{ + esp_err_t ret = ESP_OK; + pcnt_group_t *group = unit->group; + bool clock_selection_conflict = false; + bool do_clock_init = false; + // group clock source is shared by all units + portENTER_CRITICAL(&group->spinlock); + if (group->clk_src == 0) { + group->clk_src = clk_src; + do_clock_init = true; + } else { + clock_selection_conflict = (group->clk_src != clk_src); + } + portEXIT_CRITICAL(&group->spinlock); + ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_ARG, TAG, + "group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src); + + if (do_clock_init) { + +#if CONFIG_PM_ENABLE + // PCNT filter module is sensitive to the clock frequency + // to make the pcnt works reliable, the source clock must stay alive and unchanged + esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP; +#if PCNT_LL_CLOCK_SUPPORT_APB + if (clk_src == PCNT_CLK_SRC_APB) { + // APB clock frequency can be changed during DFS + // thus we choose the APM_MAX lock to prevent the function clock from being changed + pm_lock_type = ESP_PM_APB_FREQ_MAX; + } +#endif // PCNT_LL_CLOCK_SUPPORT_APB + ret = esp_pm_lock_create(pm_lock_type, 0, soc_pcnt_signals[group->group_id].module_name, &group->pm_lock); + ESP_RETURN_ON_ERROR(ret, TAG, "create pm lock failed"); +#endif // CONFIG_PM_ENABLE + + PCNT_CLOCK_SRC_ATOMIC() { + pcnt_ll_set_clock_source(group->hal.dev, clk_src); + } + } + return ret; +} + IRAM_ATTR static void pcnt_default_isr(void *args) { bool need_yield = false; diff --git a/components/esp_driver_pcnt/test_apps/pulse_cnt/README.md b/components/esp_driver_pcnt/test_apps/pulse_cnt/README.md index c0916a10f2..7a0b38da27 100644 --- a/components/esp_driver_pcnt/test_apps/pulse_cnt/README.md +++ b/components/esp_driver_pcnt/test_apps/pulse_cnt/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | diff --git a/components/hal/esp32/include/hal/pcnt_ll.h b/components/hal/esp32/include/hal/pcnt_ll.h index 612611fa70..5a589c9001 100644 --- a/components/hal/esp32/include/hal/pcnt_ll.h +++ b/components/hal/esp32/include/hal/pcnt_ll.h @@ -19,10 +19,11 @@ #include #include #include "soc/pcnt_struct.h" -#include "hal/pcnt_types.h" -#include "hal/misc.h" #include "soc/dport_access.h" #include "soc/dport_reg.h" +#include "hal/pcnt_types.h" +#include "hal/misc.h" +#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -45,6 +46,19 @@ typedef enum { #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} /** * @brief Set PCNT channel edge action diff --git a/components/hal/esp32c5/include/hal/pcnt_ll.h b/components/hal/esp32c5/include/hal/pcnt_ll.h index 19e2b1e52a..e7f84e102c 100644 --- a/components/hal/esp32c5/include/hal/pcnt_ll.h +++ b/components/hal/esp32c5/include/hal/pcnt_ll.h @@ -10,9 +10,10 @@ #include #include #include "soc/pcnt_struct.h" +#include "soc/pcr_struct.h" #include "hal/pcnt_types.h" #include "hal/misc.h" -#include "soc/pcr_struct.h" +#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -40,6 +41,19 @@ typedef enum { #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} /** * @brief Set PCNT channel edge action diff --git a/components/hal/esp32c6/include/hal/pcnt_ll.h b/components/hal/esp32c6/include/hal/pcnt_ll.h index 1b2a50d722..a328d2b558 100644 --- a/components/hal/esp32c6/include/hal/pcnt_ll.h +++ b/components/hal/esp32c6/include/hal/pcnt_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,8 +18,9 @@ #include #include #include "soc/pcnt_struct.h" -#include "hal/pcnt_types.h" #include "soc/pcr_struct.h" +#include "hal/pcnt_types.h" +#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -42,6 +43,19 @@ typedef enum { #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} /** * @brief Set PCNT channel edge action diff --git a/components/hal/esp32h2/include/hal/pcnt_ll.h b/components/hal/esp32h2/include/hal/pcnt_ll.h index c83011cc0a..9ff52d658c 100644 --- a/components/hal/esp32h2/include/hal/pcnt_ll.h +++ b/components/hal/esp32h2/include/hal/pcnt_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,11 +18,12 @@ #include #include #include "soc/pcnt_struct.h" -#include "hal/pcnt_types.h" -#include "hal/misc.h" -#include "hal/efuse_hal.h" #include "soc/chip_revision.h" #include "soc/pcr_struct.h" +#include "hal/pcnt_types.h" +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/efuse_hal.h" #ifdef __cplusplus extern "C" { @@ -48,9 +49,22 @@ typedef enum { PCNT_LL_STEP_EVENT_REACH_INTERVAL } pcnt_ll_step_event_id_t; -#define PCNT_LL_STEP_NOTIFY_DIR_LIMIT 1 #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_STEP_NOTIFY_DIR_LIMIT 1 +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} /** * @brief Set PCNT channel edge action diff --git a/components/hal/esp32h21/include/hal/pcnt_ll.h b/components/hal/esp32h21/include/hal/pcnt_ll.h index c104fbe23a..16e9c46642 100644 --- a/components/hal/esp32h21/include/hal/pcnt_ll.h +++ b/components/hal/esp32h21/include/hal/pcnt_ll.h @@ -10,9 +10,10 @@ #include #include #include "soc/pcnt_struct.h" +#include "soc/pcr_struct.h" #include "hal/pcnt_types.h" #include "hal/misc.h" -#include "soc/pcr_struct.h" +#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -40,6 +41,19 @@ typedef enum { #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} /** * @brief Set PCNT channel edge action diff --git a/components/hal/esp32h4/include/hal/pcnt_ll.h b/components/hal/esp32h4/include/hal/pcnt_ll.h new file mode 100644 index 0000000000..b2bbba30ba --- /dev/null +++ b/components/hal/esp32h4/include/hal/pcnt_ll.h @@ -0,0 +1,527 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include "soc/pcnt_struct.h" +#include "soc/pcr_struct.h" +#include "hal/pcnt_types.h" +#include "hal/misc.h" +#include "hal/assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT) : NULL) +#define PCNT_LL_MAX_GLITCH_WIDTH 1023 +#define PCNT_LL_MAX_LIM SHRT_MAX +#define PCNT_LL_MIN_LIM SHRT_MIN + +typedef enum { + PCNT_LL_WATCH_EVENT_INVALID = -1, + PCNT_LL_WATCH_EVENT_THRES1, + PCNT_LL_WATCH_EVENT_THRES0, + PCNT_LL_WATCH_EVENT_LOW_LIMIT, + PCNT_LL_WATCH_EVENT_HIGH_LIMIT, + PCNT_LL_WATCH_EVENT_ZERO_CROSS, + PCNT_LL_WATCH_EVENT_MAX +} pcnt_ll_watch_event_id_t; + +typedef enum { + PCNT_LL_STEP_EVENT_REACH_INTERVAL_FORWARD = PCNT_LL_WATCH_EVENT_MAX, + PCNT_LL_STEP_EVENT_REACH_INTERVAL_BACKWARD, +} pcnt_ll_step_event_id_t; + +#define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) +#define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + switch (clk_src) { + case PCNT_CLK_SRC_XTAL: + PCR.pcnt_conf.pcnt_clk_sel = 0; + break; + case PCNT_CLK_SRC_RC_FAST: + PCR.pcnt_conf.pcnt_clk_sel = 1; + break; + default: + HAL_ASSERT(false && "unsupported clock source"); + break; + } +} + +/** + * @brief Set PCNT channel edge action + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param channel PCNT channel number + * @param pos_act Counter action when detecting positive edge + * @param neg_act Counter action when detecting negative edge + */ +static inline void pcnt_ll_set_edge_action(pcnt_dev_t *hw, uint32_t unit, uint32_t channel, pcnt_channel_edge_action_t pos_act, pcnt_channel_edge_action_t neg_act) +{ + if (channel == 0) { + hw->conf_unit[unit].conf0.ch0_pos_mode_un = pos_act; + hw->conf_unit[unit].conf0.ch0_neg_mode_un = neg_act; + } else { + hw->conf_unit[unit].conf0.ch1_pos_mode_un = pos_act; + hw->conf_unit[unit].conf0.ch1_neg_mode_un = neg_act; + } +} + +/** + * @brief Set PCNT channel level action + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param channel PCNT channel number + * @param high_act Counter action when control signal is high level + * @param low_act Counter action when control signal is low level + */ +static inline void pcnt_ll_set_level_action(pcnt_dev_t *hw, uint32_t unit, uint32_t channel, pcnt_channel_level_action_t high_act, pcnt_channel_level_action_t low_act) +{ + if (channel == 0) { + hw->conf_unit[unit].conf0.ch0_hctrl_mode_un = high_act; + hw->conf_unit[unit].conf0.ch0_lctrl_mode_un = low_act; + } else { + hw->conf_unit[unit].conf0.ch1_hctrl_mode_un = high_act; + hw->conf_unit[unit].conf0.ch1_lctrl_mode_un = low_act; + } +} + +/** + * @brief Get pulse counter value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit Pulse Counter unit number + * @return PCNT count value (a signed integer) + */ +__attribute__((always_inline)) +static inline int pcnt_ll_get_count(pcnt_dev_t *hw, uint32_t unit) +{ + pcnt_un_cnt_reg_t cnt_reg; + cnt_reg.val = hw->cnt_unit[unit].val; + + int16_t value = cnt_reg.pulse_cnt_un; + return value; +} + +/** + * @brief Pause PCNT counter of PCNT unit + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + */ +__attribute__((always_inline)) +static inline void pcnt_ll_stop_count(pcnt_dev_t *hw, uint32_t unit) +{ + hw->ctrl.val |= 1 << (2 * unit + 1); +} + +/** + * @brief Resume counting for PCNT counter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number, select from uint32_t + */ +__attribute__((always_inline)) +static inline void pcnt_ll_start_count(pcnt_dev_t *hw, uint32_t unit) +{ + hw->ctrl.val &= ~(1 << (2 * unit + 1)); +} + +/** + * @brief Clear PCNT counter value to zero + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number, select from uint32_t + */ +__attribute__((always_inline)) +static inline void pcnt_ll_clear_count(pcnt_dev_t *hw, uint32_t unit) +{ + hw->ctrl.val |= 1 << (2 * unit); + hw->ctrl.val &= ~(1 << (2 * unit)); +} + +/** + * @brief Enable PCNT step comparator event + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param enable true to enable, false to disable + */ +static inline void pcnt_ll_enable_step_notify(pcnt_dev_t *hw, uint32_t unit, bool enable) +{ + if (enable) { + hw->ctrl.val |= 1 << (8 + unit); + } else { + hw->ctrl.val &= ~(1 << (8 + unit)); + } +} + +/** + * @brief Set PCNT step value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param direction PCNT step direction + * @param value PCNT step value + */ +static inline void pcnt_ll_set_step_value(pcnt_dev_t *hw, uint32_t unit, pcnt_step_direction_t direction, uint16_t value) +{ + if (direction == PCNT_STEP_FORWARD) { + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->conf_unit[unit].conf3, cnt_h_step_un, value); + } else { + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->conf_unit[unit].conf3, cnt_l_step_un, value); + } +} + +/** + * @brief Enable PCNT interrupt for PCNT unit + * @note Each PCNT unit has five watch point events that share the same interrupt bit. + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit_mask PCNT units mask + * @param enable True to enable interrupt, False to disable interrupt + */ +static inline void pcnt_ll_enable_intr(pcnt_dev_t *hw, uint32_t unit_mask, bool enable) +{ + if (enable) { + hw->int_ena.val |= unit_mask; + } else { + hw->int_ena.val &= ~unit_mask; + } +} + +/** + * @brief Get PCNT interrupt status + * + * @param hw Peripheral PCNT hardware instance address. + * @return Interrupt status word + */ +__attribute__((always_inline)) +static inline uint32_t pcnt_ll_get_intr_status(pcnt_dev_t *hw) +{ + return hw->int_st.val; +} + +/** + * @brief Clear PCNT interrupt status + * + * @param hw Peripheral PCNT hardware instance address. + * @param status value to clear interrupt status + */ +__attribute__((always_inline)) +static inline void pcnt_ll_clear_intr_status(pcnt_dev_t *hw, uint32_t status) +{ + hw->int_clr.val = status; +} + +/** + * @brief Enable PCNT high limit event + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param enable true to enable, false to disable + */ +static inline void pcnt_ll_enable_high_limit_event(pcnt_dev_t *hw, uint32_t unit, bool enable) +{ + hw->conf_unit[unit].conf0.thr_h_lim_en_un = enable; +} + +/** + * @brief Enable PCNT low limit event + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param enable true to enable, false to disable + */ +static inline void pcnt_ll_enable_low_limit_event(pcnt_dev_t *hw, uint32_t unit, bool enable) +{ + hw->conf_unit[unit].conf0.thr_l_lim_en_un = enable; +} + +/** + * @brief Enable PCNT zero cross event + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param enable true to enable, false to disable + */ +static inline void pcnt_ll_enable_zero_cross_event(pcnt_dev_t *hw, uint32_t unit, bool enable) +{ + hw->conf_unit[unit].conf0.thr_zero_en_un = enable; +} + +/** + * @brief Enable PCNT threshold event + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param thres Threshold ID + * @param enable true to enable, false to disable + */ +static inline void pcnt_ll_enable_thres_event(pcnt_dev_t *hw, uint32_t unit, uint32_t thres, bool enable) +{ + if (thres == 0) { + hw->conf_unit[unit].conf0.thr_thres0_en_un = enable; + } else { + hw->conf_unit[unit].conf0.thr_thres1_en_un = enable; + } +} + +/** + * @brief Disable all PCNT threshold events + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit unit number + */ +static inline void pcnt_ll_disable_all_events(pcnt_dev_t *hw, uint32_t unit) +{ + hw->conf_unit[unit].conf0.val &= ~(PCNT_LL_WATCH_EVENT_MASK << 11); +} + +/** + * @brief Set PCNT high limit value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param value PCNT high limit value + */ +static inline void pcnt_ll_set_high_limit_value(pcnt_dev_t *hw, uint32_t unit, int value) +{ + pcnt_un_conf2_reg_t conf2_reg; + conf2_reg.val = hw->conf_unit[unit].conf2.val; + + conf2_reg.cnt_h_lim_un = value; + hw->conf_unit[unit].conf2.val = conf2_reg.val; +} + +/** + * @brief Set PCNT low limit value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param value PCNT low limit value + */ +static inline void pcnt_ll_set_low_limit_value(pcnt_dev_t *hw, uint32_t unit, int value) +{ + pcnt_un_conf2_reg_t conf2_reg; + conf2_reg.val = hw->conf_unit[unit].conf2.val; + + conf2_reg.cnt_l_lim_un = value; + hw->conf_unit[unit].conf2.val = conf2_reg.val; +} + +/** + * @brief Set PCNT threshold value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param thres Threshold ID + * @param value PCNT threshold value + */ +static inline void pcnt_ll_set_thres_value(pcnt_dev_t *hw, uint32_t unit, uint32_t thres, int value) +{ + pcnt_un_conf1_reg_t conf1_reg; + conf1_reg.val = hw->conf_unit[unit].conf1.val; + + if (thres == 0) { + conf1_reg.cnt_thres0_un = value; + } else { + conf1_reg.cnt_thres1_un = value; + } + hw->conf_unit[unit].conf1.val = conf1_reg.val; +} + +/** + * @brief Get PCNT high limit value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @return PCNT high limit value + */ +static inline int pcnt_ll_get_high_limit_value(pcnt_dev_t *hw, uint32_t unit) +{ + pcnt_un_conf2_reg_t conf2_reg; + conf2_reg.val = hw->conf_unit[unit].conf2.val; + + int16_t value = conf2_reg.cnt_h_lim_un; + return value; +} + +/** + * @brief Get PCNT low limit value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @return PCNT high limit value + */ +static inline int pcnt_ll_get_low_limit_value(pcnt_dev_t *hw, uint32_t unit) +{ + pcnt_un_conf2_reg_t conf2_reg; + conf2_reg.val = hw->conf_unit[unit].conf2.val; + + int16_t value = conf2_reg.cnt_l_lim_un ; + return value; +} + +/** + * @brief Get PCNT threshold value + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param thres Threshold ID + * @return PCNT threshold value + */ +__attribute__((always_inline)) +static inline int pcnt_ll_get_thres_value(pcnt_dev_t *hw, uint32_t unit, uint32_t thres) +{ + int16_t value; + pcnt_un_conf1_reg_t conf1_reg; + conf1_reg.val = hw->conf_unit[unit].conf1.val; + + if (thres == 0) { + value = conf1_reg.cnt_thres0_un ; + } else { + value = conf1_reg.cnt_thres1_un ; + } + return value; +} + +/** + * @brief Get PCNT unit runtime status + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @return PCNT unit runtime status + */ +static inline uint32_t pcnt_ll_get_unit_status(pcnt_dev_t *hw, uint32_t unit) +{ + return hw->status_unit[unit].val; +} + +/** + * @brief Get PCNT zero cross mode + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @return Zero cross mode + */ +__attribute__((always_inline)) +static inline pcnt_unit_zero_cross_mode_t pcnt_ll_get_zero_cross_mode(pcnt_dev_t *hw, uint32_t unit) +{ + return (pcnt_unit_zero_cross_mode_t)(hw->status_unit[unit].val & 0x03); +} + +/** + * @brief Get PCNT event status + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @return Event status word + */ +__attribute__((always_inline)) +static inline uint32_t pcnt_ll_get_event_status(pcnt_dev_t *hw, uint32_t unit) +{ + return hw->status_unit[unit].val >> 2; +} + +/** + * @brief Set PCNT glitch filter threshold + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param filter_val PCNT signal filter value, counter in APB_CLK cycles. + * Any pulses lasting shorter than this will be ignored when the filter is enabled. + */ +static inline void pcnt_ll_set_glitch_filter_thres(pcnt_dev_t *hw, uint32_t unit, uint32_t filter_val) +{ + hw->conf_unit[unit].conf0.filter_thres_un = filter_val; +} + +/** + * @brief Get PCNT glitch filter threshold + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @return glitch filter threshold + */ +static inline uint32_t pcnt_ll_get_glitch_filter_thres(pcnt_dev_t *hw, uint32_t unit) +{ + return hw->conf_unit[unit].conf0.filter_thres_un; +} + +/** + * @brief Enable PCNT glitch filter + * + * @param hw Peripheral PCNT hardware instance address. + * @param unit PCNT unit number + * @param enable True to enable the filter, False to disable the filter + */ +static inline void pcnt_ll_enable_glitch_filter(pcnt_dev_t *hw, uint32_t unit, bool enable) +{ + hw->conf_unit[unit].conf0.filter_en_un = enable; +} + +/** + * @brief Get interrupt status register address. + * + * @param hw Beginning address of the peripheral registers. + * + * @return Interrupt status register address + */ +static inline volatile void *pcnt_ll_get_intr_status_reg(pcnt_dev_t *hw) +{ + return &hw->int_st.val; +} + +/** + * @brief Enable or disable the bus clock for the PCNT module + * + * @param set_bit True to set bit, false to clear bit + */ +static inline void pcnt_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.pcnt_conf.pcnt_clk_en = enable; + PCR.pcnt_conf.pcnt_reg_clk_en = enable; +} + +/** + * @brief Reset the PCNT module + */ +static inline void pcnt_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.pcnt_conf.pcnt_rst_en = 1; + PCR.pcnt_conf.pcnt_rst_en = 0; +} + +/** + * @brief Check if the step notify is supported + */ +static inline bool pcnt_ll_is_step_notify_supported(int group_id) +{ + (void)group_id; + return true; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/pcnt_ll.h b/components/hal/esp32p4/include/hal/pcnt_ll.h index 3a9cabcf90..fba58b90a3 100644 --- a/components/hal/esp32p4/include/hal/pcnt_ll.h +++ b/components/hal/esp32p4/include/hal/pcnt_ll.h @@ -18,9 +18,10 @@ #include #include #include "soc/pcnt_struct.h" +#include "soc/hp_sys_clkrst_struct.h" #include "hal/pcnt_types.h" #include "hal/misc.h" -#include "soc/hp_sys_clkrst_struct.h" +#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -43,6 +44,26 @@ typedef enum { #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void _pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define pcnt_ll_set_clock_source(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _pcnt_ll_set_clock_source(__VA_ARGS__); \ + } while(0) /** * @brief Set PCNT channel edge action diff --git a/components/hal/esp32s2/include/hal/pcnt_ll.h b/components/hal/esp32s2/include/hal/pcnt_ll.h index e18757b6bc..d52595fa57 100644 --- a/components/hal/esp32s2/include/hal/pcnt_ll.h +++ b/components/hal/esp32s2/include/hal/pcnt_ll.h @@ -18,9 +18,10 @@ #include #include #include "soc/pcnt_struct.h" -#include "hal/pcnt_types.h" #include "soc/dport_reg.h" #include "soc/dport_access.h" +#include "hal/pcnt_types.h" +#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -43,6 +44,19 @@ typedef enum { #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} /** * @brief Set PCNT channel edge action diff --git a/components/hal/esp32s3/include/hal/pcnt_ll.h b/components/hal/esp32s3/include/hal/pcnt_ll.h index b5b18cb686..5a67c3e682 100644 --- a/components/hal/esp32s3/include/hal/pcnt_ll.h +++ b/components/hal/esp32s3/include/hal/pcnt_ll.h @@ -18,8 +18,9 @@ #include #include #include "soc/pcnt_struct.h" -#include "hal/pcnt_types.h" #include "soc/system_struct.h" +#include "hal/pcnt_types.h" +#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -42,6 +43,19 @@ typedef enum { #define PCNT_LL_WATCH_EVENT_MASK ((1 << PCNT_LL_WATCH_EVENT_MAX) - 1) #define PCNT_LL_UNIT_WATCH_EVENT(unit_id) (1 << (unit_id)) +#define PCNT_LL_CLOCK_SUPPORT_APB 1 + +/** + * @brief Set clock source for pcnt group + * + * @param hw Peripheral PCNT hardware instance address. + * @param clk_src Clock source + */ +static inline void pcnt_ll_set_clock_source(pcnt_dev_t *hw, pcnt_clock_source_t clk_src) +{ + (void)hw; + HAL_ASSERT(clk_src == PCNT_CLK_SRC_APB && "unsupported clock source"); +} /** * @brief Set PCNT channel edge action diff --git a/components/hal/include/hal/pcnt_types.h b/components/hal/include/hal/pcnt_types.h index 1b7c08c104..e0dc9667eb 100644 --- a/components/hal/include/hal/pcnt_types.h +++ b/components/hal/include/hal/pcnt_types.h @@ -6,10 +6,26 @@ #pragma once +#include "soc/clk_tree_defs.h" +#include "soc/soc_caps.h" + #ifdef __cplusplus extern "C" { #endif +#if SOC_HAS(PCNT) +/** + * @brief PCNT clock source + * @note User should select the clock source based on the power and resolution requirement + */ +typedef soc_periph_pcnt_clk_src_t pcnt_clock_source_t; +#else +/** + * @brief Default type + */ +typedef int pcnt_clock_source_t; +#endif + /** * @brief PCNT channel action on control level */ diff --git a/components/soc/esp32/include/soc/clk_tree_defs.h b/components/soc/esp32/include/soc/clk_tree_defs.h index 5c62fccb06..08ce95d449 100644 --- a/components/soc/esp32/include/soc/clk_tree_defs.h +++ b/components/soc/esp32/include/soc/clk_tree_defs.h @@ -218,6 +218,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_APB, /*!< RMT source clock default choice is APB */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32c5/include/soc/clk_tree_defs.h b/components/soc/esp32c5/include/soc/clk_tree_defs.h index f3a8e089f3..9b68ac9cd0 100644 --- a/components/soc/esp32c5/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c5/include/soc/clk_tree_defs.h @@ -87,6 +87,7 @@ typedef enum { SOC_MOD_CLK_RTC_FAST, /*!< RTC_FAST_CLK can be sourced from XTAL_D2 or RC_FAST by configuring soc_rtc_fast_clk_src_t */ SOC_MOD_CLK_RTC_SLOW, /*!< RTC_SLOW_CLK can be sourced from RC_SLOW, XTAL32K, or OSC_SLOW by configuring soc_rtc_slow_clk_src_t */ // For digital domain: peripherals, WIFI, BLE + SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_F12M, /*!< PLL_F12M_CLK is derived from SPLL (clock gating + fixed divider of 40), it has a fixed frequency of 12MHz */ SOC_MOD_CLK_PLL_F20M, /*!< PLL_F20M_CLK is derived from SPLL (clock gating + fixed divider of 24), it has a fixed frequency of 20MHz */ SOC_MOD_CLK_PLL_F40M, /*!< PLL_F40M_CLK is derived from SPLL (clock gating + fixed divider of 12), it has a fixed frequency of 40MHz */ @@ -218,6 +219,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock default choice is PLL_F80M */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32c6/include/soc/clk_tree_defs.h b/components/soc/esp32c6/include/soc/clk_tree_defs.h index bd72e212f0..11f02a6c1d 100644 --- a/components/soc/esp32c6/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c6/include/soc/clk_tree_defs.h @@ -140,6 +140,7 @@ typedef enum { SOC_MOD_CLK_RTC_FAST, /*!< RTC_FAST_CLK can be sourced from XTAL_D2 or RC_FAST by configuring soc_rtc_fast_clk_src_t */ SOC_MOD_CLK_RTC_SLOW, /*!< RTC_SLOW_CLK can be sourced from RC_SLOW, XTAL32K, RC32K, or OSC_SLOW by configuring soc_rtc_slow_clk_src_t */ // For digital domain: peripherals, WIFI, BLE + SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_F80M, /*!< PLL_F80M_CLK is derived from PLL (clock gating + fixed divider of 6), it has a fixed frequency of 80MHz */ SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from PLL (clock gating + fixed divider of 3), it has a fixed frequency of 160MHz */ SOC_MOD_CLK_PLL_F240M, /*!< PLL_F240M_CLK is derived from PLL (clock gating + fixed divider of 2), it has a fixed frequency of 240MHz */ @@ -215,6 +216,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock default choice is PLL_F80M */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32h2/include/soc/clk_tree_defs.h b/components/soc/esp32h2/include/soc/clk_tree_defs.h index a2d3b73c53..73d01df674 100644 --- a/components/soc/esp32h2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h2/include/soc/clk_tree_defs.h @@ -152,6 +152,7 @@ typedef enum { SOC_MOD_CLK_RTC_FAST, /*!< RTC_FAST_CLK can be sourced from XTAL_D2, RC_FAST, or LP_PLL by configuring soc_rtc_fast_clk_src_t */ SOC_MOD_CLK_RTC_SLOW, /*!< RTC_SLOW_CLK can be sourced from RC_SLOW, XTAL32K, OSC_SLOW, or RC32K by configuring soc_rtc_slow_clk_src_t */ // For digital domain: peripherals, WIFI, BLE + SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_F48M, /*!< PLL_F48M_CLK is derived from PLL (clock gating + fixed divider of 2), it has a fixed frequency of 48MHz */ SOC_MOD_CLK_PLL_F64M, /*!< PLL_F64M_CLK is derived from FLASH_PLL (clock gating), it has a fixed frequency of 64MHz */ SOC_MOD_CLK_PLL_F96M, /*!< PLL_F96M_CLK is derived from PLL (clock gating), it has a fixed frequency of 96MHz */ @@ -222,6 +223,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< RMT source clock default choice is XTAL */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32h21/include/soc/clk_tree_defs.h b/components/soc/esp32h21/include/soc/clk_tree_defs.h index 3432d7834a..69a7ff64f2 100644 --- a/components/soc/esp32h21/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h21/include/soc/clk_tree_defs.h @@ -133,6 +133,7 @@ typedef enum { SOC_MOD_CLK_RTC_FAST, /*!< RTC_FAST_CLK can be sourced from XTAL_D2, RC_FAST, or LP_PLL by configuring soc_rtc_fast_clk_src_t */ SOC_MOD_CLK_RTC_SLOW, /*!< RTC_SLOW_CLK can be sourced from RC_SLOW, XTAL32K, OSC_SLOW, or RC32K by configuring soc_rtc_slow_clk_src_t */ // For digital domain: peripherals, BLE + SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_F48M, /*!< PLL_F48M_CLK is derived from PLL (clock gating + fixed divider of 2), it has a fixed frequency of 48MHz */ // SOC_MOD_CLK_XTAL_X2_F64M, /*!< XTAL_X2_F64M_CLK is derived from XTAL_X2 (clock gating), it has a fixed frequency of 64MHz */ SOC_MOD_CLK_PLL_F96M, /*!< PLL_F96M_CLK is derived from PLL (clock gating), it has a fixed frequency of 96MHz */ @@ -211,6 +212,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< RMT source clock default choice is XTAL */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 035e132b26..feb45b507b 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -19,6 +19,10 @@ config SOC_GPTIMER_SUPPORTED bool default y +config SOC_PCNT_SUPPORTED + bool + default y + config SOC_TWAI_SUPPORTED bool default y @@ -519,6 +523,18 @@ config SOC_MMU_DI_VADDR_SHARED bool default y +config SOC_PCNT_SUPPORT_RUNTIME_THRES_UPDATE + bool + default y + +config SOC_PCNT_SUPPORT_CLEAR_SIGNAL + bool + default y + +config SOC_PCNT_SUPPORT_STEP_NOTIFY + bool + default y + config SOC_RMT_GROUPS int default 1 diff --git a/components/soc/esp32h4/include/soc/clk_tree_defs.h b/components/soc/esp32h4/include/soc/clk_tree_defs.h index 8bd291b5bf..d6c9e0a1a6 100644 --- a/components/soc/esp32h4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h4/include/soc/clk_tree_defs.h @@ -214,6 +214,23 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< RMT source clock default choice is XTAL */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + PCNT_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + // PCNT_CLK_SRC_XTAL_X2_F32M = SOC_MOD_CLK_XTAL_X2_F32M, /*!< Select XTAL_X2_F32M as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default choice */ +} soc_periph_pcnt_clk_src_t; + ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 7cf25e5666..df429adcd1 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -38,7 +38,7 @@ #define SOC_GDMA_SUPPORTED 1 #define SOC_AHB_GDMA_SUPPORTED 1 #define SOC_GPTIMER_SUPPORTED 1 -// #define SOC_PCNT_SUPPORTED 1 // TODO: [ESP32H4] IDF-12338 +#define SOC_PCNT_SUPPORTED 1 // #define SOC_MCPWM_SUPPORTED 1 // TODO: [ESP32H4] IDF-12380 #define SOC_TWAI_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 @@ -315,11 +315,9 @@ // #define SOC_MPU_REGION_WO_SUPPORTED 0 /*-------------------------- PCNT CAPS ---------------------------------------*/ -// #define SOC_PCNT_GROUPS 1U -// #define SOC_PCNT_UNITS_PER_GROUP 4 -// #define SOC_PCNT_CHANNELS_PER_UNIT 2 -// #define SOC_PCNT_THRES_POINT_PER_UNIT 2 -// #define SOC_PCNT_SUPPORT_RUNTIME_THRES_UPDATE 1 +#define SOC_PCNT_SUPPORT_RUNTIME_THRES_UPDATE 1 +#define SOC_PCNT_SUPPORT_CLEAR_SIGNAL 1 +#define SOC_PCNT_SUPPORT_STEP_NOTIFY 1 /*--------------------------- RMT CAPS ---------------------------------------*/ #define SOC_RMT_GROUPS 1U /*!< One RMT group */ diff --git a/components/soc/esp32h4/include/soc/soc_caps_full.h b/components/soc/esp32h4/include/soc/soc_caps_full.h index d9ce210e7d..95748b6bc6 100644 --- a/components/soc/esp32h4/include/soc/soc_caps_full.h +++ b/components/soc/esp32h4/include/soc/soc_caps_full.h @@ -24,6 +24,12 @@ #define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances #define _SOC_CAPS_SDM_CHANS_PER_INST 4 // Number of channels in each SDM instance +/*--------------------------- PCNT (Pulse Counter) ------------------------*/ +#define _SOC_CAPS_PCNT_INST_NUM 1 // Number of PCNT instances +#define _SOC_CAPS_PCNT_UNITS_PER_INST 4 // Number of units in each PCNT instance +#define _SOC_CAPS_PCNT_CHANS_PER_UNIT 2 // Number of channels in each PCNT unit +#define _SOC_CAPS_PCNT_THRES_POINT_PER_UNIT 2 // Number of threshold points in each PCNT unit + /*--------------------------- ETM (Event Task Matrix) ----------------------------*/ #define _SOC_CAPS_ETM_INST_NUM 1 // Number of ETM instances #define _SOC_CAPS_ETM_CHANS_PER_INST 50 // Number of channels in each ETM instance diff --git a/components/soc/esp32h4/pcnt_periph.c b/components/soc/esp32h4/pcnt_periph.c new file mode 100644 index 0000000000..3f16293c77 --- /dev/null +++ b/components/soc/esp32h4/pcnt_periph.c @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/pcnt_periph.h" +#include "soc/gpio_sig_map.h" +#include "soc/pcnt_reg.h" + +const soc_pcnt_signal_desc_t soc_pcnt_signals[1] = { + [0] = { + .irq_id = ETS_PCNT_INTR_SOURCE, + .module_name = "pcnt0", + .units = { + [0] = { + .channels = { + [0] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH0_IN0_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH0_IN0_IDX + }, + [1] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH1_IN0_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH1_IN0_IDX + } + }, + .clear_sig_id_matrix = PCNT_RST_IN0_IDX + }, + [1] = { + .channels = { + [0] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH0_IN1_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH0_IN1_IDX, + }, + [1] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH1_IN1_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH1_IN1_IDX + } + }, + .clear_sig_id_matrix = PCNT_RST_IN1_IDX + }, + [2] = { + .channels = { + [0] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH0_IN2_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH0_IN2_IDX, + }, + [1] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH1_IN2_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH1_IN2_IDX + } + }, + .clear_sig_id_matrix = PCNT_RST_IN2_IDX + }, + [3] = { + .channels = { + [0] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH0_IN3_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH0_IN3_IDX, + }, + [1] = { + .ctl_sig_id_matrix = PCNT_CTRL_CH1_IN3_IDX, + .pulse_sig_id_matrix = PCNT_SIG_CH1_IN3_IDX + } + }, + .clear_sig_id_matrix = PCNT_RST_IN3_IDX + } + } + } +}; diff --git a/components/soc/esp32h4/register/soc/pcnt_struct.h b/components/soc/esp32h4/register/soc/pcnt_struct.h index 11e9e818d8..f5f00fda50 100644 --- a/components/soc/esp32h4/register/soc/pcnt_struct.h +++ b/components/soc/esp32h4/register/soc/pcnt_struct.h @@ -148,73 +148,22 @@ typedef union { uint32_t val; } pcnt_un_conf2_reg_t; -/** Type of u0_conf3 register - * Configuration register for unit $n's step value. +/** Type of un_conf3 register + * Configuration register for unit n's step value. */ typedef union { struct { - /** cnt_h_step_u0 : R/W; bitpos: [15:0]; default: 0; - * Configures the forward rotation step value for unit 0. + /** cnt_h_step_un : R/W; bitpos: [15:0]; default: 0; + * Configures the forward rotation step value for unit n. */ - uint32_t cnt_h_step_u0:16; - /** cnt_l_step_u0 : R/W; bitpos: [31:16]; default: 0; - * Configures the reverse rotation step value for unit 0. + uint32_t cnt_h_step_un:16; + /** cnt_l_step_un : R/W; bitpos: [31:16]; default: 0; + * Configures the reverse rotation step value for unit n. */ - uint32_t cnt_l_step_u0:16; + uint32_t cnt_l_step_un:16; }; uint32_t val; -} pcnt_u0_conf3_reg_t; - -/** Type of u1_conf3 register - * Configuration register for unit $n's step value. - */ -typedef union { - struct { - /** cnt_h_step_u1 : R/W; bitpos: [15:0]; default: 0; - * Configures the forward rotation step value for unit 1. - */ - uint32_t cnt_h_step_u1:16; - /** cnt_l_step_u1 : R/W; bitpos: [31:16]; default: 0; - * Configures the reverse rotation step value for unit 1. - */ - uint32_t cnt_l_step_u1:16; - }; - uint32_t val; -} pcnt_u1_conf3_reg_t; - -/** Type of u2_conf3 register - * Configuration register for unit $n's step value. - */ -typedef union { - struct { - /** cnt_h_step_u2 : R/W; bitpos: [15:0]; default: 0; - * Configures the forward rotation step value for unit 2. - */ - uint32_t cnt_h_step_u2:16; - /** cnt_l_step_u2 : R/W; bitpos: [31:16]; default: 0; - * Configures the reverse rotation step value for unit 2. - */ - uint32_t cnt_l_step_u2:16; - }; - uint32_t val; -} pcnt_u2_conf3_reg_t; - -/** Type of u3_conf3 register - * Configuration register for unit $n's step value. - */ -typedef union { - struct { - /** cnt_h_step_u3 : R/W; bitpos: [15:0]; default: 0; - * Configures the forward rotation step value for unit 3. - */ - uint32_t cnt_h_step_u3:16; - /** cnt_l_step_u3 : R/W; bitpos: [31:16]; default: 0; - * Configures the reverse rotation step value for unit 3. - */ - uint32_t cnt_l_step_u3:16; - }; - uint32_t val; -} pcnt_u3_conf3_reg_t; +} pcnt_un_conf3_reg_t; /** Type of ctrl register * Control register for all counters @@ -484,29 +433,19 @@ typedef union { } pcnt_date_reg_t; -typedef struct { - volatile pcnt_un_conf0_reg_t u0_conf0; - volatile pcnt_un_conf1_reg_t u0_conf1; - volatile pcnt_un_conf2_reg_t u0_conf2; - volatile pcnt_u0_conf3_reg_t u0_conf3; - volatile pcnt_un_conf0_reg_t u1_conf0; - volatile pcnt_un_conf1_reg_t u1_conf1; - volatile pcnt_un_conf2_reg_t u1_conf2; - volatile pcnt_u1_conf3_reg_t u1_conf3; - volatile pcnt_un_conf0_reg_t u2_conf0; - volatile pcnt_un_conf1_reg_t u2_conf1; - volatile pcnt_un_conf2_reg_t u2_conf2; - volatile pcnt_u2_conf3_reg_t u2_conf3; - volatile pcnt_un_conf0_reg_t u3_conf0; - volatile pcnt_un_conf1_reg_t u3_conf1; - volatile pcnt_un_conf2_reg_t u3_conf2; - volatile pcnt_u3_conf3_reg_t u3_conf3; - volatile pcnt_un_cnt_reg_t un_cnt[4]; +typedef struct pcnt_dev_t { + volatile struct { + pcnt_un_conf0_reg_t conf0; + pcnt_un_conf1_reg_t conf1; + pcnt_un_conf2_reg_t conf2; + pcnt_un_conf3_reg_t conf3; + } conf_unit[4]; + volatile pcnt_un_cnt_reg_t cnt_unit[4]; volatile pcnt_int_raw_reg_t int_raw; volatile pcnt_int_st_reg_t int_st; volatile pcnt_int_ena_reg_t int_ena; volatile pcnt_int_clr_reg_t int_clr; - volatile pcnt_un_status_reg_t un_status[4]; + volatile pcnt_un_status_reg_t status_unit[4]; volatile pcnt_ctrl_reg_t ctrl; uint32_t reserved_074[34]; volatile pcnt_date_reg_t date; diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 765b7032ad..4a1913ed47 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -160,6 +160,7 @@ typedef enum { SOC_MOD_CLK_RTC_FAST, /*!< RTC_FAST_CLK can be sourced from XTAL, RC_FAST, or LP_PLL by configuring soc_rtc_fast_clk_src_t */ SOC_MOD_CLK_RTC_SLOW, /*!< RTC_SLOW_CLK can be sourced from RC_SLOW, XTAL32K, or RC32K by configuring soc_rtc_slow_clk_src_t */ // For digital domain: peripherals + SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_F20M, /*!< PLL_F20M_CLK is derived from SPLL (clock gating + default divider 24), its default frequency is 20MHz */ SOC_MOD_CLK_PLL_F25M, /*!< PLL_F25M_CLK is derived from MPLL (clock gating + configurable divider), it will have a frequency of 25MHz */ SOC_MOD_CLK_PLL_F50M, /*!< PLL_F50M_CLK is derived from MPLL (clock gating + configurable divider 10), it will have a frequency of 50MHz */ @@ -256,6 +257,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock default choice is PLL_F80M */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32s2/include/soc/clk_tree_defs.h b/components/soc/esp32s2/include/soc/clk_tree_defs.h index 8eee411858..6e7dac668f 100644 --- a/components/soc/esp32s2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s2/include/soc/clk_tree_defs.h @@ -214,6 +214,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_APB, /*!< RMT source clock default choice is APB */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32s3/include/soc/clk_tree_defs.h b/components/soc/esp32s3/include/soc/clk_tree_defs.h index 0b513b3f95..0fbd09dc1a 100644 --- a/components/soc/esp32s3/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s3/include/soc/clk_tree_defs.h @@ -233,6 +233,21 @@ typedef enum { RMT_BASECLK_DEFAULT = SOC_MOD_CLK_APB, /*!< RMT source clock default choice is APB */ } soc_periph_rmt_clk_src_legacy_t; +//////////////////////////////////////////////////PCNT////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PCNT + */ +#define SOC_PCNT_CLKS {SOC_MOD_CLK_APB} + +/** + * @brief Type of PCNT clock source + */ +typedef enum { + PCNT_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */ + PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ +} soc_periph_pcnt_clk_src_t; + //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// /** diff --git a/components/soc/include/soc/pcnt_periph.h b/components/soc/include/soc/pcnt_periph.h index 817661aa79..dfd6060f9f 100644 --- a/components/soc/include/soc/pcnt_periph.h +++ b/components/soc/include/soc/pcnt_periph.h @@ -9,7 +9,7 @@ #include #include #include "soc/soc_caps_full.h" -#include "soc/periph_defs.h" +#include "soc/interrupts.h" // helper macros to access module attributes #define SOC_PCNT_ATTR(_attr) SOC_MODULE_ATTR(PCNT, _attr) diff --git a/docs/docs_not_updated/esp32h4.txt b/docs/docs_not_updated/esp32h4.txt index c863cf2096..4b8ed1ce94 100644 --- a/docs/docs_not_updated/esp32h4.txt +++ b/docs/docs_not_updated/esp32h4.txt @@ -179,7 +179,6 @@ api-reference/peripherals/lcd/dsi_lcd.rst api-reference/peripherals/lcd/spi_lcd.rst api-reference/peripherals/lcd/rgb_lcd.rst api-reference/peripherals/lcd/parl_lcd.rst -api-reference/peripherals/pcnt.rst api-reference/peripherals/ppa.rst api-reference/peripherals/ldo_regulator.rst api-reference/peripherals/ledc.rst diff --git a/examples/peripherals/pcnt/rotary_encoder/README.md b/examples/peripherals/pcnt/rotary_encoder/README.md index fe0f5079d0..753547f7d5 100644 --- a/examples/peripherals/pcnt/rotary_encoder/README.md +++ b/examples/peripherals/pcnt/rotary_encoder/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # Rotary Encoder Example