Răsfoiți Sursa

driver: fix timer driver initialization sequence to not trigger interrupt immediately

add timer_hal_reset_periph()
fix timer_init() to reset timer counter during init
Alex Lisitsyn 4 ani în urmă
părinte
comite
c5d0d89508

+ 36 - 2
components/driver/test/test_timer.c

@@ -960,8 +960,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,
@@ -998,6 +998,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);
 }
@@ -1006,3 +1009,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);
+}

+ 3 - 2
components/driver/timer.c

@@ -282,13 +282,14 @@ 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);
+    // Disable level interrupt by default
+    timer_hal_set_level_int_enable(&(p_timer_obj[group_num][timer_num]->hal), false);
     if (config->intr_type != TIMER_INTR_LEVEL) {
         ESP_LOGW(TIMER_TAG, "only support Level Interrupt, switch to Level Interrupt instead");
     }

+ 9 - 0
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
  *

+ 7 - 0
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);
+}