feat(pcnt): re-support pcnt on ESP32-C5 V1.0

This commit is contained in:
Chen Jichang
2025-04-18 15:17:20 +08:00
parent 182b33efb2
commit ca981fdf4d
13 changed files with 762 additions and 2512 deletions

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
*/
@ -316,7 +316,7 @@ esp_err_t pcnt_unit_remove_watch_point(pcnt_unit_handle_t unit, int watch_point)
* @brief Add a step notify for PCNT unit, PCNT will generate an event when the incremental(can be positive or negative) of counter value reaches the step interval
*
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
* @param[in] step_interval PCNT step notify interval value
* @param[in] step_interval PCNT step notify interval value. Positive value means step forward, negative value means step backward.
* @return
* - ESP_OK: Add step notify successfully
* - ESP_ERR_INVALID_ARG: Add step notify failed because of invalid argument (e.g. the value incremental to be watched is out of the limitation set in `pcnt_unit_config_t`)
@ -326,7 +326,7 @@ esp_err_t pcnt_unit_remove_watch_point(pcnt_unit_handle_t unit, int watch_point)
esp_err_t pcnt_unit_add_watch_step(pcnt_unit_handle_t unit, int step_interval);
/**
* @brief Remove a step notify for PCNT unit
* @brief Remove all step notify for PCNT unit
*
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
* @return
@ -335,7 +335,25 @@ esp_err_t pcnt_unit_add_watch_step(pcnt_unit_handle_t unit, int step_interval);
* - ESP_ERR_INVALID_STATE: Remove step notify failed because the step notify was not added by `pcnt_unit_add_watch_step()` yet
* - ESP_FAIL: Remove step notify failed because of other error
*/
esp_err_t pcnt_unit_remove_watch_step(pcnt_unit_handle_t unit);
esp_err_t pcnt_unit_remove_all_watch_step(pcnt_unit_handle_t unit);
/**
* @brief Remove a step notify for PCNT unit
*
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
* @param[in] step_interval Step notify interval value
* @return
* - ESP_OK: Remove step notify successfully
* - ESP_ERR_INVALID_ARG: Remove step notify failed because of invalid argument
* - ESP_ERR_INVALID_STATE: Remove step notify failed because the step notify was not added by `pcnt_unit_add_watch_step()` yet
* - ESP_FAIL: Remove step notify failed because of other error
*/
esp_err_t pcnt_unit_remove_single_watch_step(pcnt_unit_handle_t unit, int step_interval);
#define _pcnt_unit_remove_all_watch_step(unit) pcnt_unit_remove_all_watch_step(unit)
#define _pcnt_unit_remove_single_watch_step(unit, step_interval) pcnt_unit_remove_single_watch_step(unit, step_interval)
#define _pcnt_get_remove_func(_1, _2, FUNC, ...) FUNC
#define pcnt_unit_remove_watch_step(...) _pcnt_get_remove_func(__VA_ARGS__, _pcnt_unit_remove_single_watch_step, _pcnt_unit_remove_all_watch_step)(__VA_ARGS__)
/**
* @brief Create PCNT channel for specific unit, each PCNT has several channels associated with it

View File

@ -92,6 +92,16 @@ typedef struct {
int watch_point_value; // value to be watched
} pcnt_watch_point_t;
typedef struct {
#if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
int step_interval; // step interval
int step_limit; // step limit value
#else
int step_interval_forward; // step interval for forward direction
int step_interval_backward; // step interval for backward direction
#endif
} pcnt_step_interval_t;
typedef enum {
PCNT_UNIT_FSM_INIT,
PCNT_UNIT_FSM_ENABLE,
@ -103,10 +113,9 @@ struct pcnt_unit_t {
int unit_id; // allocated unit numerical ID
int low_limit; // low limit value
int high_limit; // high limit value
int step_limit; // step limit value
int clear_signal_gpio_num; // which gpio clear signal input
int accum_value; // accumulated count value
int step_interval; // PCNT step notify interval value
pcnt_step_interval_t step_info; // step interval info
pcnt_chan_t *channels[SOC_PCNT_CHANNELS_PER_UNIT]; // array of PCNT channels
pcnt_watch_point_t watchers[PCNT_LL_WATCH_EVENT_MAX]; // array of PCNT watchers
intr_handle_t intr; // interrupt handle
@ -281,11 +290,11 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
unit->flags.en_step_notify_up = config->flags.en_step_notify_up;
#if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
if (config->flags.en_step_notify_up) {
unit->step_limit = config->high_limit;
unit->step_info.step_limit = config->high_limit;
} else if (config->flags.en_step_notify_down) {
unit->step_limit = config->low_limit;
unit->step_info.step_limit = config->low_limit;
}
pcnt_ll_set_step_limit_value(group->hal.dev, unit_id, unit->step_limit);
pcnt_ll_set_step_limit_value(group->hal.dev, unit_id, unit->step_info.step_limit);
#endif
#endif
@ -679,11 +688,26 @@ esp_err_t pcnt_unit_add_watch_step(pcnt_unit_handle_t unit, int step_interval)
ESP_ERR_INVALID_ARG, TAG, "invalid step interval");
ESP_RETURN_ON_FALSE(step_interval >= unit->low_limit && step_interval <= unit->high_limit,
ESP_ERR_INVALID_ARG, TAG, "step interval out of range [%d,%d]", unit->low_limit, unit->high_limit);
ESP_RETURN_ON_FALSE(unit->step_interval == 0,
ESP_ERR_INVALID_STATE, TAG, "watch step has been set to %d already", unit->step_interval);
unit->step_interval = step_interval;
pcnt_ll_set_step_value(group->hal.dev, unit->unit_id, step_interval);
#if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
ESP_RETURN_ON_FALSE(unit->step_info.step_interval == 0,
ESP_ERR_INVALID_STATE, TAG, "watch step has been set to %d already", unit->step_info.step_interval);
pcnt_ll_set_step_value(group->hal.dev, unit->unit_id, step_interval > 0 ? PCNT_STEP_FORWARD : PCNT_STEP_BACKWARD, (uint16_t)step_interval);
unit->step_info.step_interval = step_interval;
#else
if (step_interval > 0) {
ESP_RETURN_ON_FALSE(unit->step_info.step_interval_forward == 0,
ESP_ERR_INVALID_STATE, TAG, "watch step in forward has been set to %d already", unit->step_info.step_interval_forward);
pcnt_ll_set_step_value(group->hal.dev, unit->unit_id, PCNT_STEP_FORWARD, (uint16_t)step_interval);
unit->step_info.step_interval_forward = step_interval;
} else {
ESP_RETURN_ON_FALSE(unit->step_info.step_interval_backward == 0,
ESP_ERR_INVALID_STATE, TAG, "watch step in backward has been set to %d already", unit->step_info.step_interval_backward);
pcnt_ll_set_step_value(group->hal.dev, unit->unit_id, PCNT_STEP_BACKWARD, (uint16_t)step_interval);
unit->step_info.step_interval_backward = step_interval;
}
#endif //PCNT_LL_STEP_NOTIFY_DIR_LIMIT
// different units are mixing in the same register, so we use the group's spinlock here
portENTER_CRITICAL(&group->spinlock);
pcnt_ll_enable_step_notify(group->hal.dev, unit->unit_id, true);
@ -692,14 +716,20 @@ esp_err_t pcnt_unit_add_watch_step(pcnt_unit_handle_t unit, int step_interval)
return ESP_OK;
}
esp_err_t pcnt_unit_remove_watch_step(pcnt_unit_handle_t unit)
esp_err_t pcnt_unit_remove_all_watch_step(pcnt_unit_handle_t unit)
{
pcnt_group_t *group = NULL;
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
group = unit->group;
ESP_RETURN_ON_FALSE(unit->step_interval != 0, ESP_ERR_INVALID_STATE, TAG, "watch step not added yet");
unit->step_interval = 0;
#if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
ESP_RETURN_ON_FALSE(unit->step_info.step_interval != 0, ESP_ERR_INVALID_STATE, TAG, "watch step not added yet");
unit->step_info.step_interval = 0;
#else
ESP_RETURN_ON_FALSE(unit->step_info.step_interval_forward != 0 || unit->step_info.step_interval_backward != 0,
ESP_ERR_INVALID_STATE, TAG, "watch step in forward or backward not added yet");
unit->step_info.step_interval_forward = 0;
unit->step_info.step_interval_backward = 0;
#endif
portENTER_CRITICAL(&group->spinlock);
pcnt_ll_enable_step_notify(group->hal.dev, unit->unit_id, false);
@ -707,6 +737,36 @@ esp_err_t pcnt_unit_remove_watch_step(pcnt_unit_handle_t unit)
return ESP_OK;
}
esp_err_t pcnt_unit_remove_single_watch_step(pcnt_unit_handle_t unit, int step_interval)
{
pcnt_group_t *group = NULL;
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
group = unit->group;
#if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
ESP_RETURN_ON_FALSE(unit->step_info.step_interval == step_interval, ESP_ERR_INVALID_STATE, TAG, "watch step %d not added yet", step_interval);
unit->step_info.step_interval = 0;
portENTER_CRITICAL(&group->spinlock);
pcnt_ll_enable_step_notify(group->hal.dev, unit->unit_id, false);
portEXIT_CRITICAL(&group->spinlock);
#else
if (step_interval > 0) {
ESP_RETURN_ON_FALSE(unit->step_info.step_interval_forward == step_interval, ESP_ERR_INVALID_STATE, TAG, "watch step %d not added yet", step_interval);
pcnt_ll_set_step_value(group->hal.dev, unit->unit_id, PCNT_STEP_FORWARD, 0);
unit->step_info.step_interval_forward = 0;
} else {
ESP_RETURN_ON_FALSE(unit->step_info.step_interval_backward == step_interval, ESP_ERR_INVALID_STATE, TAG, "watch step %d not added yet", step_interval);
pcnt_ll_set_step_value(group->hal.dev, unit->unit_id, PCNT_STEP_BACKWARD, 0);
unit->step_info.step_interval_backward = 0;
}
if (unit->step_info.step_interval_forward == 0 && unit->step_info.step_interval_backward == 0) {
portENTER_CRITICAL(&group->spinlock);
pcnt_ll_enable_step_notify(group->hal.dev, unit->unit_id, false);
portEXIT_CRITICAL(&group->spinlock);
}
#endif
return ESP_OK;
}
#endif //SOC_PCNT_SUPPORT_STEP_NOTIFY
esp_err_t pcnt_new_channel(pcnt_unit_handle_t unit, const pcnt_chan_config_t *config, pcnt_channel_handle_t *ret_chan)
@ -962,6 +1022,7 @@ IRAM_ATTR static void pcnt_default_isr(void *args)
// using while loop so that we don't miss any event
while (event_status) {
#if SOC_PCNT_SUPPORT_STEP_NOTIFY
#if PCNT_LL_STEP_NOTIFY_DIR_LIMIT
// step event has higher priority than pointer event
if (event_status & (BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL) | BIT(PCNT_LL_STEP_EVENT_REACH_LIMIT))) {
if (event_status & BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL)) {
@ -972,13 +1033,27 @@ IRAM_ATTR static void pcnt_default_isr(void *args)
if (event_status & BIT(PCNT_LL_STEP_EVENT_REACH_LIMIT)) {
event_status &= ~BIT(PCNT_LL_STEP_EVENT_REACH_LIMIT);
// adjust current count value to the step limit
count_value = unit->step_limit;
count_value = unit->step_info.step_limit;
if (unit->flags.accum_count) {
portENTER_CRITICAL_ISR(&unit->spinlock);
unit->accum_value += unit->step_limit;
unit->accum_value += unit->step_info.step_limit;
portEXIT_CRITICAL_ISR(&unit->spinlock);
}
}
#else
// step event has higher priority than pointer event
if (event_status & (BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL_FORWARD) | BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL_BACKWARD))) {
if (event_status & BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL_FORWARD)) {
event_status &= ~BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL_FORWARD);
// align current count value to the step interval
count_value = pcnt_ll_get_count(group->hal.dev, unit_id);
}
if (event_status & BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL_BACKWARD)) {
event_status &= ~BIT(PCNT_LL_STEP_EVENT_REACH_INTERVAL_BACKWARD);
// align current count value to the step interval
count_value = pcnt_ll_get_count(group->hal.dev, unit_id);
}
#endif // PCNT_LL_STEP_NOTIFY_DIR_LIMIT
// step event may happen with other pointer event at the same time, we don't need to process them again
event_status &= ~(BIT(PCNT_LL_WATCH_EVENT_LOW_LIMIT) | BIT(PCNT_LL_WATCH_EVENT_HIGH_LIMIT) |
BIT(PCNT_LL_WATCH_EVENT_THRES0) | BIT(PCNT_LL_WATCH_EVENT_THRES1));

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
*/
@ -681,6 +681,9 @@ TEST_CASE("pcnt_step_notify_event", "[pcnt]")
if (pcnt_ll_is_step_notify_supported(0)) { // for ESP32H2, only support in chip version v1.2 and above
test_gpio_init_for_simulation(TEST_PCNT_GPIO_A);
test_gpio_init_for_simulation(TEST_PCNT_GPIO_B);
// ensure the simulation signal in a stable state
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_A, 1));
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_B, 1));
pcnt_unit_config_t unit_config = {
.low_limit = -100,
@ -715,10 +718,6 @@ TEST_CASE("pcnt_step_notify_event", "[pcnt]")
TEST_ESP_OK(pcnt_channel_set_edge_action(channelB, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_DECREASE));
TEST_ESP_OK(pcnt_channel_set_level_action(channelB, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_INVERSE));
// ensure the simulation signal in a stable state
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_A, 1));
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_B, 1));
pcnt_event_callbacks_t cbs = {
.on_reach = test_pcnt_quadrature_reach_watch_point,
};
@ -820,6 +819,141 @@ TEST_CASE("pcnt_step_notify_event", "[pcnt]")
TEST_ESP_OK(pcnt_unit_disable(unit));
TEST_ESP_OK(pcnt_del_unit(unit));
}
}
#if !PCNT_LL_STEP_NOTIFY_DIR_LIMIT
TEST_CASE("pcnt_step_notify_event_bidirectional", "[pcnt]")
{
if (pcnt_ll_is_step_notify_supported(0)) { // for ESP32H2, only support in chip version v1.2 and above
test_gpio_init_for_simulation(TEST_PCNT_GPIO_A);
test_gpio_init_for_simulation(TEST_PCNT_GPIO_B);
// ensure the simulation signal in a stable state
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_A, 1));
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_B, 1));
pcnt_unit_config_t unit_config = {
.low_limit = -100,
.high_limit = 100,
.flags = {
.en_step_notify_down = true,
.en_step_notify_up = true,
},
};
printf("install pcnt unit\r\n");
pcnt_unit_handle_t unit = NULL;
TEST_ESP_OK(pcnt_new_unit(&unit_config, &unit));
pcnt_glitch_filter_config_t filter_config = {
.max_glitch_ns = 1000,
};
TEST_ESP_OK(pcnt_unit_set_glitch_filter(unit, &filter_config));
printf("install two pcnt channels with different edge/level action\r\n");
pcnt_chan_config_t channel_config = {
.edge_gpio_num = TEST_PCNT_GPIO_A,
.level_gpio_num = TEST_PCNT_GPIO_B,
};
pcnt_channel_handle_t channelA = NULL;
TEST_ESP_OK(pcnt_new_channel(unit, &channel_config, &channelA));
TEST_ESP_OK(pcnt_channel_set_edge_action(channelA, PCNT_CHANNEL_EDGE_ACTION_DECREASE, PCNT_CHANNEL_EDGE_ACTION_INCREASE));
TEST_ESP_OK(pcnt_channel_set_level_action(channelA, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_INVERSE));
// switch edge gpio and level gpio, the assign to another channel in the same unit
pcnt_channel_handle_t channelB = NULL;
channel_config.edge_gpio_num = TEST_PCNT_GPIO_B;
channel_config.level_gpio_num = TEST_PCNT_GPIO_A;
TEST_ESP_OK(pcnt_new_channel(unit, &channel_config, &channelB));
TEST_ESP_OK(pcnt_channel_set_edge_action(channelB, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_DECREASE));
TEST_ESP_OK(pcnt_channel_set_level_action(channelB, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_INVERSE));
pcnt_event_callbacks_t cbs = {
.on_reach = test_pcnt_quadrature_reach_watch_point,
};
test_pcnt_quadrature_context_t user_data = {
.index = 0,
.triggered_watch_values = {0},
};
TEST_ESP_OK(pcnt_unit_register_event_callbacks(unit, &cbs, &user_data));
printf("add watch step and point\r\n");
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, pcnt_unit_add_watch_step(unit, 0));
TEST_ESP_OK(pcnt_unit_add_watch_step(unit, -25));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, pcnt_unit_add_watch_step(unit, -120));
TEST_ESP_OK(pcnt_unit_add_watch_step(unit, 20));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_unit_add_watch_step(unit, 100));
TEST_ESP_OK(pcnt_unit_add_watch_point(unit, -100));
TEST_ESP_OK(pcnt_unit_add_watch_point(unit, 0));
TEST_ESP_OK(pcnt_unit_add_watch_point(unit, -50));
TEST_ESP_OK(pcnt_unit_add_watch_point(unit, 11));
TEST_ESP_OK(pcnt_unit_enable(unit));
TEST_ESP_OK(pcnt_unit_start(unit));
printf("simulating quadrature signals and count down\r\n");
test_gpio_simulate_quadrature_signals(TEST_PCNT_GPIO_A, TEST_PCNT_GPIO_B, 25); // 25*(-4) = -100 -> 0
int count_value;
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
printf("counter stopped at %d\r\n", count_value);
for (int i = 0 ; i < user_data.index; i++) {
printf("%d:%d\r\n", i, user_data.triggered_watch_values[i]);
}
TEST_ASSERT_EQUAL(0, count_value);
TEST_ASSERT_EQUAL(5, user_data.index);
TEST_ASSERT_EQUAL(-25, user_data.triggered_watch_values[0]); // step point (-25*1)
TEST_ASSERT_EQUAL(-50, user_data.triggered_watch_values[1]); // step point && watch point
TEST_ASSERT_EQUAL(-75, user_data.triggered_watch_values[2]); // step point (-25*3)
TEST_ASSERT_EQUAL(-100, user_data.triggered_watch_values[3]);// step point && watch point
TEST_ASSERT_EQUAL(0, user_data.triggered_watch_values[4]); // watch point (overflow zero cross)
printf("simulating quadrature signals and count up\r\n");
user_data.index = 0;
test_gpio_simulate_quadrature_signals(TEST_PCNT_GPIO_B, TEST_PCNT_GPIO_A, 25); // 0+25*4 = 100 -> 0
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
printf("counter stopped at %d\r\n", count_value);
for (int i = 0 ; i < user_data.index; i++) {
printf("%d:%d\r\n", i, user_data.triggered_watch_values[i]);
}
TEST_ASSERT_EQUAL(0, count_value);
TEST_ASSERT_EQUAL(6, user_data.index);
TEST_ASSERT_EQUAL(11, user_data.triggered_watch_values[0]); // watch point
TEST_ASSERT_EQUAL(20, user_data.triggered_watch_values[1]); // step point (20*1)
TEST_ASSERT_EQUAL(40, user_data.triggered_watch_values[2]); // step point (20*2)
TEST_ASSERT_EQUAL(60, user_data.triggered_watch_values[3]); // step point (40+20*2)
TEST_ASSERT_EQUAL(80, user_data.triggered_watch_values[4]); // step point (60+20*2)
TEST_ASSERT_EQUAL(0, user_data.triggered_watch_values[5]); // watch point (overflow zero cross)
printf("change step interval\r\n");
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_unit_remove_watch_step(unit, -20)); // -20 is not a step point
TEST_ESP_OK(pcnt_unit_remove_watch_step(unit, -25));
TEST_ESP_OK(pcnt_unit_add_watch_step(unit, -20));
printf("simulating quadrature signals and count down\r\n");
user_data.index = 0;
test_gpio_simulate_quadrature_signals(TEST_PCNT_GPIO_A, TEST_PCNT_GPIO_B, 20); // 20*(-4) = -80
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
printf("counter stopped at %d\r\n", count_value);
for (int i = 0 ; i < user_data.index; i++) {
printf("%d:%d\r\n", i, user_data.triggered_watch_values[i]);
}
TEST_ASSERT_EQUAL(-80, count_value);
TEST_ASSERT_EQUAL(5, user_data.index);
TEST_ASSERT_EQUAL(-20, user_data.triggered_watch_values[0]); // step point (-20*1)
TEST_ASSERT_EQUAL(-40, user_data.triggered_watch_values[1]); // step point (-20*2)
TEST_ASSERT_EQUAL(-50, user_data.triggered_watch_values[2]); // watch point
TEST_ASSERT_EQUAL(-60, user_data.triggered_watch_values[3]); // step point (-20*3)
TEST_ASSERT_EQUAL(-80, user_data.triggered_watch_values[4]); // step point (-20*4)
printf("remove step_notify and uninstall channels\r\n");
TEST_ESP_OK(pcnt_unit_remove_watch_step(unit));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_unit_remove_watch_step(unit));
TEST_ESP_OK(pcnt_del_channel(channelA));
TEST_ESP_OK(pcnt_del_channel(channelB));
TEST_ESP_OK(pcnt_unit_stop(unit));
TEST_ESP_OK(pcnt_unit_disable(unit));
TEST_ESP_OK(pcnt_del_unit(unit));
}
}
#endif //PCNT_LL_STEP_NOTIFY_DIR_LIMIT
#endif // SOC_PCNT_SUPPORT_STEP_NOTIFY

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -34,11 +34,10 @@ typedef enum {
} pcnt_ll_watch_event_id_t;
typedef enum {
PCNT_LL_STEP_EVENT_REACH_LIMIT = PCNT_LL_WATCH_EVENT_MAX,
PCNT_LL_STEP_EVENT_REACH_INTERVAL
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_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))
@ -157,23 +156,16 @@ static inline void pcnt_ll_enable_step_notify(pcnt_dev_t *hw, uint32_t unit, boo
*
* @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, int value)
static inline void pcnt_ll_set_step_value(pcnt_dev_t *hw, uint32_t unit, pcnt_step_direction_t direction, uint16_t value)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->change_conf_unit[3 - unit], cnt_step, value);
}
/**
* @brief Set PCNT step limit value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param value PCNT step limit value
*/
static inline void pcnt_ll_set_step_limit_value(pcnt_dev_t *hw, uint32_t unit, int value)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->change_conf_unit[3 - unit], cnt_step_lim, 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);
}
}
/**

View File

@ -167,10 +167,12 @@ static inline void pcnt_ll_enable_step_notify(pcnt_dev_t *hw, uint32_t unit, boo
*
* @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, int value)
static inline void pcnt_ll_set_step_value(pcnt_dev_t *hw, uint32_t unit, pcnt_step_direction_t direction, int value)
{
(void)direction;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->change_conf_unit[3 - unit], cnt_step, value);
}

View File

@ -159,10 +159,12 @@ static inline void pcnt_ll_enable_step_notify(pcnt_dev_t *hw, uint32_t unit, boo
*
* @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, int value)
static inline void pcnt_ll_set_step_value(pcnt_dev_t *hw, uint32_t unit, pcnt_step_direction_t direction, int value)
{
(void)direction;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->change_conf_unit[3 - unit], cnt_step, value);
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -39,6 +39,14 @@ typedef enum {
PCNT_UNIT_ZERO_CROSS_INVALID, /*!< invalid zero cross mode */
} pcnt_unit_zero_cross_mode_t;
/**
* @brief PCNT step direction
*/
typedef enum {
PCNT_STEP_FORWARD, /*!< step forward, e.g., [N]->[N+1]->[N+2]->... */
PCNT_STEP_BACKWARD, /*!< step backward, e.g., [N]->[N-1]->[N-2]->... */
} pcnt_step_direction_t;
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -12,14 +12,14 @@ extern "C" {
/** Group: Configuration Register */
/** Type of un_conf0 register
* Configuration register 0 for unit 0
* Configuration register 0 for unit n
*/
typedef union {
struct {
/** filter_thres_un : 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. \\
* Measurement unit: APB_CLK cycles.\\
* this will be ignored when the filter is enabled.
* Measurement unit: APB_CLK cycles.
*/
uint32_t filter_thres_un:10;
/** filter_en_un : R/W; bitpos: [10]; default: 1;
@ -49,67 +49,63 @@ typedef union {
*/
uint32_t thr_thres1_en_un:1;
/** ch0_neg_mode_un : R/W; bitpos: [17:16]; default: 0;
* Configures the behavior when the signal input of channel 0 detects a negative
* edge.\\
* 1: Increment the counter\\
* 2: Decrement the counter\\
* 0, 3: No effect \\
* Configures the behavior when the signal input of channel 0 detects a negative edge.
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch0_neg_mode_un:2;
/** ch0_pos_mode_un : R/W; bitpos: [19:18]; default: 0;
* Configures the behavior when the signal input of channel 0 detects a positive edge.
* \\
* 1: Increment the counter\\
* 2: Decrement the counter\\
* 0, 3: No effect \\
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch0_pos_mode_un:2;
/** ch0_hctrl_mode_un : R/W; bitpos: [21:20]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is high. \\
* 0: No modification\\
* 1: Invert behavior (increase -> decrease, decrease -> increase)\\
* 2, 3: Inhibit counter modification \\
* control signal is high.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch0_hctrl_mode_un:2;
/** ch0_lctrl_mode_un : R/W; bitpos: [23:22]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is low. \\
* 0: No modification\\
* 1: Invert behavior (increase -> decrease, decrease -> increase)\\
* 2, 3: Inhibit counter modification\\
* control signal is low.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch0_lctrl_mode_un:2;
/** ch1_neg_mode_un : R/W; bitpos: [25:24]; default: 0;
* Configures the behavior when the signal input of channel 1 detects a negative edge.
* \\
* 1: Increment the counter\\
* 2: Decrement the counter\\
* 0, 3: No effect \\
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch1_neg_mode_un:2;
/** ch1_pos_mode_un : R/W; bitpos: [27:26]; default: 0;
* Configures the behavior when the signal input of channel 1 detects a positive edge.
* \\
* 1: Increment the counter\\
* 2: Decrement the counter\\
* 0, 3: No effect \\
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch1_pos_mode_un:2;
/** ch1_hctrl_mode_un : R/W; bitpos: [29:28]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is high. \\
* 0: No modification\\
* 1: Invert behavior (increase -> decrease, decrease -> increase)\\
* 2, 3: Inhibit counter modification \\
* control signal is high.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch1_hctrl_mode_un:2;
/** ch1_lctrl_mode_un : R/W; bitpos: [31:30]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is low. \\
* 0: No modification\\
* 1: Invert behavior (increase -> decrease, decrease -> increase)\\
* 2, 3: Inhibit counter modification \\
* control signal is low.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch1_lctrl_mode_un:2;
};
@ -117,7 +113,7 @@ typedef union {
} pcnt_un_conf0_reg_t;
/** Type of un_conf1 register
* Configuration register 1 for unit 0
* Configuration register 1 for unit n
*/
typedef union {
struct {
@ -134,7 +130,7 @@ typedef union {
} pcnt_un_conf1_reg_t;
/** Type of un_conf2 register
* Configuration register 2 for unit 0
* Configuration register 2 for unit n
*/
typedef union {
struct {
@ -152,6 +148,24 @@ typedef union {
uint32_t val;
} pcnt_un_conf2_reg_t;
/** Type of un_conf3 register
* Configuration register for unit n's step value.
*/
typedef union {
struct {
/** 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_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_un:16;
};
uint32_t val;
} pcnt_un_conf3_reg_t;
/** Type of ctrl register
* Control register for all counters
*/
@ -217,26 +231,10 @@ typedef union {
uint32_t val;
} pcnt_ctrl_reg_t;
/** Type of un_change_conf register
* Configuration register for unit $n's step value.
*/
typedef union {
struct {
/** cnt_step : R/W; bitpos: [15:0]; default: 0;
* Configures the step value for unit n.
*/
uint32_t cnt_step:16;
/** cnt_step_lim_u3 : R/W; bitpos: [31:16]; default: 0;
* Configures the step limit value for unit n.
*/
uint32_t cnt_step_lim:16;
};
uint32_t val;
} pcnt_un_change_conf_reg_t;
/** Group: Status Register */
/** Type of un_cnt register
* Counter value for unit 0
* Counter value for unit n
*/
typedef union {
struct {
@ -250,65 +248,65 @@ typedef union {
} pcnt_un_cnt_reg_t;
/** Type of un_status register
* PNCT UNIT0 status register
* PNCT UNITn status register
*/
typedef union {
struct {
/** cnt_thr_zero_mode_un : RO; bitpos: [1:0]; default: 0;
* Represents the pulse counter status of PCNT_Un corresponding to 0. \\
* 0: pulse counter decreases from positive to 0\\
* 1: pulse counter increases from negative to 0\\
* 2: pulse counter is negative\\
* 3: pulse counter is positive \\
* Represents the pulse counter status of PCNT_Un corresponding to 0.
* 0: pulse counter decreases from positive to 0
* 1: pulse counter increases from negative to 0
* 2: pulse counter is negative
* 3: pulse counter is positive
*/
uint32_t cnt_thr_zero_mode_un:2;
/** cnt_thr_thres1_lat_un : RO; bitpos: [2]; default: 0;
* Represents the latched value of thres1 event of PCNT_Un when threshold event
* interrupt is valid. \\
* 0: others\\
* 1: the current pulse counter equals to thres1 and thres1 event is valid \\
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thres1 and thres1 event is valid
*/
uint32_t cnt_thr_thres1_lat_un:1;
/** cnt_thr_thres0_lat_un : RO; bitpos: [3]; default: 0;
* Represents the latched value of thres0 event of PCNT_Un when threshold event
* interrupt is valid. \\
* 0: others\\
* 1: the current pulse counter equals to thres0 and thres0 event is valid \\
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thres0 and thres0 event is valid
*/
uint32_t cnt_thr_thres0_lat_un:1;
/** cnt_thr_l_lim_lat_un : RO; bitpos: [4]; default: 0;
* Represents the latched value of low limit event of PCNT_Un when threshold event
* interrupt is valid. \\
* 0: others\\
* 1: the current pulse counter equals to thr_l_lim and low limit event is valid. \\
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thr_l_lim and low limit event is valid.
*/
uint32_t cnt_thr_l_lim_lat_un:1;
/** cnt_thr_h_lim_lat_un : RO; bitpos: [5]; default: 0;
* Represents the latched value of high limit event of PCNT_Un when threshold event
* interrupt is valid. \\
* 0: others\\
* 1: the current pulse counter equals to thr_h_lim and high limit event is valid. \\
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thr_h_lim and high limit event is valid.
*/
uint32_t cnt_thr_h_lim_lat_un:1;
/** cnt_thr_zero_lat_un : RO; bitpos: [6]; default: 0;
* Represents the latched value of zero threshold event of PCNT_Un when threshold
* event interrupt is valid. \\
* 0: others\\
* 1: the current pulse counter equals to 0 and zero threshold event is valid. \\
* event interrupt is valid.
* 0: others
* 1: the current pulse counter equals to 0 and zero threshold event is valid.
*/
uint32_t cnt_thr_zero_lat_un:1;
/** cnt_thr_step_lim_lat_un : RO; bitpos: [7]; default: 0;
* The latched value of step counter limit event of PCNT_Un when step counter event
* interrupt is valid. 1: the current pulse counter equals to reg_cnt_step_lim and
* step counter event is valid. 0: others
/** cnt_thr_h_step_lat_un : RO; bitpos: [7]; default: 0;
* Represents the latched value of step counter event of PCNT_Un when step counter
* event interrupt is valid. 1: the current pulse counter decrement equals to
* reg_cnt_step and step counter event is valid. 0: others
*/
uint32_t cnt_thr_step_lim_lat_un:1;
/** cnt_thr_step_lat_un : RO; bitpos: [8]; default: 0;
* The latched value of step counter event of PCNT_Un when step counter event
* interrupt is valid. 1: the current pulse counter increment equals to reg_cnt_step
* and step counter event is valid. 0: others
uint32_t cnt_thr_h_step_lat_un:1;
/** cnt_thr_l_step_lat_un : RO; bitpos: [8]; default: 0;
* Represents the latched value of step counter event of PCNT_Un when step counter
* event interrupt is valid. 1: the current pulse counter increment equals to
* reg_cnt_step and step counter event is valid. 0: others
*/
uint32_t cnt_thr_step_lat_un:1;
uint32_t cnt_thr_l_step_lat_un:1;
uint32_t reserved_9:23;
};
uint32_t val;
@ -427,7 +425,7 @@ typedef union {
*/
typedef union {
struct {
/** date : R/W; bitpos: [31:0]; default: 36765968;
/** date : R/W; bitpos: [31:0]; default: 37778192;
* Version control register.
*/
uint32_t date:32;
@ -441,6 +439,7 @@ typedef struct pcnt_dev_t {
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;
@ -449,7 +448,6 @@ typedef struct pcnt_dev_t {
volatile pcnt_int_clr_reg_t int_clr;
volatile pcnt_un_status_reg_t status_unit[4];
volatile pcnt_ctrl_reg_t ctrl;
volatile pcnt_un_change_conf_reg_t change_conf_unit[4]; // Note the unit order is 3210
uint32_t reserved_074[34];
volatile pcnt_date_reg_t date;
} pcnt_dev_t;

View File

@ -1,523 +0,0 @@
/**
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Group: Configuration Register */
/** Type of un_conf0 register
* Configuration register 0 for unit n
*/
typedef union {
struct {
/** filter_thres_un : 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.
* Measurement unit: APB_CLK cycles.
*/
uint32_t filter_thres_un:10;
/** filter_en_un : R/W; bitpos: [10]; default: 1;
* This is the enable bit for unit n's input filter.
*/
uint32_t filter_en_un:1;
/** thr_zero_en_un : R/W; bitpos: [11]; default: 1;
* This is the enable bit for unit n's zero comparator.
*/
uint32_t thr_zero_en_un:1;
/** thr_h_lim_en_un : R/W; bitpos: [12]; default: 1;
* This is the enable bit for unit n's thr_h_lim comparator. Configures it to enable
* the high limit interrupt.
*/
uint32_t thr_h_lim_en_un:1;
/** thr_l_lim_en_un : R/W; bitpos: [13]; default: 1;
* This is the enable bit for unit n's thr_l_lim comparator. Configures it to enable
* the low limit interrupt.
*/
uint32_t thr_l_lim_en_un:1;
/** thr_thres0_en_un : R/W; bitpos: [14]; default: 0;
* This is the enable bit for unit n's thres0 comparator.
*/
uint32_t thr_thres0_en_un:1;
/** thr_thres1_en_un : R/W; bitpos: [15]; default: 0;
* This is the enable bit for unit n's thres1 comparator.
*/
uint32_t thr_thres1_en_un:1;
/** ch0_neg_mode_un : R/W; bitpos: [17:16]; default: 0;
* Configures the behavior when the signal input of channel 0 detects a negative edge.
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch0_neg_mode_un:2;
/** ch0_pos_mode_un : R/W; bitpos: [19:18]; default: 0;
* Configures the behavior when the signal input of channel 0 detects a positive edge.
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch0_pos_mode_un:2;
/** ch0_hctrl_mode_un : R/W; bitpos: [21:20]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is high.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch0_hctrl_mode_un:2;
/** ch0_lctrl_mode_un : R/W; bitpos: [23:22]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is low.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch0_lctrl_mode_un:2;
/** ch1_neg_mode_un : R/W; bitpos: [25:24]; default: 0;
* Configures the behavior when the signal input of channel 1 detects a negative edge.
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch1_neg_mode_un:2;
/** ch1_pos_mode_un : R/W; bitpos: [27:26]; default: 0;
* Configures the behavior when the signal input of channel 1 detects a positive edge.
* 1: Increment the counter
* 2: Decrement the counter
* 0, 3: No effect
*/
uint32_t ch1_pos_mode_un:2;
/** ch1_hctrl_mode_un : R/W; bitpos: [29:28]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is high.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch1_hctrl_mode_un:2;
/** ch1_lctrl_mode_un : R/W; bitpos: [31:30]; default: 0;
* Configures how the CHn_POS_MODE/CHn_NEG_MODE settings will be modified when the
* control signal is low.
* 0: No modification
* 1: Invert behavior (increase -> decrease, decrease -> increase)
* 2, 3: Inhibit counter modification
*/
uint32_t ch1_lctrl_mode_un:2;
};
uint32_t val;
} pcnt_un_conf0_reg_t;
/** Type of un_conf1 register
* Configuration register 1 for unit n
*/
typedef union {
struct {
/** cnt_thres0_un : R/W; bitpos: [15:0]; default: 0;
* Configures the thres0 value for unit n.
*/
uint32_t cnt_thres0_un:16;
/** cnt_thres1_un : R/W; bitpos: [31:16]; default: 0;
* Configures the thres1 value for unit n.
*/
uint32_t cnt_thres1_un:16;
};
uint32_t val;
} pcnt_un_conf1_reg_t;
/** Type of un_conf2 register
* Configuration register 2 for unit n
*/
typedef union {
struct {
/** cnt_h_lim_un : R/W; bitpos: [15:0]; default: 0;
* Configures the thr_h_lim value for unit n. When pulse_cnt reaches this value, the
* counter will be cleared to 0.
*/
uint32_t cnt_h_lim_un:16;
/** cnt_l_lim_un : R/W; bitpos: [31:16]; default: 0;
* Configures the thr_l_lim value for unit n. When pulse_cnt reaches this value, the
* counter will be cleared to 0.
*/
uint32_t cnt_l_lim_un:16;
};
uint32_t val;
} pcnt_un_conf2_reg_t;
/** Type of u0_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.
*/
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_l_step_u0: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;
/** Type of ctrl register
* Control register for all counters
*/
typedef union {
struct {
/** pulse_cnt_rst_u0 : R/W; bitpos: [0]; default: 1;
* Set this bit to clear unit 0's counter.
*/
uint32_t pulse_cnt_rst_u0:1;
/** cnt_pause_u0 : R/W; bitpos: [1]; default: 0;
* Set this bit to freeze unit 0's counter.
*/
uint32_t cnt_pause_u0:1;
/** pulse_cnt_rst_u1 : R/W; bitpos: [2]; default: 1;
* Set this bit to clear unit 1's counter.
*/
uint32_t pulse_cnt_rst_u1:1;
/** cnt_pause_u1 : R/W; bitpos: [3]; default: 0;
* Set this bit to freeze unit 1's counter.
*/
uint32_t cnt_pause_u1:1;
/** pulse_cnt_rst_u2 : R/W; bitpos: [4]; default: 1;
* Set this bit to clear unit 2's counter.
*/
uint32_t pulse_cnt_rst_u2:1;
/** cnt_pause_u2 : R/W; bitpos: [5]; default: 0;
* Set this bit to freeze unit 2's counter.
*/
uint32_t cnt_pause_u2:1;
/** pulse_cnt_rst_u3 : R/W; bitpos: [6]; default: 1;
* Set this bit to clear unit 3's counter.
*/
uint32_t pulse_cnt_rst_u3:1;
/** cnt_pause_u3 : R/W; bitpos: [7]; default: 0;
* Set this bit to freeze unit 3's counter.
*/
uint32_t cnt_pause_u3:1;
/** dalta_change_en_u0 : R/W; bitpos: [8]; default: 0;
* Configures this bit to enable unit 0's step comparator.
*/
uint32_t dalta_change_en_u0:1;
/** dalta_change_en_u1 : R/W; bitpos: [9]; default: 0;
* Configures this bit to enable unit 1's step comparator.
*/
uint32_t dalta_change_en_u1:1;
/** dalta_change_en_u2 : R/W; bitpos: [10]; default: 0;
* Configures this bit to enable unit 2's step comparator.
*/
uint32_t dalta_change_en_u2:1;
/** dalta_change_en_u3 : R/W; bitpos: [11]; default: 0;
* Configures this bit to enable unit 3's step comparator.
*/
uint32_t dalta_change_en_u3:1;
uint32_t reserved_12:4;
/** clk_en : R/W; bitpos: [16]; default: 0;
* The registers clock gate enable signal of PCNT module. 1: the registers can be read
* and written by application. 0: the registers can not be read or written by
* application
*/
uint32_t clk_en:1;
uint32_t reserved_17:15;
};
uint32_t val;
} pcnt_ctrl_reg_t;
/** Group: Status Register */
/** Type of un_cnt register
* Counter value for unit n
*/
typedef union {
struct {
/** pulse_cnt_un : RO; bitpos: [15:0]; default: 0;
* Represents the current pulse count value for unit n.
*/
uint32_t pulse_cnt_un:16;
uint32_t reserved_16:16;
};
uint32_t val;
} pcnt_un_cnt_reg_t;
/** Type of un_status register
* PNCT UNITn status register
*/
typedef union {
struct {
/** cnt_thr_zero_mode_un : RO; bitpos: [1:0]; default: 0;
* Represents the pulse counter status of PCNT_Un corresponding to 0.
* 0: pulse counter decreases from positive to 0
* 1: pulse counter increases from negative to 0
* 2: pulse counter is negative
* 3: pulse counter is positive
*/
uint32_t cnt_thr_zero_mode_un:2;
/** cnt_thr_thres1_lat_un : RO; bitpos: [2]; default: 0;
* Represents the latched value of thres1 event of PCNT_Un when threshold event
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thres1 and thres1 event is valid
*/
uint32_t cnt_thr_thres1_lat_un:1;
/** cnt_thr_thres0_lat_un : RO; bitpos: [3]; default: 0;
* Represents the latched value of thres0 event of PCNT_Un when threshold event
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thres0 and thres0 event is valid
*/
uint32_t cnt_thr_thres0_lat_un:1;
/** cnt_thr_l_lim_lat_un : RO; bitpos: [4]; default: 0;
* Represents the latched value of low limit event of PCNT_Un when threshold event
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thr_l_lim and low limit event is valid.
*/
uint32_t cnt_thr_l_lim_lat_un:1;
/** cnt_thr_h_lim_lat_un : RO; bitpos: [5]; default: 0;
* Represents the latched value of high limit event of PCNT_Un when threshold event
* interrupt is valid.
* 0: others
* 1: the current pulse counter equals to thr_h_lim and high limit event is valid.
*/
uint32_t cnt_thr_h_lim_lat_un:1;
/** cnt_thr_zero_lat_un : RO; bitpos: [6]; default: 0;
* Represents the latched value of zero threshold event of PCNT_Un when threshold
* event interrupt is valid.
* 0: others
* 1: the current pulse counter equals to 0 and zero threshold event is valid.
*/
uint32_t cnt_thr_zero_lat_un:1;
/** cnt_thr_h_step_lat_un : RO; bitpos: [7]; default: 0;
* Represents the latched value of step counter event of PCNT_Un when step counter
* event interrupt is valid. 1: the current pulse counter decrement equals to
* reg_cnt_step and step counter event is valid. 0: others
*/
uint32_t cnt_thr_h_step_lat_un:1;
/** cnt_thr_l_step_lat_un : RO; bitpos: [8]; default: 0;
* Represents the latched value of step counter event of PCNT_Un when step counter
* event interrupt is valid. 1: the current pulse counter increment equals to
* reg_cnt_step and step counter event is valid. 0: others
*/
uint32_t cnt_thr_l_step_lat_un:1;
uint32_t reserved_9:23;
};
uint32_t val;
} pcnt_un_status_reg_t;
/** Group: Interrupt Register */
/** Type of int_raw register
* Interrupt raw status register
*/
typedef union {
struct {
/** 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.
*/
uint32_t cnt_thr_event_u0_int_raw:1;
/** cnt_thr_event_u1_int_raw : R/WTC/SS; bitpos: [1]; default: 0;
* The raw interrupt status bit for the PCNT_CNT_THR_EVENT_U1_INT interrupt.
*/
uint32_t cnt_thr_event_u1_int_raw:1;
/** cnt_thr_event_u2_int_raw : R/WTC/SS; bitpos: [2]; default: 0;
* The raw interrupt status bit for the PCNT_CNT_THR_EVENT_U2_INT interrupt.
*/
uint32_t cnt_thr_event_u2_int_raw:1;
/** cnt_thr_event_u3_int_raw : R/WTC/SS; bitpos: [3]; default: 0;
* The raw interrupt status bit for the PCNT_CNT_THR_EVENT_U3_INT interrupt.
*/
uint32_t cnt_thr_event_u3_int_raw:1;
uint32_t reserved_4:28;
};
uint32_t val;
} pcnt_int_raw_reg_t;
/** Type of int_st register
* Interrupt status register
*/
typedef union {
struct {
/** 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.
*/
uint32_t cnt_thr_event_u0_int_st:1;
/** cnt_thr_event_u1_int_st : RO; bitpos: [1]; default: 0;
* The masked interrupt status bit for the PCNT_CNT_THR_EVENT_U1_INT interrupt.
*/
uint32_t cnt_thr_event_u1_int_st:1;
/** cnt_thr_event_u2_int_st : RO; bitpos: [2]; default: 0;
* The masked interrupt status bit for the PCNT_CNT_THR_EVENT_U2_INT interrupt.
*/
uint32_t cnt_thr_event_u2_int_st:1;
/** cnt_thr_event_u3_int_st : RO; bitpos: [3]; default: 0;
* The masked interrupt status bit for the PCNT_CNT_THR_EVENT_U3_INT interrupt.
*/
uint32_t cnt_thr_event_u3_int_st:1;
uint32_t reserved_4:28;
};
uint32_t val;
} pcnt_int_st_reg_t;
/** Type of int_ena register
* Interrupt enable register
*/
typedef union {
struct {
/** 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.
*/
uint32_t cnt_thr_event_u0_int_ena:1;
/** cnt_thr_event_u1_int_ena : R/W; bitpos: [1]; default: 0;
* The interrupt enable bit for the PCNT_CNT_THR_EVENT_U1_INT interrupt.
*/
uint32_t cnt_thr_event_u1_int_ena:1;
/** cnt_thr_event_u2_int_ena : R/W; bitpos: [2]; default: 0;
* The interrupt enable bit for the PCNT_CNT_THR_EVENT_U2_INT interrupt.
*/
uint32_t cnt_thr_event_u2_int_ena:1;
/** cnt_thr_event_u3_int_ena : R/W; bitpos: [3]; default: 0;
* The interrupt enable bit for the PCNT_CNT_THR_EVENT_U3_INT interrupt.
*/
uint32_t cnt_thr_event_u3_int_ena:1;
uint32_t reserved_4:28;
};
uint32_t val;
} pcnt_int_ena_reg_t;
/** Type of int_clr register
* Interrupt clear register
*/
typedef union {
struct {
/** cnt_thr_event_u0_int_clr : WT; bitpos: [0]; default: 0;
* Set this bit to clear the PCNT_CNT_THR_EVENT_U0_INT interrupt.
*/
uint32_t cnt_thr_event_u0_int_clr:1;
/** cnt_thr_event_u1_int_clr : WT; bitpos: [1]; default: 0;
* Set this bit to clear the PCNT_CNT_THR_EVENT_U1_INT interrupt.
*/
uint32_t cnt_thr_event_u1_int_clr:1;
/** cnt_thr_event_u2_int_clr : WT; bitpos: [2]; default: 0;
* Set this bit to clear the PCNT_CNT_THR_EVENT_U2_INT interrupt.
*/
uint32_t cnt_thr_event_u2_int_clr:1;
/** cnt_thr_event_u3_int_clr : WT; bitpos: [3]; default: 0;
* Set this bit to clear the PCNT_CNT_THR_EVENT_U3_INT interrupt.
*/
uint32_t cnt_thr_event_u3_int_clr:1;
uint32_t reserved_4:28;
};
uint32_t val;
} pcnt_int_clr_reg_t;
/** Group: Version Register */
/** Type of date register
* PCNT version control register
*/
typedef union {
struct {
/** date : R/W; bitpos: [31:0]; default: 37778192;
* Version control register.
*/
uint32_t date:32;
};
uint32_t val;
} 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];
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_ctrl_reg_t ctrl;
uint32_t reserved_074[34];
volatile pcnt_date_reg_t date;
} pcnt_dev_t;
extern pcnt_dev_t PCNT;
#ifndef __cplusplus
_Static_assert(sizeof(pcnt_dev_t) == 0x100, "Invalid size of pcnt_dev_t structure");
#endif
#ifdef __cplusplus
}
#endif

View File

@ -158,7 +158,11 @@ It is recommended to remove the unused watch point by :cpp:func:`pcnt_unit_remov
PCNT unit can be configured to watch a specific value increment (can be positive or negative) that you are interested in. The function of watching value increment is also called **Watch Step**. To install watch step requires enabling :cpp:member:`pcnt_unit_config_t::en_step_notify_up` or :cpp:member:`pcnt_unit_config_t::en_step_notify_down`. The step interval itself can not exceed the range set in :cpp:type:`pcnt_unit_config_t` by :cpp:member:`pcnt_unit_config_t::low_limit` and :cpp:member:`pcnt_unit_config_t::high_limit`.When the counter increment reaches step interval, a watch event will be triggered and notify you by interrupt if any watch event callback has ever registered in :cpp:func:`pcnt_unit_register_event_callbacks`. See :ref:`pcnt-register-event-callbacks` for how to register event callbacks.
The watch step can be added and removed by :cpp:func:`pcnt_unit_add_watch_step` and :cpp:func:`pcnt_unit_remove_watch_step`. You can not add multiple watch step, otherwise it will return error :c:macro:`ESP_ERR_INVALID_STATE`
The watch step can be added and removed by :cpp:func:`pcnt_unit_add_watch_step` and :cpp:func:`pcnt_unit_remove_watch_step`. The parameter ``step_interval`` can be positive(step forward, e.g., [N]->[N+1]->[N+2]->...) or negative(step backward, e.g., [N]->[N-1]->[N-2]->...). The same direction can only add one watch step, otherwise it will return error :c:macro:`ESP_ERR_INVALID_STATE`.
.. note::
Due to hardware limitations, some chips may only support adding one direction of watch step. Please check the return value of :cpp:func:`pcnt_unit_add_watch_step` for more details.
It is recommended to remove the unused watch step by :cpp:func:`pcnt_unit_remove_watch_step` to recycle the watch step resources.
@ -318,8 +322,7 @@ The internal hardware counter will be cleared to zero automatically when it reac
.. list::
1. Enable :cpp:member:`pcnt_unit_config_t::accum_count` when installing the PCNT unit.
:SOC_PCNT_SUPPORT_STEP_NOTIFY: 2. Add the high/low limit as the :ref:`pcnt-watch-points` or add watch step as the :ref:`pcnt-step-notify`.
:not SOC_PCNT_SUPPORT_STEP_NOTIFY: 2. Add the high/low limit as the :ref:`pcnt-watch-points`.
2. Add the high/low limit as the :ref:`pcnt-watch-points`.
3. Now, the returned count value from the :cpp:func:`pcnt_unit_get_count` function not only reflects the hardware's count value, but also accumulates the high/low overflow loss to it.
.. note::

View File

@ -158,7 +158,11 @@ PCNT 单元可被设置为观察几个特定的数值,这些被观察的数值
PCNT 单元可被设置为观察一个特定的数值增量(可以是正方向或负方向),这个观察数值增量的功能被称为 **观察步进**。启用观察步进需要使能 :cpp:member:`pcnt_unit_config_t::en_step_notify_up`:cpp:member:`pcnt_unit_config_t::en_step_notify_down` 选项。 步进间隔不能超过 :cpp:type:`pcnt_unit_config_t` 设置的范围,最小值和最大值分别为 :cpp:member:`pcnt_unit_config_t::low_limit`:cpp:member:`pcnt_unit_config_t::high_limit`。当计数器增量到达步进间隔时,会触发一个观察事件,如果在 :cpp:func:`pcnt_unit_register_event_callbacks` 注册过事件回调函数,该事件就会通过中断发送通知。关于如何注册事件回调函数,请参考 :ref:`pcnt-register-event-callbacks`
观察步进分别可以通过 :cpp:func:`pcnt_unit_add_watch_step`:cpp:func:`pcnt_unit_remove_watch_step` 进行添加和删除。不能同时添加个观察步进,否则将返回错误 :c:macro:`ESP_ERR_INVALID_STATE`
观察步进分别可以通过 :cpp:func:`pcnt_unit_add_watch_step`:cpp:func:`pcnt_unit_remove_watch_step` 进行添加和删除。参数 ``step_interval`` 的为正数表示正方向的步进(例如 [N]->[N+1]->[N+2]->...),为负数表示负方向的步进(例如 [N]->[N-1]->[N-2]->...)。同一个方向只能添加个观察步进,否则将返回错误 :c:macro:`ESP_ERR_INVALID_STATE`
.. note::
由于硬件上的限制,部分芯片可能只能支持添加一个方向的观察步进,请检查 :cpp:func:`pcnt_unit_add_watch_step` 的返回值。
建议通过 :cpp:func:`pcnt_unit_remove_watch_step` 删除未使用的观察步进来回收资源。
@ -318,8 +322,7 @@ PCNT 内部的硬件计数器会在计数达到高/低门限的时候自动清
.. list::
1. 在安装 PCNT 计数单元的时候使能 :cpp:member:`pcnt_unit_config_t::accum_count` 选项。
:SOC_PCNT_SUPPORT_STEP_NOTIFY: 2. 将高/低计数门限设置为 :ref:`pcnt-watch-points` 或添加观察步进 :ref:`pcnt-step-notify`
:not SOC_PCNT_SUPPORT_STEP_NOTIFY: 2. 将高/低计数门限设置为 :ref:`pcnt-watch-points`。
2. 将高/低计数门限设置为 :ref:`pcnt-watch-points`
3. 现在,:cpp:func:`pcnt_unit_get_count` 函数返回的计数值就会包含硬件计数器当前的计数值,累加上计数器溢出造成的损失。
.. note::