From e48f87468e290c8ec485d134614e3d77639e9cb5 Mon Sep 17 00:00:00 2001 From: Alex Lisitsyn Date: Wed, 16 Feb 2022 04:05:37 +0000 Subject: [PATCH] modbus: fix esp restart does not reset timer groups periph (backport v4.3) --- components/driver/test/test_timer.c | 38 ++++++++++++++++++++++++-- components/driver/timer.c | 4 +-- components/hal/include/hal/timer_hal.h | 9 ++++++ components/hal/timer_hal.c | 7 +++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/components/driver/test/test_timer.c b/components/driver/test/test_timer.c index e52569a05b..f4203aece4 100644 --- a/components/driver/test/test_timer.c +++ b/components/driver/test/test_timer.c @@ -955,8 +955,8 @@ TEST_CASE("Timer memory test", "[hw_timer]") // This case will check under this fix, whether the interrupt status is cleared after timer_group initialization. static void timer_group_test_init(void) { - static const uint32_t time_ms = 100; //Alarm value 100ms. - static const uint16_t timer_div = 10; //Timer prescaler + static const uint32_t time_ms = 100; // Alarm value 100ms. + static const uint16_t timer_div = TIMER_DIVIDER; // Timer prescaler static const uint32_t ste_val = time_ms * (TIMER_BASE_CLK / timer_div / 1000); timer_config_t config = { .divider = timer_div, @@ -993,6 +993,9 @@ static void timer_group_test_second_stage(void) { TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason()); timer_group_test_init(); + TEST_ASSERT_EQUAL(0, timer_group_get_intr_status_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0); + // After enable the interrupt, timer alarm should not trigger immediately + TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_0, TIMER_0)); //After the timer_group is initialized, TIMERG0.int_raw.t0 should be cleared. TEST_ASSERT_EQUAL(0, timer_group_get_intr_status_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0); } @@ -1001,3 +1004,34 @@ TEST_CASE_MULTIPLE_STAGES("timer_group software reset test", "[intr_status][intr_status = 0]", timer_group_test_first_stage, timer_group_test_second_stage); + +// +// Timer check reinitialization sequence +// +TEST_CASE("Timer check reinitialization sequence", "[hw_timer]") +{ + // 1. step - install driver + timer_group_test_init(); + // 2 - register interrupt and start timer + TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_0, TIMER_0)); + TEST_ESP_OK(timer_start(TIMER_GROUP_0, TIMER_0)); + // Do some work + vTaskDelay(80 / portTICK_PERIOD_MS); + // 3 - deinit timer driver + TEST_ESP_OK(timer_deinit(TIMER_GROUP_0, TIMER_0)); + timer_config_t config = { + .divider = TIMER_DIVIDER, + .counter_dir = TIMER_COUNT_UP, + .counter_en = TIMER_START, + .alarm_en = TIMER_ALARM_EN, + .intr_type = TIMER_INTR_LEVEL, + .auto_reload = TIMER_AUTORELOAD_EN, + }; + // 4 - reinstall driver + TEST_ESP_OK(timer_init(TIMER_GROUP_0, TIMER_0, &config)); + // 5 - enable interrupt + TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_0, TIMER_0)); + vTaskDelay(30 / portTICK_PERIOD_MS); + // The pending timer interrupt should not be triggered + TEST_ASSERT_EQUAL(0, timer_group_get_intr_status_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0); +} diff --git a/components/driver/timer.c b/components/driver/timer.c index c04607dcda..2043943609 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -295,13 +295,13 @@ esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); timer_hal_init(&(p_timer_obj[group_num][timer_num]->hal), group_num, timer_num); - timer_hal_intr_disable(&(p_timer_obj[group_num][timer_num]->hal)); + timer_hal_reset_periph(&(p_timer_obj[group_num][timer_num]->hal)); timer_hal_clear_intr_status(&(p_timer_obj[group_num][timer_num]->hal)); timer_hal_set_auto_reload(&(p_timer_obj[group_num][timer_num]->hal), config->auto_reload); timer_hal_set_divider(&(p_timer_obj[group_num][timer_num]->hal), config->divider); timer_hal_set_counter_increase(&(p_timer_obj[group_num][timer_num]->hal), config->counter_dir); timer_hal_set_alarm_enable(&(p_timer_obj[group_num][timer_num]->hal), config->alarm_en); - timer_hal_set_level_int_enable(&(p_timer_obj[group_num][timer_num]->hal), true); + timer_hal_set_level_int_enable(&(p_timer_obj[group_num][timer_num]->hal), config->intr_type == TIMER_INTR_LEVEL); if (config->intr_type != TIMER_INTR_LEVEL) { ESP_LOGW(TIMER_TAG, "only support Level Interrupt, switch to Level Interrupt instead"); } diff --git a/components/hal/include/hal/timer_hal.h b/components/hal/include/hal/timer_hal.h index f8c91739d9..cb3d5e0671 100644 --- a/components/hal/include/hal/timer_hal.h +++ b/components/hal/include/hal/timer_hal.h @@ -59,6 +59,15 @@ void timer_hal_init(timer_hal_context_t *hal, timer_group_t group_num, timer_idx */ void timer_hal_get_status_reg_mask_bit(timer_hal_context_t *hal, uint32_t *status_reg, uint32_t *mask_bit); +/** + * @brief Reset timer peripheral + * + * @param hal Context of the HAL layer + * + * @return None + */ +void timer_hal_reset_periph(timer_hal_context_t *hal); + /** * @brief Set timer clock prescale value * diff --git a/components/hal/timer_hal.c b/components/hal/timer_hal.c index 7337b19464..48a918e9c7 100644 --- a/components/hal/timer_hal.c +++ b/components/hal/timer_hal.c @@ -26,3 +26,10 @@ void timer_hal_get_status_reg_mask_bit(timer_hal_context_t *hal, uint32_t *statu *status_reg = timer_ll_get_intr_status_reg(hal->dev); *mask_bit = timer_ll_get_intr_mask_bit(hal->dev, hal->idx); } + +void timer_hal_reset_periph(timer_hal_context_t *hal) +{ + timer_ll_intr_disable(hal->dev, hal->idx); + timer_ll_set_counter_enable(hal->dev, hal->idx, TIMER_PAUSE); + timer_ll_set_counter_value(hal->dev, hal->idx, 0ULL); +}