소스 검색

Merge branch 'bugfix/set_driver_default_int_priority' into 'master'

MCPWM: driver-ng follow-up updates

Closes IDFGH-8010 and IDFGH-8013

See merge request espressif/esp-idf!19432
morris 3 년 전
부모
커밋
814351acdf
35개의 변경된 파일155개의 추가작업 그리고 556개의 파일을 삭제
  1. 1 1
      components/driver/deprecated/mcpwm_legacy.c
  2. 2 2
      components/driver/gptimer.c
  3. 2 2
      components/driver/i2s/i2s_common.c
  4. 2 1
      components/driver/include/driver/gptimer.h
  5. 34 0
      components/driver/include/driver/mcpwm_cap.h
  6. 2 0
      components/driver/include/driver/mcpwm_cmpr.h
  7. 2 0
      components/driver/include/driver/mcpwm_fault.h
  8. 2 0
      components/driver/include/driver/mcpwm_oper.h
  9. 3 0
      components/driver/include/driver/mcpwm_timer.h
  10. 2 1
      components/driver/include/driver/pulse_cnt.h
  11. 40 6
      components/driver/mcpwm/mcpwm_cap.c
  12. 9 3
      components/driver/mcpwm/mcpwm_private.h
  13. 1 1
      components/driver/mcpwm/mcpwm_timer.c
  14. 4 4
      components/driver/pulse_cnt.c
  15. 2 2
      components/driver/rmt/rmt_private.h
  16. 15 0
      components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c
  17. 1 1
      components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c
  18. 4 0
      components/driver/test_apps/mcpwm/main/test_mcpwm_iram.c
  19. 2 2
      components/esp_hw_support/gdma.c
  20. 1 1
      components/esp_lcd/src/esp_lcd_panel_io_i2s.c
  21. 1 1
      components/esp_lcd/src/esp_lcd_panel_io_i80.c
  22. 1 1
      components/esp_lcd/src/esp_lcd_rgb_panel.c
  23. 5 0
      docs/en/api-reference/peripherals/mcpwm.rst
  24. 1 1
      docs/en/migration-guides/release-5.x/peripherals.rst
  25. 2 2
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md
  26. 0 9
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/CMakeLists.txt
  27. 0 7
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/README.md
  28. 0 145
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/include/bdc_motor.h
  29. 0 116
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/interface/bdc_motor_interface.h
  30. 0 62
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor.c
  31. 0 185
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor_mcpwm_impl.c
  32. 1 0
      examples/peripherals/mcpwm/mcpwm_bdc_speed_control/main/idf_component.yml
  33. 9 0
      examples/peripherals/mcpwm/mcpwm_bldc_hall_control/main/mcpwm_bldc_hall_control_example_main.c
  34. 3 0
      examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/main/mcpwm_capture_hc_sr04.c
  35. 1 0
      examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py

+ 1 - 1
components/driver/deprecated/mcpwm_legacy.c

@@ -787,7 +787,7 @@ esp_err_t mcpwm_capture_enable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_cha
     mcpwm_ll_capture_enable_negedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_NEG_EDGE);
     mcpwm_ll_capture_enable_negedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_NEG_EDGE);
     mcpwm_ll_capture_enable_posedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_POS_EDGE);
     mcpwm_ll_capture_enable_posedge(hal->dev, cap_channel, cap_conf->cap_edge & MCPWM_POS_EDGE);
     mcpwm_ll_capture_set_prescale(hal->dev, cap_channel, cap_conf->cap_prescale);
     mcpwm_ll_capture_set_prescale(hal->dev, cap_channel, cap_conf->cap_prescale);
-    // capture feature should be used with interupt, so enable it by default
+    // capture feature should be used with interrupt, so enable it by default
     mcpwm_ll_intr_enable(hal->dev, MCPWM_LL_EVENT_CAPTURE(cap_channel), true);
     mcpwm_ll_intr_enable(hal->dev, MCPWM_LL_EVENT_CAPTURE(cap_channel), true);
     mcpwm_ll_intr_clear_capture_status(hal->dev, 1 << cap_channel);
     mcpwm_ll_intr_clear_capture_status(hal->dev, 1 << cap_channel);
     mcpwm_critical_exit(mcpwm_num);
     mcpwm_critical_exit(mcpwm_num);

+ 2 - 2
components/driver/gptimer.c

@@ -245,7 +245,6 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
 {
 {
     gptimer_group_t *group = NULL;
     gptimer_group_t *group = NULL;
     ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    ESP_RETURN_ON_FALSE(timer->fsm == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
     group = timer->group;
     group = timer->group;
     int group_id = group->group_id;
     int group_id = group->group_id;
     int timer_id = timer->timer_id;
     int timer_id = timer->timer_id;
@@ -261,6 +260,7 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
 
 
     // lazy install interrupt service
     // lazy install interrupt service
     if (!timer->intr) {
     if (!timer->intr) {
+        ESP_RETURN_ON_FALSE(timer->fsm == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
         // if user wants to control the interrupt allocation more precisely, we can expose more flags in `gptimer_config_t`
         // if user wants to control the interrupt allocation more precisely, we can expose more flags in `gptimer_config_t`
         int isr_flags = timer->flags.intr_shared ? ESP_INTR_FLAG_SHARED | GPTIMER_INTR_ALLOC_FLAGS : GPTIMER_INTR_ALLOC_FLAGS;
         int isr_flags = timer->flags.intr_shared ? ESP_INTR_FLAG_SHARED | GPTIMER_INTR_ALLOC_FLAGS : GPTIMER_INTR_ALLOC_FLAGS;
         ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_id].timer_irq_id[timer_id], isr_flags,
         ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(timer_group_periph_signals.groups[group_id].timer_irq_id[timer_id], isr_flags,
@@ -318,7 +318,7 @@ esp_err_t gptimer_enable(gptimer_handle_t timer)
     if (timer->pm_lock) {
     if (timer->pm_lock) {
         ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(timer->pm_lock), TAG, "acquire pm_lock failed");
         ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(timer->pm_lock), TAG, "acquire pm_lock failed");
     }
     }
-    // enable interrupt interupt service
+    // enable interrupt service
     if (timer->intr) {
     if (timer->intr) {
         ESP_RETURN_ON_ERROR(esp_intr_enable(timer->intr), TAG, "enable interrupt service failed");
         ESP_RETURN_ON_ERROR(esp_intr_enable(timer->intr), TAG, "enable interrupt service failed");
     }
     }

+ 2 - 2
components/driver/i2s/i2s_common.c

@@ -55,10 +55,10 @@
 // If ISR handler is allowed to run whilst cache is disabled,
 // If ISR handler is allowed to run whilst cache is disabled,
 // Make sure all the code and related variables used by the handler are in the SRAM
 // Make sure all the code and related variables used by the handler are in the SRAM
 #if CONFIG_I2S_ISR_IRAM_SAFE
 #if CONFIG_I2S_ISR_IRAM_SAFE
-#define I2S_INTR_ALLOC_FLAGS    (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
+#define I2S_INTR_ALLOC_FLAGS    (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
 #define I2S_MEM_ALLOC_CAPS      (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
 #define I2S_MEM_ALLOC_CAPS      (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
 #else
 #else
-#define I2S_INTR_ALLOC_FLAGS    (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
+#define I2S_INTR_ALLOC_FLAGS    (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
 #define I2S_MEM_ALLOC_CAPS      MALLOC_CAP_DEFAULT
 #define I2S_MEM_ALLOC_CAPS      MALLOC_CAP_DEFAULT
 #endif //CONFIG_I2S_ISR_IRAM_SAFE
 #endif //CONFIG_I2S_ISR_IRAM_SAFE
 #define I2S_DMA_ALLOC_CAPS      (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
 #define I2S_DMA_ALLOC_CAPS      (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)

+ 2 - 1
components/driver/include/driver/gptimer.h

@@ -138,7 +138,8 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, uint64_t *value);
  * @brief Set callbacks for GPTimer
  * @brief Set callbacks for GPTimer
  *
  *
  * @note User registered callbacks are expected to be runnable within ISR context
  * @note User registered callbacks are expected to be runnable within ISR context
- * @note This function should be called when the timer is in the init state (i.e. before calling `gptimer_enable()`)
+ * @note The first call to this function needs to be before the call to `gptimer_enable`
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
  *
  *
  * @param[in] timer Timer handle created by `gptimer_new_timer()`
  * @param[in] timer Timer handle created by `gptimer_new_timer()`
  * @param[in] cbs Group of callback functions
  * @param[in] cbs Group of callback functions

+ 34 - 0
components/driver/include/driver/mcpwm_cap.h

@@ -134,6 +134,8 @@ typedef struct {
 /**
 /**
  * @brief Create MCPWM capture channel
  * @brief Create MCPWM capture channel
  *
  *
+ * @note The created capture channel won't be enabled until calling `mcpwm_capture_channel_enable`
+ *
  * @param[in] cap_timer MCPWM capture timer, allocated by `mcpwm_new_capture_timer()`, will be connected to the new capture channel
  * @param[in] cap_timer MCPWM capture timer, allocated by `mcpwm_new_capture_timer()`, will be connected to the new capture channel
  * @param[in] config MCPWM capture channel configuration
  * @param[in] config MCPWM capture channel configuration
  * @param[out] ret_cap_channel Returned MCPWM capture channel
  * @param[out] ret_cap_channel Returned MCPWM capture channel
@@ -157,6 +159,33 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc
  */
  */
 esp_err_t mcpwm_del_capture_channel(mcpwm_cap_channel_handle_t cap_channel);
 esp_err_t mcpwm_del_capture_channel(mcpwm_cap_channel_handle_t cap_channel);
 
 
+/**
+ * @brief Enable MCPWM capture channel
+ *
+ * @note This function will transit the channel state from init to enable.
+ * @note This function will enable the interrupt service, if it's lazy installed in `mcpwm_capture_channel_register_event_callbacks()`.
+ *
+ * @param[in] cap_channel MCPWM capture channel handle, allocated by `mcpwm_new_capture_channel()`
+ * @return
+ *      - ESP_OK: Enable MCPWM capture channel successfully
+ *      - ESP_ERR_INVALID_ARG: Enable MCPWM capture channel failed because of invalid argument
+ *      - ESP_ERR_INVALID_STATE: Enable MCPWM capture channel failed because the channel is already enabled
+ *      - ESP_FAIL: Enable MCPWM capture channel failed because of other error
+ */
+esp_err_t mcpwm_capture_channel_enable(mcpwm_cap_channel_handle_t cap_channel);
+
+/**
+ * @brief Disable MCPWM capture channel
+ *
+ * @param[in] cap_channel MCPWM capture channel handle, allocated by `mcpwm_new_capture_channel()`
+ * @return
+ *      - ESP_OK: Disable MCPWM capture channel successfully
+ *      - ESP_ERR_INVALID_ARG: Disable MCPWM capture channel failed because of invalid argument
+ *      - ESP_ERR_INVALID_STATE: Disable MCPWM capture channel failed because the channel is not enabled yet
+ *      - ESP_FAIL: Disable MCPWM capture channel failed because of other error
+ */
+esp_err_t mcpwm_capture_channel_disable(mcpwm_cap_channel_handle_t cap_channel);
+
 /**
 /**
  * @brief Group of supported MCPWM capture event callbacks
  * @brief Group of supported MCPWM capture event callbacks
  * @note The callbacks are all running under ISR environment
  * @note The callbacks are all running under ISR environment
@@ -168,12 +197,16 @@ typedef struct {
 /**
 /**
  * @brief Set event callbacks for MCPWM capture channel
  * @brief Set event callbacks for MCPWM capture channel
  *
  *
+ * @note The first call to this function needs to be before the call to `mcpwm_capture_channel_enable`
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
+ *
  * @param[in] cap_channel MCPWM capture channel handle, allocated by `mcpwm_new_capture_channel()`
  * @param[in] cap_channel MCPWM capture channel handle, allocated by `mcpwm_new_capture_channel()`
  * @param[in] cbs Group of callback functions
  * @param[in] cbs Group of callback functions
  * @param[in] user_data User data, which will be passed to callback functions directly
  * @param[in] user_data User data, which will be passed to callback functions directly
  * @return
  * @return
  *      - ESP_OK: Set event callbacks successfully
  *      - ESP_OK: Set event callbacks successfully
  *      - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
  *      - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
+ *      - ESP_ERR_INVALID_STATE: Set event callbacks failed because the channel is not in init state
  *      - ESP_FAIL: Set event callbacks failed because of other error
  *      - ESP_FAIL: Set event callbacks failed because of other error
  */
  */
 esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_callbacks_t *cbs, void *user_data);
 esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_callbacks_t *cbs, void *user_data);
@@ -185,6 +218,7 @@ esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handl
  * @return
  * @return
  *      - ESP_OK: Trigger software catch successfully
  *      - ESP_OK: Trigger software catch successfully
  *      - ESP_ERR_INVALID_ARG: Trigger software catch failed because of invalid argument
  *      - ESP_ERR_INVALID_ARG: Trigger software catch failed because of invalid argument
+ *      - ESP_ERR_INVALID_STATE: Trigger software catch failed because the channel is not enabled yet
  *      - ESP_FAIL: Trigger software catch failed because of other error
  *      - ESP_FAIL: Trigger software catch failed because of other error
  */
  */
 esp_err_t mcpwm_capture_channel_trigger_soft_catch(mcpwm_cap_channel_handle_t cap_channel);
 esp_err_t mcpwm_capture_channel_trigger_soft_catch(mcpwm_cap_channel_handle_t cap_channel);

+ 2 - 0
components/driver/include/driver/mcpwm_cmpr.h

@@ -63,6 +63,8 @@ typedef struct {
 /**
 /**
  * @brief Set event callbacks for MCPWM comparator
  * @brief Set event callbacks for MCPWM comparator
  *
  *
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
+ *
  * @param[in] cmpr MCPWM comparator handle, allocated by `mcpwm_new_comparator()`
  * @param[in] cmpr MCPWM comparator handle, allocated by `mcpwm_new_comparator()`
  * @param[in] cbs Group of callback functions
  * @param[in] cbs Group of callback functions
  * @param[in] user_data User data, which will be passed to callback functions directly
  * @param[in] user_data User data, which will be passed to callback functions directly

+ 2 - 0
components/driver/include/driver/mcpwm_fault.h

@@ -97,6 +97,8 @@ typedef struct {
 /**
 /**
  * @brief Set event callbacks for MCPWM fault
  * @brief Set event callbacks for MCPWM fault
  *
  *
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
+ *
  * @param[in] fault MCPWM GPIO fault handle, allocated by `mcpwm_new_gpio_fault()`
  * @param[in] fault MCPWM GPIO fault handle, allocated by `mcpwm_new_gpio_fault()`
  * @param[in] cbs Group of callback functions
  * @param[in] cbs Group of callback functions
  * @param[in] user_data User data, which will be passed to callback functions directly
  * @param[in] user_data User data, which will be passed to callback functions directly

+ 2 - 0
components/driver/include/driver/mcpwm_oper.h

@@ -119,6 +119,8 @@ typedef struct {
 /**
 /**
  * @brief Set event callbacks for MCPWM operator
  * @brief Set event callbacks for MCPWM operator
  *
  *
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
+ *
  * @param[in] oper MCPWM operator handle, allocated by `mcpwm_new_operator()`
  * @param[in] oper MCPWM operator handle, allocated by `mcpwm_new_operator()`
  * @param[in] cbs Group of callback functions
  * @param[in] cbs Group of callback functions
  * @param[in] user_data User data, which will be passed to callback functions directly
  * @param[in] user_data User data, which will be passed to callback functions directly

+ 3 - 0
components/driver/include/driver/mcpwm_timer.h

@@ -107,6 +107,9 @@ esp_err_t mcpwm_timer_start_stop(mcpwm_timer_handle_t timer, mcpwm_timer_start_s
 /**
 /**
  * @brief Set event callbacks for MCPWM timer
  * @brief Set event callbacks for MCPWM timer
  *
  *
+ * @note The first call to this function needs to be before the call to `mcpwm_timer_enable`
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
+ *
  * @param[in] timer MCPWM timer handle, allocated by `mcpwm_new_timer()`
  * @param[in] timer MCPWM timer handle, allocated by `mcpwm_new_timer()`
  * @param[in] cbs Group of callback functions
  * @param[in] cbs Group of callback functions
  * @param[in] user_data User data, which will be passed to callback functions directly
  * @param[in] user_data User data, which will be passed to callback functions directly

+ 2 - 1
components/driver/include/driver/pulse_cnt.h

@@ -233,7 +233,8 @@ esp_err_t pcnt_unit_get_count(pcnt_unit_handle_t unit, int *value);
  * @brief Set event callbacks for PCNT unit
  * @brief Set event callbacks for PCNT unit
  *
  *
  * @note User registered callbacks are expected to be runnable within ISR context
  * @note User registered callbacks are expected to be runnable within ISR context
- * @note This function is only allowed to be called when the unit is in the init state (i.e. before calling `pcnt_unit_enable()`)
+ * @note The first call to this function needs to be before the call to `pcnt_unit_enable`
+ * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL.
  *
  *
  * @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
  * @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
  * @param[in] cbs Group of callback functions
  * @param[in] cbs Group of callback functions

+ 40 - 6
components/driver/mcpwm/mcpwm_cap.c

@@ -242,7 +242,6 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc
     mcpwm_hal_context_t *hal = &group->hal;
     mcpwm_hal_context_t *hal = &group->hal;
     int cap_chan_id = cap_chan->cap_chan_id;
     int cap_chan_id = cap_chan->cap_chan_id;
 
 
-    mcpwm_ll_capture_enable_channel(hal->dev, cap_chan_id, true); // enable channel
     mcpwm_ll_capture_enable_negedge(hal->dev, cap_chan_id, config->flags.neg_edge);
     mcpwm_ll_capture_enable_negedge(hal->dev, cap_chan_id, config->flags.neg_edge);
     mcpwm_ll_capture_enable_posedge(hal->dev, cap_chan_id, config->flags.pos_edge);
     mcpwm_ll_capture_enable_posedge(hal->dev, cap_chan_id, config->flags.pos_edge);
     mcpwm_ll_invert_input(hal->dev, cap_chan_id, config->flags.invert_cap_signal);
     mcpwm_ll_invert_input(hal->dev, cap_chan_id, config->flags.invert_cap_signal);
@@ -262,6 +261,7 @@ esp_err_t mcpwm_new_capture_channel(mcpwm_cap_timer_handle_t cap_timer, const mc
     }
     }
 
 
     cap_chan->gpio_num = config->gpio_num;
     cap_chan->gpio_num = config->gpio_num;
+    cap_chan->fsm = MCPWM_CAP_CHAN_FSM_INIT;
     *ret_cap_channel = cap_chan;
     *ret_cap_channel = cap_chan;
     ESP_LOGD(TAG, "new capture channel (%d,%d) at %p", group->group_id, cap_chan_id, cap_chan);
     ESP_LOGD(TAG, "new capture channel (%d,%d) at %p", group->group_id, cap_chan_id, cap_chan);
     return ESP_OK;
     return ESP_OK;
@@ -275,6 +275,7 @@ err:
 esp_err_t mcpwm_del_capture_channel(mcpwm_cap_channel_handle_t cap_channel)
 esp_err_t mcpwm_del_capture_channel(mcpwm_cap_channel_handle_t cap_channel)
 {
 {
     ESP_RETURN_ON_FALSE(cap_channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE(cap_channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
+    ESP_RETURN_ON_FALSE(cap_channel->fsm == MCPWM_CAP_CHAN_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "channel not in init state");
     mcpwm_cap_timer_t *cap_timer = cap_channel->cap_timer;
     mcpwm_cap_timer_t *cap_timer = cap_channel->cap_timer;
     mcpwm_group_t *group = cap_timer->group;
     mcpwm_group_t *group = cap_timer->group;
     mcpwm_hal_context_t *hal = &group->hal;
     mcpwm_hal_context_t *hal = &group->hal;
@@ -290,14 +291,46 @@ esp_err_t mcpwm_del_capture_channel(mcpwm_cap_channel_handle_t cap_channel)
     mcpwm_ll_intr_clear_status(hal->dev, MCPWM_LL_EVENT_CAPTURE(cap_chan_id));
     mcpwm_ll_intr_clear_status(hal->dev, MCPWM_LL_EVENT_CAPTURE(cap_chan_id));
     portEXIT_CRITICAL(&group->spinlock);
     portEXIT_CRITICAL(&group->spinlock);
 
 
-    // disable capture channel
-    mcpwm_ll_capture_enable_channel(group->hal.dev, cap_channel->cap_chan_id, false);
-
     // recycle memory resource
     // recycle memory resource
     ESP_RETURN_ON_ERROR(mcpwm_capture_channel_destory(cap_channel), TAG, "destory capture channel failed");
     ESP_RETURN_ON_ERROR(mcpwm_capture_channel_destory(cap_channel), TAG, "destory capture channel failed");
     return ESP_OK;
     return ESP_OK;
 }
 }
 
 
+esp_err_t mcpwm_capture_channel_enable(mcpwm_cap_channel_handle_t cap_channel)
+{
+    ESP_RETURN_ON_FALSE(cap_channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
+    ESP_RETURN_ON_FALSE(cap_channel->fsm == MCPWM_CAP_CHAN_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "channel not in init state");
+    mcpwm_hal_context_t *hal = &cap_channel->cap_timer->group->hal;
+
+    // enable interrupt service
+    if (cap_channel->intr) {
+        ESP_RETURN_ON_ERROR(esp_intr_enable(cap_channel->intr), TAG, "enable interrupt service failed");
+    }
+    // enable channel
+    mcpwm_ll_capture_enable_channel(hal->dev, cap_channel->cap_chan_id, true);
+
+    cap_channel->fsm = MCPWM_CAP_CHAN_FSM_ENABLE;
+    return ESP_OK;
+}
+
+esp_err_t mcpwm_capture_channel_disable(mcpwm_cap_channel_handle_t cap_channel)
+{
+    ESP_RETURN_ON_FALSE(cap_channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
+    ESP_RETURN_ON_FALSE(cap_channel->fsm == MCPWM_CAP_CHAN_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "channel not in enable state");
+    mcpwm_hal_context_t *hal = &cap_channel->cap_timer->group->hal;
+
+    // disable channel
+    mcpwm_ll_capture_enable_channel(hal->dev, cap_channel->cap_chan_id, false);
+
+    // disable interrupt service
+    if (cap_channel->intr) {
+        ESP_RETURN_ON_ERROR(esp_intr_disable(cap_channel->intr), TAG, "disable interrupt service failed");
+    }
+
+    cap_channel->fsm = MCPWM_CAP_CHAN_FSM_INIT;
+    return ESP_OK;
+}
+
 esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_callbacks_t *cbs, void *user_data)
 esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_callbacks_t *cbs, void *user_data)
 {
 {
     ESP_RETURN_ON_FALSE(cap_channel && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE(cap_channel && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
@@ -317,8 +350,8 @@ esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handl
 
 
     // lazy install interrupt service
     // lazy install interrupt service
     if (!cap_channel->intr) {
     if (!cap_channel->intr) {
-        // we want the interrupt service to be enabled after allocation successfully
-        int isr_flags = MCPWM_INTR_ALLOC_FLAG & ~ ESP_INTR_FLAG_INTRDISABLED;
+        ESP_RETURN_ON_FALSE(cap_channel->fsm == MCPWM_CAP_CHAN_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "channel not in init state");
+        int isr_flags = MCPWM_INTR_ALLOC_FLAG;
         ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags,
         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_CAPTURE(cap_chan_id),
                             (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_CAPTURE(cap_chan_id),
                             mcpwm_capture_default_isr, cap_channel, &cap_channel->intr), TAG, "install interrupt service for cap channel failed");
                             mcpwm_capture_default_isr, cap_channel, &cap_channel->intr), TAG, "install interrupt service for cap channel failed");
@@ -337,6 +370,7 @@ esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handl
 esp_err_t mcpwm_capture_channel_trigger_soft_catch(mcpwm_cap_channel_handle_t cap_channel)
 esp_err_t mcpwm_capture_channel_trigger_soft_catch(mcpwm_cap_channel_handle_t cap_channel)
 {
 {
     ESP_RETURN_ON_FALSE(cap_channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE(cap_channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
+    ESP_RETURN_ON_FALSE(cap_channel->fsm == MCPWM_CAP_CHAN_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "channel not enabled yet");
     mcpwm_cap_timer_t *cap_timer = cap_channel->cap_timer;
     mcpwm_cap_timer_t *cap_timer = cap_channel->cap_timer;
     mcpwm_group_t *group = cap_timer->group;
     mcpwm_group_t *group = cap_timer->group;
 
 

+ 9 - 3
components/driver/mcpwm/mcpwm_private.h

@@ -29,9 +29,9 @@ extern "C" {
 #endif
 #endif
 
 
 #if CONFIG_MCPWM_ISR_IRAM_SAFE
 #if CONFIG_MCPWM_ISR_IRAM_SAFE
-#define MCPWM_INTR_ALLOC_FLAG     (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM)
+#define MCPWM_INTR_ALLOC_FLAG     (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM)
 #else
 #else
-#define MCPWM_INTR_ALLOC_FLAG     (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED)
+#define MCPWM_INTR_ALLOC_FLAG     (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED)
 #endif
 #endif
 
 
 #define MCPWM_PERIPH_CLOCK_PRE_SCALE (2)
 #define MCPWM_PERIPH_CLOCK_PRE_SCALE (2)
@@ -193,6 +193,11 @@ typedef enum {
     MCPWM_CAP_TIMER_FSM_ENABLE,
     MCPWM_CAP_TIMER_FSM_ENABLE,
 } mcpwm_cap_timer_fsm_t;
 } mcpwm_cap_timer_fsm_t;
 
 
+typedef enum {
+    MCPWM_CAP_CHAN_FSM_INIT,
+    MCPWM_CAP_CHAN_FSM_ENABLE,
+} mcpwm_cap_channel_fsm_t;
+
 struct mcpwm_cap_timer_t {
 struct mcpwm_cap_timer_t {
     mcpwm_group_t *group;   // which group the capture timer belongs to
     mcpwm_group_t *group;   // which group the capture timer belongs to
     portMUX_TYPE spinlock;  // spin lock, to prevent concurrently accessing capture timer level resources, including registers
     portMUX_TYPE spinlock;  // spin lock, to prevent concurrently accessing capture timer level resources, including registers
@@ -206,7 +211,8 @@ struct mcpwm_cap_channel_t {
     int cap_chan_id;                  // capture channel ID, index from 0
     int cap_chan_id;                  // capture channel ID, index from 0
     mcpwm_cap_timer_t *cap_timer;     // which capture timer that the channel resides in
     mcpwm_cap_timer_t *cap_timer;     // which capture timer that the channel resides in
     uint32_t prescale;                // prescale of capture signal
     uint32_t prescale;                // prescale of capture signal
-    int gpio_num;                 // GPIO number used by the channel
+    int gpio_num;                     // GPIO number used by the channel
+    mcpwm_cap_channel_fsm_t fsm;      // driver FSM
     intr_handle_t intr;               // Interrupt handle
     intr_handle_t intr;               // Interrupt handle
     mcpwm_capture_event_cb_t on_cap;  // Callback function which would be invoked in capture interrupt routine
     mcpwm_capture_event_cb_t on_cap;  // Callback function which would be invoked in capture interrupt routine
     void *user_data;                  // user data which would be passed to the capture callback
     void *user_data;                  // user data which would be passed to the capture callback

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

@@ -166,7 +166,6 @@ esp_err_t mcpwm_del_timer(mcpwm_timer_handle_t timer)
 esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const mcpwm_timer_event_callbacks_t *cbs, void *user_data)
 esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const mcpwm_timer_event_callbacks_t *cbs, void *user_data)
 {
 {
     ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    ESP_RETURN_ON_FALSE(timer->fsm == MCPWM_TIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
     mcpwm_group_t *group = timer->group;
     mcpwm_group_t *group = timer->group;
     int group_id = group->group_id;
     int group_id = group->group_id;
     int timer_id = timer->timer_id;
     int timer_id = timer->timer_id;
@@ -189,6 +188,7 @@ esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const
 
 
     // lazy install interrupt service
     // lazy install interrupt service
     if (!timer->intr) {
     if (!timer->intr) {
+        ESP_RETURN_ON_FALSE(timer->fsm == MCPWM_TIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
         int isr_flags = MCPWM_INTR_ALLOC_FLAG;
         int isr_flags = MCPWM_INTR_ALLOC_FLAG;
         ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(mcpwm_periph_signals.groups[group_id].irq_id, isr_flags,
         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_TIMER_MASK(timer_id),
                             (uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_TIMER_MASK(timer_id),

+ 4 - 4
components/driver/pulse_cnt.c

@@ -41,9 +41,9 @@
 #endif
 #endif
 
 
 #if CONFIG_PCNT_ISR_IRAM_SAFE
 #if CONFIG_PCNT_ISR_IRAM_SAFE
-#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
+#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
 #else
 #else
-#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
+#define PCNT_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
 #endif
 #endif
 
 
 #define PCNT_PM_LOCK_NAME_LEN_MAX 16
 #define PCNT_PM_LOCK_NAME_LEN_MAX 16
@@ -283,7 +283,7 @@ esp_err_t pcnt_unit_enable(pcnt_unit_handle_t unit)
     if (unit->pm_lock) {
     if (unit->pm_lock) {
         ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(unit->pm_lock), TAG, "acquire pm_lock failed");
         ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(unit->pm_lock), TAG, "acquire pm_lock failed");
     }
     }
-    // enable interupt service
+    // enable interrupt service
     if (unit->intr) {
     if (unit->intr) {
         ESP_RETURN_ON_ERROR(esp_intr_enable(unit->intr), TAG, "enable interrupt service failed");
         ESP_RETURN_ON_ERROR(esp_intr_enable(unit->intr), TAG, "enable interrupt service failed");
     }
     }
@@ -366,7 +366,6 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt
 {
 {
     ESP_RETURN_ON_FALSE(unit && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE(unit && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     // unit event callbacks should be registered in init state
     // unit event callbacks should be registered in init state
-    ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
     pcnt_group_t *group = unit->group;
     pcnt_group_t *group = unit->group;
     int group_id = group->group_id;
     int group_id = group->group_id;
     int unit_id = unit->unit_id;
     int unit_id = unit->unit_id;
@@ -382,6 +381,7 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt
 
 
     // lazy install interrupt service
     // lazy install interrupt service
     if (!unit->intr) {
     if (!unit->intr) {
+        ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
         int isr_flags = PCNT_INTR_ALLOC_FLAGS;
         int isr_flags = PCNT_INTR_ALLOC_FLAGS;
         ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(pcnt_periph_signals.groups[group_id].irq, isr_flags,
         ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(pcnt_periph_signals.groups[group_id].irq, isr_flags,
                             (uint32_t)pcnt_ll_get_intr_status_reg(group->hal.dev), PCNT_LL_UNIT_WATCH_EVENT(unit_id),
                             (uint32_t)pcnt_ll_get_intr_status_reg(group->hal.dev), PCNT_LL_UNIT_WATCH_EVENT(unit_id),

+ 2 - 2
components/driver/rmt/rmt_private.h

@@ -34,9 +34,9 @@ extern "C" {
 
 
 // RMT driver object is per-channel, the interrupt source is shared between channels
 // RMT driver object is per-channel, the interrupt source is shared between channels
 #if CONFIG_RMT_ISR_IRAM_SAFE
 #if CONFIG_RMT_ISR_IRAM_SAFE
-#define RMT_INTR_ALLOC_FLAG     (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM)
+#define RMT_INTR_ALLOC_FLAG     (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM)
 #else
 #else
-#define RMT_INTR_ALLOC_FLAG     ESP_INTR_FLAG_SHARED
+#define RMT_INTR_ALLOC_FLAG     (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED)
 #endif
 #endif
 
 
 // Hopefully the channel offset won't change in other targets
 // Hopefully the channel offset won't change in other targets

+ 15 - 0
components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c

@@ -102,6 +102,9 @@ TEST_CASE("mcpwm_capture_ext_gpio", "[mcpwm]")
     uint32_t cap_value[2] = {0};
     uint32_t cap_value[2] = {0};
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(pps_channel, &cbs, cap_value));
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(pps_channel, &cbs, cap_value));
 
 
+    printf("enable capture channel\r\n");
+    TEST_ESP_OK(mcpwm_capture_channel_enable(pps_channel));
+
     printf("enable and start capture timer\r\n");
     printf("enable and start capture timer\r\n");
     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
@@ -117,6 +120,7 @@ TEST_CASE("mcpwm_capture_ext_gpio", "[mcpwm]")
     TEST_ASSERT_UINT_WITHIN(100000, clk_src_res / 10, cap_value[1] - cap_value[0]);
     TEST_ASSERT_UINT_WITHIN(100000, clk_src_res / 10, cap_value[1] - cap_value[0]);
 
 
     printf("uninstall capture channel and timer\r\n");
     printf("uninstall capture channel and timer\r\n");
+    TEST_ESP_OK(mcpwm_capture_channel_disable(pps_channel));
     TEST_ESP_OK(mcpwm_del_capture_channel(pps_channel));
     TEST_ESP_OK(mcpwm_del_capture_channel(pps_channel));
     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
@@ -154,12 +158,17 @@ TEST_CASE("mcpwm_capture_software_catch", "[mcpwm]")
     test_soft_catch_user_data_t test_callback_data = {};
     test_soft_catch_user_data_t test_callback_data = {};
     TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel));
     TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel));
 
 
+    TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_capture_channel_trigger_soft_catch(cap_channel));
+
     printf("register event callback for capture channel\r\n");
     printf("register event callback for capture channel\r\n");
     mcpwm_capture_event_callbacks_t cbs = {
     mcpwm_capture_event_callbacks_t cbs = {
         .on_cap = soft_cap_callback,
         .on_cap = soft_cap_callback,
     };
     };
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &test_callback_data));
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &test_callback_data));
 
 
+    printf("enable capture channel\r\n");
+    TEST_ESP_OK(mcpwm_capture_channel_enable(cap_channel));
+
     printf("enable and start capture timer\r\n");
     printf("enable and start capture timer\r\n");
     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
@@ -179,6 +188,7 @@ TEST_CASE("mcpwm_capture_software_catch", "[mcpwm]")
     TEST_ASSERT_UINT_WITHIN(80000, clk_src_res / 100, delta);
     TEST_ASSERT_UINT_WITHIN(80000, clk_src_res / 100, delta);
 
 
     printf("uninstall capture channel and timer\r\n");
     printf("uninstall capture channel and timer\r\n");
+    TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel));
     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
     TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel));
     TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
@@ -211,6 +221,7 @@ TEST_CASE("mcpwm_capture_timer_sync_phase_lock", "[mcpwm]")
         .sync_src = soft_sync,
         .sync_src = soft_sync,
     };
     };
     TEST_ESP_OK(mcpwm_capture_timer_set_phase_on_sync(cap_timer, &sync_config));
     TEST_ESP_OK(mcpwm_capture_timer_set_phase_on_sync(cap_timer, &sync_config));
+
     mcpwm_cap_channel_handle_t cap_channel = NULL;
     mcpwm_cap_channel_handle_t cap_channel = NULL;
     mcpwm_capture_channel_config_t cap_chan_config = {
     mcpwm_capture_channel_config_t cap_chan_config = {
         .gpio_num = -1, // don't need any GPIO, we use software to trigger a catch
         .gpio_num = -1, // don't need any GPIO, we use software to trigger a catch
@@ -224,6 +235,9 @@ TEST_CASE("mcpwm_capture_timer_sync_phase_lock", "[mcpwm]")
     uint32_t cap_data;
     uint32_t cap_data;
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &cap_data));
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &cap_data));
 
 
+    printf("enable capture channel\r\n");
+    TEST_ESP_OK(mcpwm_capture_channel_enable(cap_channel));
+
     TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel));
     TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel));
     vTaskDelay(pdMS_TO_TICKS(10));
     vTaskDelay(pdMS_TO_TICKS(10));
     printf("capture data before sync: %"PRIu32"\r\n", cap_data);
     printf("capture data before sync: %"PRIu32"\r\n", cap_data);
@@ -233,6 +247,7 @@ TEST_CASE("mcpwm_capture_timer_sync_phase_lock", "[mcpwm]")
     vTaskDelay(pdMS_TO_TICKS(10));
     vTaskDelay(pdMS_TO_TICKS(10));
     printf("capture data after sync: %"PRIu32"\r\n", cap_data);
     printf("capture data after sync: %"PRIu32"\r\n", cap_data);
     TEST_ASSERT_EQUAL(1000, cap_data);
     TEST_ASSERT_EQUAL(1000, cap_data);
+    TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel));
     TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel));
     TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
     TEST_ESP_OK(mcpwm_del_sync_src(soft_sync));
     TEST_ESP_OK(mcpwm_del_sync_src(soft_sync));

+ 1 - 1
components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c

@@ -76,7 +76,7 @@ TEST_CASE("mcpwm_comparator_event_callback", "[mcpwm]")
         .group_id = 0,
         .group_id = 0,
     };
     };
     mcpwm_comparator_config_t comparator_config = {};
     mcpwm_comparator_config_t comparator_config = {};
-    printf("install timer, operator and comparator");
+    printf("install timer, operator and comparator\r\n");
     TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
     TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
     TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
     TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
     TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator));
     TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator));

+ 4 - 0
components/driver/test_apps/mcpwm/main/test_mcpwm_iram.c

@@ -69,6 +69,9 @@ TEST_CASE("mcpwm_capture_iram_safe", "[mcpwm]")
     uint32_t cap_value[2] = {0};
     uint32_t cap_value[2] = {0};
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(pps_channel, &cbs, cap_value));
     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(pps_channel, &cbs, cap_value));
 
 
+    printf("enable capture channel\r\n");
+    TEST_ESP_OK(mcpwm_capture_channel_enable(pps_channel));
+
     printf("enable and start capture timer\r\n");
     printf("enable and start capture timer\r\n");
     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
@@ -82,6 +85,7 @@ TEST_CASE("mcpwm_capture_iram_safe", "[mcpwm]")
     TEST_ASSERT_UINT_WITHIN(2000, clk_src_res / 1000, cap_value[1] - cap_value[0]);
     TEST_ASSERT_UINT_WITHIN(2000, clk_src_res / 1000, cap_value[1] - cap_value[0]);
 
 
     printf("uninstall capture channel and timer\r\n");
     printf("uninstall capture channel and timer\r\n");
+    TEST_ESP_OK(mcpwm_capture_channel_disable(pps_channel));
     TEST_ESP_OK(mcpwm_del_capture_channel(pps_channel));
     TEST_ESP_OK(mcpwm_del_capture_channel(pps_channel));
     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));

+ 2 - 2
components/esp_hw_support/gdma.c

@@ -764,7 +764,7 @@ static esp_err_t gdma_install_rx_interrupt(gdma_rx_channel_t *rx_chan)
     // pre-alloc a interrupt handle, with handler disabled
     // pre-alloc a interrupt handle, with handler disabled
     int isr_flags = GDMA_INTR_ALLOC_FLAGS;
     int isr_flags = GDMA_INTR_ALLOC_FLAGS;
 #if SOC_GDMA_TX_RX_SHARE_INTERRUPT
 #if SOC_GDMA_TX_RX_SHARE_INTERRUPT
-    isr_flags |= ESP_INTR_FLAG_SHARED;
+    isr_flags |= ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
 #endif
 #endif
     intr_handle_t intr = NULL;
     intr_handle_t intr = NULL;
     ret = esp_intr_alloc_intrstatus(gdma_periph_signals.groups[group->group_id].pairs[pair->pair_id].rx_irq_id, isr_flags,
     ret = esp_intr_alloc_intrstatus(gdma_periph_signals.groups[group->group_id].pairs[pair->pair_id].rx_irq_id, isr_flags,
@@ -791,7 +791,7 @@ static esp_err_t gdma_install_tx_interrupt(gdma_tx_channel_t *tx_chan)
     // pre-alloc a interrupt handle, with handler disabled
     // pre-alloc a interrupt handle, with handler disabled
     int isr_flags = GDMA_INTR_ALLOC_FLAGS;
     int isr_flags = GDMA_INTR_ALLOC_FLAGS;
 #if SOC_GDMA_TX_RX_SHARE_INTERRUPT
 #if SOC_GDMA_TX_RX_SHARE_INTERRUPT
-    isr_flags |= ESP_INTR_FLAG_SHARED;
+    isr_flags |= ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
 #endif
 #endif
     intr_handle_t intr = NULL;
     intr_handle_t intr = NULL;
     ret = esp_intr_alloc_intrstatus(gdma_periph_signals.groups[group->group_id].pairs[pair->pair_id].tx_irq_id, isr_flags,
     ret = esp_intr_alloc_intrstatus(gdma_periph_signals.groups[group->group_id].pairs[pair->pair_id].tx_irq_id, isr_flags,

+ 1 - 1
components/esp_lcd/src/esp_lcd_panel_io_i2s.c

@@ -170,7 +170,7 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
     i2s_ll_tx_reset_fifo(bus->hal.dev);
     i2s_ll_tx_reset_fifo(bus->hal.dev);
     // install interrupt service, (I2S LCD mode only uses the "TX Unit", which leaves "RX Unit" for other purpose)
     // install interrupt service, (I2S LCD mode only uses the "TX Unit", which leaves "RX Unit" for other purpose)
     // So the interrupt should also be able to share with other functionality
     // So the interrupt should also be able to share with other functionality
-    int isr_flags = LCD_I80_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED;
+    int isr_flags = LCD_I80_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
     ret = esp_intr_alloc_intrstatus(lcd_periph_signals.buses[bus->bus_id].irq_id, isr_flags,
     ret = esp_intr_alloc_intrstatus(lcd_periph_signals.buses[bus->bus_id].irq_id, isr_flags,
                                     (uint32_t)i2s_ll_get_intr_status_reg(bus->hal.dev),
                                     (uint32_t)i2s_ll_get_intr_status_reg(bus->hal.dev),
                                     I2S_LL_EVENT_TX_EOF, lcd_default_isr_handler, bus, &bus->intr);
                                     I2S_LL_EVENT_TX_EOF, lcd_default_isr_handler, bus, &bus->intr);

+ 1 - 1
components/esp_lcd/src/esp_lcd_panel_io_i80.c

@@ -153,7 +153,7 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
     ESP_GOTO_ON_ERROR(ret, err, TAG, "select periph clock %d failed", bus_config->clk_src);
     ESP_GOTO_ON_ERROR(ret, err, TAG, "select periph clock %d failed", bus_config->clk_src);
     // install interrupt service, (LCD peripheral shares the same interrupt source with Camera peripheral with different mask)
     // install interrupt service, (LCD peripheral shares the same interrupt source with Camera peripheral with different mask)
     // interrupt is disabled by default
     // interrupt is disabled by default
-    int isr_flags = LCD_I80_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED;
+    int isr_flags = LCD_I80_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
     ret = esp_intr_alloc_intrstatus(lcd_periph_signals.buses[bus_id].irq_id, isr_flags,
     ret = esp_intr_alloc_intrstatus(lcd_periph_signals.buses[bus_id].irq_id, isr_flags,
                                     (uint32_t)lcd_ll_get_interrupt_status_reg(bus->hal.dev),
                                     (uint32_t)lcd_ll_get_interrupt_status_reg(bus->hal.dev),
                                     LCD_LL_EVENT_TRANS_DONE, lcd_default_isr_handler, bus, &bus->intr);
                                     LCD_LL_EVENT_TRANS_DONE, lcd_default_isr_handler, bus, &bus->intr);

+ 1 - 1
components/esp_lcd/src/esp_lcd_rgb_panel.c

@@ -278,7 +278,7 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
         rgb_panel->lcd_clk_flags |= LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK;
         rgb_panel->lcd_clk_flags |= LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK;
     }
     }
     // install interrupt service, (LCD peripheral shares the interrupt source with Camera by different mask)
     // install interrupt service, (LCD peripheral shares the interrupt source with Camera by different mask)
-    int isr_flags = LCD_RGB_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED;
+    int isr_flags = LCD_RGB_INTR_ALLOC_FLAGS | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED;
     ret = esp_intr_alloc_intrstatus(lcd_periph_signals.panels[panel_id].irq_id, isr_flags,
     ret = esp_intr_alloc_intrstatus(lcd_periph_signals.panels[panel_id].irq_id, isr_flags,
                                     (uint32_t)lcd_ll_get_interrupt_status_reg(rgb_panel->hal.dev),
                                     (uint32_t)lcd_ll_get_interrupt_status_reg(rgb_panel->hal.dev),
                                     LCD_LL_EVENT_VSYNC_END, lcd_default_isr_handler, rgb_panel, &rgb_panel->intr);
                                     LCD_LL_EVENT_VSYNC_END, lcd_default_isr_handler, rgb_panel, &rgb_panel->intr);

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

@@ -814,6 +814,11 @@ The parameter ``user_data`` of :cpp:func:`mcpwm_capture_channel_register_event_c
 
 
 This function will lazy install interrupt service for the MCPWM capture channel, whereas the service can only be removed in :cpp:type:`mcpwm_del_capture_channel`.
 This function will lazy install interrupt service for the MCPWM capture channel, whereas the service can only be removed in :cpp:type:`mcpwm_del_capture_channel`.
 
 
+Enable and Disable Capture Channel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The capture channel is not enabled after allocation by :cpp:func:`mcpwm_new_capture_channel`. You should call :cpp:func:`mcpwm_capture_channel_enable` and :cpp:func:`mcpwm_capture_channel_disable` accordingly to enable or disable the channel. If the interrupt service is lazy installed during registering event callbacks for the channel in :cpp:func:`mcpwm_capture_channel_register_event_callbacks`, :cpp:func:`mcpwm_capture_channel_enable` will enable the interrupt service as well.
+
 Enable and Disable Capture Timer
 Enable and Disable Capture Timer
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 

+ 1 - 1
docs/en/migration-guides/release-5.x/peripherals.rst

@@ -308,7 +308,7 @@ LCD
     - ``mcpwm_fault_set_oneshot_mode``, ``mcpwm_fault_set_cyc_mode`` are replaced by :cpp:func:`mcpwm_operator_set_brake_on_fault` and :cpp:func:`mcpwm_generator_set_actions_on_brake_event`.
     - ``mcpwm_fault_set_oneshot_mode``, ``mcpwm_fault_set_cyc_mode`` are replaced by :cpp:func:`mcpwm_operator_set_brake_on_fault` and :cpp:func:`mcpwm_generator_set_actions_on_brake_event`.
     - ``mcpwm_capture_enable`` is removed. It's duplicated to :cpp:func:`mcpwm_capture_enable_channel`.
     - ``mcpwm_capture_enable`` is removed. It's duplicated to :cpp:func:`mcpwm_capture_enable_channel`.
     - ``mcpwm_capture_disable`` is removed. It's duplicated to :cpp:func:`mcpwm_capture_capture_disable_channel`.
     - ``mcpwm_capture_disable`` is removed. It's duplicated to :cpp:func:`mcpwm_capture_capture_disable_channel`.
-    - ``mcpwm_capture_enable_channel`` and ``mcpwm_capture_disable_channel`` are replaced by :cpp:func:`mcpwm_new_capture_channel` and :cpp:func:`mcpwm_del_capture_channel`.
+    - ``mcpwm_capture_enable_channel`` and ``mcpwm_capture_disable_channel`` are replaced by :cpp:func:`mcpwm_capture_channel_enable` and :cpp:func:`mcpwm_capture_channel_disable`.
     - ``mcpwm_capture_signal_get_value`` and ``mcpwm_capture_signal_get_edge``: Capture timer count value and capture edge are provided in the capture event callback, via :cpp:type:`mcpwm_capture_event_data_t`. Capture data are only valuable when capture event happens. Providing single API to fetch capture data is meaningless.
     - ``mcpwm_capture_signal_get_value`` and ``mcpwm_capture_signal_get_edge``: Capture timer count value and capture edge are provided in the capture event callback, via :cpp:type:`mcpwm_capture_event_data_t`. Capture data are only valuable when capture event happens. Providing single API to fetch capture data is meaningless.
     - ``mcpwm_sync_enable`` is removed. It's duplicated to :cpp:func:`mcpwm_sync_configure`.
     - ``mcpwm_sync_enable`` is removed. It's duplicated to :cpp:func:`mcpwm_sync_configure`.
     - ``mcpwm_sync_configure`` is replaced by :cpp:func:`mcpwm_timer_set_phase_on_sync`.
     - ``mcpwm_sync_configure`` is replaced by :cpp:func:`mcpwm_timer_set_phase_on_sync`.

+ 2 - 2
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md

@@ -4,11 +4,11 @@
 
 
 (See the README.md file in the upper level 'examples' directory for more information about examples.)
 (See the README.md file in the upper level 'examples' directory for more information about examples.)
 
 
-This example mainly illustrates how to drive a brushed DC motor by generating two specific PWM signals. However the PWM signals from ESP chip can't drive motors directly as the motor usually consumes high current. So an H-bridge like [DRV8848](https://www.ti.com/product/DRV8848) should be used to provide the needed voltage and current for brushed DC motor. To simplify the DC motor control of MCPWM peripheral driver, there's a component called [bdc_motor](components/bdc_motor/README.md) which abstracts the common operations into a generic interface. The most useful operations are: `forward`, `reverse`, `coast` and `brake`.
+This example mainly illustrates how to drive a brushed DC motor by generating two specific PWM signals. However the PWM signals from ESP chip can't drive motors directly as the motor usually consumes high current. So an H-bridge like [DRV8848](https://www.ti.com/product/DRV8848) should be used to provide the needed voltage and current for brushed DC motor. To simplify the DC motor control of MCPWM peripheral driver, there's a component called [bdc_motor](https://components.espressif.com/component/espressif/bdc_motor) which abstracts the common operations into a generic interface. The most useful operations are: `forward`, `reverse`, `coast` and `brake`.
 
 
 To measure the speed of motor, a photoelectric encoder is used to generate the "speed feedback" signals (e.g. a pair of quadrature signal). In the example, we use the PCNT peripheral to decode that quadrature signals. For more information, please refer to [rotary encoder example](../../pcnt/rotary_encoder/README.md) as well.
 To measure the speed of motor, a photoelectric encoder is used to generate the "speed feedback" signals (e.g. a pair of quadrature signal). In the example, we use the PCNT peripheral to decode that quadrature signals. For more information, please refer to [rotary encoder example](../../pcnt/rotary_encoder/README.md) as well.
 
 
-The example uses a simple PID algorithm to keep the motor spin in a stable speed. The PID component is fetched from the [IDF Component Registry](https://components.espressif.com/component/espressif/pid_ctrl).
+The example uses a simple PID algorithm to keep the motor spin in a stable speed. Like the [bdc_motor](https://components.espressif.com/component/espressif/bdc_motor), the [PID component](https://components.espressif.com/component/espressif/pid_ctrl) is also managed by the component manager. These components' dependencies are listed in the [manifest file](main/idf_component.yml).
 
 
 ## How to Use Example
 ## How to Use Example
 
 

+ 0 - 9
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/CMakeLists.txt

@@ -1,9 +0,0 @@
-set(srcs "src/bdc_motor.c")
-
-if(CONFIG_SOC_MCPWM_SUPPORTED)
-    list(APPEND srcs "src/bdc_motor_mcpwm_impl.c")
-endif()
-
-idf_component_register(SRCS ${srcs}
-                       INCLUDE_DIRS "include" "interface"
-                       PRIV_REQUIRES "driver")

+ 0 - 7
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/README.md

@@ -1,7 +0,0 @@
-# Brushed DC Motor Component
-
-This directory contains an implementation for Brushed DC Motor by different peripherals. Currently only MCPWM is supported as the BDC motor backend.
-
-To learn more about how to use this component, please check API Documentation from header file [bdc_motor.h](./include/bdc_motor.h).
-
-Please note that this component is not considered to be a part of ESP-IDF stable API. It may change and it may be removed in the future releases.

+ 0 - 145
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/include/bdc_motor.h

@@ -1,145 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#pragma once
-
-#include <stdint.h>
-#include "esp_err.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Brushed DC Motor handle
- */
-typedef struct bdc_motor_t *bdc_motor_handle_t;
-
-/**
- * @brief Enable BDC motor
- *
- * @param motor: BDC Motor handle
- *
- * @return
- *      - ESP_OK: Enable motor successfully
- *      - ESP_ERR_INVALID_ARG: Enable motor failed because of invalid parameters
- *      - ESP_FAIL: Enable motor failed because other error occurred
- */
-esp_err_t bdc_motor_enable(bdc_motor_handle_t motor);
-
-/**
- * @brief Disable BDC motor
- *
- * @param motor: BDC Motor handle
- *
- * @return
- *      - ESP_OK: Disable motor successfully
- *      - ESP_ERR_INVALID_ARG: Disable motor failed because of invalid parameters
- *      - ESP_FAIL: Disable motor failed because other error occurred
- */
-esp_err_t bdc_motor_disable(bdc_motor_handle_t motor);
-
-/**
- * @brief Set speed for bdc motor
- *
- * @param motor: BDC Motor handle
- * @param speed: BDC speed
- *
- * @return
- *      - ESP_OK: Set motor speed successfully
- *      - ESP_ERR_INVALID_ARG: Set motor speed failed because of invalid parameters
- *      - ESP_FAIL: Set motor speed failed because other error occurred
- */
-esp_err_t bdc_motor_set_speed(bdc_motor_handle_t motor, uint32_t speed);
-
-/**
- * @brief Forward BDC motor
- *
- * @param motor: BDC Motor handle
- *
- * @return
- *      - ESP_OK: Forward motor successfully
- *      - ESP_FAIL: Forward motor failed because some other error occurred
- */
-esp_err_t bdc_motor_forward(bdc_motor_handle_t motor);
-
-/**
- * @brief Reverse BDC Motor
- *
- * @param strip: BDC Motor handle
- *
- * @return
- *      - ESP_OK: Reverse motor successfully
- *      - ESP_FAIL: Reverse motor failed because some other error occurred
- */
-esp_err_t bdc_motor_reverse(bdc_motor_handle_t motor);
-
-/**
- * @brief Stop motor in a coast way (a.k.a Fast Decay)
- *
- * @param motor: BDC Motor handle
- *
- * @return
- *      - ESP_OK: Stop motor successfully
- *      - ESP_FAIL: Stop motor failed because some other error occurred
- */
-esp_err_t bdc_motor_coast(bdc_motor_handle_t motor);
-
-/**
- * @brief Stop motor in a brake way (a.k.a Slow Decay)
- *
- * @param motor: BDC Motor handle
- *
- * @return
- *      - ESP_OK: Stop motor successfully
- *      - ESP_FAIL: Stop motor failed because some other error occurred
- */
-esp_err_t bdc_motor_brake(bdc_motor_handle_t motor);
-
-/**
- * @brief Free BDC Motor resources
- *
- * @param strip: BDC Motor handle
- *
- * @return
- *      - ESP_OK: Free resources successfully
- *      - ESP_FAIL: Free resources failed because error occurred
- */
-esp_err_t bdc_motor_del(bdc_motor_handle_t motor);
-
-/**
- * @brief BDC Motor Configuration
- */
-typedef struct {
-    uint32_t pwma_gpio_num; /*!< BDC Motor PWM A gpio number */
-    uint32_t pwmb_gpio_num; /*!< BDC Motor PWM B gpio number */
-    uint32_t pwm_freq_hz;   /*!< PWM frequency, in Hz */
-} bdc_motor_config_t;
-
-/**
- * @brief BDC Motor MCPWM specific configuration
- */
-typedef struct {
-    int group_id;           /*!< MCPWM group number */
-    uint32_t resolution_hz; /*!< MCPWM timer resolution */
-} bdc_motor_mcpwm_config_t;
-
-/**
- * @brief Create BDC Motor based on MCPWM peripheral
- *
- * @param motor_config: BDC Motor configuration
- * @param mcpwm_config: MCPWM specific configuration
- * @param ret_motor Returned BDC Motor handle
- * @return
- *      - ESP_OK: Create BDC Motor handle successfully
- *      - ESP_ERR_INVALID_ARG: Create BDC Motor handle failed because of invalid argument
- *      - ESP_ERR_NO_MEM: Create BDC Motor handle failed because of out of memory
- *      - ESP_FAIL: Create BDC Motor handle failed because some other error
- */
-esp_err_t bdc_motor_new_mcpwm_device(const bdc_motor_config_t *motor_config, const bdc_motor_mcpwm_config_t *mcpwm_config, bdc_motor_handle_t *ret_motor);
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 116
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/interface/bdc_motor_interface.h

@@ -1,116 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#pragma once
-
-#include <stdint.h>
-#include "esp_err.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct bdc_motor_t bdc_motor_t; /*!< Type of BDC motor */
-
-/**
- * @brief BDC motor interface definition
- */
-struct bdc_motor_t {
-    /**
-     * @brief Enable BDC motor
-     *
-     * @param motor: BDC Motor handle
-     *
-     * @return
-     *      - ESP_OK: Enable motor successfully
-     *      - ESP_ERR_INVALID_ARG: Enable motor failed because of invalid parameters
-     *      - ESP_FAIL: Enable motor failed because other error occurred
-     */
-    esp_err_t (*enable)(bdc_motor_t *motor);
-
-    /**
-     * @brief Disable BDC motor
-     *
-     * @param motor: BDC Motor handle
-     *
-     * @return
-     *      - ESP_OK: Disable motor successfully
-     *      - ESP_ERR_INVALID_ARG: Disable motor failed because of invalid parameters
-     *      - ESP_FAIL: Disable motor failed because other error occurred
-     */
-    esp_err_t (*disable)(bdc_motor_t *motor);
-
-    /**
-     * @brief Set speed for bdc motor
-     *
-     * @param motor: BDC Motor handle
-     * @param speed: BDC speed
-     *
-     * @return
-     *      - ESP_OK: Set motor speed successfully
-     *      - ESP_ERR_INVALID_ARG: Set motor speed failed because of invalid parameters
-     *      - ESP_FAIL: Set motor speed failed because other error occurred
-     */
-    esp_err_t (*set_speed)(bdc_motor_t *motor, uint32_t speed);
-
-    /**
-     * @brief Forward BDC motor
-     *
-     * @param motor: BDC Motor handle
-     *
-     * @return
-     *      - ESP_OK: Forward motor successfully
-     *      - ESP_FAIL: Forward motor failed because some other error occurred
-     */
-    esp_err_t (*forward)(bdc_motor_t *motor);
-
-    /**
-     * @brief Reverse BDC Motor
-     *
-     * @param motor: BDC Motor handle
-     *
-     * @return
-     *      - ESP_OK: Reverse motor successfully
-     *      - ESP_FAIL: Reverse motor failed because some other error occurred
-     */
-    esp_err_t (*reverse)(bdc_motor_t *motor);
-
-    /**
-     * @brief Stop motor in a coast way (a.k.a Fast Decay)
-     *
-     * @param motor: BDC Motor handle
-     *
-     * @return
-     *      - ESP_OK: Stop motor successfully
-     *      - ESP_FAIL: Stop motor failed because some other error occurred
-     */
-    esp_err_t (*coast)(bdc_motor_t *motor);
-
-    /**
-     * @brief Stop motor in a brake way (a.k.a Slow Decay)
-     *
-     * @param motor: BDC Motor handle
-     *
-     * @return
-     *      - ESP_OK: Stop motor successfully
-     *      - ESP_FAIL: Stop motor failed because some other error occurred
-     */
-    esp_err_t (*brake)(bdc_motor_t *motor);
-
-    /**
-     * @brief Free BDC Motor handle resources
-     *
-     * @param motor: BDC Motor handle
-     *
-     * @return
-     *      - ESP_OK: Free resources successfully
-     *      - ESP_FAIL: Free resources failed because error occurred
-     */
-    esp_err_t (*del)(bdc_motor_t *motor);
-};
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 62
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor.c

@@ -1,62 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include "esp_log.h"
-#include "esp_check.h"
-#include "bdc_motor.h"
-#include "bdc_motor_interface.h"
-
-static const char *TAG = "bdc_motor";
-
-esp_err_t bdc_motor_enable(bdc_motor_handle_t motor)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->enable(motor);
-}
-
-esp_err_t bdc_motor_disable(bdc_motor_handle_t motor)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->disable(motor);
-}
-
-esp_err_t bdc_motor_set_speed(bdc_motor_handle_t motor, uint32_t speed)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->set_speed(motor, speed);
-}
-
-esp_err_t bdc_motor_forward(bdc_motor_handle_t motor)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->forward(motor);
-}
-
-esp_err_t bdc_motor_reverse(bdc_motor_handle_t motor)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->reverse(motor);
-}
-
-esp_err_t bdc_motor_coast(bdc_motor_handle_t motor)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->coast(motor);
-}
-
-esp_err_t bdc_motor_brake(bdc_motor_handle_t motor)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->brake(motor);
-}
-
-esp_err_t bdc_motor_del(bdc_motor_handle_t motor)
-{
-    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
-    return motor->del(motor);
-}

+ 0 - 185
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor_mcpwm_impl.c

@@ -1,185 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include "esp_log.h"
-#include "esp_check.h"
-#include "driver/mcpwm_prelude.h"
-#include "bdc_motor.h"
-#include "bdc_motor_interface.h"
-
-static const char *TAG = "bdc_motor_mcpwm";
-
-typedef struct {
-    bdc_motor_t base;
-    mcpwm_timer_handle_t timer;
-    mcpwm_oper_handle_t operator;
-    mcpwm_cmpr_handle_t cmpa;
-    mcpwm_cmpr_handle_t cmpb;
-    mcpwm_gen_handle_t gena;
-    mcpwm_gen_handle_t genb;
-} bdc_motor_mcpwm_obj;
-
-static esp_err_t bdc_motor_mcpwm_set_speed(bdc_motor_t *motor, uint32_t speed)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    ESP_RETURN_ON_ERROR(mcpwm_comparator_set_compare_value(mcpwm_motor->cmpa, speed), TAG, "set compare value failed");
-    ESP_RETURN_ON_ERROR(mcpwm_comparator_set_compare_value(mcpwm_motor->cmpb, speed), TAG, "set compare value failed");
-    return ESP_OK;
-}
-
-static esp_err_t bdc_motor_mcpwm_enable(bdc_motor_t *motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    ESP_RETURN_ON_ERROR(mcpwm_timer_enable(mcpwm_motor->timer), TAG, "enable timer failed");
-    ESP_RETURN_ON_ERROR(mcpwm_timer_start_stop(mcpwm_motor->timer, MCPWM_TIMER_START_NO_STOP), TAG, "start timer failed");
-    return ESP_OK;
-}
-
-static esp_err_t bdc_motor_mcpwm_disable(bdc_motor_t *motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    ESP_RETURN_ON_ERROR(mcpwm_timer_start_stop(mcpwm_motor->timer, MCPWM_TIMER_STOP_EMPTY), TAG, "stop timer failed");
-    ESP_RETURN_ON_ERROR(mcpwm_timer_disable(mcpwm_motor->timer), TAG, "disable timer failed");
-    return ESP_OK;
-}
-
-static esp_err_t bdc_motor_mcpwm_forward(bdc_motor_t *motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, -1, true), TAG, "disable force level for gena failed");
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, 0, true), TAG, "set force level for genb failed");
-    return ESP_OK;
-}
-
-static esp_err_t bdc_motor_mcpwm_reverse(bdc_motor_t *motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, -1, true), TAG, "disable force level for genb failed");
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, 0, true), TAG, "set force level for gena failed");
-    return ESP_OK;
-}
-
-static esp_err_t bdc_motor_mcpwm_coast(bdc_motor_t *motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, 0, true), TAG, "set force level for gena failed");
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, 0, true), TAG, "set force level for genb failed");
-    return ESP_OK;
-}
-
-static esp_err_t bdc_motor_mcpwm_brake(bdc_motor_t *motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, 1, true), TAG, "set force level for gena failed");
-    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, 1, true), TAG, "set force level for genb failed");
-    return ESP_OK;
-}
-
-static esp_err_t bdc_motor_mcpwm_del(bdc_motor_t *motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);
-    mcpwm_del_generator(mcpwm_motor->gena);
-    mcpwm_del_generator(mcpwm_motor->genb);
-    mcpwm_del_comparator(mcpwm_motor->cmpa);
-    mcpwm_del_comparator(mcpwm_motor->cmpb);
-    mcpwm_del_operator(mcpwm_motor->operator);
-    mcpwm_del_timer(mcpwm_motor->timer);
-    free(mcpwm_motor);
-    return ESP_OK;
-}
-
-esp_err_t bdc_motor_new_mcpwm_device(const bdc_motor_config_t *motor_config, const bdc_motor_mcpwm_config_t *mcpwm_config, bdc_motor_handle_t *ret_motor)
-{
-    bdc_motor_mcpwm_obj *mcpwm_motor = NULL;
-    esp_err_t ret = ESP_OK;
-    ESP_GOTO_ON_FALSE(motor_config && mcpwm_config && ret_motor, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
-    mcpwm_motor = calloc(1, sizeof(bdc_motor_mcpwm_obj));
-    ESP_GOTO_ON_FALSE(mcpwm_motor, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt motor");
-
-    // mcpwm timer
-    mcpwm_timer_config_t timer_config = {
-        .group_id = mcpwm_config->group_id,
-        .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
-        .resolution_hz = mcpwm_config->resolution_hz,
-        .period_ticks = mcpwm_config->resolution_hz / motor_config->pwm_freq_hz,
-        .count_mode = MCPWM_TIMER_COUNT_MODE_UP,
-    };
-    ESP_GOTO_ON_ERROR(mcpwm_new_timer(&timer_config, &mcpwm_motor->timer), err, TAG, "create MCPWM timer failed");
-
-    mcpwm_operator_config_t operator_config = {
-        .group_id = mcpwm_config->group_id,
-    };
-    ESP_GOTO_ON_ERROR(mcpwm_new_operator(&operator_config, &mcpwm_motor->operator), err, TAG, "create MCPWM operator failed");
-
-    ESP_GOTO_ON_ERROR(mcpwm_operator_connect_timer(mcpwm_motor->operator, mcpwm_motor->timer), err, TAG, "connect timer and operator failed");
-
-    mcpwm_comparator_config_t comparator_config = {
-        .flags.update_cmp_on_tez = true,
-    };
-    ESP_GOTO_ON_ERROR(mcpwm_new_comparator(mcpwm_motor->operator, &comparator_config, &mcpwm_motor->cmpa), err, TAG, "create comparator failed");
-    ESP_GOTO_ON_ERROR(mcpwm_new_comparator(mcpwm_motor->operator, &comparator_config, &mcpwm_motor->cmpb), err, TAG, "create comparator failed");
-
-    // set the initial compare value for both comparators
-    mcpwm_comparator_set_compare_value(mcpwm_motor->cmpa, 0);
-    mcpwm_comparator_set_compare_value(mcpwm_motor->cmpb, 0);
-
-    mcpwm_generator_config_t generator_config = {
-        .gen_gpio_num = motor_config->pwma_gpio_num,
-    };
-    ESP_GOTO_ON_ERROR(mcpwm_new_generator(mcpwm_motor->operator, &generator_config, &mcpwm_motor->gena), err, TAG, "create generator failed");
-    generator_config.gen_gpio_num = motor_config->pwmb_gpio_num;
-    ESP_GOTO_ON_ERROR(mcpwm_new_generator(mcpwm_motor->operator, &generator_config, &mcpwm_motor->genb), err, TAG, "create generator failed");
-
-    mcpwm_generator_set_actions_on_timer_event(mcpwm_motor->gena,
-            MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
-            MCPWM_GEN_TIMER_EVENT_ACTION_END());
-    mcpwm_generator_set_actions_on_compare_event(mcpwm_motor->gena,
-            MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, mcpwm_motor->cmpa, MCPWM_GEN_ACTION_LOW),
-            MCPWM_GEN_COMPARE_EVENT_ACTION_END());
-    mcpwm_generator_set_actions_on_timer_event(mcpwm_motor->genb,
-            MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
-            MCPWM_GEN_TIMER_EVENT_ACTION_END());
-    mcpwm_generator_set_actions_on_compare_event(mcpwm_motor->genb,
-            MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, mcpwm_motor->cmpb, MCPWM_GEN_ACTION_LOW),
-            MCPWM_GEN_COMPARE_EVENT_ACTION_END());
-
-    mcpwm_motor->base.enable = bdc_motor_mcpwm_enable;
-    mcpwm_motor->base.disable = bdc_motor_mcpwm_disable;
-    mcpwm_motor->base.forward = bdc_motor_mcpwm_forward;
-    mcpwm_motor->base.reverse = bdc_motor_mcpwm_reverse;
-    mcpwm_motor->base.coast = bdc_motor_mcpwm_coast;
-    mcpwm_motor->base.brake = bdc_motor_mcpwm_brake;
-    mcpwm_motor->base.set_speed = bdc_motor_mcpwm_set_speed;
-    mcpwm_motor->base.del = bdc_motor_mcpwm_del;
-    *ret_motor = &mcpwm_motor->base;
-    return ESP_OK;
-
-err:
-    if (mcpwm_motor) {
-        if (mcpwm_motor->gena) {
-            mcpwm_del_generator(mcpwm_motor->gena);
-        }
-        if (mcpwm_motor->genb) {
-            mcpwm_del_generator(mcpwm_motor->genb);
-        }
-        if (mcpwm_motor->cmpa) {
-            mcpwm_del_comparator(mcpwm_motor->cmpa);
-        }
-        if (mcpwm_motor->cmpb) {
-            mcpwm_del_comparator(mcpwm_motor->cmpb);
-        }
-        if (mcpwm_motor->operator) {
-            mcpwm_del_operator(mcpwm_motor->operator);
-        }
-        if (mcpwm_motor->timer) {
-            mcpwm_del_timer(mcpwm_motor->timer);
-        }
-        free(mcpwm_motor);
-    }
-    return ret;
-}

+ 1 - 0
examples/peripherals/mcpwm/mcpwm_bdc_speed_control/main/idf_component.yml

@@ -1,2 +1,3 @@
 dependencies:
 dependencies:
   pid_ctrl: "^0.1.1"
   pid_ctrl: "^0.1.1"
+  bdc_motor: "^0.1.0"

+ 9 - 0
examples/peripherals/mcpwm/mcpwm_bldc_hall_control/main/mcpwm_bldc_hall_control_example_main.c

@@ -321,6 +321,15 @@ void app_main(void)
         ESP_ERROR_CHECK(mcpwm_capture_channel_register_event_callbacks(cap_channels[i], &cbs, task_to_notify));
         ESP_ERROR_CHECK(mcpwm_capture_channel_register_event_callbacks(cap_channels[i], &cbs, task_to_notify));
     }
     }
 
 
+    ESP_LOGI(TAG, "Enable capture channels");
+    for (int i = 0; i < 3; i++) {
+        ESP_ERROR_CHECK(mcpwm_capture_channel_enable(cap_channels[i]));
+    }
+
+    ESP_LOGI(TAG, "Enable and start capture timer");
+    ESP_ERROR_CHECK(mcpwm_capture_timer_enable(cap_timer));
+    ESP_ERROR_CHECK(mcpwm_capture_timer_start(cap_timer));
+
     ESP_LOGI(TAG, "Start a timer to adjust motor speed periodically");
     ESP_LOGI(TAG, "Start a timer to adjust motor speed periodically");
     esp_timer_handle_t periodic_timer = NULL;
     esp_timer_handle_t periodic_timer = NULL;
     const esp_timer_create_args_t periodic_timer_args = {
     const esp_timer_create_args_t periodic_timer_args = {

+ 3 - 0
examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/main/mcpwm_capture_hc_sr04.c

@@ -83,6 +83,9 @@ void app_main(void)
     };
     };
     ESP_ERROR_CHECK(mcpwm_capture_channel_register_event_callbacks(cap_chan, &cbs, cur_task));
     ESP_ERROR_CHECK(mcpwm_capture_channel_register_event_callbacks(cap_chan, &cbs, cur_task));
 
 
+    ESP_LOGI(TAG, "Enable capture channel");
+    ESP_ERROR_CHECK(mcpwm_capture_channel_enable(cap_chan));
+
     ESP_LOGI(TAG, "Configure Trig pin");
     ESP_LOGI(TAG, "Configure Trig pin");
     gpio_config_t io_conf = {
     gpio_config_t io_conf = {
         .mode = GPIO_MODE_OUTPUT,
         .mode = GPIO_MODE_OUTPUT,

+ 1 - 0
examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py

@@ -12,5 +12,6 @@ def test_hc_sr04_example(dut: Dut) -> None:
     dut.expect_exact('example: Install capture timer')
     dut.expect_exact('example: Install capture timer')
     dut.expect_exact('example: Install capture channel')
     dut.expect_exact('example: Install capture channel')
     dut.expect_exact('example: Register capture callback')
     dut.expect_exact('example: Register capture callback')
+    dut.expect_exact('example: Enable capture channel')
     dut.expect_exact('example: Configure Trig pin')
     dut.expect_exact('example: Configure Trig pin')
     dut.expect_exact('example: Enable and start capture timer')
     dut.expect_exact('example: Enable and start capture timer')