Просмотр исходного кода

timer: example migrate to pytest

morris 4 лет назад
Родитель
Сommit
f2d3a18f43

+ 17 - 30
examples/peripherals/timer_group/README.md

@@ -19,40 +19,27 @@ See the [ESP-IDF Getting Started Guide](https://idf.espressif.com/) for all the
 ## Example Output
 
 ```
-Timer Group with auto reload
-Group[0], timer[0] alarm event
-------- EVENT TIME --------
-Counter: 0x0000000000000008
-Time   : 0.00000160 s
--------- TASK TIME --------
-Counter: 0x0000000000004ed8
-Time   : 0.00403680 s
-Timer Group without auto reload
-Group[1], timer[0] alarm event
-------- EVENT TIME --------
-Counter: 0x00000000017d7848
-Time   : 5.00000160 s
--------- TASK TIME --------
-Counter: 0x00000000017dcb32
-Time   : 5.00424680 s
-Timer Group with auto reload
-Group[0], timer[0] alarm event
-------- EVENT TIME --------
-Counter: 0x0000000000000008
-Time   : 0.00000160 s
--------- TASK TIME --------
-Counter: 0x0000000000004dd4
-Time   : 0.00398480 s
+I (0) cpu_start: Starting scheduler on APP CPU.
+I (325) example: Init timer with auto-reload
+I (835) example: Timer auto reloaded, count value in ISR: 3
+I (1335) example: Timer auto reloaded, count value in ISR: 3
+I (1835) example: Timer auto reloaded, count value in ISR: 3
+I (2335) example: Timer auto reloaded, count value in ISR: 3
+I (2335) example: Init timer without auto-reload
+I (2835) example: Timer alarmed at 500003
+I (3335) example: Timer alarmed at 1000003
+I (3835) example: Timer alarmed at 1500003
+I (4335) example: Timer alarmed at 2000003
 ```
 
 ## Functionality Overview
 
-* Two timers are configured
-* Each timer is set with some sample alarm interval
-* On reaching the interval value each timer will generate an alarm
-* One of the timers is configured to automatically reload it's counter value on the alarm
-* The other timer is configured to keep incrementing and is reloaded by the application each time the alarm happens
-* Alarms trigger subsequent interrupts, that is tracked with messages printed on the terminal:
+* Configure one timer with auto-reload enabled, alarm period set to 0.5s
+* On reaching the interval value the timer will generate an alarm
+* The timer will reload with initial count value on alarm, by hardware
+* Reconfigure the timer with auto-reload disabled, initial alarm value set to 0.5s
+* The timer keeps incrementing and in the alarm callback, the software reconfigures its alarm value by increasing 0.5s
+* The main task will print the count value that captured in the alarm callback
 
 ## Troubleshooting
 

+ 0 - 42
examples/peripherals/timer_group/example_test.py

@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-#
-# SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
-#
-# SPDX-License-Identifier: CC0-1.0
-#
-
-from __future__ import unicode_literals
-
-import re
-from typing import Any
-
-import ttfw_idf
-
-
-@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3'])
-def test_examples_timergroup(env, extra_data):  # type: (Any, Any) -> None
-    dut = env.get_dut('timer_group', 'examples/peripherals/timer_group')
-    dut.start_app()
-
-    # check auto reload function
-    with_auto_reload = dut.expect(re.compile(r'Timer Group (\S+) auto reload'), timeout=30)[0]
-    assert with_auto_reload == 'with'
-    select_groups = dut.expect(re.compile(r'Group\[(\d)\], timer\[(\d)\] alarm event'))
-    timer_group_num = int(select_groups[0])
-    timer_instance_num = int(select_groups[1])
-    assert timer_group_num == 0 and timer_instance_num == 0
-    dut.expect('EVENT TIME')
-    counter_value = dut.expect(re.compile(r'Counter:\s+(0x\d+)'))[0]
-    counter_value = int(counter_value, 16)
-    print('counter value at auto reload event: ', counter_value)
-    assert counter_value < 20
-
-    # check timer interval
-    dut.expect('Timer Group without auto reload', timeout=5)
-    dut.expect('EVENT TIME')
-    event_time0 = dut.expect(re.compile(r'Time\s+:\s+(\d+\.\d+)\s+s'))[0]
-    print('event0={}'.format(event_time0))
-
-
-if __name__ == '__main__':
-    test_examples_timergroup()

+ 83 - 95
examples/peripherals/timer_group/main/timer_group_example_main.c

@@ -9,131 +9,119 @@
 #include "freertos/task.h"
 #include "freertos/queue.h"
 #include "driver/timer.h"
+#include "esp_log.h"
 
-#define TIMER_DIVIDER         (16)  //  Hardware timer clock divider
-#define TIMER_SCALE           (TIMER_BASE_CLK / TIMER_DIVIDER)  // convert counter value to seconds
+#define TIMER_RESOLUTION_HZ   1000000 // 1MHz resolution
+#define TIMER_ALARM_PERIOD_S  0.5     // Alarm period 0.5s
 
-typedef struct {
-    int timer_group;
-    int timer_idx;
-    int alarm_interval;
-    bool auto_reload;
-} example_timer_info_t;
+static const char *TAG = "example";
 
 /**
  * @brief A sample structure to pass events from the timer ISR to task
- *
  */
 typedef struct {
-    example_timer_info_t info;
-    uint64_t timer_counter_value;
+    uint64_t timer_count_value;
 } example_timer_event_t;
 
-static xQueueHandle s_timer_queue;
-
-/*
- * A simple helper function to print the raw timer counter value
- * and the counter value converted to seconds
+/**
+ * @brief Timer user data, will be pass to timer alarm callback
  */
-static void inline print_timer_counter(uint64_t counter_value)
-{
-    printf("Counter: 0x%08x%08x\r\n", (uint32_t) (counter_value >> 32),
-           (uint32_t) (counter_value));
-    printf("Time   : %.8f s\r\n", (double) counter_value / TIMER_SCALE);
-}
+typedef struct {
+    xQueueHandle user_queue;
+    int timer_group;
+    int timer_idx;
+    int alarm_value;
+    bool auto_reload;
+} example_timer_user_data_t;
 
 static bool IRAM_ATTR timer_group_isr_callback(void *args)
 {
     BaseType_t high_task_awoken = pdFALSE;
-    example_timer_info_t *info = (example_timer_info_t *) args;
-
-    uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(info->timer_group, info->timer_idx);
-
-    /* Prepare basic event data that will be then sent back to task */
+    example_timer_user_data_t *user_data = (example_timer_user_data_t *) args;
+    // fetch current count value
+    uint64_t timer_count_value = timer_group_get_counter_value_in_isr(user_data->timer_group, user_data->timer_idx);
     example_timer_event_t evt = {
-        .info.timer_group = info->timer_group,
-        .info.timer_idx = info->timer_idx,
-        .info.auto_reload = info->auto_reload,
-        .info.alarm_interval = info->alarm_interval,
-        .timer_counter_value = timer_counter_value
+        .timer_count_value = timer_count_value,
     };
 
-    if (!info->auto_reload) {
-        timer_counter_value += info->alarm_interval * TIMER_SCALE;
-        timer_group_set_alarm_value_in_isr(info->timer_group, info->timer_idx, timer_counter_value);
+    // set new alarm value if necessary
+    if (!user_data->auto_reload) {
+        user_data->alarm_value += TIMER_ALARM_PERIOD_S * TIMER_RESOLUTION_HZ;
+        timer_group_set_alarm_value_in_isr(user_data->timer_group, user_data->timer_idx, user_data->alarm_value);
     }
 
-    /* Now just send the event data back to the main program task */
-    xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken);
+    // Send the event data back to the main program task
+    xQueueSendFromISR(user_data->user_queue, &evt, &high_task_awoken);
 
-    return high_task_awoken == pdTRUE; // return whether we need to yield at the end of ISR
+    return high_task_awoken == pdTRUE; // return whether a task switch is needed
 }
 
-/**
- * @brief Initialize selected timer of timer group
- *
- * @param group Timer Group number, index from 0
- * @param timer timer ID, index from 0
- * @param auto_reload whether auto-reload on alarm event
- * @param timer_interval_sec interval of alarm
- */
-static void example_tg_timer_init(int group, int timer, bool auto_reload, int timer_interval_sec)
+static void example_tg_timer_init(example_timer_user_data_t *user_data)
 {
-    /* Select and initialize basic parameters of the timer */
+    int group = user_data->timer_group;
+    int timer = user_data->timer_idx;
+
     timer_config_t config = {
-        .divider = TIMER_DIVIDER,
+        .clk_src = TIMER_SRC_CLK_APB,
+        .divider = APB_CLK_FREQ / TIMER_RESOLUTION_HZ,
         .counter_dir = TIMER_COUNT_UP,
         .counter_en = TIMER_PAUSE,
         .alarm_en = TIMER_ALARM_EN,
-        .auto_reload = auto_reload,
-    }; // default clock source is APB
-    timer_init(group, timer, &config);
-
-    /* Timer's counter will initially start from value below.
-       Also, if auto_reload is set, this value will be automatically reload on alarm */
-    timer_set_counter_value(group, timer, 0);
-
-    /* Configure the alarm value and the interrupt on alarm. */
-    timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);
-    timer_enable_intr(group, timer);
-
-    example_timer_info_t *timer_info = calloc(1, sizeof(example_timer_info_t));
-    timer_info->timer_group = group;
-    timer_info->timer_idx = timer;
-    timer_info->auto_reload = auto_reload;
-    timer_info->alarm_interval = timer_interval_sec;
-    timer_isr_callback_add(group, timer, timer_group_isr_callback, timer_info, 0);
-
-    timer_start(group, timer);
+        .auto_reload = user_data->auto_reload,
+    };
+    ESP_ERROR_CHECK(timer_init(group, timer, &config));
+
+    // For the timer counter to a initial value
+    ESP_ERROR_CHECK(timer_set_counter_value(group, timer, 0));
+    // Set alarm value and enable alarm interrupt
+    ESP_ERROR_CHECK(timer_set_alarm_value(group, timer, user_data->alarm_value));
+    ESP_ERROR_CHECK(timer_enable_intr(group, timer));
+    // Hook interrupt callback
+    ESP_ERROR_CHECK(timer_isr_callback_add(group, timer, timer_group_isr_callback, user_data, 0));
+    // Start timer
+    ESP_ERROR_CHECK(timer_start(group, timer));
+}
+
+static void example_tg_timer_deinit(int group, int timer)
+{
+    ESP_ERROR_CHECK(timer_isr_callback_remove(group, timer));
+    ESP_ERROR_CHECK(timer_deinit(group, timer));
 }
 
 void app_main(void)
 {
-    s_timer_queue = xQueueCreate(10, sizeof(example_timer_event_t));
-
-    example_tg_timer_init(TIMER_GROUP_0, TIMER_0, true, 3);
-    example_tg_timer_init(TIMER_GROUP_1, TIMER_0, false, 5);
-
-    while (1) {
-        example_timer_event_t evt;
-        xQueueReceive(s_timer_queue, &evt, portMAX_DELAY);
-
-        /* Print information that the timer reported an event */
-        if (evt.info.auto_reload) {
-            printf("Timer Group with auto reload\n");
-        } else {
-            printf("Timer Group without auto reload\n");
-        }
-        printf("Group[%d], timer[%d] alarm event\n", evt.info.timer_group, evt.info.timer_idx);
-
-        /* Print the timer values passed by event */
-        printf("------- EVENT TIME --------\n");
-        print_timer_counter(evt.timer_counter_value);
-
-        /* Print the timer values as visible by this task */
-        printf("-------- TASK TIME --------\n");
-        uint64_t task_counter_value;
-        timer_get_counter_value(evt.info.timer_group, evt.info.timer_idx, &task_counter_value);
-        print_timer_counter(task_counter_value);
+    example_timer_user_data_t *user_data = calloc(1, sizeof(example_timer_user_data_t));
+    assert(user_data);
+    user_data->user_queue = xQueueCreate(10, sizeof(example_timer_event_t));
+    assert(user_data->user_queue);
+    user_data->timer_group = 0;
+    user_data->timer_idx = 0;
+    user_data->alarm_value = TIMER_ALARM_PERIOD_S * TIMER_RESOLUTION_HZ;
+
+
+    ESP_LOGI(TAG, "Init timer with auto-reload");
+    user_data->auto_reload = true;
+    example_tg_timer_init(user_data);
+
+    example_timer_event_t evt;
+    uint32_t test_count = 4;
+    while (test_count--) {
+        xQueueReceive(user_data->user_queue, &evt, portMAX_DELAY);
+        ESP_LOGI(TAG, "Timer auto reloaded, count value in ISR: %llu", evt.timer_count_value);
     }
+    example_tg_timer_deinit(user_data->timer_group, user_data->timer_idx);
+
+    ESP_LOGI(TAG, "Init timer without auto-reload");
+    user_data->auto_reload = false;
+    example_tg_timer_init(user_data);
+
+    test_count = 4;
+    while (test_count--) {
+        xQueueReceive(user_data->user_queue, &evt, portMAX_DELAY);
+        ESP_LOGI(TAG, "Timer alarmed at %llu", evt.timer_count_value);
+    }
+    example_tg_timer_deinit(user_data->timer_group, user_data->timer_idx);
+
+    vQueueDelete(user_data->user_queue);
+    free(user_data);
 }

+ 24 - 0
examples/peripherals/timer_group/pytest_timer_group.py

@@ -0,0 +1,24 @@
+# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: CC0-1.0
+
+import pytest
+from pytest_embedded.dut import Dut
+
+
+@pytest.mark.esp32
+@pytest.mark.esp32s2
+@pytest.mark.esp32s3
+@pytest.mark.esp32c3
+@pytest.mark.generic
+def test_timer_group_example(dut: Dut):  # type: ignore
+    dut.expect(r'Init timer with auto-reload', timeout=5)
+    res = dut.expect(r'Timer auto reloaded, count value in ISR: (\d+)', timeout=5)
+    reloaded_count = res.group(1).decode('utf8')
+    assert 0 <= int(reloaded_count) < 10
+
+    alarm_increase_step = 500000
+    dut.expect(r'Init timer without auto-reload')
+    for i in range(1, 5):
+        res = dut.expect(r'Timer alarmed at (\d+)', timeout=3)
+        alarm_count = res.group(1).decode('utf8')
+        assert (i * alarm_increase_step - 10) < int(alarm_count) < (i * alarm_increase_step + 10)