feat(mcpwm): support update timer period dynamically
Implement the requirement asked in https://www.esp32.com/viewtopic.php?f=13&t=35919
This commit is contained in:
@@ -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
|
||||
*
|
||||
|
||||
@@ -3,3 +3,4 @@ archive: libdriver.a
|
||||
entries:
|
||||
if MCPWM_CTRL_FUNC_IN_IRAM = y:
|
||||
mcpwm_cmpr: mcpwm_comparator_set_compare_value (noflash)
|
||||
mcpwm_timer: mcpwm_timer_set_period (noflash)
|
||||
|
||||
@@ -95,6 +95,12 @@ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle
|
||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & MCPWM_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err,
|
||||
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");
|
||||
@@ -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
|
||||
@@ -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");
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -251,13 +251,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,13 +249,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,13 +247,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,13 +307,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,13 +247,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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user