mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-28 16:46:31 +03:00
feat(pcnt): support pcnt on esp32s31 & add group_id config
This commit is contained in:
@@ -59,6 +59,7 @@ typedef struct {
|
||||
* @brief PCNT unit configuration
|
||||
*/
|
||||
typedef struct {
|
||||
int group_id; /*!< Specify from which PCNT instance (peripheral group) to allocate the unit */
|
||||
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 */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -164,32 +164,31 @@ static esp_err_t pcnt_unit_install_interrupt(pcnt_unit_t *unit)
|
||||
return esp_intr_alloc_info(&intr_info, &unit->intr);
|
||||
}
|
||||
|
||||
static esp_err_t pcnt_register_to_group(pcnt_unit_t *unit)
|
||||
static esp_err_t pcnt_register_to_group(pcnt_unit_t *unit, int requested_group)
|
||||
{
|
||||
pcnt_group_t *group = NULL;
|
||||
int group_id = requested_group;
|
||||
|
||||
pcnt_group_t *group = pcnt_acquire_group_handle(group_id);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", group_id);
|
||||
|
||||
int unit_id = -1;
|
||||
for (int i = 0; i < PCNT_LL_GET(INST_NUM); i++) {
|
||||
group = pcnt_acquire_group_handle(i);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", i);
|
||||
// loop to search free unit in the group
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
for (int j = 0; j < PCNT_LL_GET(UNITS_PER_INST); j++) {
|
||||
if (!group->units[j]) {
|
||||
unit_id = j;
|
||||
group->units[j] = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
if (unit_id < 0) {
|
||||
pcnt_release_group_handle(group);
|
||||
} else {
|
||||
unit->group = group;
|
||||
unit->unit_id = unit_id;
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
for (int j = 0; j < PCNT_LL_GET(UNITS_PER_INST); j++) {
|
||||
if (!group->units[j]) {
|
||||
unit_id = j;
|
||||
group->units[j] = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(unit_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free unit");
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
if (unit_id < 0) {
|
||||
// No free unit in the requested instance; release the reference we just took
|
||||
pcnt_release_group_handle(group);
|
||||
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_FOUND, TAG, "no free unit in group (%d)", group_id);
|
||||
}
|
||||
unit->group = group;
|
||||
unit->unit_id = unit_id;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -237,10 +236,12 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
|
||||
ESP_LOGW(TAG, "can't overflow at high limit: %d due to hardware limitation", config->high_limit);
|
||||
}
|
||||
#endif
|
||||
ESP_GOTO_ON_FALSE(config->group_id >= 0 && config->group_id < PCNT_LL_GET(INST_NUM),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "invalid group_id %d", config->group_id);
|
||||
unit = heap_caps_calloc(1, sizeof(pcnt_unit_t), PCNT_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, TAG, "no mem for unit");
|
||||
// register unit to the group (because one group can have several units)
|
||||
ESP_GOTO_ON_ERROR(pcnt_register_to_group(unit), err, TAG, "register unit failed");
|
||||
ESP_GOTO_ON_ERROR(pcnt_register_to_group(unit, config->group_id), err, TAG, "register unit failed");
|
||||
pcnt_group_t *group = unit->group;
|
||||
int group_id = group->group_id;
|
||||
int unit_id = unit->unit_id;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | 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 | ESP32-S31 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -25,30 +25,46 @@ TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]")
|
||||
.intr_priority = 0,
|
||||
.flags.accum_count = true,
|
||||
};
|
||||
pcnt_unit_handle_t units[PCNT_LL_GET(UNITS_PER_INST)];
|
||||
// total available units across all PCNT instances on this SoC
|
||||
const int units_per_inst = PCNT_LL_GET(UNITS_PER_INST);
|
||||
const int total_units = PCNT_LL_GET(INST_NUM) * units_per_inst;
|
||||
pcnt_unit_handle_t units[total_units];
|
||||
int count_value = 0;
|
||||
|
||||
// The driver no longer auto-spreads units across instances, so the test must
|
||||
// walk every instance explicitly to exhaust all hardware units.
|
||||
printf("install pcnt units and check initial count\r\n");
|
||||
for (int i = 0; i < PCNT_LL_GET(UNITS_PER_INST) - 1; i++) {
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &units[i]));
|
||||
TEST_ESP_OK(pcnt_unit_get_count(units[i], &count_value));
|
||||
TEST_ASSERT_EQUAL(0, count_value);
|
||||
for (int g = 0; g < PCNT_LL_GET(INST_NUM); g++) {
|
||||
unit_config.group_id = g;
|
||||
const int units_to_install = (g == PCNT_LL_GET(INST_NUM) - 1) ? (units_per_inst - 1) : units_per_inst;
|
||||
for (int u = 0; u < units_to_install; u++) {
|
||||
int idx = g * units_per_inst + u;
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &units[idx]));
|
||||
TEST_ESP_OK(pcnt_unit_get_count(units[idx], &count_value));
|
||||
TEST_ASSERT_EQUAL(0, count_value);
|
||||
}
|
||||
}
|
||||
|
||||
// unit with a different interrupt priority
|
||||
// unit with a different interrupt priority, must conflict with the existing
|
||||
// shared interrupt that is already allocated at the default priority
|
||||
unit_config.group_id = PCNT_LL_GET(INST_NUM) - 1;
|
||||
unit_config.intr_priority = 3;
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, pcnt_new_unit(&unit_config, &units[PCNT_LL_GET(UNITS_PER_INST) - 1]));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, pcnt_new_unit(&unit_config, &units[total_units - 1]));
|
||||
unit_config.intr_priority = 0;
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &units[PCNT_LL_GET(UNITS_PER_INST) - 1]));
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &units[total_units - 1]));
|
||||
|
||||
// no more free pcnt units
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, pcnt_new_unit(&unit_config, &units[0]));
|
||||
// no more free pcnt units in any instance
|
||||
for (int g = 0; g < PCNT_LL_GET(INST_NUM); g++) {
|
||||
unit_config.group_id = g;
|
||||
pcnt_unit_handle_t overflow_unit = NULL;
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, pcnt_new_unit(&unit_config, &overflow_unit));
|
||||
}
|
||||
|
||||
printf("set glitch filter\r\n");
|
||||
pcnt_glitch_filter_config_t filter_config = {
|
||||
.max_glitch_ns = 1000,
|
||||
};
|
||||
for (int i = 0; i < PCNT_LL_GET(UNITS_PER_INST); i++) {
|
||||
for (int i = 0; i < total_units; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_set_glitch_filter(units[i], &filter_config));
|
||||
}
|
||||
// invalid glitch configuration
|
||||
@@ -58,30 +74,30 @@ TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]")
|
||||
.on_reach = NULL,
|
||||
};
|
||||
printf("enable pcnt units\r\n");
|
||||
for (int i = 0; i < PCNT_LL_GET(UNITS_PER_INST); i++) {
|
||||
for (int i = 0; i < total_units; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_register_event_callbacks(units[i], &cbs, NULL));
|
||||
TEST_ESP_OK(pcnt_unit_enable(units[i]));
|
||||
}
|
||||
|
||||
printf("start pcnt units\r\n");
|
||||
for (int i = 0; i < PCNT_LL_GET(UNITS_PER_INST); i++) {
|
||||
for (int i = 0; i < total_units; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_start(units[i]));
|
||||
}
|
||||
|
||||
printf("stop pcnt units\r\n");
|
||||
for (int i = 0; i < PCNT_LL_GET(UNITS_PER_INST); i++) {
|
||||
for (int i = 0; i < total_units; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_stop(units[i]));
|
||||
}
|
||||
|
||||
// can't uninstall unit before disable it
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_del_unit(units[0]));
|
||||
printf("disable pcnt units\r\n");
|
||||
for (int i = 0; i < PCNT_LL_GET(UNITS_PER_INST); i++) {
|
||||
for (int i = 0; i < total_units; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_disable(units[i]));
|
||||
}
|
||||
|
||||
printf("uninstall pcnt units\r\n");
|
||||
for (int i = 0; i < PCNT_LL_GET(UNITS_PER_INST); i++) {
|
||||
for (int i = 0; i < total_units; i++) {
|
||||
TEST_ESP_OK(pcnt_del_unit(units[i]));
|
||||
}
|
||||
}
|
||||
@@ -242,12 +258,10 @@ static bool test_pcnt_quadrature_reach_watch_point(pcnt_unit_handle_t handle, co
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("pcnt_quadrature_decode_event", "[pcnt]")
|
||||
static void test_pcnt_quadrature_decode_event_on_one_unit(int group_id)
|
||||
{
|
||||
test_gpio_init_for_simulation(TEST_PCNT_GPIO_A);
|
||||
test_gpio_init_for_simulation(TEST_PCNT_GPIO_B);
|
||||
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.group_id = group_id,
|
||||
.low_limit = -100,
|
||||
.high_limit = 100,
|
||||
};
|
||||
@@ -361,6 +375,18 @@ TEST_CASE("pcnt_quadrature_decode_event", "[pcnt]")
|
||||
TEST_ESP_OK(pcnt_del_unit(unit));
|
||||
}
|
||||
|
||||
TEST_CASE("pcnt_quadrature_decode_event", "[pcnt]")
|
||||
{
|
||||
test_gpio_init_for_simulation(TEST_PCNT_GPIO_A);
|
||||
test_gpio_init_for_simulation(TEST_PCNT_GPIO_B);
|
||||
|
||||
// test on each PCNT instance, allocating the unit explicitly via group_id
|
||||
for (int inst = 0; inst < PCNT_LL_GET(INST_NUM); inst++) {
|
||||
printf("test quadrature decode event on PCNT instance %d\r\n", inst);
|
||||
test_pcnt_quadrature_decode_event_on_one_unit(inst);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
pcnt_unit_zero_cross_mode_t mode;
|
||||
} test_pcnt_zero_cross_context_t;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
from pytest_embedded_idf.utils import soc_filtered_targets
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@@ -14,8 +15,7 @@ from pytest_embedded_idf.utils import idf_parametrize
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize(
|
||||
'target', ['esp32', 'esp32s2', 'esp32s3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], indirect=['target']
|
||||
)
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_PCNT_SUPPORTED == 1'), indirect=['target'])
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners')
|
||||
def test_pulse_cnt(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
533
components/esp_hal_pcnt/esp32s31/include/hal/pcnt_ll.h
Normal file
533
components/esp_hal_pcnt/esp32s31/include/hal/pcnt_ll.h
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 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/hp_sys_clkrst_struct.h"
|
||||
#include "hal/pcnt_types.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Get PCNT attribute
|
||||
#define PCNT_LL_GET(attr) (PCNT_LL_ ## attr)
|
||||
|
||||
#define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT0) : ((num) == 1) ? (&PCNT1) : 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;
|
||||
|
||||
// SoC-based capabilities
|
||||
#define PCNT_LL_INST_NUM 2 // Number of PCNT instances
|
||||
#define PCNT_LL_UNITS_PER_INST 4 // Number of units in each PCNT instance
|
||||
#define PCNT_LL_CHANS_PER_UNIT 2 // Number of channels in each PCNT unit
|
||||
#define PCNT_LL_THRES_POINT_PER_UNIT 2 // Number of threshold points in each PCNT unit
|
||||
|
||||
#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
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
if (group_id == 0) {
|
||||
HP_SYS_CLKRST.pcnt_ctrl0.reg_pcnt0_apb_clk_en = enable;
|
||||
} else if (group_id == 1) {
|
||||
HP_SYS_CLKRST.pcnt_ctrl0.reg_pcnt1_apb_clk_en = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the PCNT module
|
||||
*/
|
||||
static inline void pcnt_ll_reset_register(int group_id)
|
||||
{
|
||||
if (group_id == 0) {
|
||||
HP_SYS_CLKRST.pcnt_ctrl0.reg_pcnt0_rst_en = 1;
|
||||
HP_SYS_CLKRST.pcnt_ctrl0.reg_pcnt0_rst_en = 0;
|
||||
} else if (group_id == 1) {
|
||||
HP_SYS_CLKRST.pcnt_ctrl0.reg_pcnt1_rst_en = 1;
|
||||
HP_SYS_CLKRST.pcnt_ctrl0.reg_pcnt1_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
|
||||
128
components/esp_hal_pcnt/esp32s31/pcnt_periph.c
Normal file
128
components/esp_hal_pcnt/esp32s31/pcnt_periph.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/pcnt_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/pcnt_reg.h"
|
||||
|
||||
const soc_pcnt_signal_desc_t soc_pcnt_signals[2] = {
|
||||
[0] = {
|
||||
.irq_id = ETS_PCNT0_INTR_SOURCE,
|
||||
.module_name = "pcnt0",
|
||||
.units = {
|
||||
[0] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH0_IN0_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH0_IN0_IDX
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH1_IN0_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH1_IN0_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT0_RST_IN0_IDX
|
||||
},
|
||||
[1] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH0_IN1_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH0_IN1_IDX,
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH1_IN1_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH1_IN1_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT0_RST_IN1_IDX
|
||||
},
|
||||
[2] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH0_IN2_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH0_IN2_IDX,
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH1_IN2_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH1_IN2_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT0_RST_IN2_IDX
|
||||
},
|
||||
[3] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH0_IN3_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH0_IN3_IDX,
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT0_CTRL_CH1_IN3_IDX,
|
||||
.pulse_sig_id_matrix = PCNT0_SIG_CH1_IN3_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT0_RST_IN3_IDX
|
||||
}
|
||||
}
|
||||
},
|
||||
[1] = {
|
||||
.irq_id = ETS_PCNT1_INTR_SOURCE,
|
||||
.module_name = "pcnt1",
|
||||
.units = {
|
||||
[0] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH0_IN0_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH0_IN0_IDX
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH1_IN0_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH1_IN0_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT1_RST_IN0_IDX
|
||||
},
|
||||
[1] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH0_IN1_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH0_IN1_IDX,
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH1_IN1_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH1_IN1_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT1_RST_IN1_IDX
|
||||
},
|
||||
[2] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH0_IN2_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH0_IN2_IDX,
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH1_IN2_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH1_IN2_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT1_RST_IN2_IDX
|
||||
},
|
||||
[3] = {
|
||||
.channels = {
|
||||
[0] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH0_IN3_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH0_IN3_IDX,
|
||||
},
|
||||
[1] = {
|
||||
.ctl_sig_id_matrix = PCNT1_CTRL_CH1_IN3_IDX,
|
||||
.pulse_sig_id_matrix = PCNT1_SIG_CH1_IN3_IDX
|
||||
}
|
||||
},
|
||||
.clear_sig_id_matrix = PCNT1_RST_IN3_IDX
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
@@ -76,6 +76,9 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr
|
||||
case SOC_MOD_CLK_XTAL_D2:
|
||||
clk_src_freq = (clk_hal_xtal_get_freq_mhz() * MHZ) >> 1;
|
||||
break;
|
||||
case SOC_MOD_CLK_APB:
|
||||
clk_src_freq = clk_hal_apb_get_freq_hz();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,10 @@ config SOC_LCD_RGB_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_PCNT_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MCPWM_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
@@ -591,6 +595,18 @@ config SOC_I2C_SUPPORT_SLEEP_RETENTION
|
||||
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_MMU_PAGE_SIZE_CONFIGURABLE
|
||||
bool
|
||||
default y
|
||||
|
||||
@@ -152,6 +152,7 @@ typedef enum {
|
||||
SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */
|
||||
SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 40MHz crystal */
|
||||
SOC_MOD_CLK_APLL, /*!< Audio PLL is sourced from PLL, and its frequency is configurable through APLL configuration registers */
|
||||
SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */
|
||||
// For LP peripherals
|
||||
SOC_MOD_CLK_XTAL_D2, /*!< XTAL_D2_CLK comes from the external 40MHz crystal, passing a div of 2 to the LP peripherals */
|
||||
SOC_MOD_CLK_LP_DYN_FAST, /*!< LP_DYN_FAST can be derived from RTC_SLOW_CLK or RTC_FAST_CLK depending on the chip’s power mode:
|
||||
@@ -464,7 +465,7 @@ typedef enum {
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of MCPWM Carrier
|
||||
*/
|
||||
#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F20M, SOC_MOD_CLK_PLL_F160M}
|
||||
#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F160M}
|
||||
|
||||
/**
|
||||
* @brief Type of MCPWM carrier clock source
|
||||
@@ -647,6 +648,21 @@ typedef enum {
|
||||
CORDIC_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,
|
||||
} soc_periph_cordic_clk_src_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;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,13 +34,13 @@
|
||||
#define SOC_LP_AHB_GDMA_SUPPORTED 1
|
||||
#define SOC_DMA2D_SUPPORTED 1
|
||||
#define SOC_GPTIMER_SUPPORTED 1
|
||||
// #define SOC_PCNT_SUPPORTED 1 // TODO: [ESP32S31] IDF-14699
|
||||
#define SOC_LCDCAM_SUPPORTED 1
|
||||
// #define SOC_LCDCAM_CAM_SUPPORTED 1 // TODO: [ESP32S31] IDF-14722
|
||||
#define SOC_LCDCAM_I80_LCD_SUPPORTED 1
|
||||
#define SOC_LCDCAM_RGB_LCD_SUPPORTED 1
|
||||
#define SOC_LCD_I80_SUPPORTED 1
|
||||
#define SOC_LCD_RGB_SUPPORTED 1
|
||||
#define SOC_PCNT_SUPPORTED 1
|
||||
#define SOC_MCPWM_SUPPORTED 1
|
||||
#define SOC_TWAI_SUPPORTED 1
|
||||
#define SOC_TWAI_FD_SUPPORTED 1
|
||||
@@ -260,6 +260,11 @@
|
||||
|
||||
#define SOC_I2C_SUPPORT_SLEEP_RETENTION (1)
|
||||
|
||||
/*-------------------------- PCNT CAPS ---------------------------------------*/
|
||||
#define SOC_PCNT_SUPPORT_RUNTIME_THRES_UPDATE 1
|
||||
#define SOC_PCNT_SUPPORT_CLEAR_SIGNAL 1
|
||||
#define SOC_PCNT_SUPPORT_STEP_NOTIFY 1
|
||||
|
||||
/*-------------------------- MMU CAPS ----------------------------------------*/
|
||||
#define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1)
|
||||
#define SOC_MMU_PERIPH_NUM (2U)
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/reg_base.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Multi-instance reg base macro */
|
||||
#define REG_PCNT_BASE(i) (DR_REG_PCNT0_BASE + (i * 0x14000))
|
||||
|
||||
/** PCNT_U0_CONF0_REG register
|
||||
* Configuration register 0 for unit 0
|
||||
*/
|
||||
#define PCNT_U0_CONF0_REG (DR_REG_PCNT_BASE + 0x0)
|
||||
#define PCNT_U0_CONF0_REG(i) (REG_PCNT_BASE(i) + 0x0)
|
||||
/** PCNT_FILTER_THRES_U0 : R/W; bitpos: [9:0]; default: 16;
|
||||
* Configures the maximum threshold for the filter. Any pulses with width less than
|
||||
* this will be ignored when the filter is enabled.
|
||||
@@ -155,7 +160,7 @@ extern "C" {
|
||||
/** PCNT_U0_CONF1_REG register
|
||||
* Configuration register 1 for unit 0
|
||||
*/
|
||||
#define PCNT_U0_CONF1_REG (DR_REG_PCNT_BASE + 0x4)
|
||||
#define PCNT_U0_CONF1_REG(i) (REG_PCNT_BASE(i) + 0x4)
|
||||
/** PCNT_CNT_THRES0_U0 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thres0 value for unit 0.
|
||||
*/
|
||||
@@ -174,7 +179,7 @@ extern "C" {
|
||||
/** PCNT_U0_CONF2_REG register
|
||||
* Configuration register 2 for unit 0
|
||||
*/
|
||||
#define PCNT_U0_CONF2_REG (DR_REG_PCNT_BASE + 0x8)
|
||||
#define PCNT_U0_CONF2_REG(i) (REG_PCNT_BASE(i) + 0x8)
|
||||
/** PCNT_CNT_H_LIM_U0 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thr_h_lim value for unit 0. When pulse_cnt reaches this value, the
|
||||
* counter will be cleared to 0.
|
||||
@@ -195,7 +200,7 @@ extern "C" {
|
||||
/** PCNT_U0_CONF3_REG register
|
||||
* Configuration register for unit $n's step value.
|
||||
*/
|
||||
#define PCNT_U0_CONF3_REG (DR_REG_PCNT_BASE + 0xc)
|
||||
#define PCNT_U0_CONF3_REG(i) (REG_PCNT_BASE(i) + 0xc)
|
||||
/** PCNT_CNT_H_STEP_U0 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the forward rotation step value for unit 0.
|
||||
*/
|
||||
@@ -214,7 +219,7 @@ extern "C" {
|
||||
/** PCNT_U1_CONF0_REG register
|
||||
* Configuration register 0 for unit 1
|
||||
*/
|
||||
#define PCNT_U1_CONF0_REG (DR_REG_PCNT_BASE + 0x10)
|
||||
#define PCNT_U1_CONF0_REG(i) (REG_PCNT_BASE(i) + 0x10)
|
||||
/** PCNT_FILTER_THRES_U1 : R/W; bitpos: [9:0]; default: 16;
|
||||
* Configures the maximum threshold for the filter. Any pulses with width less than
|
||||
* this will be ignored when the filter is enabled.
|
||||
@@ -356,7 +361,7 @@ extern "C" {
|
||||
/** PCNT_U1_CONF1_REG register
|
||||
* Configuration register 1 for unit 1
|
||||
*/
|
||||
#define PCNT_U1_CONF1_REG (DR_REG_PCNT_BASE + 0x14)
|
||||
#define PCNT_U1_CONF1_REG(i) (REG_PCNT_BASE(i) + 0x14)
|
||||
/** PCNT_CNT_THRES0_U1 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thres0 value for unit 1.
|
||||
*/
|
||||
@@ -375,7 +380,7 @@ extern "C" {
|
||||
/** PCNT_U1_CONF2_REG register
|
||||
* Configuration register 2 for unit 1
|
||||
*/
|
||||
#define PCNT_U1_CONF2_REG (DR_REG_PCNT_BASE + 0x18)
|
||||
#define PCNT_U1_CONF2_REG(i) (REG_PCNT_BASE(i) + 0x18)
|
||||
/** PCNT_CNT_H_LIM_U1 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thr_h_lim value for unit 1. When pulse_cnt reaches this value, the
|
||||
* counter will be cleared to 0.
|
||||
@@ -396,7 +401,7 @@ extern "C" {
|
||||
/** PCNT_U1_CONF3_REG register
|
||||
* Configuration register for unit $n's step value.
|
||||
*/
|
||||
#define PCNT_U1_CONF3_REG (DR_REG_PCNT_BASE + 0x1c)
|
||||
#define PCNT_U1_CONF3_REG(i) (REG_PCNT_BASE(i) + 0x1c)
|
||||
/** PCNT_CNT_H_STEP_U1 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the forward rotation step value for unit 1.
|
||||
*/
|
||||
@@ -415,7 +420,7 @@ extern "C" {
|
||||
/** PCNT_U2_CONF0_REG register
|
||||
* Configuration register 0 for unit 2
|
||||
*/
|
||||
#define PCNT_U2_CONF0_REG (DR_REG_PCNT_BASE + 0x20)
|
||||
#define PCNT_U2_CONF0_REG(i) (REG_PCNT_BASE(i) + 0x20)
|
||||
/** PCNT_FILTER_THRES_U2 : R/W; bitpos: [9:0]; default: 16;
|
||||
* Configures the maximum threshold for the filter. Any pulses with width less than
|
||||
* this will be ignored when the filter is enabled.
|
||||
@@ -557,7 +562,7 @@ extern "C" {
|
||||
/** PCNT_U2_CONF1_REG register
|
||||
* Configuration register 1 for unit 2
|
||||
*/
|
||||
#define PCNT_U2_CONF1_REG (DR_REG_PCNT_BASE + 0x24)
|
||||
#define PCNT_U2_CONF1_REG(i) (REG_PCNT_BASE(i) + 0x24)
|
||||
/** PCNT_CNT_THRES0_U2 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thres0 value for unit 2.
|
||||
*/
|
||||
@@ -576,7 +581,7 @@ extern "C" {
|
||||
/** PCNT_U2_CONF2_REG register
|
||||
* Configuration register 2 for unit 2
|
||||
*/
|
||||
#define PCNT_U2_CONF2_REG (DR_REG_PCNT_BASE + 0x28)
|
||||
#define PCNT_U2_CONF2_REG(i) (REG_PCNT_BASE(i) + 0x28)
|
||||
/** PCNT_CNT_H_LIM_U2 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thr_h_lim value for unit 2. When pulse_cnt reaches this value, the
|
||||
* counter will be cleared to 0.
|
||||
@@ -597,7 +602,7 @@ extern "C" {
|
||||
/** PCNT_U2_CONF3_REG register
|
||||
* Configuration register for unit $n's step value.
|
||||
*/
|
||||
#define PCNT_U2_CONF3_REG (DR_REG_PCNT_BASE + 0x2c)
|
||||
#define PCNT_U2_CONF3_REG(i) (REG_PCNT_BASE(i) + 0x2c)
|
||||
/** PCNT_CNT_H_STEP_U2 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the forward rotation step value for unit 2.
|
||||
*/
|
||||
@@ -616,7 +621,7 @@ extern "C" {
|
||||
/** PCNT_U3_CONF0_REG register
|
||||
* Configuration register 0 for unit 3
|
||||
*/
|
||||
#define PCNT_U3_CONF0_REG (DR_REG_PCNT_BASE + 0x30)
|
||||
#define PCNT_U3_CONF0_REG(i) (REG_PCNT_BASE(i) + 0x30)
|
||||
/** PCNT_FILTER_THRES_U3 : R/W; bitpos: [9:0]; default: 16;
|
||||
* Configures the maximum threshold for the filter. Any pulses with width less than
|
||||
* this will be ignored when the filter is enabled.
|
||||
@@ -758,7 +763,7 @@ extern "C" {
|
||||
/** PCNT_U3_CONF1_REG register
|
||||
* Configuration register 1 for unit 3
|
||||
*/
|
||||
#define PCNT_U3_CONF1_REG (DR_REG_PCNT_BASE + 0x34)
|
||||
#define PCNT_U3_CONF1_REG(i) (REG_PCNT_BASE(i) + 0x34)
|
||||
/** PCNT_CNT_THRES0_U3 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thres0 value for unit 3.
|
||||
*/
|
||||
@@ -777,7 +782,7 @@ extern "C" {
|
||||
/** PCNT_U3_CONF2_REG register
|
||||
* Configuration register 2 for unit 3
|
||||
*/
|
||||
#define PCNT_U3_CONF2_REG (DR_REG_PCNT_BASE + 0x38)
|
||||
#define PCNT_U3_CONF2_REG(i) (REG_PCNT_BASE(i) + 0x38)
|
||||
/** PCNT_CNT_H_LIM_U3 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the thr_h_lim value for unit 3. When pulse_cnt reaches this value, the
|
||||
* counter will be cleared to 0.
|
||||
@@ -798,7 +803,7 @@ extern "C" {
|
||||
/** PCNT_U3_CONF3_REG register
|
||||
* Configuration register for unit $n's step value.
|
||||
*/
|
||||
#define PCNT_U3_CONF3_REG (DR_REG_PCNT_BASE + 0x3c)
|
||||
#define PCNT_U3_CONF3_REG(i) (REG_PCNT_BASE(i) + 0x3c)
|
||||
/** PCNT_CNT_H_STEP_U3 : R/W; bitpos: [15:0]; default: 0;
|
||||
* Configures the forward rotation step value for unit 3.
|
||||
*/
|
||||
@@ -817,7 +822,7 @@ extern "C" {
|
||||
/** PCNT_U0_CNT_REG register
|
||||
* Counter value for unit 0
|
||||
*/
|
||||
#define PCNT_U0_CNT_REG (DR_REG_PCNT_BASE + 0x40)
|
||||
#define PCNT_U0_CNT_REG(i) (REG_PCNT_BASE(i) + 0x40)
|
||||
/** PCNT_PULSE_CNT_U0 : RO; bitpos: [15:0]; default: 0;
|
||||
* Represents the current pulse count value for unit 0.
|
||||
*/
|
||||
@@ -829,7 +834,7 @@ extern "C" {
|
||||
/** PCNT_U1_CNT_REG register
|
||||
* Counter value for unit 1
|
||||
*/
|
||||
#define PCNT_U1_CNT_REG (DR_REG_PCNT_BASE + 0x44)
|
||||
#define PCNT_U1_CNT_REG(i) (REG_PCNT_BASE(i) + 0x44)
|
||||
/** PCNT_PULSE_CNT_U1 : RO; bitpos: [15:0]; default: 0;
|
||||
* Represents the current pulse count value for unit 1.
|
||||
*/
|
||||
@@ -841,7 +846,7 @@ extern "C" {
|
||||
/** PCNT_U2_CNT_REG register
|
||||
* Counter value for unit 2
|
||||
*/
|
||||
#define PCNT_U2_CNT_REG (DR_REG_PCNT_BASE + 0x48)
|
||||
#define PCNT_U2_CNT_REG(i) (REG_PCNT_BASE(i) + 0x48)
|
||||
/** PCNT_PULSE_CNT_U2 : RO; bitpos: [15:0]; default: 0;
|
||||
* Represents the current pulse count value for unit 2.
|
||||
*/
|
||||
@@ -853,7 +858,7 @@ extern "C" {
|
||||
/** PCNT_U3_CNT_REG register
|
||||
* Counter value for unit 3
|
||||
*/
|
||||
#define PCNT_U3_CNT_REG (DR_REG_PCNT_BASE + 0x4c)
|
||||
#define PCNT_U3_CNT_REG(i) (REG_PCNT_BASE(i) + 0x4c)
|
||||
/** PCNT_PULSE_CNT_U3 : RO; bitpos: [15:0]; default: 0;
|
||||
* Represents the current pulse count value for unit 3.
|
||||
*/
|
||||
@@ -865,7 +870,7 @@ extern "C" {
|
||||
/** PCNT_INT_RAW_REG register
|
||||
* Interrupt raw status register
|
||||
*/
|
||||
#define PCNT_INT_RAW_REG (DR_REG_PCNT_BASE + 0x50)
|
||||
#define PCNT_INT_RAW_REG(i) (REG_PCNT_BASE(i) + 0x50)
|
||||
/** PCNT_CNT_THR_EVENT_U0_INT_RAW : R/WTC/SS; bitpos: [0]; default: 0;
|
||||
* The raw interrupt status bit for the PCNT_CNT_THR_EVENT_U0_INT interrupt.
|
||||
*/
|
||||
@@ -898,7 +903,7 @@ extern "C" {
|
||||
/** PCNT_INT_ST_REG register
|
||||
* Interrupt status register
|
||||
*/
|
||||
#define PCNT_INT_ST_REG (DR_REG_PCNT_BASE + 0x54)
|
||||
#define PCNT_INT_ST_REG(i) (REG_PCNT_BASE(i) + 0x54)
|
||||
/** PCNT_CNT_THR_EVENT_U0_INT_ST : RO; bitpos: [0]; default: 0;
|
||||
* The masked interrupt status bit for the PCNT_CNT_THR_EVENT_U0_INT interrupt.
|
||||
*/
|
||||
@@ -931,7 +936,7 @@ extern "C" {
|
||||
/** PCNT_INT_ENA_REG register
|
||||
* Interrupt enable register
|
||||
*/
|
||||
#define PCNT_INT_ENA_REG (DR_REG_PCNT_BASE + 0x58)
|
||||
#define PCNT_INT_ENA_REG(i) (REG_PCNT_BASE(i) + 0x58)
|
||||
/** PCNT_CNT_THR_EVENT_U0_INT_ENA : R/W; bitpos: [0]; default: 0;
|
||||
* The interrupt enable bit for the PCNT_CNT_THR_EVENT_U0_INT interrupt.
|
||||
*/
|
||||
@@ -964,7 +969,7 @@ extern "C" {
|
||||
/** PCNT_INT_CLR_REG register
|
||||
* Interrupt clear register
|
||||
*/
|
||||
#define PCNT_INT_CLR_REG (DR_REG_PCNT_BASE + 0x5c)
|
||||
#define PCNT_INT_CLR_REG(i) (REG_PCNT_BASE(i) + 0x5c)
|
||||
/** PCNT_CNT_THR_EVENT_U0_INT_CLR : WT; bitpos: [0]; default: 0;
|
||||
* Set this bit to clear the PCNT_CNT_THR_EVENT_U0_INT interrupt.
|
||||
*/
|
||||
@@ -997,7 +1002,7 @@ extern "C" {
|
||||
/** PCNT_U0_STATUS_REG register
|
||||
* PNCT UNIT0 status register
|
||||
*/
|
||||
#define PCNT_U0_STATUS_REG (DR_REG_PCNT_BASE + 0x60)
|
||||
#define PCNT_U0_STATUS_REG(i) (REG_PCNT_BASE(i) + 0x60)
|
||||
/** PCNT_CNT_THR_ZERO_MODE_U0 : RO; bitpos: [1:0]; default: 0;
|
||||
* Represents the pulse counter status of PCNT_U0 corresponding to 0.
|
||||
* 0: pulse counter decreases from positive to 0
|
||||
@@ -1081,7 +1086,7 @@ extern "C" {
|
||||
/** PCNT_U1_STATUS_REG register
|
||||
* PNCT UNIT1 status register
|
||||
*/
|
||||
#define PCNT_U1_STATUS_REG (DR_REG_PCNT_BASE + 0x64)
|
||||
#define PCNT_U1_STATUS_REG(i) (REG_PCNT_BASE(i) + 0x64)
|
||||
/** PCNT_CNT_THR_ZERO_MODE_U1 : RO; bitpos: [1:0]; default: 0;
|
||||
* Represents the pulse counter status of PCNT_U1 corresponding to 0.
|
||||
* 0: pulse counter decreases from positive to 0
|
||||
@@ -1165,7 +1170,7 @@ extern "C" {
|
||||
/** PCNT_U2_STATUS_REG register
|
||||
* PNCT UNIT2 status register
|
||||
*/
|
||||
#define PCNT_U2_STATUS_REG (DR_REG_PCNT_BASE + 0x68)
|
||||
#define PCNT_U2_STATUS_REG(i) (REG_PCNT_BASE(i) + 0x68)
|
||||
/** PCNT_CNT_THR_ZERO_MODE_U2 : RO; bitpos: [1:0]; default: 0;
|
||||
* Represents the pulse counter status of PCNT_U2 corresponding to 0.
|
||||
* 0: pulse counter decreases from positive to 0
|
||||
@@ -1249,7 +1254,7 @@ extern "C" {
|
||||
/** PCNT_U3_STATUS_REG register
|
||||
* PNCT UNIT3 status register
|
||||
*/
|
||||
#define PCNT_U3_STATUS_REG (DR_REG_PCNT_BASE + 0x6c)
|
||||
#define PCNT_U3_STATUS_REG(i) (REG_PCNT_BASE(i) + 0x6c)
|
||||
/** PCNT_CNT_THR_ZERO_MODE_U3 : RO; bitpos: [1:0]; default: 0;
|
||||
* Represents the pulse counter status of PCNT_U3 corresponding to 0.
|
||||
* 0: pulse counter decreases from positive to 0
|
||||
@@ -1333,7 +1338,7 @@ extern "C" {
|
||||
/** PCNT_CTRL_REG register
|
||||
* Control register for all counters
|
||||
*/
|
||||
#define PCNT_CTRL_REG (DR_REG_PCNT_BASE + 0x70)
|
||||
#define PCNT_CTRL_REG(i) (REG_PCNT_BASE(i) + 0x70)
|
||||
/** PCNT_PULSE_CNT_RST_U0 : R/W; bitpos: [0]; default: 1;
|
||||
* Set this bit to clear unit 0's counter.
|
||||
*/
|
||||
@@ -1431,7 +1436,7 @@ extern "C" {
|
||||
/** PCNT_DATE_REG register
|
||||
* PCNT version control register
|
||||
*/
|
||||
#define PCNT_DATE_REG (DR_REG_PCNT_BASE + 0xfc)
|
||||
#define PCNT_DATE_REG(i) (REG_PCNT_BASE(i) + 0xfc)
|
||||
/** PCNT_DATE : R/W; bitpos: [31:0]; default: 37822848;
|
||||
* Version control register.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*/
|
||||
@@ -148,73 +148,22 @@ typedef union {
|
||||
uint32_t val;
|
||||
} pcnt_un_conf2_reg_t;
|
||||
|
||||
/** Type of u0_conf3 register
|
||||
/** 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,34 +433,26 @@ 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;
|
||||
} pcnt_dev_t;
|
||||
|
||||
extern pcnt_dev_t PCNT0;
|
||||
extern pcnt_dev_t PCNT1;
|
||||
|
||||
#ifndef __cplusplus
|
||||
_Static_assert(sizeof(pcnt_dev_t) == 0x100, "Invalid size of pcnt_dev_t structure");
|
||||
|
||||
@@ -50,15 +50,19 @@ To install a PCNT unit, there is a configuration structure that needs to be give
|
||||
|
||||
.. list::
|
||||
|
||||
- :cpp:member:`pcnt_unit_config_t::group_id` specifies which PCNT peripheral group (hardware instance) to allocate the unit from. Must be a valid group index in range ``[0, PCNT_LL_INST_NUM)``. When you have multiple independent PCNT groups on a chip (e.g., ESP32-S31), this field allows you to pin a unit to a specific group.
|
||||
- :cpp:member:`pcnt_unit_config_t::clk_src` selects the clock source for the PCNT unit.
|
||||
- :cpp:member:`pcnt_unit_config_t::low_limit` and :cpp:member:`pcnt_unit_config_t::high_limit` specify the range for the internal hardware counter. The counter will reset to zero automatically when it crosses either the high or low limit.
|
||||
- :cpp:member:`pcnt_unit_config_t::intr_priority` sets the interrupt priority. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority.
|
||||
- :cpp:member:`pcnt_unit_config_t::flags::accum_count` sets whether to create an internal accumulator for the counter. This is helpful when you want to extend the counter's width, which by default is 16 bit at most, defined in the hardware. See also :ref:`pcnt-compensate-overflow-loss` for how to use this feature to compensate the overflow loss.
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_unit_config_t::flags::en_step_notify_up` Configure whether to enable watch step to count in the positive direction.
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_unit_config_t::flags::en_step_notify_down` Configure whether to enable watch step to count in the negative direction.
|
||||
- :cpp:member:`pcnt_unit_config_t::intr_priority` sets the priority of the interrupt. If it is set to ``0``, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority.
|
||||
|
||||
.. note::
|
||||
|
||||
Since all PCNT units share the same interrupt source, when installing multiple PCNT units make sure that the interrupt priority :cpp:member:`pcnt_unit_config_t::intr_priority` is the same for each unit.
|
||||
All units within the **same PCNT group** share the same hardware interrupt source and the same peripheral clock. Therefore, when installing multiple PCNT units in the same group, the following constraints apply:
|
||||
|
||||
- Both :cpp:member:`pcnt_unit_config_t::intr_priority` and :cpp:member:`pcnt_unit_config_t::clk_src` must be the same for all units within the same group. If there is a mismatch, :cpp:func:`pcnt_new_unit` will return :c:macro:`ESP_ERR_INVALID_ARG`.
|
||||
|
||||
Unit allocation and initialization is done by calling a function :cpp:func:`pcnt_new_unit` with :cpp:type:`pcnt_unit_config_t` as an input parameter. The function will return a PCNT unit handle only when it runs correctly. Specifically, when there are no more free PCNT units in the pool (i.e., unit resources have been used up), then this function will return :c:macro:`ESP_ERR_NOT_FOUND` error.
|
||||
|
||||
|
||||
@@ -50,15 +50,19 @@ PCNT 单元和通道分别用 :cpp:type:`pcnt_unit_handle_t` 与 :cpp:type:`pcnt
|
||||
|
||||
.. list::
|
||||
|
||||
- :cpp:member:`pcnt_unit_config_t::group_id` 用于指定从哪个 PCNT 外设组(硬件实例)中分配该单元。必须是合法的组索引,范围为 ``[0, PCNT_LL_INST_NUM)``。当芯片拥有多个独立 PCNT 组时(例如 ESP32-S31),可通过此字段将单元绑定到特定的组。
|
||||
- :cpp:member:`pcnt_unit_config_t::clk_src` 用于选择 PCNT 单元的时钟源。
|
||||
- :cpp:member:`pcnt_unit_config_t::low_limit` 与 :cpp:member:`pcnt_unit_config_t::high_limit` 用于指定内部计数器的最小值和最大值。当计数器超过任一限值时,计数器将归零。
|
||||
- :cpp:member:`pcnt_unit_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。
|
||||
- :cpp:member:`pcnt_unit_config_t::flags::accum_count` 用于设置是否需要软件在硬件计数值溢出的时候进行累加保存,这有助于“拓宽”计数器的实际位宽。默认情况下,计数器的位宽最高只有 16 比特。请参考 :ref:`pcnt-compensate-overflow-loss` 了解如何利用此功能来补偿硬件计数器的溢出损失。
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_unit_config_t::flags::en_step_notify_up` 配置是否使能观察正方向步进。
|
||||
:SOC_PCNT_SUPPORT_STEP_NOTIFY: - :cpp:member:`pcnt_unit_config_t::flags::en_step_notify_down` 配置是否使能观察负方向步进。
|
||||
- :cpp:member:`pcnt_unit_config_t::intr_priority` 设置中断的优先级。如果设置为 ``0``,则会分配一个默认优先级的中断,否则会使用指定的优先级。
|
||||
|
||||
.. note::
|
||||
|
||||
由于所有 PCNT 单元共享一个中断源,安装多个 PCNT 单元时请确保每个单元的中断优先级 :cpp:member:`pcnt_unit_config_t::intr_priority` 一致。
|
||||
**同一 PCNT 组** 内的所有单元共享同一硬件中断源和同一外设时钟,因此在同一组内安装多个 PCNT 单元时,需满足以下约束:
|
||||
|
||||
- :cpp:member:`pcnt_unit_config_t::intr_priority` 和 :cpp:member:`pcnt_unit_config_t::clk_src` 在同组内须一致,不一致将导致 :cpp:func:`pcnt_new_unit` 返回 :c:macro:`ESP_ERR_INVALID_ARG`。
|
||||
|
||||
调用函数 :cpp:func:`pcnt_new_unit` 并将 :cpp:type:`pcnt_unit_config_t` 作为其输入值,可对 PCNT 单元进行分配和初始化。该函数正常运行时,会返回一个 PCNT 单元句柄。没有可用的 PCNT 单元时(即 PCNT 单元全部被占用),该函数会返回错误 :c:macro:`ESP_ERR_NOT_FOUND`。
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- |
|
||||
# MCPWM Brushed DC Motor Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | 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 | ESP32-S31 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
|
||||
|
||||
# Rotary Encoder Example
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded.dut import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
from pytest_embedded_idf.utils import soc_filtered_targets
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize(
|
||||
'target', ['esp32', 'esp32s2', 'esp32s3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], indirect=['target']
|
||||
)
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_PCNT_SUPPORTED == 1'), indirect=['target'])
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32h21', 'esp32h4'], reason='lack of runners')
|
||||
def test_rotary_encoder(dut: Dut) -> None:
|
||||
dut.expect_exact('install pcnt unit')
|
||||
dut.expect_exact('set glitch filter')
|
||||
|
||||
Reference in New Issue
Block a user