feat(pcnt): support pcnt on esp32h4

This commit is contained in:
Chen Jichang
2025-08-26 16:40:14 +08:00
parent 04b934951e
commit ad5bdc83a7
30 changed files with 997 additions and 115 deletions

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 |
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |

View File

@@ -19,10 +19,11 @@
#include <stdbool.h>
#include <soc/soc.h>
#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

View File

@@ -10,9 +10,10 @@
#include <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -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 <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -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 <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -10,9 +10,10 @@
#include <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -0,0 +1,527 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <limits.h>
#include <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -18,9 +18,10 @@
#include <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -18,9 +18,10 @@
#include <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -18,8 +18,9 @@
#include <stdlib.h>
#include <stdbool.h>
#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

View File

@@ -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
*/

View File

@@ -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/////////////////////////////////////////////////////////////////
/**

View File

@@ -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///////////////////////////////////////////////////////////
/**

View File

@@ -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///////////////////////////////////////////////////////////
/**

View File

@@ -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///////////////////////////////////////////////////////////
/**

View File

@@ -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/////////////////////////////////////////////////////////////////
/**

View File

@@ -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

View File

@@ -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/////////////////////////////////////////////////////////////////
/**

View File

@@ -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 */

View File

@@ -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

View File

@@ -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
}
}
}
};

View File

@@ -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;

View File

@@ -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/////////////////////////////////////////////////////////////////
/**

View File

@@ -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///////////////////////////////////////////////////////////
/**

View File

@@ -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///////////////////////////////////////////////////////////
/**

View File

@@ -9,7 +9,7 @@
#include <stdint.h>
#include <stddef.h>
#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)

View File

@@ -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

View File

@@ -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