Skip to content

Commit

Permalink
feat(mcpwm): support update timer period dynamically
Browse files Browse the repository at this point in the history
Implement the requirement asked in
https://www.esp32.com/viewtopic.php?f=13&t=35919
  • Loading branch information
suda-morris committed Oct 24, 2023
1 parent 8c6114d commit 9b4a42e
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 33 deletions.
1 change: 1 addition & 0 deletions components/driver/linker.lf
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ entries:
dac_continuous: dac_continuous_write_asynchronously (noflash)
if MCPWM_CTRL_FUNC_IN_IRAM = y:
mcpwm_cmpr: mcpwm_comparator_set_compare_value (noflash)
mcpwm_timer: mcpwm_timer_set_period (noflash)
18 changes: 18 additions & 0 deletions components/driver/mcpwm/include/driver/mcpwm_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,24 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
*/
esp_err_t mcpwm_del_timer(mcpwm_timer_handle_t timer);

/**
* @brief Set a new period for MCPWM timer
*
* @note If `mcpwm_timer_config_t::update_period_on_empty` and `mcpwm_timer_config_t::update_period_on_sync` are not set,
* the new period will take effect immediately.
* Otherwise, the new period will take effect when timer counts to zero or on sync event.
* @note You may need to use `mcpwm_comparator_set_compare_value` to set a new compare value for MCPWM comparator
* in order to keep the same PWM duty cycle.
*
* @param[in] timer MCPWM timer handle, allocated by `mcpwm_new_timer`
* @param[in] period_ticks New period in count ticks
* @return
* - ESP_OK: Set new period for MCPWM timer successfully
* - ESP_ERR_INVALID_ARG: Set new period for MCPWM timer failed because of invalid argument
* - ESP_FAIL: Set new period for MCPWM timer failed because of other error
*/
esp_err_t mcpwm_timer_set_period(mcpwm_timer_handle_t timer, uint32_t period_ticks);

/**
* @brief Enable MCPWM timer
*
Expand Down
30 changes: 24 additions & 6 deletions components/driver/mcpwm/mcpwm_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
TAG, "invalid interrupt priority:%d", config->intr_priority);
}
// check the peak ticks that the timer can reach to
uint32_t peak_ticks = config->period_ticks;
if (config->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) {
peak_ticks /= 2; // in symmetric mode, peak_ticks = period_ticks / 2
}
ESP_GOTO_ON_FALSE(peak_ticks > 0 && peak_ticks < MCPWM_LL_MAX_COUNT_VALUE, ESP_ERR_INVALID_ARG, err, TAG, "invalid period ticks");

timer = heap_caps_calloc(1, sizeof(mcpwm_timer_t), MCPWM_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(timer, ESP_ERR_NO_MEM, err, TAG, "no mem for timer");
Expand Down Expand Up @@ -125,10 +131,6 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle

// set the peak tickes that the timer can reach to
timer->count_mode = config->count_mode;
uint32_t peak_ticks = config->period_ticks;
if (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) {
peak_ticks /= 2; // in symmetric mode, peak_ticks = period_ticks / 2
}
timer->peak_ticks = peak_ticks;
mcpwm_ll_timer_set_peak(hal->dev, timer_id, peak_ticks, timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN);
// set count direction
Expand Down Expand Up @@ -174,6 +176,22 @@ esp_err_t mcpwm_del_timer(mcpwm_timer_handle_t timer)
return ESP_OK;
}

esp_err_t mcpwm_timer_set_period(mcpwm_timer_handle_t timer, uint32_t period_ticks)
{
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
mcpwm_group_t *group = timer->group;
int timer_id = timer->timer_id;
mcpwm_hal_context_t *hal = &group->hal;
uint32_t peak_ticks = period_ticks;
if (timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN) {
peak_ticks /= 2; // in symmetric mode, peak_ticks = period_ticks / 2
}
ESP_RETURN_ON_FALSE_ISR(peak_ticks > 0 && peak_ticks < MCPWM_LL_MAX_COUNT_VALUE, ESP_ERR_INVALID_ARG, TAG, "invalid period ticks");
mcpwm_ll_timer_set_peak(hal->dev, timer_id, peak_ticks, timer->count_mode == MCPWM_TIMER_COUNT_MODE_UP_DOWN);
timer->peak_ticks = peak_ticks;
return ESP_OK;
}

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");
Expand Down Expand Up @@ -203,8 +221,8 @@ esp_err_t mcpwm_timer_register_event_callbacks(mcpwm_timer_handle_t timer, const
int isr_flags = MCPWM_INTR_ALLOC_FLAG;
isr_flags |= mcpwm_get_intr_priority_flag(group);
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),
mcpwm_timer_default_isr, timer, &timer->intr), TAG, "install interrupt service for timer failed");
(uint32_t)mcpwm_ll_intr_get_status_reg(hal->dev), MCPWM_LL_EVENT_TIMER_MASK(timer_id),
mcpwm_timer_default_isr, timer, &timer->intr), TAG, "install interrupt service for timer failed");
}

// enable/disable interrupt events
Expand Down
19 changes: 18 additions & 1 deletion components/driver/test_apps/mcpwm/main/test_mcpwm_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,26 @@ TEST_CASE("mcpwm_timer_event_callbacks", "[mcpwm]")
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_STOP, pdTRUE, pdTRUE, pdMS_TO_TICKS(50));
TEST_ASSERT_EQUAL(TEST_MCPWM_TIMER_EVENT_BIT_STOP, bits);

printf("update timer period\r\n");
TEST_ESP_OK(mcpwm_timer_set_period(timer, 50 * 1000)); // period: 50ms, 20Hz
udata.accumulate_empty_counts = 0;
udata.accumulate_full_counts = 0;

printf("start timer\r\n");
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));

printf("wait for full and empty events\r\n");
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, pdTRUE, pdTRUE, pdMS_TO_TICKS(1500));
// because the timer period changed, the previous wait time is not sufficient, so timeout
TEST_ASSERT_EQUAL(0, bits);

bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, pdTRUE, pdTRUE, pdMS_TO_TICKS(1500));
TEST_ASSERT_EQUAL(TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, bits);

printf("stop timer\r\n");
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
printf("disable timer\r\n");
TEST_ESP_OK(mcpwm_timer_disable(timer));

printf("delete timer\r\n");
TEST_ESP_OK(mcpwm_del_timer(timer));
vEventGroupDelete(event_group);
Expand Down
3 changes: 1 addition & 2 deletions components/hal/esp32/include/hal/mcpwm_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}
Expand Down
3 changes: 1 addition & 2 deletions components/hal/esp32c6/include/hal/mcpwm_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}
Expand Down
3 changes: 1 addition & 2 deletions components/hal/esp32h2/include/hal/mcpwm_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}
Expand Down
3 changes: 1 addition & 2 deletions components/hal/esp32s3/include/hal/mcpwm_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,12 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
* @param peak Peak value
* @param symmetric True to set symmetric peak value, False to set asymmetric peak value
*/
__attribute__((always_inline))
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
HAL_ASSERT(peak > 0 && peak <= MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak - 1);
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
HAL_ASSERT(peak < MCPWM_LL_MAX_COUNT_VALUE);
HAL_FORCE_MODIFY_U32_REG_FIELD(mcpwm->timer[timer_id].timer_cfg0, timer_period, peak);
}
}
Expand Down
Loading

0 comments on commit 9b4a42e

Please sign in to comment.