Merge branch 'refactor/mcpwm_rcc_atomic' into 'master'

MCPWM: add RCC low level functions

Closes IDF-7731, IDF-7722, IDF-7716, IDF-7738, and IDF-7713

See merge request espressif/esp-idf!25959
This commit is contained in:
morris 2023-09-16 01:04:54 +08:00
commit fd26abebce
16 changed files with 317 additions and 59 deletions

View File

@ -46,6 +46,18 @@ _Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_GROUPS, "MCPWM unit number not equal
#define MCPWM_INTR_FLAG 0
#endif
#if SOC_PERIPH_CLK_CTRL_SHARED
#define MCPWM_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define MCPWM_CLOCK_SRC_ATOMIC()
#endif
#if !SOC_RCC_IS_INDEPENDENT
#define MCPWM_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define MCPWM_RCC_ATOMIC()
#endif
// Note: we can't modify the default MCPWM group resolution once it's determined
// otherwise we may break user's existing code which configures the dead-time based on this resolution, see `mcpwm_deadtime_enable`
#if CONFIG_IDF_TARGET_ESP32H2
@ -93,6 +105,7 @@ typedef struct {
int timer_resolution_hz[SOC_MCPWM_TIMERS_PER_GROUP];
intr_handle_t mcpwm_intr_handle; // handler for ISR register, one per MCPWM group
cap_isr_func_t cap_isr_func[SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER]; // handler for ISR callback, one for each cap ch
int module_ref_count;
} mcpwm_context_t;
static mcpwm_context_t context[SOC_MCPWM_GROUPS] = {
@ -132,6 +145,31 @@ static inline void mcpwm_mutex_unlock(mcpwm_unit_t mcpwm_num)
_lock_release(&context[mcpwm_num].mutex_lock);
}
static void mcpwm_module_enable(mcpwm_unit_t mcpwm_num)
{
mcpwm_critical_enter(mcpwm_num);
if (context[mcpwm_num].module_ref_count == 0) {
MCPWM_RCC_ATOMIC() {
mcpwm_ll_enable_bus_clock(mcpwm_num, true);
mcpwm_ll_reset_register(mcpwm_num);
}
}
context[mcpwm_num].module_ref_count++;
mcpwm_critical_exit(mcpwm_num);
}
static void mcpwm_module_disable(mcpwm_unit_t mcpwm_num)
{
mcpwm_critical_enter(mcpwm_num);
context[mcpwm_num].module_ref_count--;
if (context[mcpwm_num].module_ref_count == 0) {
MCPWM_RCC_ATOMIC() {
mcpwm_ll_enable_bus_clock(mcpwm_num, false);
}
}
mcpwm_critical_exit(mcpwm_num);
}
esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int gpio_num)
{
if (gpio_num < 0) { // ignore on minus gpio number
@ -231,9 +269,9 @@ esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, uint32_t resolution
ESP_RETURN_ON_FALSE(pre_scale_temp >= 1, ESP_ERR_INVALID_ARG, TAG, "invalid resolution");
context[mcpwm_num].group_resolution_hz = clk_src_hz / pre_scale_temp;
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_group_set_clock_prescale(hal->dev, pre_scale_temp);
mcpwm_critical_exit(mcpwm_num);
MCPWM_CLOCK_SRC_ATOMIC() {
mcpwm_ll_group_set_clock_prescale(hal->dev, pre_scale_temp);
}
return ESP_OK;
}
@ -408,7 +446,7 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw
const int op = timer_num;
MCPWM_TIMER_ID_CHECK(mcpwm_num, op);
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
mcpwm_module_enable(mcpwm_num);
mcpwm_hal_init_config_t config = {
.group_id = mcpwm_num
};
@ -421,10 +459,13 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw
uint32_t group_pre_scale = clk_src_hz / group_resolution;
uint32_t timer_pre_scale = group_resolution / timer_resolution;
MCPWM_CLOCK_SRC_ATOMIC() {
mcpwm_ll_group_enable_clock(hal->dev, true);
mcpwm_ll_group_set_clock_source(hal->dev, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT);
mcpwm_ll_group_set_clock_prescale(hal->dev, group_pre_scale);
}
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_group_enable_clock(hal->dev, true);
mcpwm_ll_group_set_clock_source(hal->dev, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT);
mcpwm_ll_group_set_clock_prescale(hal->dev, group_pre_scale);
mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, timer_pre_scale);
mcpwm_ll_timer_set_count_mode(hal->dev, timer_num, mcpwm_conf->counter_mode);
mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
@ -804,7 +845,7 @@ esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_cha
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
// enable MCPWM module incase user don't use `mcpwm_init` at all. always increase reference count
periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
mcpwm_module_enable(mcpwm_num);
mcpwm_hal_init_config_t init_config = {
.group_id = mcpwm_num
@ -816,10 +857,13 @@ esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_cha
uint32_t group_resolution = mcpwm_group_get_resolution(mcpwm_num);
uint32_t group_pre_scale = clk_src_hz / group_resolution;
MCPWM_CLOCK_SRC_ATOMIC() {
mcpwm_ll_group_enable_clock(hal->dev, true);
mcpwm_ll_group_set_clock_source(hal->dev, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT);
mcpwm_ll_group_set_clock_prescale(hal->dev, group_pre_scale);
}
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_group_enable_clock(hal->dev, true);
mcpwm_ll_group_set_clock_source(hal->dev, (soc_module_clk_t)MCPWM_CAPTURE_CLK_SRC_DEFAULT);
mcpwm_ll_group_set_clock_prescale(hal->dev, group_pre_scale);
mcpwm_ll_capture_enable_timer(hal->dev, true);
mcpwm_ll_capture_enable_channel(hal->dev, cap_channel, true);
mcpwm_ll_capture_enable_negedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_NEG_EDGE);
@ -878,7 +922,7 @@ esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_ch
mcpwm_mutex_unlock(mcpwm_num);
// always decrease reference count
periph_module_disable(mcpwm_periph_signals.groups[mcpwm_num].module);
mcpwm_module_disable(mcpwm_num);
return ret;
}

View File

@ -20,6 +20,18 @@
#include "hal/mcpwm_ll.h"
#include "mcpwm_private.h"
#if SOC_PERIPH_CLK_CTRL_SHARED
#define MCPWM_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define MCPWM_CLOCK_SRC_ATOMIC()
#endif
#if !SOC_RCC_IS_INDEPENDENT
#define MCPWM_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define MCPWM_RCC_ATOMIC()
#endif
static const char *TAG = "mcpwm";
typedef struct {
@ -46,8 +58,10 @@ mcpwm_group_t *mcpwm_acquire_group_handle(int group_id)
group->intr_priority = -1;
group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
// enable APB to access MCPWM registers
periph_module_enable(mcpwm_periph_signals.groups[group_id].module);
periph_module_reset(mcpwm_periph_signals.groups[group_id].module);
MCPWM_RCC_ATOMIC() {
mcpwm_ll_enable_bus_clock(group_id, true);
mcpwm_ll_reset_register(group_id);
}
// initialize HAL context
mcpwm_hal_init_config_t hal_config = {
.group_id = group_id
@ -57,7 +71,11 @@ mcpwm_group_t *mcpwm_acquire_group_handle(int group_id)
// 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);
mcpwm_ll_group_enable_clock(hal->dev, true);
// enable function clock
MCPWM_CLOCK_SRC_ATOMIC() {
mcpwm_ll_group_enable_clock(group->hal.dev, true);
}
}
} else { // group already install
group = s_platform.groups[group_id];
@ -84,10 +102,14 @@ void mcpwm_release_group_handle(mcpwm_group_t *group)
if (s_platform.group_ref_counts[group_id] == 0) {
do_deinitialize = true;
s_platform.groups[group_id] = NULL; // deregister from platfrom
mcpwm_ll_group_enable_clock(group->hal.dev, false);
MCPWM_CLOCK_SRC_ATOMIC() {
mcpwm_ll_group_enable_clock(group->hal.dev, false);
}
// hal layer deinitialize
mcpwm_hal_deinit(&group->hal);
periph_module_disable(mcpwm_periph_signals.groups[group_id].module);
MCPWM_RCC_ATOMIC() {
mcpwm_ll_enable_bus_clock(group_id, false);
}
free(group);
}
_lock_release(&s_platform.mutex);
@ -149,12 +171,14 @@ esp_err_t mcpwm_select_periph_clock(mcpwm_group_t *group, soc_module_clk_t clk_s
ESP_LOGD(TAG, "install NO_LIGHT_SLEEP lock for MCPWM group(%d)", group->group_id);
#endif // CONFIG_PM_ENABLE
mcpwm_ll_group_set_clock_source(group->hal.dev, clk_src);
MCPWM_CLOCK_SRC_ATOMIC() {
mcpwm_ll_group_set_clock_source(group->hal.dev, clk_src);
}
}
return ret;
}
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)
{
ESP_RETURN_ON_FALSE(group && expect_module_resolution_hz && module_prescale_max, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
uint32_t periph_src_clk_hz = 0;
@ -206,7 +230,9 @@ esp_err_t mcpwm_set_prescale(mcpwm_group_t *group, uint32_t expect_module_resolu
if (group->prescale == 0) {
group->prescale = group_prescale;
group->resolution_hz = group_resolution_hz;
mcpwm_ll_group_set_clock_prescale(group->hal.dev, group_prescale);
MCPWM_CLOCK_SRC_ATOMIC() {
mcpwm_ll_group_set_clock_prescale(group->hal.dev, group_prescale);
}
} else {
prescale_conflict = (group->prescale != group_prescale);
}

View File

@ -17,6 +17,7 @@
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "soc/mcpwm_struct.h"
#include "soc/dport_reg.h"
#include "hal/mcpwm_types.h"
#include "hal/misc.h"
#include "hal/assert.h"
@ -67,6 +68,49 @@ typedef enum {
////////////////////////////////////////MCPWM Group Specific////////////////////////////////////////////////////////////
/**
* @brief Enable the bus clock for MCPWM module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void mcpwm_ll_enable_bus_clock(int group_id, bool enable)
{
uint32_t reg_val = DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG);
if (group_id == 0) {
reg_val &= ~DPORT_PWM0_CLK_EN;
reg_val |= enable << 17;
} else {
reg_val &= ~DPORT_PWM1_CLK_EN;
reg_val |= enable << 20;
}
DPORT_WRITE_PERI_REG(DPORT_PERIP_CLK_EN_REG, reg_val);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the MCPWM module
*
* @param group_id Group ID
*/
static inline void mcpwm_ll_reset_register(int group_id)
{
if (group_id == 0) {
DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, DPORT_PWM0_RST);
DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, 0);
} else {
DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, DPORT_PWM1_RST);
DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, 0);
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_reset_register(__VA_ARGS__)
/**
* @brief Set the clock source for MCPWM
*

View File

@ -76,6 +76,30 @@ typedef enum {
////////////////////////////////////////MCPWM Group Specific////////////////////////////////////////////////////////////
/**
* @brief Enable the bus clock for MCPWM module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void mcpwm_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
PCR.pwm_conf.pwm_clk_en = enable;
}
/**
* @brief Reset the MCPWM module
*
* @param group_id Group ID
*/
static inline void mcpwm_ll_reset_register(int group_id)
{
(void)group_id;
PCR.pwm_conf.pwm_rst_en = 1;
PCR.pwm_conf.pwm_rst_en = 0;
}
/**
* @brief Set the clock source for MCPWM
*

View File

@ -74,6 +74,30 @@ typedef enum {
////////////////////////////////////////MCPWM Group Specific////////////////////////////////////////////////////////////
/**
* @brief Enable the bus clock for MCPWM module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void mcpwm_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
PCR.pwm_conf.pwm_clk_en = enable;
}
/**
* @brief Reset the MCPWM module
*
* @param group_id Group ID
*/
static inline void mcpwm_ll_reset_register(int group_id)
{
(void)group_id;
PCR.pwm_conf.pwm_rst_en = 1;
PCR.pwm_conf.pwm_rst_en = 0;
}
/**
* @brief Set the clock source for MCPWM
*

View File

@ -72,10 +72,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
return HP_SYS_CLKRST_REG_I3C_MST_CLK_EN;
case PERIPH_CAM_MODULE:
return HP_SYS_CLKRST_REG_CAM_CLK_EN;
case PERIPH_MCPWM0_MODULE:
return HP_SYS_CLKRST_REG_MCPWM0_APB_CLK_EN;
case PERIPH_MCPWM1_MODULE:
return HP_SYS_CLKRST_REG_MCPWM1_APB_CLK_EN;
case PERIPH_SYSTIMER_MODULE:
return HP_SYS_CLKRST_REG_SYSTIMER_CLK_EN;
case PERIPH_LEDC_MODULE:
@ -104,8 +100,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
return HP_SYS_CLKRST_REG_CRYPTO_ECDSA_CLK_EN;
case PERIPH_ISP_MODULE:
return HP_SYS_CLKRST_REG_ISP_CLK_EN;
case PERIPH_PCNT_MODULE:
return HP_SYS_CLKRST_REG_PCNT_APB_CLK_EN;
default:
return 0;
}
@ -155,10 +149,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
return HP_SYS_CLKRST_REG_RST_EN_I2C1;
case PERIPH_RMT_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_RMT;
case PERIPH_MCPWM0_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_PWM0;
case PERIPH_MCPWM1_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_PWM1;
case PERIPH_TWAI0_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_CAN0;
case PERIPH_TWAI1_MODULE:
@ -167,8 +157,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
return HP_SYS_CLKRST_REG_RST_EN_CAN2;
case PERIPH_LEDC_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_LEDC;
case PERIPH_PCNT_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_PCNT;
case PERIPH_PARLIO_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_PARLIO | HP_SYS_CLKRST_REG_RST_EN_PARLIO_RX | HP_SYS_CLKRST_REG_RST_EN_PARLIO_TX;
case PERIPH_I2S0_MODULE:
@ -263,10 +251,6 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
case PERIPH_I3C_MODULE:
case PERIPH_CAM_MODULE:
return HP_SYS_CLKRST_PERI_CLK_CTRL119_REG;
case PERIPH_MCPWM0_MODULE:
case PERIPH_MCPWM1_MODULE:
case PERIPH_PCNT_MODULE:
return HP_SYS_CLKRST_SOC_CLK_CTRL2_REG;
case PERIPH_SYSTIMER_MODULE:
case PERIPH_LEDC_MODULE:
case PERIPH_RMT_MODULE:
@ -316,13 +300,10 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
case PERIPH_I2C1_MODULE:
return HP_SYS_CLKRST_HP_RST_EN1_REG;
case PERIPH_RMT_MODULE:
case PERIPH_MCPWM0_MODULE:
case PERIPH_MCPWM1_MODULE:
case PERIPH_TWAI0_MODULE:
case PERIPH_TWAI1_MODULE:
case PERIPH_TWAI2_MODULE:
case PERIPH_LEDC_MODULE:
case PERIPH_PCNT_MODULE:
case PERIPH_PARLIO_MODULE:
case PERIPH_I2S0_MODULE:
return HP_SYS_CLKRST_HP_RST_EN1_REG;

View File

@ -93,6 +93,45 @@ typedef enum {
////////////////////////////////////////MCPWM Group Specific////////////////////////////////////////////////////////////
/**
* @brief Enable the bus clock for MCPWM module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void mcpwm_ll_enable_bus_clock(int group_id, bool enable)
{
if (group_id == 0) {
HP_SYS_CLKRST.soc_clk_ctrl2.reg_mcpwm0_apb_clk_en = enable;
} else {
HP_SYS_CLKRST.soc_clk_ctrl2.reg_mcpwm1_apb_clk_en = enable;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the MCPWM module
*
* @param group_id Group ID
*/
static inline void mcpwm_ll_reset_register(int group_id)
{
if (group_id == 0) {
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_pwm0 = 1;
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_pwm0 = 0;
} else {
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_pwm1 = 1;
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_pwm1 = 0;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_reset_register(__VA_ARGS__)
/**
* @brief Set the clock source for MCPWM
*
@ -123,6 +162,10 @@ static inline void mcpwm_ll_group_set_clock_source(mcpwm_dev_t *mcpwm, soc_modul
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_group_set_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_group_set_clock_source(__VA_ARGS__)
/**
* @brief Enable MCPWM module clock
*
@ -138,6 +181,10 @@ static inline void mcpwm_ll_group_enable_clock(mcpwm_dev_t *mcpwm, bool en)
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_group_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_group_enable_clock(__VA_ARGS__)
/**
* @brief Set the MCPWM group clock prescale
*
@ -155,6 +202,10 @@ static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_group_set_clock_prescale(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_group_set_clock_prescale(__VA_ARGS__)
/**
* @brief Enable update MCPWM active registers from shadow registers
*

View File

@ -20,6 +20,7 @@
#include "hal/mcpwm_types.h"
#include "hal/misc.h"
#include "hal/assert.h"
#include "soc/system_struct.h"
#ifdef __cplusplus
extern "C" {
@ -67,6 +68,45 @@ typedef enum {
////////////////////////////////////////MCPWM Group Specific////////////////////////////////////////////////////////////
/**
* @brief Enable the bus clock for MCPWM module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void mcpwm_ll_enable_bus_clock(int group_id, bool enable)
{
if (group_id == 0) {
SYSTEM.perip_clk_en0.pwm0_clk_en = enable;
} else {
SYSTEM.perip_clk_en0.pwm1_clk_en = enable;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the MCPWM module
*
* @param group_id Group ID
*/
static inline void mcpwm_ll_reset_register(int group_id)
{
if (group_id == 0) {
SYSTEM.perip_rst_en0.pwm0_rst = 1;
SYSTEM.perip_rst_en0.pwm0_rst = 0;
} else {
SYSTEM.perip_rst_en0.pwm1_rst = 1;
SYSTEM.perip_rst_en0.pwm1_rst = 0;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define mcpwm_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; mcpwm_ll_reset_register(__VA_ARGS__)
/**
* @brief Set the clock source for MCPWM
*

View File

@ -1043,6 +1043,10 @@ config SOC_CLK_RC32K_SUPPORTED
bool
default y
config SOC_PERIPH_CLK_CTRL_SHARED
bool
default y
config SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC
bool
default y

View File

@ -502,6 +502,8 @@
#define SOC_CLK_OSC_SLOW_SUPPORTED (1) /*!< Support to connect an external oscillator, not a crystal */
#define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */
#define SOC_PERIPH_CLK_CTRL_SHARED (1) /*!< Peripheral clock control (e.g. set clock source) is shared between various peripherals */
/*-------------------------- Temperature Sensor CAPS -------------------------------------*/
#define SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC (1)
#define SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL (1)

View File

@ -111,13 +111,9 @@ api-reference/peripherals/gpio.rst
api-reference/peripherals/sdspi_host.rst
api-reference/peripherals/dac.rst
api-reference/peripherals/spi_slave.rst
api-reference/peripherals/etm.rst
api-reference/peripherals/i2s.rst
api-reference/peripherals/gptimer.rst
api-reference/peripherals/pcnt.rst
api-reference/peripherals/touch_element.rst
api-reference/peripherals/lcd.rst
api-reference/peripherals/mcpwm.rst
api-reference/peripherals/ana_cmpr.rst
api-reference/peripherals/secure_element.rst
api-reference/peripherals/ledc.rst
@ -167,7 +163,6 @@ api-reference/system/ulp-lp-core.rst
api-reference/system/ulp.rst
api-reference/system/esp_function_with_shared_stack.rst
api-reference/system/ulp_instruction_set.rst
api-reference/system/async_memcpy.rst
api-reference/system/random.rst
api-reference/system/esp_event.rst
api-reference/system/system_time.rst

View File

@ -95,6 +95,7 @@ INPUT = \
$(PROJECT_PATH)/components/driver/ledc/include/driver/ledc.h \
$(PROJECT_PATH)/components/driver/mcpwm/include/driver/mcpwm_cap.h \
$(PROJECT_PATH)/components/driver/mcpwm/include/driver/mcpwm_cmpr.h \
$(PROJECT_PATH)/components/driver/mcpwm/include/driver/mcpwm_etm.h \
$(PROJECT_PATH)/components/driver/mcpwm/include/driver/mcpwm_fault.h \
$(PROJECT_PATH)/components/driver/mcpwm/include/driver/mcpwm_gen.h \
$(PROJECT_PATH)/components/driver/mcpwm/include/driver/mcpwm_oper.h \

View File

@ -111,6 +111,10 @@ The :cpp:func:`mcpwm_new_comparator` will return a pointer to the allocated comp
On the contrary, calling the :cpp:func:`mcpwm_del_comparator` function will free the allocated comparator object.
.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
There's another kind of comparator called "Event Comparator", which **can not** control the final PWM directly but only generates the ETM events at a configurable time stamp. You can allocate an event comparator by calling the :cpp:func:`mcpwm_new_event_comparator` function. This function will return the same handle type as :cpp:func:`mcpwm_new_comparator`, but with a different configuration structure :cpp:type:`mcpwm_event_comparator_config_t`. For more information, please refer to :ref:`mcpwm-etm-event-and-task`.
MCPWM Generators
~~~~~~~~~~~~~~~~
@ -279,6 +283,12 @@ The parameter ``user_data`` of :cpp:func:`mcpwm_comparator_register_event_callba
This function will lazy the installation of interrupt service for the MCPWM comparator, whereas the service can only be removed in :cpp:type:`mcpwm_del_comparator`.
.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
.. note::
It is not supported to register event callbacks for an **Event Comparator** because it can not generate any interrupt.
Set Compare Value
~~~~~~~~~~~~~~~~~
@ -1026,6 +1036,7 @@ API Reference
.. include-build-file:: inc/mcpwm_fault.inc
.. include-build-file:: inc/mcpwm_sync.inc
.. include-build-file:: inc/mcpwm_cap.inc
.. include-build-file:: inc/mcpwm_etm.inc
.. include-build-file:: inc/components/driver/mcpwm/include/driver/mcpwm_types.inc
.. include-build-file:: inc/components/hal/include/hal/mcpwm_types.inc

View File

@ -27,7 +27,7 @@ Description of the PCNT functionality is divided into the following sections:
- :ref:`pcnt-watch-points` - describes how to configure PCNT watch points (i.e., tell PCNT unit to trigger an event when the count reaches a certain value).
- :ref:`pcnt-register-event-callbacks` - describes how to hook your specific code to the watch point event callback function.
- :ref:`pcnt-set-glitch-filter` - describes how to enable and set the timing parameters for the internal glitch filter.
:SOC_PCNT_SUPPORT_CLEAR_SIGNAL: - :ref:`pcnt-set-clear-signal` - describes how to set the parameters for the zero signal.
:SOC_PCNT_SUPPORT_CLEAR_SIGNAL: - :ref:`pcnt-set-clear-signal` - describes how to set the parameters for the external clear signal.
- :ref:`pcnt-enable-disable-unit` - describes how to enable and disable the PCNT unit.
- :ref:`pcnt-unit-io-control` - describes IO control functions of PCNT unit, like enable glitch filter, start and stop unit, get and clear count value.
- :ref:`pcnt-power-management` - describes what functionality will prevent the chip from going into low power mode.
@ -205,16 +205,16 @@ This function should be called when the unit is in the init state. Otherwise, it
.. _pcnt-set-clear-signal:
Set Clear Signal
^^^^^^^^^^^^^^^^
Use External Clear Signal
^^^^^^^^^^^^^^^^^^^^^^^^^
The PCNT unit can receive a zero signal from the GPIO. The parameters that can be configured for the zero signal are listed in :cpp:type:`pcnt_clear_signal_config_t`:
The PCNT unit can receive a clear signal from the GPIO. The parameters that can be configured for the clear signal are listed in :cpp:type:`pcnt_clear_signal_config_t`:
- :cpp:member:`pcnt_clear_signal_config_t::zero_input_gpio_num` specify the GPIO numbers used by **zero** signal. The default active level is high, and the input mode is pull-down enabled.
- :cpp:member:`pcnt_clear_signal_config_t::invert_zero_input` is used to decide whether to invert the input signal before it going into PCNT hardware. The invert is done by GPIO matrix instead of PCNT hardware. The input mode is pull-up enabled when the input signal is invert.
- :cpp:member:`pcnt_clear_signal_config_t::io_loop_back` is for debug only, which enables both the GPIO's input and output paths. This can help to simulate the zreo pulse signals by function :cpp:func:`gpio_set_level` on the same GPIO.
- :cpp:member:`pcnt_clear_signal_config_t::clear_signal_gpio_num` specify the GPIO numbers used by **clear** signal. The default active level is high, and the input mode is pull-down enabled.
- :cpp:member:`pcnt_clear_signal_config_t::invert_clear_signal` is used to decide whether to invert the input signal before it going into PCNT hardware. The invert is done by GPIO matrix instead of PCNT hardware. The input mode is pull-up enabled when the input signal is inverted.
- :cpp:member:`pcnt_clear_signal_config_t::io_loop_back` is for debug only, which enables both the GPIO's input and output paths. This can help to simulate the clear signal by function :cpp:func:`gpio_set_level` for the same GPIO.
This signal acts in the same way as calling :cpp:func:`pcnt_unit_clear_count`, but is not subject to software latency, and is suitable for use in situations with high latency requirements.
This signal acts in the same way as calling :cpp:func:`pcnt_unit_clear_count`, but is not subject to software latency, and is suitable for use in situations with low latency requirements. Also please note, the flip frequency of this signal can not be too high.
.. code:: c

View File

@ -111,6 +111,10 @@ MCPWM 比较器
反之,调用 :cpp:func:`mcpwm_del_comparator` 函数将释放已分配的比较器。
.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
MCPWM 中还有另外一种比较器 —— “事件比较器”,它不能直接控制 PWM 的输出,只能用来产生 EMT 子系统中使用到的事件。事件比较器能够设置的阈值也是可配的。调用 :cpp:func:`mcpwm_new_event_comparator` 函数可以申请一个事件比较器,该函数返回的句柄类型和 :cpp:func:`mcpwm_new_comparator` 函数一样,但是需要的配置结构体是不同的。事件比较器的配置位于 :cpp:type:`mcpwm_event_comparator_config_t`。更多相关内容请参阅 :ref:`mcpwm-etm-event-and-task`
MCPWM 生成器
~~~~~~~~~~~~~~~~
@ -279,6 +283,12 @@ MCPWM 比较器可以在定时器计数器等于比较值时发送通知。若
此函数会延迟安装 MCPWM 比较器的中断服务。中断服务只能通过 :cpp:type:`mcpwm_del_comparator` 移除。
.. only:: SOC_MCPWM_SUPPORT_EVENT_COMPARATOR
.. note::
对于事件比较器,你无法通过该函数来注册回调函数,因为事件比较器触发产生任何中断事件。
设置比较值
~~~~~~~~~~~~~~~~~
@ -1026,6 +1036,7 @@ API Reference
.. include-build-file:: inc/mcpwm_fault.inc
.. include-build-file:: inc/mcpwm_sync.inc
.. include-build-file:: inc/mcpwm_cap.inc
.. include-build-file:: inc/mcpwm_etm.inc
.. include-build-file:: inc/components/driver/mcpwm/include/driver/mcpwm_types.inc
.. include-build-file:: inc/components/hal/include/hal/mcpwm_types.inc

View File

@ -27,7 +27,7 @@ PCNT 的功能从以下几个方面进行说明:
- :ref:`pcnt-watch-points` - 说明如何配置观察点,即当计数达到某个数值时,命令 PCNT 单元触发某个事件。
- :ref:`pcnt-register-event-callbacks` - 说明如何将您的代码挂载到观察点事件的回调函数上。
- :ref:`pcnt-set-glitch-filter` - 说明如何使能毛刺滤波器并设置其时序参数。
:SOC_PCNT_SUPPORT_CLEAR_SIGNAL: - :ref:`pcnt-set-clear-signal` - 说明如何使能清零信号并设置其参数。
:SOC_PCNT_SUPPORT_CLEAR_SIGNAL: - :ref:`pcnt-set-clear-signal` - 说明如何使能外部清零信号并设置其参数。
- :ref:`pcnt-enable-disable-unit` - 说明如何使能和关闭 PCNT 单元。
- :ref:`pcnt-unit-io-control` - 说明 PCNT 单元的 IO 控制功能,例如使能毛刺滤波器,开启和停用 PCNT 单元,获取和清除计数。
- :ref:`pcnt-power-management` - 说明哪些功能会阻止芯片进入低功耗模式。
@ -205,16 +205,16 @@ PCNT 单元的滤波器可滤除信号中的短时毛刺,:cpp:type:`pcnt_glitc
.. _pcnt-set-clear-signal:
设置清零信号
使用外部清零信号
^^^^^^^^^^^^^^^^
PCNT 单元的可以接收来自 GPIO 的清零信号,:cpp:type:`pcnt_clear_signal_config_t` 中列出了清零信号的配置参数:
- :cpp:member:`pcnt_clear_signal_config_t::zero_input_gpio_num` 用于指定 **清零** 信号对应的 GPIO 编号。默认有效电平为高,使能下拉输入。
- :cpp:member:`pcnt_clear_signal_config_t::invert_zero_input` 用于确定信号在输入 PCNT 之前是否需要被翻转,信号翻转由 GPIO 矩阵 (不是 PCNT 单元) 执行。翻转时使能上拉输入
- :cpp:member:`pcnt_clear_signal_config_t::io_loop_back` 仅用于调试,它可以使能 GPIO 的输入和输出路径。这样,就可以通过调用位于同一 GPIO 上的函数 :cpp:func:`gpio_set_level` 来模拟脉冲清零信号。
- :cpp:member:`pcnt_clear_signal_config_t::clear_signal_gpio_num` 用于指定 **清零** 信号对应的 GPIO 编号。默认有效电平为高,使能下拉输入。
- :cpp:member:`pcnt_clear_signal_config_t::invert_clear_signal` 用于确定信号在输入 PCNT 之前是否需要被翻转,信号翻转由 GPIO 矩阵 (不是 PCNT 单元) 执行。驱动会使能上拉输入,以确保信号在未连接时保持高电平
- :cpp:member:`pcnt_clear_signal_config_t::io_loop_back` 仅用于调试,它可以使能 GPIO 的输入和输出路径。这样,就可以通过 :cpp:func:`gpio_set_level` 函数来模拟外部输入的清零信号。
该信号作用与调用 :cpp:func:`pcnt_unit_clear_count` 相同,但不受软件延迟的限制,适用于对延迟要求较高的场合
输入信号作用与调用 :cpp:func:`pcnt_unit_clear_count` 函数相同,但它不受软件延迟的限制,更适用于需要低延迟的场合。请注意,该信号的翻转频率不能太高
.. code:: c