Просмотр исходного кода

Merge branch 'feature/add_mcpwm_carrier_clk_source' into 'master'

feat(MCPWM): Add mcpwm carrier clk source

Closes IDF-8029

See merge request espressif/esp-idf!25342
Chen Ji Chang 2 лет назад
Родитель
Сommit
b39fd79cb8

+ 1 - 0
components/driver/mcpwm/include/driver/mcpwm_oper.h

@@ -135,6 +135,7 @@ esp_err_t mcpwm_operator_register_event_callbacks(mcpwm_oper_handle_t oper, cons
  * @brief MCPWM carrier configuration structure
  */
 typedef struct {
+    mcpwm_carrier_clock_source_t clk_src;  /*!< MCPWM carrier clock source */
     uint32_t frequency_hz;            /*!< Carrier frequency in Hz */
     uint32_t first_pulse_duration_us; /*!< The duration of the first PWM pulse, in us */
     float duty_cycle;                 /*!< Carrier duty cycle */

+ 8 - 3
components/driver/mcpwm/mcpwm_oper.c

@@ -182,9 +182,14 @@ esp_err_t mcpwm_operator_apply_carrier(mcpwm_oper_handle_t oper, const mcpwm_car
     float real_duty = 0.0;
 
     if (config && config->frequency_hz) {
-        uint8_t pre_scale = group->resolution_hz / 8 / config->frequency_hz;
-        mcpwm_ll_carrier_set_prescale(hal->dev, oper_id, pre_scale);
-        real_frequency = group->resolution_hz / 8 / pre_scale;
+        // select the clock source
+        mcpwm_carrier_clock_source_t clk_src = config->clk_src ? config->clk_src : MCPWM_CARRIER_CLK_SRC_DEFAULT;
+        ESP_RETURN_ON_ERROR(mcpwm_select_periph_clock(group, (soc_module_clk_t)clk_src), TAG, "set group clock failed");
+
+        uint8_t prescale = group->resolution_hz / 8 / config->frequency_hz;
+        ESP_RETURN_ON_FALSE(prescale > 0 && prescale <= MCPWM_LL_MAX_CARRIER_PRESCALE, ESP_ERR_INVALID_STATE, TAG, "group clock cannot match the frequency");
+        mcpwm_ll_carrier_set_prescale(hal->dev, oper_id, prescale);
+        real_frequency = group->resolution_hz / 8 / prescale;
 
         uint8_t duty = (uint8_t)(config->duty_cycle * 8);
         mcpwm_ll_carrier_set_duty(hal->dev, oper_id, duty);

+ 1 - 0
components/driver/mcpwm/mcpwm_timer.c

@@ -106,6 +106,7 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
     mcpwm_hal_timer_reset(hal, timer_id);
     // set timer resolution
     uint32_t prescale = group->resolution_hz / config->resolution_hz;
+    ESP_RETURN_ON_FALSE(prescale > 0 && prescale <= MCPWM_LL_MAX_TIMER_PRESCALE, ESP_ERR_INVALID_STATE, TAG, "group clock cannot match the resolution");
     mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_id, prescale);
     timer->resolution_hz = group->resolution_hz / prescale;
     if (timer->resolution_hz != config->resolution_hz) {

+ 14 - 27
components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c

@@ -64,22 +64,11 @@ TEST_CASE("mcpwm_operator_install_uninstall", "[mcpwm]")
 
 TEST_CASE("mcpwm_operator_carrier", "[mcpwm]")
 {
-    mcpwm_timer_config_t timer_config = {
-        .group_id = 0,
-        .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
-        .resolution_hz = 1000000, // 1MHz, 1us per tick
-        .period_ticks = 20000,
-        .count_mode = MCPWM_TIMER_COUNT_MODE_UP,
-    };
-    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));
 
     mcpwm_generator_config_t generator_config = {
         .gen_gpio_num = 0,
@@ -87,36 +76,34 @@ TEST_CASE("mcpwm_operator_carrier", "[mcpwm]")
     mcpwm_gen_handle_t generator = NULL;
     TEST_ESP_OK(mcpwm_new_generator(oper, &generator_config, &generator));
 
-    TEST_ESP_OK(mcpwm_generator_set_action_on_timer_event(generator,
-                MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_TOGGLE)));
-
     printf("add carrier to PWM wave\r\n");
     mcpwm_carrier_config_t carrier_config = {
+        .clk_src = MCPWM_CARRIER_CLK_SRC_DEFAULT,
         .frequency_hz = 1000000, // 1MHz carrier
         .duty_cycle = 0.5,
         .first_pulse_duration_us = 10,
     };
-    TEST_ESP_OK(mcpwm_operator_apply_carrier(oper, &carrier_config));
-
-    TEST_ESP_OK(mcpwm_timer_enable(timer));
 
-    TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
-    vTaskDelay(pdMS_TO_TICKS(100));
-    TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
-    vTaskDelay(pdMS_TO_TICKS(100));
+    TEST_ESP_OK(mcpwm_operator_apply_carrier(oper, &carrier_config));
+    TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 1, true));
+    vTaskDelay(pdMS_TO_TICKS(10));
+    TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 0, true));
+    vTaskDelay(pdMS_TO_TICKS(10));
+    TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 1, true));
+    vTaskDelay(pdMS_TO_TICKS(10));
 
     printf("remove carrier from PWM wave\r\n");
     carrier_config.frequency_hz = 0;
     TEST_ESP_OK(mcpwm_operator_apply_carrier(oper, &carrier_config));
-    TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
-    vTaskDelay(pdMS_TO_TICKS(200));
-    TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
-    vTaskDelay(pdMS_TO_TICKS(100));
+    TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 1, true));
+    vTaskDelay(pdMS_TO_TICKS(10));
+    TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 0, true));
+    vTaskDelay(pdMS_TO_TICKS(10));
+    TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 1, true));
+    vTaskDelay(pdMS_TO_TICKS(10));
 
-    TEST_ESP_OK(mcpwm_timer_disable(timer));
     TEST_ESP_OK(mcpwm_del_generator(generator));
     TEST_ESP_OK(mcpwm_del_operator(oper));
-    TEST_ESP_OK(mcpwm_del_timer(timer));
 }
 
 static bool IRAM_ATTR test_cbc_brake_on_gpio_fault_callback(mcpwm_oper_handle_t oper, const mcpwm_brake_event_data_t *edata, void *user_data)

+ 2 - 0
components/hal/esp32/include/hal/mcpwm_ll.h

@@ -43,6 +43,8 @@ extern "C" {
 #define MCPWM_LL_EVENT_CAPTURE(cap)          (1 << ((cap) + 27))
 
 // Maximum values due to limited register bit width
+#define MCPWM_LL_MAX_TIMER_PRESCALE          256
+#define MCPWM_LL_MAX_CARRIER_PRESCALE        16
 #define MCPWM_LL_MAX_CARRIER_ONESHOT         16
 #define MCPWM_LL_MAX_CAPTURE_PRESCALE        256
 #define MCPWM_LL_MAX_DEAD_DELAY              65536

+ 2 - 0
components/hal/esp32c6/include/hal/mcpwm_ll.h

@@ -45,6 +45,8 @@ extern "C" {
 #define MCPWM_LL_EVENT_CAPTURE(cap)          (1 << ((cap) + 27))
 
 // Maximum values due to limited register bit width
+#define MCPWM_LL_MAX_TIMER_PRESCALE          256
+#define MCPWM_LL_MAX_CARRIER_PRESCALE        16
 #define MCPWM_LL_MAX_CARRIER_ONESHOT         16
 #define MCPWM_LL_MAX_CAPTURE_PRESCALE        256
 #define MCPWM_LL_MAX_DEAD_DELAY              65536

+ 2 - 0
components/hal/esp32h2/include/hal/mcpwm_ll.h

@@ -43,6 +43,8 @@ extern "C" {
 #define MCPWM_LL_EVENT_CAPTURE(cap)          (1 << ((cap) + 27))
 
 // Maximum values due to limited register bit width
+#define MCPWM_LL_MAX_TIMER_PRESCALE          256
+#define MCPWM_LL_MAX_CARRIER_PRESCALE        16
 #define MCPWM_LL_MAX_CARRIER_ONESHOT         16
 #define MCPWM_LL_MAX_CAPTURE_PRESCALE        256
 #define MCPWM_LL_MAX_DEAD_DELAY              65536

+ 2 - 0
components/hal/esp32p4/include/hal/mcpwm_ll.h

@@ -45,6 +45,8 @@ extern "C" {
 #define MCPWM_LL_EVENT_CAPTURE(cap)          (1 << ((cap) + 27))
 
 // Maximum values due to limited register bit width
+#define MCPWM_LL_MAX_TIMER_PRESCALE          256
+#define MCPWM_LL_MAX_CARRIER_PRESCALE        16
 #define MCPWM_LL_MAX_CARRIER_ONESHOT         16
 #define MCPWM_LL_MAX_CAPTURE_PRESCALE        256
 #define MCPWM_LL_MAX_DEAD_DELAY              65536

+ 2 - 0
components/hal/esp32s3/include/hal/mcpwm_ll.h

@@ -43,6 +43,8 @@ extern "C" {
 #define MCPWM_LL_EVENT_CAPTURE(cap)          (1 << ((cap) + 27))
 
 // Maximum values due to limited register bit width
+#define MCPWM_LL_MAX_TIMER_PRESCALE          256
+#define MCPWM_LL_MAX_CARRIER_PRESCALE        16
 #define MCPWM_LL_MAX_CARRIER_ONESHOT         16
 #define MCPWM_LL_MAX_CAPTURE_PRESCALE        256
 #define MCPWM_LL_MAX_DEAD_DELAY              65536

+ 9 - 0
components/hal/include/hal/mcpwm_types.h

@@ -31,6 +31,15 @@ typedef soc_periph_mcpwm_capture_clk_src_t mcpwm_capture_clock_source_t;
 typedef int mcpwm_capture_clock_source_t;
 #endif // SOC_MCPWM_SUPPORTED
 
+/**
+ * @brief MCPWM carrier clock source
+ */
+#if SOC_MCPWM_SUPPORTED
+typedef soc_periph_mcpwm_carrier_clk_src_t mcpwm_carrier_clock_source_t;
+#else
+typedef int mcpwm_carrier_clock_source_t;
+#endif // SOC_MCPWM_SUPPORTED
+
 /**
  * @brief MCPWM timer count direction
  */

+ 13 - 0
components/soc/esp32/include/soc/clk_tree_defs.h

@@ -239,6 +239,19 @@ typedef enum {
     MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default clock choice */
 } soc_periph_mcpwm_capture_clk_src_t;
 
+/**
+ * @brief Array initializer for all supported clock sources of MCPWM Carrier
+ */
+#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_PLL_F160M}
+
+/**
+ * @brief Type of MCPWM carrier clock source
+ */
+typedef enum {
+    MCPWM_CARRIER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
+    MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
+} soc_periph_mcpwm_carrier_clk_src_t;
+
 ///////////////////////////////////////////////////I2S//////////////////////////////////////////////////////////////////
 /**
  * @brief Array initializer for all supported clock sources of I2S

+ 14 - 0
components/soc/esp32c6/include/soc/clk_tree_defs.h

@@ -266,6 +266,20 @@ typedef enum {
     MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
 } soc_periph_mcpwm_capture_clk_src_t;
 
+/**
+ * @brief Array initializer for all supported clock sources of MCPWM Carrier
+ */
+#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
+
+/**
+ * @brief Type of MCPWM carrier clock source
+ */
+typedef enum {
+    MCPWM_CARRIER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
+    MCPWM_CARRIER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,         /*!< Select XTAL as the source clock */
+    MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
+} soc_periph_mcpwm_carrier_clk_src_t;
+
 ///////////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////
 
 /**

+ 14 - 0
components/soc/esp32h2/include/soc/clk_tree_defs.h

@@ -264,6 +264,20 @@ typedef enum {
     MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M,  /*!< Select PLL_F96M as the default clock choice */
 } soc_periph_mcpwm_capture_clk_src_t;
 
+/**
+ * @brief Array initializer for all supported clock sources of MCPWM Carrier
+ */
+#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_XTAL}
+
+/**
+ * @brief Type of MCPWM carrier clock source
+ */
+typedef enum {
+    MCPWM_CARRIER_CLK_SRC_PLL96M = SOC_MOD_CLK_PLL_F96M,   /*!< Select PLL_F96M as the source clock */
+    MCPWM_CARRIER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,         /*!< Select XTAL as the source clock */
+    MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M,  /*!< Select PLL_F96M as the default clock choice */
+} soc_periph_mcpwm_carrier_clk_src_t;
+
 ///////////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////
 
 /**

+ 25 - 5
components/soc/esp32p4/include/soc/clk_tree_defs.h

@@ -232,7 +232,7 @@ typedef enum {
  * @brief Array initializer for all supported clock sources of MCPWM Timer
  */
 #if SOC_CLK_TREE_SUPPORTED
-#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL}
+#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
 #else
 #define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_XTAL}
 #endif
@@ -242,7 +242,6 @@ typedef enum {
  */
 typedef enum {
     MCPWM_TIMER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
-    MCPWM_TIMER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST,   /*!< Select RC_FAST as the source clock */
     MCPWM_TIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,         /*!< Select XTAL as the source clock */
 #if SOC_CLK_TREE_SUPPORTED
     MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */
@@ -255,7 +254,7 @@ typedef enum {
  * @brief Array initializer for all supported clock sources of MCPWM Capture Timer
  */
 #if SOC_CLK_TREE_SUPPORTED
-#define SOC_MCPWM_CAPTURE_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL}
+#define SOC_MCPWM_CAPTURE_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
 #else
 #define SOC_MCPWM_CAPTURE_CLKS {SOC_MOD_CLK_XTAL}
 #endif
@@ -265,15 +264,36 @@ typedef enum {
  */
 typedef enum {
     MCPWM_CAPTURE_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
-    MCPWM_CAPTURE_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST,   /*!< Select RC_FAST as the source clock */
     MCPWM_CAPTURE_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,         /*!< Select XTAL as the source clock */
 #if SOC_CLK_TREE_SUPPORTED
-    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M,  /*!< Select PLL_F160M as the default choice */
+    MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */
 #else
     MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL,      /*!< Select XTAL as the default choice */
 #endif // SOC_CLK_TREE_SUPPORTED
 } soc_periph_mcpwm_capture_clk_src_t;
 
+/**
+ * @brief Array initializer for all supported clock sources of MCPWM Carrier
+ */
+#if SOC_CLK_TREE_SUPPORTED
+#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
+#else
+#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_XTAL}
+#endif
+
+/**
+ * @brief Type of MCPWM carrier clock source
+ */
+typedef enum {
+    MCPWM_CARRIER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
+    MCPWM_CARRIER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL,         /*!< Select XTAL as the source clock */
+#if SOC_CLK_TREE_SUPPORTED
+    MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */
+#else
+    MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL,      /*!< Select XTAL as the default choice */
+#endif // SOC_CLK_TREE_SUPPORTED
+} soc_periph_mcpwm_carrier_clk_src_t;
+
 ///////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////
 
 /////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////

+ 13 - 0
components/soc/esp32s3/include/soc/clk_tree_defs.h

@@ -257,6 +257,19 @@ typedef enum {
     MCPWM_CAPTURE_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default clock choice */
 } soc_periph_mcpwm_capture_clk_src_t;
 
+/**
+ * @brief Array initializer for all supported clock sources of MCPWM Carrier
+ */
+#define SOC_MCPWM_CARRIER_CLKS {SOC_MOD_CLK_PLL_F160M}
+
+/**
+ * @brief Type of MCPWM carrier clock source
+ */
+typedef enum {
+    MCPWM_CARRIER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
+    MCPWM_CARRIER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
+} soc_periph_mcpwm_carrier_clk_src_t;
+
 ///////////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////
 
 /**

+ 1 - 0
docs/en/api-reference/peripherals/mcpwm.rst

@@ -724,6 +724,7 @@ The MCPWM operator has a carrier submodule that can be used if galvanic isolatio
 
 To configure the carrier submodule, you can call :cpp:func:`mcpwm_operator_apply_carrier`, and provide configuration structure :cpp:type:`mcpwm_carrier_config_t`:
 
+- :cpp:member:`mcpwm_carrier_config_t::clk_src` sets the clock source of the carrier.
 - :cpp:member:`mcpwm_carrier_config_t::frequency_hz` indicates carrier frequency in Hz.
 - :cpp:member:`mcpwm_carrier_config_t::duty_cycle` indicates the duty cycle of the carrier. Note that, the supported choices of the duty cycle are discrete, the driver will search for the nearest one based on your configuration.
 - :cpp:member:`mcpwm_carrier_config_t::first_pulse_duration_us` indicates the duration of the first pulse in microseconds. The resolution of the first pulse duration is determined by the carrier frequency you set in the :cpp:member:`mcpwm_carrier_config_t::frequency_hz`. The first pulse duration can't be zero, and it has to be at least one period of the carrier. A longer pulse width can help conduct the inductance quicker.

+ 1 - 0
docs/zh_CN/api-reference/peripherals/mcpwm.rst

@@ -724,6 +724,7 @@ MCPWM 操作器具有载波子模块,可以根据需要(例如隔离式数
 
 调用 :cpp:func:`mcpwm_operator_apply_carrier`,并提供配置结构体 :cpp:type:`mcpwm_carrier_config_t`,配置载波子模块:
 
+- :cpp:member:`mcpwm_carrier_config_t::clk_src` 设置载波的时钟源。
 - :cpp:member:`mcpwm_carrier_config_t::frequency_hz` 表示载波频率,单位为赫兹。
 - :cpp:member:`mcpwm_carrier_config_t::duty_cycle` 表示载波的占空比。需注意,支持的占空比选项并不连续,驱动程序将根据配置查找最接近的占空比。
 - :cpp:member:`mcpwm_carrier_config_t::first_pulse_duration_us` 表示第一个脉冲的脉宽,单位为微秒。该脉冲的分辨率由 :cpp:member:`mcpwm_carrier_config_t::frequency_hz` 中的配置决定。第一个脉冲的脉宽不能为零,且至少为一个载波周期。脉宽越长,电感传导越快。