mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
feat(mcpwm): fix mcpwm clock init failure
Closes https://github.com/espressif/esp-idf/issues/18666 Closes https://github.com/espressif/esp-idf/issues/18777
This commit is contained in:
@@ -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
|
||||
*/
|
||||
@@ -14,11 +14,12 @@
|
||||
|
||||
static void mcpwm_capture_default_isr(void *args);
|
||||
|
||||
static esp_err_t mcpwm_cap_timer_register_to_group(mcpwm_cap_timer_t *cap_timer, int group_id)
|
||||
static esp_err_t mcpwm_cap_timer_register_to_group(mcpwm_cap_timer_t *cap_timer, int group_id, soc_module_clk_t clk_src)
|
||||
{
|
||||
mcpwm_group_t *group = mcpwm_acquire_group_handle(group_id);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", group_id);
|
||||
mcpwm_group_t *group = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_acquire_group_handle(group_id, clk_src, &group), err, TAG, "acquire group failed");
|
||||
bool new_timer = false;
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
if (!group->cap_timer) {
|
||||
@@ -27,14 +28,16 @@ static esp_err_t mcpwm_cap_timer_register_to_group(mcpwm_cap_timer_t *cap_timer,
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
if (!new_timer) {
|
||||
mcpwm_release_group_handle(group);
|
||||
group = NULL;
|
||||
} else {
|
||||
cap_timer->group = group;
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(new_timer, ESP_ERR_NOT_FOUND, TAG, "no free cap timer in group (%d)", group_id);
|
||||
ESP_GOTO_ON_FALSE(new_timer, ESP_ERR_NOT_FOUND, err, TAG, "no free cap timer in group (%d)", group_id);
|
||||
|
||||
cap_timer->group = group;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (group) {
|
||||
mcpwm_release_group_handle(group);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcpwm_cap_timer_unregister_from_group(mcpwm_cap_timer_t *cap_timer)
|
||||
@@ -75,17 +78,21 @@ esp_err_t mcpwm_new_capture_timer(const mcpwm_capture_timer_config_t *config, mc
|
||||
ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported");
|
||||
#endif // SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
mcpwm_capture_clock_source_t clk_src = config->clk_src ? config->clk_src : MCPWM_CAPTURE_CLK_SRC_DEFAULT;
|
||||
soc_module_clk_t group_clk_src = 0;
|
||||
#if SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
|
||||
group_clk_src = clk_src;
|
||||
#endif
|
||||
|
||||
cap_timer = heap_caps_calloc(1, sizeof(mcpwm_cap_timer_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(cap_timer, ESP_ERR_NO_MEM, err, TAG, "no mem for capture timer");
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_cap_timer_register_to_group(cap_timer, config->group_id), err, TAG, "register timer failed");
|
||||
ESP_GOTO_ON_ERROR(mcpwm_cap_timer_register_to_group(cap_timer, config->group_id, group_clk_src), err, TAG, "register timer failed");
|
||||
mcpwm_group_t *group = cap_timer->group;
|
||||
int group_id = group->group_id;
|
||||
|
||||
mcpwm_capture_clock_source_t clk_src = config->clk_src ? config->clk_src : MCPWM_CAPTURE_CLK_SRC_DEFAULT;
|
||||
#if SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
|
||||
// capture timer clock source is same as the MCPWM group
|
||||
ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock(group, (soc_module_clk_t)clk_src), err, TAG, "set group clock failed");
|
||||
// capture timer clock source is same as the MCPWM group, already committed in mcpwm_acquire_group_handle()
|
||||
#if CONFIG_PM_ENABLE
|
||||
cap_timer->pm_lock = group->pm_lock;
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
static esp_err_t mcpwm_create_sleep_retention_link_cb(void *arg);
|
||||
static void mcpwm_release_sleep_retention_module(int group_id);
|
||||
#endif
|
||||
// NOTE: caller MUST hold s_platform.mutex. This function does not take any lock by itself.
|
||||
static esp_err_t mcpwm_create_group_unsafe(int group_id, soc_module_clk_t clk_src, mcpwm_group_t **ret_group);
|
||||
static esp_err_t mcpwm_select_periph_clock_unsafe(mcpwm_group_t *group, soc_module_clk_t clk_src);
|
||||
|
||||
typedef struct {
|
||||
_lock_t mutex; // platform level mutex lock
|
||||
@@ -22,72 +26,102 @@ typedef struct {
|
||||
|
||||
static mcpwm_platform_t s_platform; // singleton platform
|
||||
|
||||
mcpwm_group_t *mcpwm_acquire_group_handle(int group_id)
|
||||
esp_err_t mcpwm_acquire_group_handle(int group_id, soc_module_clk_t clk_src, mcpwm_group_t **ret_group)
|
||||
{
|
||||
bool new_group = false;
|
||||
mcpwm_group_t *group = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_RETURN_ON_FALSE(ret_group, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
*ret_group = NULL;
|
||||
|
||||
// prevent install mcpwm group concurrently
|
||||
_lock_acquire(&s_platform.mutex);
|
||||
if (!s_platform.groups[group_id]) {
|
||||
group = heap_caps_calloc(1, sizeof(mcpwm_group_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
if (group) {
|
||||
new_group = true;
|
||||
s_platform.groups[group_id] = group;
|
||||
group->group_id = group_id;
|
||||
group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = mcpwm_retention_infos[group_id].retention_module;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
.handle = mcpwm_create_sleep_retention_link_cb,
|
||||
.arg = group,
|
||||
},
|
||||
},
|
||||
.attribute = SLEEP_RETENTION_MODULE_ATTR_ATTACH,
|
||||
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
|
||||
};
|
||||
// we only do retention init here. Allocate retention module in the unit initialization
|
||||
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
|
||||
// even though the sleep retention module init failed, MCPWM driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id);
|
||||
}
|
||||
#endif // MCPWM_USE_RETENTION_LINK
|
||||
// enable APB to access MCPWM registers
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mcpwm_ll_enable_bus_clock(group_id, true);
|
||||
mcpwm_ll_reset_register(group_id);
|
||||
}
|
||||
// enable function clock before initialize HAL context
|
||||
// MCPWM registers are in the core clock domain, there's a bridge between APB and the Core clock domain
|
||||
// if the core clock is not enabled, then even the APB clock is enabled, the MCPWM registers are still not accessible
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mcpwm_ll_group_enable_clock(group_id, true);
|
||||
}
|
||||
// initialize HAL context
|
||||
mcpwm_hal_init_config_t hal_config = {
|
||||
.group_id = group_id
|
||||
};
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
mcpwm_hal_init(hal, &hal_config);
|
||||
// disable all interrupts and clear pending status
|
||||
mcpwm_ll_intr_enable(hal->dev, UINT32_MAX, false);
|
||||
mcpwm_ll_intr_clear_status(hal->dev, UINT32_MAX);
|
||||
}
|
||||
} else { // group already install
|
||||
group = s_platform.groups[group_id];
|
||||
}
|
||||
mcpwm_group_t *group = s_platform.groups[group_id];
|
||||
if (group) {
|
||||
// commit or verify the group clock source while holding the platform mutex
|
||||
ret = mcpwm_select_periph_clock_unsafe(group, clk_src);
|
||||
} else {
|
||||
ret = mcpwm_create_group_unsafe(group_id, clk_src, &group);
|
||||
if (ret == ESP_OK) {
|
||||
s_platform.groups[group_id] = group;
|
||||
}
|
||||
}
|
||||
if (ret == ESP_OK) {
|
||||
// someone acquired the group handle means we have a new object that refer to this group
|
||||
s_platform.group_ref_counts[group_id]++;
|
||||
*ret_group = group;
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (new_group) {
|
||||
ESP_LOGD(TAG, "new group(%d) at %p", group_id, group);
|
||||
// NOTE: caller MUST hold s_platform.mutex. This function does not take any lock by itself.
|
||||
static esp_err_t mcpwm_create_group_unsafe(int group_id, soc_module_clk_t clk_src, mcpwm_group_t **ret_group)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
*ret_group = NULL;
|
||||
mcpwm_group_t *group = heap_caps_calloc(1, sizeof(mcpwm_group_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", group_id);
|
||||
|
||||
group->group_id = group_id;
|
||||
group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = mcpwm_retention_infos[group_id].retention_module;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
.handle = mcpwm_create_sleep_retention_link_cb,
|
||||
.arg = group,
|
||||
},
|
||||
},
|
||||
.attribute = SLEEP_RETENTION_MODULE_ATTR_ATTACH,
|
||||
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
|
||||
};
|
||||
// we only do retention init here. Allocate retention module in the unit initialization
|
||||
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
|
||||
// even though the sleep retention module init failed, MCPWM driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "init sleep retention failed %d, power domain may be turned off during sleep", group_id);
|
||||
}
|
||||
return group;
|
||||
#endif // MCPWM_USE_RETENTION_LINK
|
||||
// enable APB to access MCPWM registers
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mcpwm_ll_enable_bus_clock(group_id, true);
|
||||
mcpwm_ll_reset_register(group_id);
|
||||
}
|
||||
// enable function clock before initialize HAL context
|
||||
// MCPWM registers are in the core clock domain, there's a bridge between APB and the Core clock domain
|
||||
// if the core clock is not enabled, then even the APB clock is enabled, the MCPWM registers are still not accessible
|
||||
ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock_unsafe(group, clk_src), err, TAG, "set group clock failed");
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
#if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S3
|
||||
if (!group->clk_src) {
|
||||
// Use an always-on source only for safe register bring-up; it is not committed as the group source.
|
||||
mcpwm_ll_group_set_clock_source(group_id, MCPWM_TIMER_CLK_SRC_XTAL);
|
||||
}
|
||||
#endif
|
||||
mcpwm_ll_group_enable_clock(group_id, true);
|
||||
}
|
||||
// initialize HAL context
|
||||
mcpwm_hal_init_config_t hal_config = {
|
||||
.group_id = group_id
|
||||
};
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
mcpwm_hal_init(hal, &hal_config);
|
||||
// disable all interrupts and clear pending status
|
||||
mcpwm_ll_intr_enable(hal->dev, UINT32_MAX, false);
|
||||
mcpwm_ll_intr_clear_status(hal->dev, UINT32_MAX);
|
||||
|
||||
*ret_group = group;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mcpwm_ll_enable_bus_clock(group_id, false);
|
||||
}
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
mcpwm_release_sleep_retention_module(group_id);
|
||||
#endif // MCPWM_USE_RETENTION_LINK
|
||||
free(group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mcpwm_release_group_handle(mcpwm_group_t *group)
|
||||
@@ -108,20 +142,17 @@ void mcpwm_release_group_handle(mcpwm_group_t *group)
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mcpwm_ll_enable_bus_clock(group_id, false);
|
||||
}
|
||||
// release the group clock source acquired in mcpwm_select_periph_clock_unsafe()
|
||||
if (group->clk_src) {
|
||||
esp_clk_tree_enable_src(group->clk_src, false);
|
||||
}
|
||||
#if CONFIG_PM_ENABLE
|
||||
if (group->pm_lock) {
|
||||
esp_pm_lock_delete(group->pm_lock);
|
||||
}
|
||||
#endif
|
||||
#if MCPWM_USE_RETENTION_LINK
|
||||
const periph_retention_module_t module_id = mcpwm_retention_infos[group_id].retention_module;
|
||||
sleep_retention_module_detach(module_id);
|
||||
if (sleep_retention_is_module_created(module_id)) {
|
||||
sleep_retention_module_free(module_id);
|
||||
}
|
||||
if (sleep_retention_is_module_inited(module_id)) {
|
||||
sleep_retention_module_deinit(module_id);
|
||||
}
|
||||
mcpwm_release_sleep_retention_module(group_id);
|
||||
#endif // MCPWM_USE_RETENTION_LINK
|
||||
free(group);
|
||||
}
|
||||
@@ -132,43 +163,57 @@ void mcpwm_release_group_handle(mcpwm_group_t *group)
|
||||
}
|
||||
}
|
||||
|
||||
// The group clock source (group->clk_src / group->pm_lock and the clock source enable/disable) is owned
|
||||
// exclusively by s_platform.mutex. The caller must hold s_platform.mutex.
|
||||
static esp_err_t mcpwm_select_periph_clock_unsafe(mcpwm_group_t *group, soc_module_clk_t clk_src)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
int group_id = group->group_id;
|
||||
if (!clk_src) {
|
||||
return ESP_OK;
|
||||
}
|
||||
// check if we need to update the group clock source, group clock source is shared by all mcpwm modules
|
||||
if (group->clk_src) {
|
||||
ESP_RETURN_ON_FALSE(group->clk_src == clk_src, ESP_ERR_INVALID_STATE, TAG,
|
||||
"group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
group->clk_src = clk_src;
|
||||
ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true),
|
||||
err, TAG, "clock source enable failed");
|
||||
#if CONFIG_PM_ENABLE
|
||||
// to make the mcpwm works reliable, the source clock must stay alive and unchanged
|
||||
esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3
|
||||
// on ESP32 and ESP32S3, MCPWM's clock source (PLL_160M) frequency is automatically reduced during DFS, resulting in an inaccurate time base
|
||||
// thus we want to use the APB_MAX lock
|
||||
pm_lock_type = ESP_PM_APB_FREQ_MAX;
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_lock_type, 0, soc_mcpwm_signals[group_id].module_name, &group->pm_lock),
|
||||
err_clock_enabled, TAG, "create pm lock failed");
|
||||
#endif // CONFIG_PM_ENABLE
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mcpwm_ll_group_set_clock_source(group_id, clk_src);
|
||||
}
|
||||
return ret;
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
err_clock_enabled:
|
||||
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, false);
|
||||
#endif
|
||||
err:
|
||||
group->clk_src = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_src)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
bool clock_selection_conflict = false;
|
||||
bool do_clock_init = false;
|
||||
int group_id = group->group_id;
|
||||
// check if we need to update the group clock source, group clock source is shared by all mcpwm modules
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
if (group->clk_src == 0) {
|
||||
group->clk_src = clk_src;
|
||||
do_clock_init = true;
|
||||
} else {
|
||||
clock_selection_conflict = (group->clk_src != clk_src);
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_STATE, TAG,
|
||||
"group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src);
|
||||
|
||||
if (do_clock_init) {
|
||||
|
||||
#if CONFIG_PM_ENABLE
|
||||
// to make the mcpwm works reliable, the source clock must stay alive and unchanged
|
||||
esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3
|
||||
// on ESP32 and ESP32S3, MCPWM's clock source (PLL_160M) frequency is automatically reduced during DFS, resulting in an inaccurate time base
|
||||
// thus we want to use the APB_MAX lock
|
||||
pm_lock_type = ESP_PM_APB_FREQ_MAX;
|
||||
#endif
|
||||
ret = esp_pm_lock_create(pm_lock_type, 0, soc_mcpwm_signals[group_id].module_name, &group->pm_lock);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "create pm lock failed");
|
||||
#endif // CONFIG_PM_ENABLE
|
||||
|
||||
ESP_RETURN_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true), TAG, "clock source enable failed");
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
mcpwm_ll_group_set_clock_source(group_id, clk_src);
|
||||
}
|
||||
}
|
||||
_lock_acquire(&s_platform.mutex);
|
||||
ret = mcpwm_select_periph_clock_unsafe(group, clk_src);
|
||||
_lock_release(&s_platform.mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -256,6 +301,19 @@ static esp_err_t mcpwm_create_sleep_retention_link_cb(void *arg)
|
||||
REGDMA_LINK_PRI_MCPWM, module_id);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mcpwm_release_sleep_retention_module(int group_id)
|
||||
{
|
||||
const periph_retention_module_t module_id = mcpwm_retention_infos[group_id].retention_module;
|
||||
sleep_retention_module_detach(module_id);
|
||||
if (sleep_retention_is_module_created(module_id)) {
|
||||
sleep_retention_module_free(module_id);
|
||||
}
|
||||
if (sleep_retention_is_module_inited(module_id)) {
|
||||
sleep_retention_module_deinit(module_id);
|
||||
}
|
||||
}
|
||||
|
||||
void mcpwm_create_retention_module(mcpwm_group_t *group)
|
||||
{
|
||||
int group_id = group->group_id;
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -16,9 +16,10 @@ static esp_err_t mcpwm_del_soft_fault(mcpwm_fault_handle_t fault);
|
||||
|
||||
static esp_err_t mcpwm_gpio_fault_register_to_group(mcpwm_gpio_fault_t *fault, int group_id)
|
||||
{
|
||||
mcpwm_group_t *group = mcpwm_acquire_group_handle(group_id);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", group_id);
|
||||
mcpwm_group_t *group = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_acquire_group_handle(group_id, 0, &group), err, TAG, "acquire group failed");
|
||||
int fault_id = -1;
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
for (int i = 0; i < MCPWM_LL_GET(GPIO_FAULTS_PER_GROUP); i++) {
|
||||
@@ -29,15 +30,17 @@ static esp_err_t mcpwm_gpio_fault_register_to_group(mcpwm_gpio_fault_t *fault, i
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
if (fault_id < 0) {
|
||||
mcpwm_release_group_handle(group);
|
||||
group = NULL;
|
||||
} else {
|
||||
fault->base.group = group;
|
||||
fault->fault_id = fault_id;
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(fault_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free gpio fault in group (%d)", group_id);
|
||||
ESP_GOTO_ON_FALSE(fault_id >= 0, ESP_ERR_NOT_FOUND, err, TAG, "no free gpio fault in group (%d)", group_id);
|
||||
|
||||
fault->base.group = group;
|
||||
fault->fault_id = fault_id;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (group) {
|
||||
mcpwm_release_group_handle(group);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcpwm_gpio_fault_unregister_from_group(mcpwm_gpio_fault_t *fault)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -12,9 +12,10 @@ static void mcpwm_operator_default_isr(void *args);
|
||||
|
||||
static esp_err_t mcpwm_operator_register_to_group(mcpwm_oper_t *oper, int group_id)
|
||||
{
|
||||
mcpwm_group_t *group = mcpwm_acquire_group_handle(group_id);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", group_id);
|
||||
mcpwm_group_t *group = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_acquire_group_handle(group_id, 0, &group), err, TAG, "acquire group failed");
|
||||
int oper_id = -1;
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
for (int i = 0; i < MCPWM_LL_GET(OPERATORS_PER_GROUP); i++) {
|
||||
@@ -25,15 +26,17 @@ static esp_err_t mcpwm_operator_register_to_group(mcpwm_oper_t *oper, int group_
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
if (oper_id < 0) {
|
||||
mcpwm_release_group_handle(group);
|
||||
group = NULL;
|
||||
} else {
|
||||
oper->group = group;
|
||||
oper->oper_id = oper_id;
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(oper_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free operators in group (%d)", group_id);
|
||||
ESP_GOTO_ON_FALSE(oper_id >= 0, ESP_ERR_NOT_FOUND, err, TAG, "no free operators in group (%d)", group_id);
|
||||
|
||||
oper->group = group;
|
||||
oper->oper_id = oper_id;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (group) {
|
||||
mcpwm_release_group_handle(group);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcpwm_operator_unregister_from_group(mcpwm_oper_t *oper)
|
||||
|
||||
@@ -285,7 +285,7 @@ struct mcpwm_cap_channel_t {
|
||||
void *user_data; // user data which would be passed to the capture callback
|
||||
};
|
||||
|
||||
mcpwm_group_t *mcpwm_acquire_group_handle(int group_id);
|
||||
esp_err_t mcpwm_acquire_group_handle(int group_id, soc_module_clk_t clk_src, mcpwm_group_t **ret_group);
|
||||
void mcpwm_release_group_handle(mcpwm_group_t *group);
|
||||
esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_src);
|
||||
esp_err_t mcpwm_set_prescale(mcpwm_group_t *group, uint32_t expect_module_resolution_hz, uint32_t module_prescale_max, uint32_t *ret_module_prescale);
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -105,9 +105,10 @@ static esp_err_t mcpwm_del_timer_sync_src(mcpwm_sync_t *sync_src)
|
||||
|
||||
static esp_err_t mcpwm_gpio_sync_src_register_to_group(mcpwm_gpio_sync_src_t *gpio_sync_src, int group_id)
|
||||
{
|
||||
mcpwm_group_t *group = mcpwm_acquire_group_handle(group_id);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", group_id);
|
||||
mcpwm_group_t *group = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_acquire_group_handle(group_id, 0, &group), err, TAG, "acquire group failed");
|
||||
int sync_id = -1;
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
for (int i = 0; i < MCPWM_LL_GET(GPIO_SYNCHROS_PER_GROUP); i++) {
|
||||
@@ -119,16 +120,17 @@ static esp_err_t mcpwm_gpio_sync_src_register_to_group(mcpwm_gpio_sync_src_t *gp
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
if (sync_id < 0) {
|
||||
mcpwm_release_group_handle(group);
|
||||
group = NULL;
|
||||
} else {
|
||||
gpio_sync_src->base.group = group;
|
||||
gpio_sync_src->sync_id = sync_id;
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(sync_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free gpio sync_src in group (%d)", group_id);
|
||||
ESP_GOTO_ON_FALSE(sync_id >= 0, ESP_ERR_NOT_FOUND, err, TAG, "no free gpio sync_src in group (%d)", group_id);
|
||||
|
||||
gpio_sync_src->base.group = group;
|
||||
gpio_sync_src->sync_id = sync_id;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (group) {
|
||||
mcpwm_release_group_handle(group);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcpwm_gpio_sync_src_unregister_from_group(mcpwm_gpio_sync_src_t *gpio_sync_src)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -12,11 +12,12 @@
|
||||
|
||||
static void mcpwm_timer_default_isr(void *args);
|
||||
|
||||
static esp_err_t mcpwm_timer_register_to_group(mcpwm_timer_t *timer, int group_id)
|
||||
static esp_err_t mcpwm_timer_register_to_group(mcpwm_timer_t *timer, int group_id, soc_module_clk_t clk_src)
|
||||
{
|
||||
mcpwm_group_t *group = mcpwm_acquire_group_handle(group_id);
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", group_id);
|
||||
mcpwm_group_t *group = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_acquire_group_handle(group_id, clk_src, &group), err, TAG, "acquire group failed");
|
||||
int timer_id = -1;
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
for (int i = 0; i < MCPWM_LL_GET(TIMERS_PER_GROUP); i++) {
|
||||
@@ -27,15 +28,17 @@ static esp_err_t mcpwm_timer_register_to_group(mcpwm_timer_t *timer, int group_i
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
if (timer_id < 0) {
|
||||
mcpwm_release_group_handle(group);
|
||||
group = NULL;
|
||||
} else {
|
||||
timer->group = group;
|
||||
timer->timer_id = timer_id;
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(timer_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free timer in group (%d)", group_id);
|
||||
ESP_GOTO_ON_FALSE(timer_id >= 0, ESP_ERR_NOT_FOUND, err, TAG, "no free timer in group (%d)", group_id);
|
||||
|
||||
timer->group = group;
|
||||
timer->timer_id = timer_id;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (group) {
|
||||
mcpwm_release_group_handle(group);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcpwm_timer_unregister_from_group(mcpwm_timer_t *timer)
|
||||
@@ -85,18 +88,19 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
|
||||
ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported");
|
||||
#endif // SOC_MCPWM_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
// select the clock source before group HAL initialization if this timer creates the group
|
||||
mcpwm_timer_clock_source_t clk_src = config->clk_src ? config->clk_src : MCPWM_TIMER_CLK_SRC_DEFAULT;
|
||||
|
||||
timer = heap_caps_calloc(1, sizeof(mcpwm_timer_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for timer");
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_timer_register_to_group(timer, config->group_id), err, TAG, "register timer failed");
|
||||
ESP_GOTO_ON_ERROR(mcpwm_timer_register_to_group(timer, config->group_id, (soc_module_clk_t)clk_src), err, TAG, "register timer failed");
|
||||
mcpwm_group_t *group = timer->group;
|
||||
int group_id = group->group_id;
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
int timer_id = timer->timer_id;
|
||||
|
||||
// select the clock source
|
||||
mcpwm_timer_clock_source_t clk_src = config->clk_src ? config->clk_src : MCPWM_TIMER_CLK_SRC_DEFAULT;
|
||||
ESP_GOTO_ON_ERROR(mcpwm_select_periph_clock(group, (soc_module_clk_t)clk_src), err, TAG, "set group clock failed");
|
||||
// group clock source has already been committed in mcpwm_acquire_group_handle()
|
||||
// reset the timer to a determined state
|
||||
mcpwm_hal_timer_reset(hal, timer_id);
|
||||
// set timer resolution
|
||||
|
||||
Reference in New Issue
Block a user