fix(pcnt): only call esp_pm APIs when CONFIG_PM_ENABLE is enabled

Closes https://github.com/espressif/esp-idf/issues/15923
This commit is contained in:
morris
2025-05-12 18:55:06 +08:00
committed by Chen Jichang
parent 5783a22d84
commit 57420057b6
9 changed files with 45 additions and 29 deletions

View File

@ -51,8 +51,6 @@
#define PCNT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED
#define PCNT_PM_LOCK_NAME_LEN_MAX 16
#if !SOC_RCC_IS_INDEPENDENT
#define PCNT_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
@ -85,6 +83,9 @@ struct pcnt_group_t {
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
pcnt_hal_context_t hal;
pcnt_unit_t *units[SOC_PCNT_UNITS_PER_GROUP]; // array of PCNT units
#if CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock; // power management lock
#endif
};
typedef struct {
@ -119,10 +120,6 @@ struct pcnt_unit_t {
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
esp_pm_lock_handle_t pm_lock; // PM lock, for glitch filter, as that module can only be functional under APB
#if CONFIG_PM_ENABLE
char pm_lock_name[PCNT_PM_LOCK_NAME_LEN_MAX]; // pm lock name
#endif
pcnt_unit_fsm_t fsm; // record PCNT unit's driver state
pcnt_watch_cb_t on_reach; // user registered callback function
void *user_data; // user data registered by user, which would be passed to the right callback function
@ -191,9 +188,6 @@ static void pcnt_unregister_from_group(pcnt_unit_t *unit)
static esp_err_t pcnt_destroy(pcnt_unit_t *unit)
{
if (unit->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(unit->pm_lock), TAG, "delete pm lock failed");
}
if (unit->intr) {
ESP_RETURN_ON_ERROR(esp_intr_free(unit->intr), TAG, "delete interrupt service failed");
}
@ -206,9 +200,6 @@ static esp_err_t pcnt_destroy(pcnt_unit_t *unit)
esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *ret_unit)
{
#if CONFIG_PCNT_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
pcnt_unit_t *unit = NULL;
ESP_GOTO_ON_FALSE(config && ret_unit, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
@ -263,14 +254,6 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
TAG, "install interrupt service failed");
}
// PCNT uses the APB as its function clock,
// and its filter module is sensitive to the clock frequency
#if CONFIG_PM_ENABLE
sprintf(unit->pm_lock_name, "pcnt_%d_%d", group_id, unit_id); // e.g. pcnt_0_0
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, unit->pm_lock_name, &unit->pm_lock), err, TAG, "install pm lock failed");
ESP_LOGD(TAG, "install APB_FREQ_MAX lock for unit (%d,%d)", group_id, unit_id);
#endif
// some events are enabled by default, disable them all
pcnt_ll_disable_all_events(group->hal.dev, unit_id);
// disable filter by default
@ -423,10 +406,12 @@ esp_err_t pcnt_unit_enable(pcnt_unit_handle_t unit)
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
#if CONFIG_PM_ENABLE
// acquire power manager lock
if (unit->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(unit->pm_lock), TAG, "acquire pm_lock failed");
if (unit->group->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(unit->group->pm_lock), TAG, "acquire pm_lock failed");
}
#endif
// enable interrupt service
if (unit->intr) {
ESP_RETURN_ON_ERROR(esp_intr_enable(unit->intr), TAG, "enable interrupt service failed");
@ -445,10 +430,12 @@ esp_err_t pcnt_unit_disable(pcnt_unit_handle_t unit)
if (unit->intr) {
ESP_RETURN_ON_ERROR(esp_intr_disable(unit->intr), TAG, "disable interrupt service failed");
}
#if CONFIG_PM_ENABLE
// release power manager lock
if (unit->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_release(unit->pm_lock), TAG, "release APB_FREQ_MAX lock failed");
if (unit->group->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_release(unit->group->pm_lock), TAG, "release APB_FREQ_MAX lock failed");
}
#endif
unit->fsm = PCNT_UNIT_FSM_INIT;
return ESP_OK;
@ -966,6 +953,14 @@ static pcnt_group_t *pcnt_acquire_group_handle(int group_id)
_lock_release(&s_platform.mutex);
if (new_group) {
#if CONFIG_PM_ENABLE
// PCNT uses the APB as its function clock,
// and its filter module is sensitive to the clock frequency
// thus we choose the APM_MAX lock to prevent the function clock from being changed
if (esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, pcnt_periph_signals.groups[group_id].module_name, &group->pm_lock) != ESP_OK) {
ESP_LOGW(TAG, "create pm lock failed");
}
#endif
ESP_LOGD(TAG, "new group (%d) at %p", group_id, group);
}
@ -986,16 +981,21 @@ static void pcnt_release_group_handle(pcnt_group_t *group)
PCNT_RCC_ATOMIC() {
pcnt_ll_enable_bus_clock(group_id, false);
}
}
_lock_release(&s_platform.mutex);
if (do_deinitialize) {
#if PCNT_USE_RETENTION_LINK
const periph_retention_module_t module_id = pcnt_reg_retention_info[group_id].retention_module;
if (sleep_retention_is_module_inited(module_id)) {
sleep_retention_module_deinit(module_id);
}
#endif // PCNT_USE_RETENTION_LINK
}
_lock_release(&s_platform.mutex);
if (do_deinitialize) {
#if CONFIG_PM_ENABLE
if (group->pm_lock) {
esp_pm_lock_delete(group->pm_lock);
}
#endif
free(group);
ESP_LOGD(TAG, "del group (%d)", group_id);
}
@ -1122,3 +1122,11 @@ static esp_err_t pcnt_create_sleep_retention_link_cb(void *arg)
return ESP_OK;
}
#endif // PCNT_USE_RETENTION_LINK
#if CONFIG_PCNT_ENABLE_DEBUG_LOG
__attribute__((constructor))
static void pcnt_override_default_log_level(void)
{
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
}
#endif

View File

@ -12,6 +12,7 @@ const pcnt_signal_conn_t pcnt_periph_signals = {
.groups = {
[0] = {
.irq = ETS_PCNT_INTR_SOURCE,
.module_name = "pcnt0",
.units = {
[0] = {
.channels = {

View File

@ -12,6 +12,7 @@ const pcnt_signal_conn_t pcnt_periph_signals = {
.groups = {
[0] = {
.irq = ETS_PCNT_INTR_SOURCE,
.module_name = "pcnt0",
.units = {
[0] = {
.channels = {

View File

@ -12,6 +12,7 @@ const pcnt_signal_conn_t pcnt_periph_signals = {
.groups = {
[0] = {
.irq = ETS_PCNT_INTR_SOURCE,
.module_name = "pcnt0",
.units = {
[0] = {
.channels = {

View File

@ -12,6 +12,7 @@ const pcnt_signal_conn_t pcnt_periph_signals = {
.groups = {
[0] = {
.irq = ETS_PCNT_INTR_SOURCE,
.module_name = "pcnt0",
.units = {
[0] = {
.channels = {

View File

@ -12,6 +12,7 @@ const pcnt_signal_conn_t pcnt_periph_signals = {
.groups = {
[0] = {
.irq = ETS_PCNT_INTR_SOURCE,
.module_name = "pcnt0",
.units = {
[0] = {
.channels = {

View File

@ -11,6 +11,7 @@ const pcnt_signal_conn_t pcnt_periph_signals = {
.groups = {
[0] = {
.irq = ETS_PCNT_INTR_SOURCE,
.module_name = "pcnt0",
.units = {
[0] = {
.channels = {

View File

@ -11,6 +11,7 @@ const pcnt_signal_conn_t pcnt_periph_signals = {
.groups = {
[0] = {
.irq = ETS_PCNT_INTR_SOURCE,
.module_name = "pcnt0",
.units = {
[0] = {
.channels = {

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -22,6 +22,7 @@ extern "C" {
typedef struct {
struct {
const char *module_name;
struct {
struct {
const uint32_t pulse_sig;