From 0d881fc9e091357161b6be9a25a40caf288c41e2 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 8 Aug 2022 14:50:58 +0800 Subject: [PATCH 1/4] driver: specify the interrupt priority Closes https://github.com/espressif/esp-idf/issues/9520 --- components/driver/i2s/i2s_common.c | 4 ++-- components/driver/mcpwm/mcpwm_private.h | 4 ++-- components/driver/pulse_cnt.c | 4 ++-- components/driver/rmt/rmt_private.h | 4 ++-- components/esp_hw_support/gdma.c | 4 ++-- components/esp_lcd/src/esp_lcd_panel_io_i2s.c | 2 +- components/esp_lcd/src/esp_lcd_panel_io_i80.c | 2 +- components/esp_lcd/src/esp_lcd_rgb_panel.c | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index 8aca6e30f6..807c0fd672 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -55,10 +55,10 @@ // 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 #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) #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 #endif //CONFIG_I2S_ISR_IRAM_SAFE #define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) diff --git a/components/driver/mcpwm/mcpwm_private.h b/components/driver/mcpwm/mcpwm_private.h index b5881280f8..eb176fc29e 100644 --- a/components/driver/mcpwm/mcpwm_private.h +++ b/components/driver/mcpwm/mcpwm_private.h @@ -29,9 +29,9 @@ extern "C" { #endif #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 -#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 #define MCPWM_PERIPH_CLOCK_PRE_SCALE (2) diff --git a/components/driver/pulse_cnt.c b/components/driver/pulse_cnt.c index ee9e88ee87..cb4081673d 100644 --- a/components/driver/pulse_cnt.c +++ b/components/driver/pulse_cnt.c @@ -41,9 +41,9 @@ #endif #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 -#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 #define PCNT_PM_LOCK_NAME_LEN_MAX 16 diff --git a/components/driver/rmt/rmt_private.h b/components/driver/rmt/rmt_private.h index 19a80b028c..a5e0319a1f 100644 --- a/components/driver/rmt/rmt_private.h +++ b/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 #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 -#define RMT_INTR_ALLOC_FLAG ESP_INTR_FLAG_SHARED +#define RMT_INTR_ALLOC_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED) #endif // Hopefully the channel offset won't change in other targets diff --git a/components/esp_hw_support/gdma.c b/components/esp_hw_support/gdma.c index cd2e6cf62c..6ffa28fc8b 100644 --- a/components/esp_hw_support/gdma.c +++ b/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 int isr_flags = GDMA_INTR_ALLOC_FLAGS; #if SOC_GDMA_TX_RX_SHARE_INTERRUPT - isr_flags |= ESP_INTR_FLAG_SHARED; + isr_flags |= ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED; #endif 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, @@ -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 int isr_flags = GDMA_INTR_ALLOC_FLAGS; #if SOC_GDMA_TX_RX_SHARE_INTERRUPT - isr_flags |= ESP_INTR_FLAG_SHARED; + isr_flags |= ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED; #endif 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, diff --git a/components/esp_lcd/src/esp_lcd_panel_io_i2s.c b/components/esp_lcd/src/esp_lcd_panel_io_i2s.c index 282b8129f8..22b20499c4 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_i2s.c +++ b/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); // 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 - 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, (uint32_t)i2s_ll_get_intr_status_reg(bus->hal.dev), I2S_LL_EVENT_TX_EOF, lcd_default_isr_handler, bus, &bus->intr); diff --git a/components/esp_lcd/src/esp_lcd_panel_io_i80.c b/components/esp_lcd/src/esp_lcd_panel_io_i80.c index fb9aa5cc8f..f5e42e0836 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_i80.c +++ b/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); // install interrupt service, (LCD peripheral shares the same interrupt source with Camera peripheral with different mask) // 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, (uint32_t)lcd_ll_get_interrupt_status_reg(bus->hal.dev), LCD_LL_EVENT_TRANS_DONE, lcd_default_isr_handler, bus, &bus->intr); diff --git a/components/esp_lcd/src/esp_lcd_rgb_panel.c b/components/esp_lcd/src/esp_lcd_rgb_panel.c index 8aa6ea2168..a8c8c992a1 100644 --- a/components/esp_lcd/src/esp_lcd_rgb_panel.c +++ b/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; } // 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, (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); From 970d4cab09d88c327be8fb38cda815967d8e5585 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 8 Aug 2022 15:47:30 +0800 Subject: [PATCH 2/4] driver: add doc on how to unregister event callbacks Closes https://github.com/espressif/esp-idf/pull/9523 --- components/driver/gptimer.c | 2 +- components/driver/include/driver/gptimer.h | 3 ++- components/driver/include/driver/mcpwm_cap.h | 2 ++ components/driver/include/driver/mcpwm_cmpr.h | 2 ++ components/driver/include/driver/mcpwm_fault.h | 2 ++ components/driver/include/driver/mcpwm_oper.h | 2 ++ components/driver/include/driver/mcpwm_timer.h | 3 +++ components/driver/include/driver/pulse_cnt.h | 3 ++- components/driver/mcpwm/mcpwm_timer.c | 2 +- components/driver/pulse_cnt.c | 2 +- 10 files changed, 18 insertions(+), 5 deletions(-) diff --git a/components/driver/gptimer.c b/components/driver/gptimer.c index 7f921c389c..f9d8f68c68 100644 --- a/components/driver/gptimer.c +++ b/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; 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; int group_id = group->group_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 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` 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, diff --git a/components/driver/include/driver/gptimer.h b/components/driver/include/driver/gptimer.h index e6fe50420d..1f4f9cd9a8 100644 --- a/components/driver/include/driver/gptimer.h +++ b/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 * * @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] cbs Group of callback functions diff --git a/components/driver/include/driver/mcpwm_cap.h b/components/driver/include/driver/mcpwm_cap.h index 54aa3db59b..782b7042ab 100644 --- a/components/driver/include/driver/mcpwm_cap.h +++ b/components/driver/include/driver/mcpwm_cap.h @@ -168,6 +168,8 @@ typedef struct { /** * @brief Set event callbacks for MCPWM capture channel * + * @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] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly diff --git a/components/driver/include/driver/mcpwm_cmpr.h b/components/driver/include/driver/mcpwm_cmpr.h index d539f8a220..8ebae75736 100644 --- a/components/driver/include/driver/mcpwm_cmpr.h +++ b/components/driver/include/driver/mcpwm_cmpr.h @@ -63,6 +63,8 @@ typedef struct { /** * @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] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly diff --git a/components/driver/include/driver/mcpwm_fault.h b/components/driver/include/driver/mcpwm_fault.h index ddc635c679..e9833c4996 100644 --- a/components/driver/include/driver/mcpwm_fault.h +++ b/components/driver/include/driver/mcpwm_fault.h @@ -97,6 +97,8 @@ typedef struct { /** * @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] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly diff --git a/components/driver/include/driver/mcpwm_oper.h b/components/driver/include/driver/mcpwm_oper.h index 5f89f806fc..bc30887295 100644 --- a/components/driver/include/driver/mcpwm_oper.h +++ b/components/driver/include/driver/mcpwm_oper.h @@ -119,6 +119,8 @@ typedef struct { /** * @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] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly diff --git a/components/driver/include/driver/mcpwm_timer.h b/components/driver/include/driver/mcpwm_timer.h index 3bcec03ab5..1cb1d6d8cf 100644 --- a/components/driver/include/driver/mcpwm_timer.h +++ b/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 * + * @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] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly diff --git a/components/driver/include/driver/pulse_cnt.h b/components/driver/include/driver/pulse_cnt.h index ccaffead23..cef84b447f 100644 --- a/components/driver/include/driver/pulse_cnt.h +++ b/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 * * @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] cbs Group of callback functions diff --git a/components/driver/mcpwm/mcpwm_timer.c b/components/driver/mcpwm/mcpwm_timer.c index 09c22c287d..31ff2ded68 100644 --- a/components/driver/mcpwm/mcpwm_timer.c +++ b/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_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; int group_id = group->group_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 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; 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), diff --git a/components/driver/pulse_cnt.c b/components/driver/pulse_cnt.c index cb4081673d..6f8237d109 100644 --- a/components/driver/pulse_cnt.c +++ b/components/driver/pulse_cnt.c @@ -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"); // 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; int group_id = group->group_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 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; 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), From 1d4c08cef441ba45ecf75a73de9885db549a867e Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 9 Aug 2022 13:51:56 +0800 Subject: [PATCH 3/4] mcpwm: added enable/disable functions Closes https://github.com/espressif/esp-idf/pull/9523 --- components/driver/deprecated/mcpwm_legacy.c | 2 +- components/driver/gptimer.c | 2 +- components/driver/include/driver/mcpwm_cap.h | 32 +++++++++++++ components/driver/mcpwm/mcpwm_cap.c | 46 ++++++++++++++++--- components/driver/mcpwm/mcpwm_private.h | 8 +++- components/driver/pulse_cnt.c | 2 +- .../test_apps/mcpwm/main/test_mcpwm_cap.c | 15 ++++++ .../test_apps/mcpwm/main/test_mcpwm_cmpr.c | 2 +- .../test_apps/mcpwm/main/test_mcpwm_iram.c | 4 ++ docs/en/api-reference/peripherals/mcpwm.rst | 5 ++ .../release-5.x/peripherals.rst | 2 +- .../mcpwm_bldc_hall_control_example_main.c | 9 ++++ .../main/mcpwm_capture_hc_sr04.c | 3 ++ .../mcpwm_capture_hc_sr04/pytest_hc_sr04.py | 1 + 14 files changed, 121 insertions(+), 12 deletions(-) diff --git a/components/driver/deprecated/mcpwm_legacy.c b/components/driver/deprecated/mcpwm_legacy.c index 51a501563d..c7aeaa944c 100644 --- a/components/driver/deprecated/mcpwm_legacy.c +++ b/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_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); - // 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_clear_capture_status(hal->dev, 1 << cap_channel); mcpwm_critical_exit(mcpwm_num); diff --git a/components/driver/gptimer.c b/components/driver/gptimer.c index f9d8f68c68..39732aa1c2 100644 --- a/components/driver/gptimer.c +++ b/components/driver/gptimer.c @@ -318,7 +318,7 @@ esp_err_t gptimer_enable(gptimer_handle_t timer) if (timer->pm_lock) { 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) { ESP_RETURN_ON_ERROR(esp_intr_enable(timer->intr), TAG, "enable interrupt service failed"); } diff --git a/components/driver/include/driver/mcpwm_cap.h b/components/driver/include/driver/mcpwm_cap.h index 782b7042ab..d40ef2fd1a 100644 --- a/components/driver/include/driver/mcpwm_cap.h +++ b/components/driver/include/driver/mcpwm_cap.h @@ -134,6 +134,8 @@ typedef struct { /** * @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] config MCPWM capture channel configuration * @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); +/** + * @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 * @note The callbacks are all running under ISR environment @@ -168,6 +197,7 @@ typedef struct { /** * @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()` @@ -176,6 +206,7 @@ typedef struct { * @return * - ESP_OK: Set event callbacks successfully * - 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_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); @@ -187,6 +218,7 @@ esp_err_t mcpwm_capture_channel_register_event_callbacks(mcpwm_cap_channel_handl * @return * - ESP_OK: Trigger software catch successfully * - 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_err_t mcpwm_capture_channel_trigger_soft_catch(mcpwm_cap_channel_handle_t cap_channel); diff --git a/components/driver/mcpwm/mcpwm_cap.c b/components/driver/mcpwm/mcpwm_cap.c index e45804a905..75bb74045f 100644 --- a/components/driver/mcpwm/mcpwm_cap.c +++ b/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; 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_posedge(hal->dev, cap_chan_id, config->flags.pos_edge); 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->fsm = MCPWM_CAP_CHAN_FSM_INIT; *ret_cap_channel = cap_chan; ESP_LOGD(TAG, "new capture channel (%d,%d) at %p", group->group_id, cap_chan_id, cap_chan); return ESP_OK; @@ -275,6 +275,7 @@ err: 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->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_group_t *group = cap_timer->group; 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)); portEXIT_CRITICAL(&group->spinlock); - // disable capture channel - mcpwm_ll_capture_enable_channel(group->hal.dev, cap_channel->cap_chan_id, false); - // recycle memory resource ESP_RETURN_ON_ERROR(mcpwm_capture_channel_destory(cap_channel), TAG, "destory capture channel failed"); 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_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 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, (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"); @@ -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_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_group_t *group = cap_timer->group; diff --git a/components/driver/mcpwm/mcpwm_private.h b/components/driver/mcpwm/mcpwm_private.h index eb176fc29e..5b5ef12e7b 100644 --- a/components/driver/mcpwm/mcpwm_private.h +++ b/components/driver/mcpwm/mcpwm_private.h @@ -193,6 +193,11 @@ typedef enum { MCPWM_CAP_TIMER_FSM_ENABLE, } 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 { 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 @@ -206,7 +211,8 @@ struct mcpwm_cap_channel_t { int cap_chan_id; // capture channel ID, index from 0 mcpwm_cap_timer_t *cap_timer; // which capture timer that the channel resides in 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 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 diff --git a/components/driver/pulse_cnt.c b/components/driver/pulse_cnt.c index 6f8237d109..cd56d273bb 100644 --- a/components/driver/pulse_cnt.c +++ b/components/driver/pulse_cnt.c @@ -283,7 +283,7 @@ esp_err_t pcnt_unit_enable(pcnt_unit_handle_t unit) if (unit->pm_lock) { 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) { ESP_RETURN_ON_ERROR(esp_intr_enable(unit->intr), TAG, "enable interrupt service failed"); } diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c index e1fd2f11e1..911f2e8dcc 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c +++ b/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}; 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"); TEST_ESP_OK(mcpwm_capture_timer_enable(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]); 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_capture_timer_disable(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_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"); mcpwm_capture_event_callbacks_t cbs = { .on_cap = soft_cap_callback, }; 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"); TEST_ESP_OK(mcpwm_capture_timer_enable(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); 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_del_capture_channel(cap_channel)); 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, }; TEST_ESP_OK(mcpwm_capture_timer_set_phase_on_sync(cap_timer, &sync_config)); + mcpwm_cap_channel_handle_t cap_channel = NULL; mcpwm_capture_channel_config_t cap_chan_config = { .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; 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)); vTaskDelay(pdMS_TO_TICKS(10)); 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)); printf("capture data after sync: %"PRIu32"\r\n", 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_timer(cap_timer)); TEST_ESP_OK(mcpwm_del_sync_src(soft_sync)); diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c index 93a60c85a0..e5a6d4d01f 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c +++ b/components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c @@ -76,7 +76,7 @@ TEST_CASE("mcpwm_comparator_event_callback", "[mcpwm]") .group_id = 0, }; 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_operator(&operator_config, &operator)); TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator)); diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_iram.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_iram.c index d65159c859..12227242ba 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_iram.c +++ b/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}; 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"); TEST_ESP_OK(mcpwm_capture_timer_enable(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]); 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_capture_timer_disable(cap_timer)); TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index 6166899582..dce2b56de6 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/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`. +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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/en/migration-guides/release-5.x/peripherals.rst b/docs/en/migration-guides/release-5.x/peripherals.rst index 7d2f3e15f8..15103a50cf 100644 --- a/docs/en/migration-guides/release-5.x/peripherals.rst +++ b/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_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_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_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`. diff --git a/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/main/mcpwm_bldc_hall_control_example_main.c b/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/main/mcpwm_bldc_hall_control_example_main.c index 8afae790b3..f6e4d86bd1 100644 --- a/examples/peripherals/mcpwm/mcpwm_bldc_hall_control/main/mcpwm_bldc_hall_control_example_main.c +++ b/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_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_timer_handle_t periodic_timer = NULL; const esp_timer_create_args_t periodic_timer_args = { diff --git a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/main/mcpwm_capture_hc_sr04.c b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/main/mcpwm_capture_hc_sr04.c index b18fbfe81e..10e8a55eef 100644 --- a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/main/mcpwm_capture_hc_sr04.c +++ b/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_LOGI(TAG, "Enable capture channel"); + ESP_ERROR_CHECK(mcpwm_capture_channel_enable(cap_chan)); + ESP_LOGI(TAG, "Configure Trig pin"); gpio_config_t io_conf = { .mode = GPIO_MODE_OUTPUT, diff --git a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py b/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py index 6e519dff82..70ca04bc69 100644 --- a/examples/peripherals/mcpwm/mcpwm_capture_hc_sr04/pytest_hc_sr04.py +++ b/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 channel') 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: Enable and start capture timer') From 6261eae50cd4b88781b6fec63c0007bfe6c8e2dc Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 11 Aug 2022 13:34:26 +0800 Subject: [PATCH 4/4] bdc_motor: component moved to registry --- .../mcpwm/mcpwm_bdc_speed_control/README.md | 4 +- .../components/bdc_motor/CMakeLists.txt | 9 - .../components/bdc_motor/README.md | 7 - .../components/bdc_motor/include/bdc_motor.h | 145 -------------- .../bdc_motor/interface/bdc_motor_interface.h | 116 ----------- .../components/bdc_motor/src/bdc_motor.c | 62 ------ .../bdc_motor/src/bdc_motor_mcpwm_impl.c | 185 ------------------ .../main/idf_component.yml | 1 + 8 files changed, 3 insertions(+), 526 deletions(-) delete mode 100644 examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/CMakeLists.txt delete mode 100644 examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/README.md delete mode 100644 examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/include/bdc_motor.h delete mode 100644 examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/interface/bdc_motor_interface.h delete mode 100644 examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor.c delete mode 100644 examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor_mcpwm_impl.c diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md index 09ab448a55..6693150462 100644 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/README.md +++ b/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.) -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. -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 diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/CMakeLists.txt b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/CMakeLists.txt deleted file mode 100644 index e8f680b259..0000000000 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/CMakeLists.txt +++ /dev/null @@ -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") diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/README.md b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/README.md deleted file mode 100644 index 8918067552..0000000000 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/README.md +++ /dev/null @@ -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. diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/include/bdc_motor.h b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/include/bdc_motor.h deleted file mode 100644 index 1b102d91f6..0000000000 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/include/bdc_motor.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#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 diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/interface/bdc_motor_interface.h b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/interface/bdc_motor_interface.h deleted file mode 100644 index 35e9697ac2..0000000000 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/interface/bdc_motor_interface.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#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 diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor.c b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor.c deleted file mode 100644 index fbbc440312..0000000000 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#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); -} diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor_mcpwm_impl.c b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor_mcpwm_impl.c deleted file mode 100644 index 2b502a6a44..0000000000 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/components/bdc_motor/src/bdc_motor_mcpwm_impl.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#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; -} diff --git a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/main/idf_component.yml b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/main/idf_component.yml index 7d51337b61..4beea621a6 100644 --- a/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/main/idf_component.yml +++ b/examples/peripherals/mcpwm/mcpwm_bdc_speed_control/main/idf_component.yml @@ -1,2 +1,3 @@ dependencies: pid_ctrl: "^0.1.1" + bdc_motor: "^0.1.0"