mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feat/mcpwm_event_comparator_driver' into 'master'
feat(MCPWM): MCPWM event comparator driver Closes IDF-7989 See merge request espressif/esp-idf!25552
This commit is contained in:
commit
ae1a9bf015
@ -134,6 +134,10 @@ if(CONFIG_SOC_MCPWM_SUPPORTED)
|
||||
"mcpwm/mcpwm_sync.c"
|
||||
"mcpwm/mcpwm_timer.c"
|
||||
"deprecated/mcpwm_legacy.c")
|
||||
if(CONFIG_SOC_MCPWM_SUPPORT_ETM)
|
||||
list(APPEND srcs "mcpwm/mcpwm_etm.c")
|
||||
endif()
|
||||
list(APPEND ldfragments "mcpwm/linker.lf")
|
||||
endif()
|
||||
|
||||
# PCNT related source files
|
||||
|
@ -15,8 +15,6 @@ entries:
|
||||
if DAC_CTRL_FUNC_IN_IRAM = y:
|
||||
dac_oneshot: dac_oneshot_output_voltage (noflash)
|
||||
dac_continuous: dac_continuous_write_asynchronously (noflash)
|
||||
if MCPWM_CTRL_FUNC_IN_IRAM = y:
|
||||
mcpwm_cmpr: mcpwm_comparator_set_compare_value (noflash)
|
||||
if LEDC_CTRL_FUNC_IN_IRAM = y:
|
||||
ledc: ledc_stop (noflash)
|
||||
ledc: ledc_update_duty (noflash)
|
||||
|
@ -54,6 +54,29 @@ esp_err_t mcpwm_new_comparator(mcpwm_oper_handle_t oper, const mcpwm_comparator_
|
||||
*/
|
||||
esp_err_t mcpwm_del_comparator(mcpwm_cmpr_handle_t cmpr);
|
||||
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
/**
|
||||
* @brief MCPWM event comparator configuration
|
||||
*/
|
||||
typedef struct {
|
||||
} mcpwm_event_comparator_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create MCPWM event comparator
|
||||
*
|
||||
* @param[in] oper MCPWM operator, allocated by `mcpwm_new_operator()`, the new event comparator will be allocated from this operator
|
||||
* @param[in] config MCPWM comparator configuration
|
||||
* @param[out] ret_cmpr Returned MCPWM event comparator
|
||||
* @return
|
||||
* - ESP_OK: Create MCPWM event comparator successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create MCPWM event comparator failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: Create MCPWM event comparator failed because out of memory
|
||||
* - ESP_ERR_NOT_FOUND: Create MCPWM event comparator failed because can't find free resource
|
||||
* - ESP_FAIL: Create MCPWM event comparator failed because of other error
|
||||
*/
|
||||
esp_err_t mcpwm_new_event_comparator(mcpwm_oper_handle_t oper, const mcpwm_event_comparator_config_t *config, mcpwm_cmpr_handle_t *ret_cmpr);
|
||||
#endif // SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
|
||||
/**
|
||||
* @brief Group of supported MCPWM compare event callbacks
|
||||
* @note The callbacks are all running under ISR environment
|
||||
|
43
components/driver/mcpwm/include/driver/mcpwm_etm.h
Normal file
43
components/driver/mcpwm/include/driver/mcpwm_etm.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_etm.h"
|
||||
#include "driver/mcpwm_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MCPWM event comparator ETM event configuration
|
||||
*/
|
||||
typedef struct {
|
||||
mcpwm_comparator_etm_event_type_t event_type; /*!< MCPWM comparator ETM event type */
|
||||
} mcpwm_cmpr_etm_event_config_t;
|
||||
|
||||
/**
|
||||
* @brief Get the ETM event for MCPWM comparator
|
||||
*
|
||||
* @note The created ETM event object can be deleted later by calling `esp_etm_del_event`
|
||||
*
|
||||
* @param[in] cmpr MCPWM comparator, allocated by `mcpwm_new_comparator()` or `mcpwm_new_event_comparator()`
|
||||
* @param[in] config MCPWM ETM comparator event configuration
|
||||
* @param[out] out_event Returned ETM event handle
|
||||
* @return
|
||||
* - ESP_OK: Get ETM event successfully
|
||||
* - ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument
|
||||
* - ESP_FAIL: Get ETM event failed because of other error
|
||||
*/
|
||||
esp_err_t mcpwm_comparator_new_etm_event(mcpwm_cmpr_handle_t cmpr, const mcpwm_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *out_event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -18,3 +18,4 @@
|
||||
#include "driver/mcpwm_fault.h"
|
||||
#include "driver/mcpwm_sync.h"
|
||||
#include "driver/mcpwm_cap.h"
|
||||
#include "driver/mcpwm_etm.h"
|
||||
|
5
components/driver/mcpwm/linker.lf
Normal file
5
components/driver/mcpwm/linker.lf
Normal file
@ -0,0 +1,5 @@
|
||||
[mapping:mcpwm_driver]
|
||||
archive: libdriver.a
|
||||
entries:
|
||||
if MCPWM_CTRL_FUNC_IN_IRAM = y:
|
||||
mcpwm_cmpr: mcpwm_comparator_set_compare_value (noflash)
|
@ -262,8 +262,8 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc
|
||||
ESP_GOTO_ON_FALSE(cap_timer && config && ret_cap_channel, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE(config->prescale && config->prescale <= MCPWM_LL_MAX_CAPTURE_PRESCALE, ESP_ERR_INVALID_ARG, err, TAG, "invalid prescale");
|
||||
if (config->intr_priority) {
|
||||
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
}
|
||||
|
||||
// create instance firstly, then install onto platform
|
||||
|
@ -33,12 +33,31 @@ static esp_err_t mcpwm_comparator_register_to_operator(mcpwm_cmpr_t *cmpr, mcpwm
|
||||
{
|
||||
int cmpr_id = -1;
|
||||
portENTER_CRITICAL(&oper->spinlock);
|
||||
for (int i = 0; i < SOC_MCPWM_COMPARATORS_PER_OPERATOR; i++) {
|
||||
if (!oper->comparators[i]) {
|
||||
oper->comparators[i] = cmpr;
|
||||
cmpr_id = i;
|
||||
break;
|
||||
switch (cmpr->type) {
|
||||
case MCPWM_OPERATOR_COMPARATOR: {
|
||||
mcpwm_oper_cmpr_t *oper_cmpr = __containerof(cmpr, mcpwm_oper_cmpr_t, base);
|
||||
for (int i = 0; i < SOC_MCPWM_COMPARATORS_PER_OPERATOR; i++) {
|
||||
if (!oper->comparators[i]) {
|
||||
oper->comparators[i] = oper_cmpr;
|
||||
cmpr_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
case MCPWM_EVENT_COMPARATOR: {
|
||||
mcpwm_evt_cmpr_t *evt_cmpr = __containerof(cmpr, mcpwm_evt_cmpr_t, base);
|
||||
for (int i = 0; i < SOC_MCPWM_EVENT_COMPARATORS_PER_OPERATOR; i++) {
|
||||
if (!oper->event_comparators[i]) {
|
||||
oper->event_comparators[i] = evt_cmpr;
|
||||
cmpr_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
portEXIT_CRITICAL(&oper->spinlock);
|
||||
ESP_RETURN_ON_FALSE(cmpr_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free comparator in operator (%d,%d)", oper->group->group_id, oper->oper_id);
|
||||
@ -54,58 +73,81 @@ static void mcpwm_comparator_unregister_from_operator(mcpwm_cmpr_t *cmpr)
|
||||
int cmpr_id = cmpr->cmpr_id;
|
||||
|
||||
portENTER_CRITICAL(&oper->spinlock);
|
||||
oper->comparators[cmpr_id] = NULL;
|
||||
switch (cmpr->type) {
|
||||
case MCPWM_OPERATOR_COMPARATOR:
|
||||
oper->comparators[cmpr_id] = NULL;
|
||||
break;
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
case MCPWM_EVENT_COMPARATOR:
|
||||
oper->event_comparators[cmpr_id] = NULL;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
portEXIT_CRITICAL(&oper->spinlock);
|
||||
}
|
||||
|
||||
static esp_err_t mcpwm_comparator_destroy(mcpwm_cmpr_t *cmpr)
|
||||
{
|
||||
if (cmpr->intr) {
|
||||
ESP_RETURN_ON_ERROR(esp_intr_free(cmpr->intr), TAG, "uninstall interrupt service failed");
|
||||
}
|
||||
if (cmpr->oper) {
|
||||
mcpwm_comparator_unregister_from_operator(cmpr);
|
||||
}
|
||||
free(cmpr);
|
||||
switch (cmpr->type) {
|
||||
case MCPWM_OPERATOR_COMPARATOR: {
|
||||
mcpwm_oper_cmpr_t *oper_cmpr = __containerof(cmpr, mcpwm_oper_cmpr_t, base);
|
||||
if (oper_cmpr->intr) {
|
||||
ESP_RETURN_ON_ERROR(esp_intr_free(oper_cmpr->intr), TAG, "uninstall interrupt service failed");
|
||||
}
|
||||
free(oper_cmpr);
|
||||
break;
|
||||
}
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
case MCPWM_EVENT_COMPARATOR: {
|
||||
mcpwm_evt_cmpr_t *evt_cmpr = __containerof(cmpr, mcpwm_evt_cmpr_t, base);
|
||||
free(evt_cmpr);
|
||||
break;
|
||||
}
|
||||
#endif // SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_new_comparator(mcpwm_oper_handle_t oper, const mcpwm_comparator_config_t *config, mcpwm_cmpr_handle_t *ret_cmpr)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
mcpwm_cmpr_t *cmpr = NULL;
|
||||
mcpwm_oper_cmpr_t *cmpr = NULL;
|
||||
ESP_GOTO_ON_FALSE(oper && config && ret_cmpr, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
if (config->intr_priority) {
|
||||
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
}
|
||||
|
||||
cmpr = heap_caps_calloc(1, sizeof(mcpwm_cmpr_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
cmpr = heap_caps_calloc(1, sizeof(mcpwm_oper_cmpr_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(cmpr, ESP_ERR_NO_MEM, err, TAG, "no mem for comparator");
|
||||
cmpr->base.type = MCPWM_OPERATOR_COMPARATOR;
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_comparator_register_to_operator(cmpr, oper), err, TAG, "register comparator failed");
|
||||
ESP_GOTO_ON_ERROR(mcpwm_comparator_register_to_operator(&cmpr->base, oper), err, TAG, "register comparator failed");
|
||||
mcpwm_group_t *group = oper->group;
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
int oper_id = oper->oper_id;
|
||||
int cmpr_id = cmpr->cmpr_id;
|
||||
int cmpr_id = cmpr->base.cmpr_id;
|
||||
|
||||
// if interrupt priority specified before, it cannot be changed until the group is released
|
||||
// check if the new priority specified consistents with the old one
|
||||
ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group intrrupt priority failed");
|
||||
// check if the new priority specified consistent with the old one
|
||||
ESP_GOTO_ON_ERROR(mcpwm_check_intr_priority(group, config->intr_priority), err, TAG, "set group interrupt priority failed");
|
||||
|
||||
mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, oper_id, cmpr_id, config->flags.update_cmp_on_tez);
|
||||
mcpwm_ll_operator_enable_update_compare_on_tep(hal->dev, oper_id, cmpr_id, config->flags.update_cmp_on_tep);
|
||||
mcpwm_ll_operator_enable_update_compare_on_sync(hal->dev, oper_id, cmpr_id, config->flags.update_cmp_on_sync);
|
||||
|
||||
// fill in other comparator members
|
||||
cmpr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
*ret_cmpr = cmpr;
|
||||
ESP_LOGD(TAG, "new comparator (%d,%d,%d) at %p", group->group_id, oper_id, cmpr_id, cmpr);
|
||||
cmpr->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
*ret_cmpr = &cmpr->base;
|
||||
ESP_LOGD(TAG, "new operator comparator (%d,%d,%d) at %p", group->group_id, oper_id, cmpr_id, cmpr);
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (cmpr) {
|
||||
mcpwm_comparator_destroy(cmpr);
|
||||
mcpwm_comparator_destroy(&cmpr->base);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -120,8 +162,14 @@ esp_err_t mcpwm_del_comparator(mcpwm_cmpr_handle_t cmpr)
|
||||
int cmpr_id = cmpr->cmpr_id;
|
||||
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
mcpwm_ll_intr_enable(hal->dev, MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id), false);
|
||||
mcpwm_ll_intr_clear_status(hal->dev, MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id));
|
||||
switch (cmpr->type) {
|
||||
case MCPWM_OPERATOR_COMPARATOR:
|
||||
mcpwm_ll_intr_enable(hal->dev, MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id), false);
|
||||
mcpwm_ll_intr_clear_status(hal->dev, MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
ESP_LOGD(TAG, "del comparator (%d,%d,%d)", group->group_id, oper_id, cmpr_id);
|
||||
@ -130,6 +178,32 @@ esp_err_t mcpwm_del_comparator(mcpwm_cmpr_handle_t cmpr)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
esp_err_t mcpwm_new_event_comparator(mcpwm_oper_handle_t oper, const mcpwm_event_comparator_config_t *config, mcpwm_cmpr_handle_t *ret_cmpr)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
mcpwm_evt_cmpr_t *cmpr = NULL;
|
||||
ESP_GOTO_ON_FALSE(oper && config && ret_cmpr, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
cmpr = heap_caps_calloc(1, sizeof(mcpwm_evt_cmpr_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(cmpr, ESP_ERR_NO_MEM, err, TAG, "no mem for event comparator");
|
||||
cmpr->base.type = MCPWM_EVENT_COMPARATOR;
|
||||
|
||||
ESP_GOTO_ON_ERROR(mcpwm_comparator_register_to_operator(&cmpr->base, oper), err, TAG, "register event comparator failed");
|
||||
|
||||
// fill in other comparator members
|
||||
cmpr->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
*ret_cmpr = &cmpr->base;
|
||||
ESP_LOGD(TAG, "new event comparator (%d,%d,%d) at %p", oper->group->group_id, oper->oper_id, cmpr->base.cmpr_id, cmpr);
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (cmpr) {
|
||||
mcpwm_comparator_destroy(&cmpr->base);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif // SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
|
||||
esp_err_t mcpwm_comparator_set_compare_value(mcpwm_cmpr_handle_t cmpr, uint32_t cmp_ticks)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(cmpr, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
@ -139,9 +213,16 @@ esp_err_t mcpwm_comparator_set_compare_value(mcpwm_cmpr_handle_t cmpr, uint32_t
|
||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_STATE, TAG, "timer and operator are not connected");
|
||||
ESP_RETURN_ON_FALSE_ISR(cmp_ticks <= timer->peak_ticks, ESP_ERR_INVALID_ARG, TAG, "compare value out of range");
|
||||
|
||||
portENTER_CRITICAL_SAFE(&cmpr->spinlock);
|
||||
mcpwm_ll_operator_set_compare_value(group->hal.dev, oper->oper_id, cmpr->cmpr_id, cmp_ticks);
|
||||
portEXIT_CRITICAL_SAFE(&cmpr->spinlock);
|
||||
switch (cmpr->type) {
|
||||
case MCPWM_OPERATOR_COMPARATOR:
|
||||
mcpwm_ll_operator_set_compare_value(group->hal.dev, oper->oper_id, cmpr->cmpr_id, cmp_ticks);
|
||||
break;
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
case MCPWM_EVENT_COMPARATOR:
|
||||
mcpwm_ll_operator_set_event_compare_value(group->hal.dev, oper->oper_id, cmpr->cmpr_id, cmp_ticks);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cmpr->compare_ticks = cmp_ticks;
|
||||
return ESP_OK;
|
||||
@ -150,6 +231,7 @@ esp_err_t mcpwm_comparator_set_compare_value(mcpwm_cmpr_handle_t cmpr, uint32_t
|
||||
esp_err_t mcpwm_comparator_register_event_callbacks(mcpwm_cmpr_handle_t cmpr, const mcpwm_comparator_event_callbacks_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(cmpr && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(cmpr->type == MCPWM_OPERATOR_COMPARATOR, ESP_ERR_INVALID_ARG, TAG, "only oper cmpr can register event callback");
|
||||
mcpwm_oper_t *oper = cmpr->oper;
|
||||
mcpwm_group_t *group = oper->group;
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
@ -166,49 +248,50 @@ esp_err_t mcpwm_comparator_register_event_callbacks(mcpwm_cmpr_handle_t cmpr, co
|
||||
}
|
||||
#endif
|
||||
|
||||
mcpwm_oper_cmpr_t *oper_cmpr = __containerof(cmpr, mcpwm_oper_cmpr_t, base);
|
||||
// lazy install interrupt service
|
||||
if (!cmpr->intr) {
|
||||
if (!oper_cmpr->intr) {
|
||||
// we want the interrupt service to be enabled after allocation successfully
|
||||
int isr_flags = MCPWM_INTR_ALLOC_FLAG & ~ ESP_INTR_FLAG_INTRDISABLED;
|
||||
isr_flags |= mcpwm_get_intr_priority_flag(group);
|
||||
ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags,
|
||||
(uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id),
|
||||
mcpwm_comparator_default_isr, cmpr, &cmpr->intr), TAG, "install interrupt service for comparator failed");
|
||||
mcpwm_comparator_default_isr, oper_cmpr, &oper_cmpr->intr), TAG, "install interrupt service for comparator failed");
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
mcpwm_ll_intr_enable(hal->dev, MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id), cbs->on_reach != NULL);
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
cmpr->on_reach = cbs->on_reach;
|
||||
cmpr->user_data = user_data;
|
||||
oper_cmpr->on_reach = cbs->on_reach;
|
||||
oper_cmpr->user_data = user_data;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR mcpwm_comparator_default_isr(void *args)
|
||||
{
|
||||
mcpwm_cmpr_t *cmpr = (mcpwm_cmpr_t *)args;
|
||||
mcpwm_oper_t *oper = cmpr->oper;
|
||||
mcpwm_oper_cmpr_t *cmpr = (mcpwm_oper_cmpr_t *)args;
|
||||
mcpwm_oper_t *oper = cmpr->base.oper;
|
||||
mcpwm_timer_t *timer = oper->timer;
|
||||
mcpwm_group_t *group = oper->group;
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
int oper_id = oper->oper_id;
|
||||
int cmpr_id = cmpr->cmpr_id;
|
||||
int cmpr_id = cmpr->base.cmpr_id;
|
||||
bool need_yield = false;
|
||||
|
||||
uint32_t status = mcpwm_ll_intr_get_status(hal->dev);
|
||||
mcpwm_ll_intr_clear_status(hal->dev, status & MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id));
|
||||
|
||||
mcpwm_compare_event_data_t edata = {
|
||||
.compare_ticks = cmpr->compare_ticks,
|
||||
.compare_ticks = cmpr->base.compare_ticks,
|
||||
.direction = mcpwm_ll_timer_get_count_direction(hal->dev, timer->timer_id),
|
||||
};
|
||||
|
||||
if (status & MCPWM_LL_EVENT_CMP_EQUAL(oper_id, cmpr_id)) {
|
||||
mcpwm_compare_event_cb_t cb = cmpr->on_reach;
|
||||
if (cb) {
|
||||
if (cb(cmpr, &edata, cmpr->user_data)) {
|
||||
if (cb(&cmpr->base, &edata, cmpr->user_data)) {
|
||||
need_yield = true;
|
||||
}
|
||||
}
|
||||
|
105
components/driver/mcpwm/mcpwm_etm.c
Normal file
105
components/driver/mcpwm/mcpwm_etm.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/mcpwm_periph.h"
|
||||
#include "hal/mcpwm_ll.h"
|
||||
#include "driver/mcpwm_etm.h"
|
||||
#include "mcpwm_private.h"
|
||||
#include "esp_private/etm_interface.h"
|
||||
|
||||
static const char *TAG = "mcpwm-etm";
|
||||
|
||||
typedef struct {
|
||||
esp_etm_event_t base;
|
||||
mcpwm_cmpr_handle_t cmpr;
|
||||
} mcpwm_comparator_etm_event_t;
|
||||
|
||||
static esp_err_t mcpwm_del_etm_event(esp_etm_event_t *event)
|
||||
{
|
||||
mcpwm_comparator_etm_event_t *etm_event = __containerof(event, mcpwm_comparator_etm_event_t, base);
|
||||
mcpwm_cmpr_handle_t cmpr = etm_event->cmpr;
|
||||
mcpwm_oper_t *oper = cmpr->oper;
|
||||
mcpwm_group_t *group = oper->group;
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
|
||||
switch (cmpr->type) {
|
||||
case MCPWM_OPERATOR_COMPARATOR:
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
mcpwm_ll_etm_enable_comparator_event(hal->dev, oper->oper_id, cmpr->cmpr_id, false);
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
break;
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
case MCPWM_EVENT_COMPARATOR:
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
mcpwm_ll_etm_enable_evt_comparator_event(hal->dev, oper->oper_id, cmpr->cmpr_id, false);
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
break;
|
||||
#endif // SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
}
|
||||
free(etm_event);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_comparator_new_etm_event(mcpwm_cmpr_handle_t cmpr, const mcpwm_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *out_event)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
mcpwm_comparator_etm_event_t *event = NULL;
|
||||
ESP_RETURN_ON_FALSE(cmpr && config && out_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
event = heap_caps_calloc(1, sizeof(mcpwm_comparator_etm_event_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no memory for ETM event");
|
||||
|
||||
mcpwm_oper_t *oper = cmpr->oper;
|
||||
mcpwm_group_t *group = oper->group;
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
int group_id = group->group_id;
|
||||
int oper_id = oper->oper_id;
|
||||
int cmpr_id = cmpr->cmpr_id;
|
||||
uint32_t event_id = 0;
|
||||
|
||||
switch (cmpr->type) {
|
||||
case MCPWM_OPERATOR_COMPARATOR:
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
mcpwm_ll_etm_enable_comparator_event(hal->dev, oper_id, cmpr_id, true);
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
event_id = MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group_id, oper_id, cmpr_id, config->event_type);
|
||||
break;
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
case MCPWM_EVENT_COMPARATOR:
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
mcpwm_ll_etm_enable_evt_comparator_event(hal->dev, oper->oper_id, cmpr->cmpr_id, true);
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
event_id = MCPWM_LL_ETM_EVENT_COMPARATOR_EVENT_TABLE(group_id, oper_id, cmpr_id, config->event_type);
|
||||
break;
|
||||
#endif // SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
}
|
||||
ESP_GOTO_ON_FALSE(event_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported event type");
|
||||
ESP_LOGD(TAG, "MCPWM (%d) oper (%d) cmpr(%d) event_id (%"PRId32")", group_id, oper_id, cmpr_id, event_id);
|
||||
|
||||
// fill the ETM event object
|
||||
event->cmpr = cmpr;
|
||||
event->base.event_id = event_id;
|
||||
event->base.trig_periph = ETM_TRIG_PERIPH_MCPWM;
|
||||
event->base.del = mcpwm_del_etm_event;
|
||||
|
||||
*out_event = &event->base;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (event) {
|
||||
mcpwm_del_etm_event(&event->base);
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -94,8 +94,8 @@ esp_err_t mcpwm_new_gpio_fault(const mcpwm_gpio_fault_config_t *config, mcpwm_fa
|
||||
ESP_GOTO_ON_FALSE(config->group_id < SOC_MCPWM_GROUPS && config->group_id >= 0, ESP_ERR_INVALID_ARG,
|
||||
err, TAG, "invalid group ID:%d", config->group_id);
|
||||
if (config->intr_priority) {
|
||||
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
}
|
||||
|
||||
fault = heap_caps_calloc(1, sizeof(mcpwm_gpio_fault_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
|
@ -91,8 +91,8 @@ esp_err_t mcpwm_new_operator(const mcpwm_operator_config_t *config, mcpwm_oper_h
|
||||
ESP_GOTO_ON_FALSE(config->group_id < SOC_MCPWM_GROUPS && config->group_id >= 0, ESP_ERR_INVALID_ARG,
|
||||
err, TAG, "invalid group ID:%d", config->group_id);
|
||||
if (config->intr_priority) {
|
||||
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
}
|
||||
|
||||
oper = heap_caps_calloc(1, sizeof(mcpwm_oper_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
@ -146,6 +146,11 @@ esp_err_t mcpwm_del_operator(mcpwm_oper_handle_t oper)
|
||||
ESP_RETURN_ON_FALSE(!oper->generators[i], ESP_ERR_INVALID_STATE, TAG, "generator still in working");
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(!oper->soft_fault, ESP_ERR_INVALID_STATE, TAG, "soft fault still in working");
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
for (int i = 0; i < SOC_MCPWM_EVENT_COMPARATORS_PER_OPERATOR; i++) {
|
||||
ESP_RETURN_ON_FALSE(!oper->event_comparators[i], ESP_ERR_INVALID_STATE, TAG, "event comparator still in working");
|
||||
}
|
||||
#endif
|
||||
mcpwm_group_t *group = oper->group;
|
||||
int oper_id = oper->oper_id;
|
||||
mcpwm_hal_context_t *hal = &group->hal;
|
||||
|
@ -44,6 +44,8 @@ typedef struct mcpwm_timer_t mcpwm_timer_t;
|
||||
typedef struct mcpwm_cap_timer_t mcpwm_cap_timer_t;
|
||||
typedef struct mcpwm_oper_t mcpwm_oper_t;
|
||||
typedef struct mcpwm_cmpr_t mcpwm_cmpr_t;
|
||||
typedef struct mcpwm_oper_cmpr_t mcpwm_oper_cmpr_t;
|
||||
typedef struct mcpwm_evt_cmpr_t mcpwm_evt_cmpr_t;
|
||||
typedef struct mcpwm_gen_t mcpwm_gen_t;
|
||||
typedef struct mcpwm_fault_t mcpwm_fault_t;
|
||||
typedef struct mcpwm_gpio_fault_t mcpwm_gpio_fault_t;
|
||||
@ -107,7 +109,10 @@ struct mcpwm_oper_t {
|
||||
portMUX_TYPE spinlock; // spin lock
|
||||
intr_handle_t intr; // interrupt handle
|
||||
mcpwm_gen_t *generators[SOC_MCPWM_GENERATORS_PER_OPERATOR]; // mcpwm generator array
|
||||
mcpwm_cmpr_t *comparators[SOC_MCPWM_COMPARATORS_PER_OPERATOR]; // mcpwm comparator array
|
||||
mcpwm_oper_cmpr_t *comparators[SOC_MCPWM_COMPARATORS_PER_OPERATOR]; // mcpwm operator comparator array
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
mcpwm_evt_cmpr_t *event_comparators[SOC_MCPWM_EVENT_COMPARATORS_PER_OPERATOR]; // mcpwm event comparator array
|
||||
#endif
|
||||
mcpwm_trigger_source_t triggers[SOC_MCPWM_TRIGGERS_PER_OPERATOR]; // mcpwm trigger array, can be either a fault or a sync
|
||||
mcpwm_soft_fault_t *soft_fault; // mcpwm software fault
|
||||
mcpwm_operator_brake_mode_t brake_mode_on_soft_fault; // brake mode on software triggered fault
|
||||
@ -120,16 +125,32 @@ struct mcpwm_oper_t {
|
||||
void *user_data; // user data which would be passed to the trip zone callback
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MCPWM_OPERATOR_COMPARATOR, // operator comparator, can affect generator's behaviour
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
MCPWM_EVENT_COMPARATOR, // event comparator, can only generate ETM event
|
||||
#endif
|
||||
} mcpwm_comparator_type_t;
|
||||
|
||||
struct mcpwm_cmpr_t {
|
||||
int cmpr_id; // comparator ID, index from 0
|
||||
mcpwm_oper_t *oper; // which operator that the comparator resides in
|
||||
intr_handle_t intr; // interrupt handle
|
||||
portMUX_TYPE spinlock; // spin lock
|
||||
uint32_t compare_ticks; // compare value of this comparator
|
||||
mcpwm_comparator_type_t type; // comparator type
|
||||
};
|
||||
|
||||
struct mcpwm_oper_cmpr_t {
|
||||
mcpwm_cmpr_t base; // base class
|
||||
intr_handle_t intr; // interrupt handle
|
||||
mcpwm_compare_event_cb_t on_reach; // ISR callback function which would be invoked on timer counter reaches compare value
|
||||
void *user_data; // user data which would be passed to the comparator callbacks
|
||||
};
|
||||
|
||||
struct mcpwm_evt_cmpr_t {
|
||||
mcpwm_cmpr_t base; // base class
|
||||
};
|
||||
|
||||
struct mcpwm_gen_t {
|
||||
int gen_id; // generator ID, index from 0
|
||||
mcpwm_oper_t *oper; // which operator that the generator resides in
|
||||
@ -239,7 +260,7 @@ void mcpwm_release_group_handle(mcpwm_group_t *group);
|
||||
esp_err_t mcpwm_check_intr_priority(mcpwm_group_t *group, int intr_priority);
|
||||
int mcpwm_get_intr_priority_flag(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);
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -92,8 +92,8 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
|
||||
ESP_GOTO_ON_FALSE(config->group_id < SOC_MCPWM_GROUPS && config->group_id >= 0, ESP_ERR_INVALID_ARG,
|
||||
err, TAG, "invalid group ID:%d", config->group_id);
|
||||
if (config->intr_priority) {
|
||||
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
}
|
||||
|
||||
timer = heap_caps_calloc(1, sizeof(mcpwm_timer_t), MCPWM_MEM_ALLOC_CAPS);
|
||||
|
@ -185,7 +185,7 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
|
||||
config->high_limit <= PCNT_LL_MAX_LIM, ESP_ERR_INVALID_ARG, err, TAG,
|
||||
"invalid limit range:[%d,%d]", config->low_limit, config->high_limit);
|
||||
if (config->intr_priority) {
|
||||
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & PCNT_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & PCNT_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ typedef enum {
|
||||
ETM_TRIG_PERIPH_GDMA, /*!< ETM trigger source: GDMA */
|
||||
ETM_TRIG_PERIPH_GPTIMER, /*!< ETM trigger source: GPTimer */
|
||||
ETM_TRIG_PERIPH_SYSTIMER, /*!< ETM trigger source: Systimer */
|
||||
ETM_TRIG_PERIPH_MCPWM, /*!< ETM trigger source: MCPWM */
|
||||
} etm_trigger_peripheral_t;
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,10 @@ if(CONFIG_SOC_GDMA_SUPPORT_ETM)
|
||||
list(APPEND srcs "test_gdma_etm.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_MCPWM_SUPPORT_ETM)
|
||||
list(APPEND srcs "test_mcpwm_etm.c")
|
||||
endif()
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
|
153
components/esp_hw_support/test_apps/etm/main/test_mcpwm_etm.c
Normal file
153
components/esp_hw_support/test_apps/etm/main/test_mcpwm_etm.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_attr.h"
|
||||
#include "driver/gptimer_etm.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/mcpwm_prelude.h"
|
||||
|
||||
TEST_CASE("mcpwm_comparator_etm_event", "[etm]")
|
||||
{
|
||||
// MCPWM cmpra -------------------------------------> ETM channel A ---> GPTimer start
|
||||
// MCPWM cmprb / evt_cmpra (if support evt_cmpr) ---> ETM channel B ---> GPTimer stop
|
||||
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
.period_ticks = 10000,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t oper = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &oper));
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
|
||||
// install comparator
|
||||
int cmpa = 2000, cmpb = 8000;
|
||||
mcpwm_cmpr_handle_t comparator_a = NULL;
|
||||
mcpwm_cmpr_handle_t comparator_b = NULL;
|
||||
mcpwm_comparator_config_t comparator_config = {
|
||||
.flags.update_cmp_on_tez = true,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_comparator(oper, &comparator_config, &comparator_a));
|
||||
TEST_ESP_OK(mcpwm_new_comparator(oper, &comparator_config, &comparator_b));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator_a, cmpa));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator_b, cmpb));
|
||||
|
||||
// install generator
|
||||
const uint32_t gen_gpio = 10;
|
||||
mcpwm_gen_handle_t generator = NULL;
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.gen_gpio_num = gen_gpio,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_generator(oper, &generator_config, &generator));
|
||||
TEST_ESP_OK(mcpwm_generator_set_action_on_compare_event(generator,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator_a, MCPWM_GEN_ACTION_HIGH)));
|
||||
TEST_ESP_OK(mcpwm_generator_set_action_on_compare_event(generator,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator_b, MCPWM_GEN_ACTION_LOW)));
|
||||
|
||||
// allocate etm channels
|
||||
printf("allocate etm channels\r\n");
|
||||
esp_etm_channel_config_t etm_config = {};
|
||||
esp_etm_channel_handle_t etm_channel_a = NULL;
|
||||
esp_etm_channel_handle_t etm_channel_b = NULL;
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_b));
|
||||
|
||||
printf("allocate mcpwm comparator event\r\n");
|
||||
esp_etm_event_handle_t mcpwm_etm_event1 = NULL;
|
||||
esp_etm_event_handle_t mcpwm_etm_event2 = NULL;
|
||||
mcpwm_cmpr_etm_event_config_t mcpwm_cmpr_event_config = {
|
||||
.event_type = MCPWM_CMPR_ETM_EVENT_EQUAL,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_comparator_new_etm_event(comparator_a, &mcpwm_cmpr_event_config, &mcpwm_etm_event1));
|
||||
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
// install event comparator
|
||||
cmpb = 5000;
|
||||
mcpwm_cmpr_handle_t event_comparator = NULL;
|
||||
mcpwm_event_comparator_config_t event_comparator_config = {};
|
||||
TEST_ESP_OK(mcpwm_new_event_comparator(oper, &event_comparator_config, &event_comparator));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(event_comparator, cmpb));
|
||||
TEST_ESP_OK(mcpwm_comparator_new_etm_event(event_comparator, &mcpwm_cmpr_event_config, &mcpwm_etm_event2));
|
||||
#else
|
||||
TEST_ESP_OK(mcpwm_comparator_new_etm_event(comparator_b, &mcpwm_cmpr_event_config, &mcpwm_etm_event2));
|
||||
#endif // SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
|
||||
printf("create a gptimer\r\n");
|
||||
gptimer_handle_t gptimer = NULL;
|
||||
gptimer_config_t gptimer_config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&gptimer_config, &gptimer));
|
||||
|
||||
printf("get gptimer etm task handle\r\n");
|
||||
esp_etm_task_handle_t gptimer_task_start, gptimer_task_stop;
|
||||
gptimer_etm_task_config_t gptimer_etm_task_conf = {
|
||||
.task_type = GPTIMER_ETM_TASK_START_COUNT,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, &gptimer_task_start));
|
||||
gptimer_etm_task_conf.task_type = GPTIMER_ETM_TASK_STOP_COUNT;
|
||||
TEST_ESP_OK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, &gptimer_task_stop));
|
||||
|
||||
printf("enable timer\r\n");
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
|
||||
printf("connect event and task to the channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, mcpwm_etm_event1, gptimer_task_start));
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, mcpwm_etm_event2, gptimer_task_stop));
|
||||
|
||||
printf("enable etm channel\r\n");
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel_b));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
esp_rom_delay_us(100 * 1000);
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
|
||||
uint64_t cur_count_val = 0;
|
||||
TEST_ESP_OK(gptimer_get_raw_count(gptimer, &cur_count_val));
|
||||
printf("cur_count_val: %llu\r\n", cur_count_val);
|
||||
TEST_ASSERT_UINT_WITHIN(100, (cmpb - cmpa) * 10, cur_count_val);
|
||||
|
||||
// delete gptimer
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
|
||||
// delete etm primitives
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel_b));
|
||||
TEST_ESP_OK(esp_etm_del_task(gptimer_task_start));
|
||||
TEST_ESP_OK(esp_etm_del_task(gptimer_task_stop));
|
||||
TEST_ESP_OK(esp_etm_del_event(mcpwm_etm_event1));
|
||||
TEST_ESP_OK(esp_etm_del_event(mcpwm_etm_event2));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_a));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel_b));
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator));
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparator_a));
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparator_b));
|
||||
#if SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
TEST_ESP_OK(mcpwm_del_comparator(event_comparator));
|
||||
#endif
|
||||
TEST_ESP_OK(mcpwm_del_operator(oper));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
#include "hal/mcpwm_types.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "soc/soc_etm_source.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -59,6 +60,12 @@ extern "C" {
|
||||
#define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)])
|
||||
#define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)])
|
||||
|
||||
// MCPWM ETM comparator event table
|
||||
#define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \
|
||||
(uint32_t [1][MCPWM_CMPR_ETM_EVENT_MAX]){{ \
|
||||
[MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \
|
||||
}}[group][event]
|
||||
|
||||
/**
|
||||
* @brief The dead time module's clock source
|
||||
*/
|
||||
@ -1595,6 +1602,25 @@ static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////MCPWM ETM Specific////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Enable comparator ETM event
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param operator_id Operator ID, index from 0 to 2
|
||||
* @param cmpr_id Comparator ID, index from 0 to 2
|
||||
* @param en True: enable ETM module, False: disable ETM module
|
||||
*/
|
||||
static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int operator_id, int cmpr_id, bool en)
|
||||
{
|
||||
if (en) {
|
||||
mcpwm->evt_en.val |= 1 << (operator_id + 3 * cmpr_id + 9) ;
|
||||
} else {
|
||||
mcpwm->evt_en.val &= ~(1 << (operator_id + 3 * cmpr_id + 9)) ;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////Deprecated Functions//////////////////////////////////////////////////////////
|
||||
/////////////////////////////The following functions are only used by the legacy driver/////////////////////////////////
|
||||
/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)//////////////////////////////
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "hal/mcpwm_types.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "soc/soc_etm_source.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -57,6 +58,12 @@ extern "C" {
|
||||
#define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)])
|
||||
#define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)])
|
||||
|
||||
// MCPWM ETM comparator event table
|
||||
#define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \
|
||||
(uint32_t [1][MCPWM_CMPR_ETM_EVENT_MAX]){{ \
|
||||
[MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \
|
||||
}}[group][event]
|
||||
|
||||
/**
|
||||
* @brief The dead time module's clock source
|
||||
*/
|
||||
@ -1593,6 +1600,25 @@ static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////MCPWM ETM Specific////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Enable comparator ETM event
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param operator_id Operator ID, index from 0 to 2
|
||||
* @param cmpr_id Comparator ID, index from 0 to 2
|
||||
* @param en True: enable ETM module, False: disable ETM module
|
||||
*/
|
||||
static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int operator_id, int cmpr_id, bool en)
|
||||
{
|
||||
if (en) {
|
||||
mcpwm->evt_en.val |= 1 << (operator_id + 3 * cmpr_id + 9) ;
|
||||
} else {
|
||||
mcpwm->evt_en.val &= ~(1 << (operator_id + 3 * cmpr_id + 9)) ;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////Deprecated Functions//////////////////////////////////////////////////////////
|
||||
/////////////////////////////The following functions are only used by the legacy driver/////////////////////////////////
|
||||
/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)//////////////////////////////
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "hal/misc.h"
|
||||
#include "hal/assert.h"
|
||||
#include <stdio.h>
|
||||
#include "soc/soc_etm_source.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -59,6 +61,28 @@ extern "C" {
|
||||
#define MCPWM_LL_GEN_ACTION_TO_REG_CAL(action) ((uint8_t[]) {0, 1, 2, 3}[(action)])
|
||||
#define MCPWM_LL_BRAKE_MODE_TO_REG_VAL(mode) ((uint8_t[]) {0, 1}[(mode)])
|
||||
|
||||
// MCPWM ETM comparator event table
|
||||
#define MCPWM_LL_ETM_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \
|
||||
(uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \
|
||||
{ \
|
||||
[MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \
|
||||
}, \
|
||||
{ \
|
||||
[MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM1_EVT_OP0_TEA + oper_id + 3 * cmpr_id, \
|
||||
}, \
|
||||
}[group][event]
|
||||
|
||||
// MCPWM ETM event comparator event table
|
||||
#define MCPWM_LL_ETM_EVENT_COMPARATOR_EVENT_TABLE(group, oper_id, cmpr_id, event) \
|
||||
(uint32_t[2][MCPWM_CMPR_ETM_EVENT_MAX]){ \
|
||||
{ \
|
||||
[MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM0_EVT_OP0_TEE1 + oper_id + 3 * cmpr_id, \
|
||||
}, \
|
||||
{ \
|
||||
[MCPWM_CMPR_ETM_EVENT_EQUAL] = MCPWM1_EVT_OP0_TEE1 + oper_id + 3 * cmpr_id, \
|
||||
}, \
|
||||
}[group][event]
|
||||
|
||||
/**
|
||||
* @brief The dead time module's clock source
|
||||
*/
|
||||
@ -652,17 +676,17 @@ static inline void mcpwm_ll_operator_set_compare_value(mcpwm_dev_t *mcpwm, int o
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set equal value for operator
|
||||
* @brief Set equal value for operator event comparator
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param operator_id Operator ID, index from 0 to 2
|
||||
* @param equal_id Equal ID, index from 0 to 1
|
||||
* @param equal_value Equal value
|
||||
* @param event_cmpr_id Event Comparator ID, index from 0 to 1
|
||||
* @param compare_value Compare value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void mcpwm_ll_operator_set_equal_value(mcpwm_dev_t *mcpwm, int operator_id, int event_cmpr_id, uint32_t equal_value)
|
||||
static inline void mcpwm_ll_operator_set_event_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int event_cmpr_id, uint32_t compare_value)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators_timestamp[operator_id].timestamp[event_cmpr_id], op_tstmp_e, equal_value);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->operators_timestamp[operator_id].timestamp[event_cmpr_id], op_tstmp_e, compare_value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1623,6 +1647,42 @@ static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->cap_chn_cfg[channel], capn_prescale, prescale - 1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////MCPWM ETM Specific////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Enable comparator ETM event
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param operator_id Operator ID, index from 0 to 2
|
||||
* @param cmpr_id Comparator ID, index from 0 to 2
|
||||
* @param en True: enable ETM module, False: disable ETM module
|
||||
*/
|
||||
static inline void mcpwm_ll_etm_enable_comparator_event(mcpwm_dev_t *mcpwm, int operator_id, int cmpr_id, bool en)
|
||||
{
|
||||
if (en) {
|
||||
mcpwm->evt_en.val |= 1 << (operator_id + 3 * cmpr_id + 9);
|
||||
} else {
|
||||
mcpwm->evt_en.val &= ~(1 << (operator_id + 3 * cmpr_id + 9));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable event_comparator ETM event
|
||||
*
|
||||
* @param mcpwm Peripheral instance address
|
||||
* @param operator_id Operator ID, index from 0 to 2
|
||||
* @param evt_cmpr_id Event comparator ID, index from 0 to 2
|
||||
* @param en True: enable ETM module, False: disable ETM module
|
||||
*/
|
||||
static inline void mcpwm_ll_etm_enable_evt_comparator_event(mcpwm_dev_t *mcpwm, int operator_id, int evt_cmpr_id, bool en)
|
||||
{
|
||||
if (en) {
|
||||
mcpwm->evt_en2.val |= 1 << (operator_id + 3 * evt_cmpr_id);
|
||||
} else {
|
||||
mcpwm->evt_en2.val &= ~(1 << (operator_id + 3 * evt_cmpr_id));
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////Deprecated Functions//////////////////////////////////////////////////////////
|
||||
/////////////////////////////The following functions are only used by the legacy driver/////////////////////////////////
|
||||
/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)//////////////////////////////
|
||||
|
@ -105,6 +105,14 @@ typedef enum {
|
||||
MCPWM_CAP_EDGE_NEG, /*!< Capture on the negative edge */
|
||||
} mcpwm_capture_edge_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM comparator specific events that supported by the ETM module
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_CMPR_ETM_EVENT_EQUAL, /*!< The count value equals the value of comparator */
|
||||
MCPWM_CMPR_ETM_EVENT_MAX, /*!< Maximum number of comparator events */
|
||||
} mcpwm_comparator_etm_event_type_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -17,7 +17,7 @@ void timer_hal_init(timer_hal_context_t *hal, uint32_t group_num, uint32_t timer
|
||||
timer_ll_enable_counter(hal->dev, timer_num, false);
|
||||
timer_ll_enable_auto_reload(hal->dev, timer_num, false);
|
||||
timer_ll_enable_alarm(hal->dev, timer_num, false);
|
||||
// enable RTM subsystem if available
|
||||
// enable ETM subsystem if available
|
||||
#if SOC_TIMER_SUPPORT_ETM
|
||||
timer_ll_enable_etm(hal->dev, true);
|
||||
#endif
|
||||
|
@ -547,6 +547,10 @@ config SOC_MCPWM_COMPARATORS_PER_OPERATOR
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_MCPWM_EVENT_COMPARATORS_PER_OPERATOR
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_MCPWM_GENERATORS_PER_OPERATOR
|
||||
int
|
||||
default 2
|
||||
@ -579,6 +583,10 @@ config SOC_MCPWM_SUPPORT_ETM
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MCPWM_CAPTURE_CLK_FROM_GROUP
|
||||
bool
|
||||
default y
|
||||
|
@ -290,6 +290,7 @@
|
||||
#define SOC_MCPWM_TIMERS_PER_GROUP (3) ///< The number of timers that each group has
|
||||
#define SOC_MCPWM_OPERATORS_PER_GROUP (3) ///< The number of operators that each group has
|
||||
#define SOC_MCPWM_COMPARATORS_PER_OPERATOR (2) ///< The number of comparators that each operator has
|
||||
#define SOC_MCPWM_EVENT_COMPARATORS_PER_OPERATOR (2) ///< The number of event comparators that each operator has
|
||||
#define SOC_MCPWM_GENERATORS_PER_OPERATOR (2) ///< The number of generators that each operator has
|
||||
#define SOC_MCPWM_TRIGGERS_PER_OPERATOR (2) ///< The number of triggers that each operator has
|
||||
#define SOC_MCPWM_GPIO_FAULTS_PER_GROUP (3) ///< The number of fault signal detectors that each group has
|
||||
@ -298,6 +299,7 @@
|
||||
#define SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP (3) ///< The number of GPIO synchros that each group has
|
||||
#define SOC_MCPWM_SWSYNC_CAN_PROPAGATE (1) ///< Software sync event can be routed to its output
|
||||
#define SOC_MCPWM_SUPPORT_ETM (1) ///< Support ETM (Event Task Matrix)
|
||||
#define SOC_MCPWM_SUPPORT_EVENT_COMPARATOR (1) ///< Support event comparator (based on ETM)
|
||||
#define SOC_MCPWM_CAPTURE_CLK_FROM_GROUP (1) ///< Capture timer shares clock with other PWM timers
|
||||
|
||||
/*------------------------ USB SERIAL JTAG CAPS ------------------------------*/
|
||||
|
@ -69,6 +69,7 @@ Other Peripheral Events
|
||||
:SOC_SYSTIMER_SUPPORT_ETM: - Refer to :doc:`/api-reference/system/esp_timer` for how to get the ETM event handle from esp_timer.
|
||||
:SOC_TIMER_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/gptimer` for how to get the ETM event handle from GPTimer.
|
||||
:SOC_GDMA_SUPPORT_ETM: - Refer to :doc:`/api-reference/system/async_memcpy` for how to get the ETM event handle from async memcpy.
|
||||
:SOC_MCPWM_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/mcpwm` for how to get the ETM event handle from MCPWM.
|
||||
|
||||
.. _etm-task:
|
||||
|
||||
|
@ -34,23 +34,25 @@ Functional Overview
|
||||
|
||||
Description of the MCPWM functionality is divided into the following sections:
|
||||
|
||||
- :ref:`mcpwm-resource-allocation-and-initialization` - covers how to allocate various MCPWM objects, like timers, operators, comparators, generators and so on. These objects are the basis of the following IO setting and control functions.
|
||||
- :ref:`mcpwm-timer-operations-and-events` - describes control functions and event callbacks supported by the MCPWM timer.
|
||||
- :ref:`mcpwm-comparator-operations-and-events` - describes control functions and event callbacks supported by the MCPWM comparator.
|
||||
- :ref:`mcpwm-generator-actions-on-events` - describes how to set actions for MCPWM generators on particular events that are generated by the MCPWM timer and comparators.
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-generator-configurations` - demonstrates some classical PWM waveforms that can be achieved by configuring generator actions.
|
||||
- :ref:`mcpwm-dead-time` - describes how to set dead time for MCPWM generators.
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-dead-time-configurations` - demonstrates some classical PWM waveforms that can be achieved by configuring dead time.
|
||||
- :ref:`mcpwm-carrier-modulation` - describes how to set and modulate a high frequency onto the final PWM waveforms.
|
||||
- :ref:`mcpwm-faults-and-brake-actions` - describes how to set brake actions for MCPWM operators on particular fault events.
|
||||
- :ref:`mcpwm-generator-force-actions` - describes how to control the generator output level asynchronously in a forceful way.
|
||||
- :ref:`mcpwm-synchronization` - describes how to synchronize the MCPWM timers and get a fixed phase difference between the generated PWM signals.
|
||||
- :ref:`mcpwm-capture` - describes how to use the MCPWM capture module to measure the pulse width of a signal.
|
||||
- :ref:`mcpwm-power-management` - describes how different source clocks affects power consumption.
|
||||
- :ref:`mcpwm-iram-safe` - describes tips on how to make the RMT interrupt work better along with a disabled cache.
|
||||
- :ref:`mcpwm-thread-safety` - lists which APIs are guaranteed to be thread-safe by the driver.
|
||||
- :ref:`mcpwm-kconfig-options` - lists the supported Kconfig options that can bring different effects to the driver.
|
||||
.. list::
|
||||
|
||||
- :ref:`mcpwm-resource-allocation-and-initialization` - covers how to allocate various MCPWM objects, like timers, operators, comparators, generators and so on. These objects are the basis of the following IO setting and control functions.
|
||||
- :ref:`mcpwm-timer-operations-and-events` - describes control functions and event callbacks supported by the MCPWM timer.
|
||||
- :ref:`mcpwm-comparator-operations-and-events` - describes control functions and event callbacks supported by the MCPWM comparator.
|
||||
- :ref:`mcpwm-generator-actions-on-events` - describes how to set actions for MCPWM generators on particular events that are generated by the MCPWM timer and comparators.
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-generator-configurations` - demonstrates some classical PWM waveforms that can be achieved by configuring generator actions.
|
||||
- :ref:`mcpwm-dead-time` - describes how to set dead time for MCPWM generators.
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-dead-time-configurations` - demonstrates some classical PWM waveforms that can be achieved by configuring dead time.
|
||||
- :ref:`mcpwm-carrier-modulation` - describes how to set and modulate a high frequency onto the final PWM waveforms.
|
||||
- :ref:`mcpwm-faults-and-brake-actions` - describes how to set brake actions for MCPWM operators on particular fault events.
|
||||
- :ref:`mcpwm-generator-force-actions` - describes how to control the generator output level asynchronously in a forceful way.
|
||||
- :ref:`mcpwm-synchronization` - describes how to synchronize the MCPWM timers and get a fixed phase difference between the generated PWM signals.
|
||||
- :ref:`mcpwm-capture` - describes how to use the MCPWM capture module to measure the pulse width of a signal.
|
||||
:SOC_MCPWM_SUPPORT_ETM: - :ref:`mcpwm-etm-event-and-task` - describes what the events and tasks can be connected to the ETM channel.
|
||||
- :ref:`mcpwm-power-management` - describes how different source clocks affects power consumption.
|
||||
- :ref:`mcpwm-iram-safe` - describes tips on how to make the RMT interrupt work better along with a disabled cache.
|
||||
- :ref:`mcpwm-thread-safety` - lists which APIs are guaranteed to be thread-safe by the driver.
|
||||
- :ref:`mcpwm-kconfig-options` - lists the supported Kconfig options that can bring different effects to the driver.
|
||||
|
||||
.. _mcpwm-resource-allocation-and-initialization:
|
||||
|
||||
@ -934,8 +936,22 @@ Trigger a Software Capture Event
|
||||
|
||||
Sometimes, the software also wants to trigger a "fake" capture event. The :cpp:func:`mcpwm_capture_channel_trigger_soft_catch` is provided for that purpose. Please note that, even though it is a "fake" capture event, it can still cause an interrupt, thus your capture event callback function gets invoked as well.
|
||||
|
||||
.. only:: SOC_MCPWM_SUPPORT_ETM
|
||||
|
||||
.. _mcpwm-power-management:
|
||||
.. _mcpwm-etm-event-and-task:
|
||||
|
||||
ETM Event and Task
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MCPWM comparator is able to generate events that can interact with the :doc:`ETM </api-reference/peripherals/etm>` module. The supported events are listed in the :cpp:type:`mcpwm_comparator_etm_event_type_t`. You can call :cpp:func:`mcpwm_comparator_new_etm_event` to get the corresponding ETM event handle.
|
||||
|
||||
For how to connect the event and task to an ETM channel, please refer to the :doc:`ETM </api-reference/peripherals/etm>` documentation.
|
||||
|
||||
.. _mcpwm-power-management:
|
||||
|
||||
.. only:: not SOC_MCPWM_SUPPORT_ETM
|
||||
|
||||
.. _mcpwm-power-management:
|
||||
|
||||
Power Management
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
@ -69,6 +69,7 @@ GPIO **边沿** 事件是最常见的事件类型,任何 GPIO 管脚均可触
|
||||
:SOC_SYSTIMER_SUPPORT_ETM: - 要了解如何从 esp_timer 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/system/esp_timer`。
|
||||
:SOC_TIMER_SUPPORT_ETM: - 要了解如何从 GPTimer 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/gptimer`。
|
||||
:SOC_GDMA_SUPPORT_ETM: - 要了解如何从 async memcpy 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/system/async_memcpy`。
|
||||
:SOC_MCPWM_SUPPORT_ETM: - 要了解如何从 MCPWM 中获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/mcpwm`。
|
||||
|
||||
.. _etm-task:
|
||||
|
||||
|
@ -34,23 +34,25 @@ MCPWM 外设是一个多功能 PWM 生成器,集成多个子模块,在电力
|
||||
|
||||
下文将分节概述 MCPWM 的功能:
|
||||
|
||||
- :ref:`mcpwm-resource-allocation-and-initialization` - 介绍各类 MCPWM 模块的分配,如定时器、操作器、比较器、生成器等。随后介绍的 IO 设置和控制功能也将围绕这些模块进行。
|
||||
- :ref:`mcpwm-timer-operations-and-events` - 介绍 MCPWM 定时器支持的控制功能和事件回调。
|
||||
- :ref:`mcpwm-comparator-operations-and-events` - 介绍 MCPWM 比较器支持的控制功能和事件回调。
|
||||
- :ref:`mcpwm-generator-actions-on-events` - 介绍如何针对 MCPWM 定时器和比较器生成的特定事件,设置 MCPWM 生成器的相应执行操作。
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-generator-configurations` - 介绍一些经典 PWM 波形的生成器配置。
|
||||
- :ref:`mcpwm-dead-time` - 介绍如何设置 MCPWM 生成器的死区时间。
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-dead-time-configurations` - 介绍一些经典 PWM 波形的死区配置。
|
||||
- :ref:`mcpwm-carrier-modulation` - 介绍如何在最终输出的 PWM 波形上调制高频载波。
|
||||
- :ref:`mcpwm-faults-and-brake-actions` - 介绍如何为 MCPWM 操作器配置特定故障事件下的制动操作。
|
||||
- :ref:`mcpwm-generator-force-actions` - 介绍如何强制异步控制生成器的输出水平。
|
||||
- :ref:`mcpwm-synchronization` - 介绍如何同步 MCPWM 定时器,并确保生成的最终输出 PWM 信号具有固定的相位差。
|
||||
- :ref:`mcpwm-capture` - 介绍如何使用 MCPWM 捕获模块测量信号脉宽。
|
||||
- :ref:`mcpwm-power-management` - 介绍不同的时钟源对功耗的影响。
|
||||
- :ref:`mcpwm-iram-safe` - 介绍如何协调 RMT 中断与禁用缓存。
|
||||
- :ref:`mcpwm-thread-safety` - 列出了由驱动程序认证为线程安全的 API。
|
||||
- :ref:`mcpwm-kconfig-options` - 列出了针对驱动的数个 Kconfig 支持选项。
|
||||
.. list::
|
||||
|
||||
- :ref:`mcpwm-resource-allocation-and-initialization` - 介绍各类 MCPWM 模块的分配,如定时器、操作器、比较器、生成器等。随后介绍的 IO 设置和控制功能也将围绕这些模块进行。
|
||||
- :ref:`mcpwm-timer-operations-and-events` - 介绍 MCPWM 定时器支持的控制功能和事件回调。
|
||||
- :ref:`mcpwm-comparator-operations-and-events` - 介绍 MCPWM 比较器支持的控制功能和事件回调。
|
||||
- :ref:`mcpwm-generator-actions-on-events` - 介绍如何针对 MCPWM 定时器和比较器生成的特定事件,设置 MCPWM 生成器的相应执行操作。
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-generator-configurations` - 介绍一些经典 PWM 波形的生成器配置。
|
||||
- :ref:`mcpwm-dead-time` - 介绍如何设置 MCPWM 生成器的死区时间。
|
||||
- :ref:`mcpwm-classical-pwm-waveforms-and-dead-time-configurations` - 介绍一些经典 PWM 波形的死区配置。
|
||||
- :ref:`mcpwm-carrier-modulation` - 介绍如何在最终输出的 PWM 波形上调制高频载波。
|
||||
- :ref:`mcpwm-faults-and-brake-actions` - 介绍如何为 MCPWM 操作器配置特定故障事件下的制动操作。
|
||||
- :ref:`mcpwm-generator-force-actions` - 介绍如何强制异步控制生成器的输出水平。
|
||||
- :ref:`mcpwm-synchronization` - 介绍如何同步 MCPWM 定时器,并确保生成的最终输出 PWM 信号具有固定的相位差。
|
||||
- :ref:`mcpwm-capture` - 介绍如何使用 MCPWM 捕获模块测量信号脉宽。
|
||||
:SOC_MCPWM_SUPPORT_ETM: - :ref:`mcpwm-etm-event-and-task` - MCPWM 提供了哪些事件和任务可以连接到 ETM 通道上。
|
||||
- :ref:`mcpwm-power-management` - 介绍不同的时钟源对功耗的影响。
|
||||
- :ref:`mcpwm-iram-safe` - 介绍如何协调 RMT 中断与禁用缓存。
|
||||
- :ref:`mcpwm-thread-safety` - 列出了由驱动程序认证为线程安全的 API。
|
||||
- :ref:`mcpwm-kconfig-options` - 列出了针对驱动的数个 Kconfig 支持选项。
|
||||
|
||||
.. _mcpwm-resource-allocation-and-initialization:
|
||||
|
||||
@ -934,8 +936,22 @@ MCPWM 捕获通道支持在信号上检测到有效边沿时发送通知。须
|
||||
|
||||
某些场景下,可能存在需要软件触发“虚假”捕获事件的需求。此时,可以调用 :cpp:func:`mcpwm_capture_channel_trigger_soft_catch` 实现。需注意,此类“虚假”捕获事件仍然会触发中断,并从而调用捕获事件回调函数。
|
||||
|
||||
.. only:: SOC_MCPWM_SUPPORT_ETM
|
||||
|
||||
.. _mcpwm-power-management:
|
||||
.. _mcpwm-etm-event-and-task:
|
||||
|
||||
ETM 事件与任务
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MCPWM 比较器可以产生事件,这些事件可以连接到 :doc:`ETM </api-reference/peripherals/etm>` 模块。:cpp:type:`mcpwm_comparator_etm_event_type_t` 中列出了 MCPWM 比较器能够产生的事件类型。用户可以通过调用 :cpp:func:`mcpwm_comparator_new_etm_event` 来获得相应事件的 ETM event 句柄。
|
||||
|
||||
关于如何将 MCPWM 比较器事件连接到 ETM 通道中,请参阅 :doc:`ETM </api-reference/peripherals/etm>` 文档。
|
||||
|
||||
.. _mcpwm-power-management:
|
||||
|
||||
.. only:: not SOC_MCPWM_SUPPORT_ETM
|
||||
|
||||
.. _mcpwm-power-management:
|
||||
|
||||
电源管理
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
Loading…
Reference in New Issue
Block a user