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
This commit is contained in:
morris 2022-08-15 16:48:32 +08:00
commit 814351acdf
35 changed files with 155 additions and 556 deletions

View File

@ -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);

View File

@ -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,
@ -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");
}

View File

@ -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)

View File

@ -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

View File

@ -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,12 +197,16 @@ 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()`
* @param[in] cbs Group of callback functions
* @param[in] user_data User data, which will be passed to callback functions directly
* @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);
@ -185,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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)
@ -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

View File

@ -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),

View File

@ -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
@ -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");
}
@ -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),

View File

@ -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

View File

@ -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));

View File

@ -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));

View File

@ -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));

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -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`.

View File

@ -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

View File

@ -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")

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

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

View File

@ -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 = {

View File

@ -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,

View File

@ -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')