From b170aba93a6db18a39b3cef9a45e9e1d91a3cd05 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 16 Dec 2021 23:13:09 +0800 Subject: [PATCH 1/5] timer: fix wrong kconfig soc caps --- components/soc/esp32/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32/include/soc/soc_caps.h | 2 +- .../soc/esp32c3/include/soc/Kconfig.soc_caps.in | 8 ++++++-- components/soc/esp32c3/include/soc/soc_caps.h | 4 ++-- .../soc/esp32h2/include/soc/Kconfig.soc_caps.in | 8 ++++++-- components/soc/esp32h2/include/soc/soc_caps.h | 4 ++-- .../soc/esp32s2/include/soc/Kconfig.soc_caps.in | 12 ++++++++---- components/soc/esp32s2/include/soc/soc_caps.h | 4 ++-- .../soc/esp32s3/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32s3/include/soc/soc_caps.h | 2 +- .../soc/esp8684/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp8684/include/soc/soc_caps.h | 2 +- 12 files changed, 41 insertions(+), 17 deletions(-) diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index badcf053cf..d3764aadde 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -431,6 +431,10 @@ config SOC_TIMER_GROUP_COUNTER_BIT_WIDTH int default 64 +config SOC_TIMER_GROUP_TOTAL_TIMERS + int + default 4 + config SOC_TOUCH_VERSION_1 bool default y diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 84bba07f0c..2c672d56dc 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -249,7 +249,7 @@ #define SOC_TIMER_GROUPS (2) #define SOC_TIMER_GROUP_TIMERS_PER_GROUP (2) #define SOC_TIMER_GROUP_COUNTER_BIT_WIDTH (64) -#define SOC_TIMER_GROUP_TOTAL_TIMERS (SOC_TIMER_GROUPS * SOC_TIMER_GROUP_TIMERS_PER_GROUP) +#define SOC_TIMER_GROUP_TOTAL_TIMERS (4) /*-------------------------- TOUCH SENSOR CAPS -------------------------------*/ #define SOC_TOUCH_VERSION_1 (1) /*! Date: Fri, 17 Dec 2021 09:57:27 +0800 Subject: [PATCH 2/5] timer: save alarm value in driver layer --- components/driver/timer.c | 5 +++- components/hal/esp32/include/hal/timer_ll.h | 12 -------- components/hal/esp32c3/include/hal/timer_ll.h | 12 -------- components/hal/esp32h2/include/hal/timer_ll.h | 12 -------- components/hal/esp32s2/include/hal/timer_ll.h | 12 -------- components/hal/esp32s3/include/hal/timer_ll.h | 12 -------- components/hal/esp8684/include/hal/timer_ll.h | 13 --------- components/hal/include/hal/timer_types.h | 29 +++++++++---------- 8 files changed, 17 insertions(+), 90 deletions(-) diff --git a/components/driver/timer.c b/components/driver/timer.c index 43f9b0888d..55705d346d 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -47,6 +47,7 @@ typedef struct { gptimer_clock_source_t clk_src; gptimer_count_direction_t direction; uint32_t divider; + uint64_t alarm_value; bool alarm_en; bool auto_reload_en; bool counter_en; @@ -171,6 +172,7 @@ esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); timer_ll_set_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_value); + p_timer_obj[group_num][timer_num]->alarm_value = alarm_value; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -182,7 +184,7 @@ esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, ESP_RETURN_ON_FALSE(alarm_value != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_PARAM_ADDR_ERROR); ESP_RETURN_ON_FALSE(p_timer_obj[group_num][timer_num] != NULL, ESP_ERR_INVALID_ARG, TIMER_TAG, TIMER_NEVER_INIT_ERROR); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); - *alarm_value = timer_ll_get_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num); + *alarm_value = p_timer_obj[group_num][timer_num]->alarm_value; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; } @@ -430,6 +432,7 @@ uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, void IRAM_ATTR timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val) { timer_ll_set_alarm_value(p_timer_obj[group_num][timer_num]->hal.dev, timer_num, alarm_val); + p_timer_obj[group_num][timer_num]->alarm_value = alarm_val; } void IRAM_ATTR timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en) diff --git a/components/hal/esp32/include/hal/timer_ll.h b/components/hal/esp32/include/hal/timer_ll.h index fbd44ddb1f..b2855cef7b 100644 --- a/components/hal/esp32/include/hal/timer_ll.h +++ b/components/hal/esp32/include/hal/timer_ll.h @@ -144,18 +144,6 @@ static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } -/** - * @brief Get alarm value - * - * @param hw Timer Group register base address - * @param timer_num Timer number in the group - * @return Counter value to trigger the alarm event - */ -static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) -{ - return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); -} - /** * @brief Set reload value * diff --git a/components/hal/esp32c3/include/hal/timer_ll.h b/components/hal/esp32c3/include/hal/timer_ll.h index 8f2d633f1c..5149954ef6 100644 --- a/components/hal/esp32c3/include/hal/timer_ll.h +++ b/components/hal/esp32c3/include/hal/timer_ll.h @@ -147,18 +147,6 @@ static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } -/** - * @brief Get alarm value - * - * @param hw Timer Group register base address - * @param timer_num Timer number in the group - * @return Counter value to trigger the alarm event - */ -static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) -{ - return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); -} - /** * @brief Set reload value * diff --git a/components/hal/esp32h2/include/hal/timer_ll.h b/components/hal/esp32h2/include/hal/timer_ll.h index 8f2d633f1c..5149954ef6 100644 --- a/components/hal/esp32h2/include/hal/timer_ll.h +++ b/components/hal/esp32h2/include/hal/timer_ll.h @@ -147,18 +147,6 @@ static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } -/** - * @brief Get alarm value - * - * @param hw Timer Group register base address - * @param timer_num Timer number in the group - * @return Counter value to trigger the alarm event - */ -static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) -{ - return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); -} - /** * @brief Set reload value * diff --git a/components/hal/esp32s2/include/hal/timer_ll.h b/components/hal/esp32s2/include/hal/timer_ll.h index 798ff147f4..8d403b8a6c 100644 --- a/components/hal/esp32s2/include/hal/timer_ll.h +++ b/components/hal/esp32s2/include/hal/timer_ll.h @@ -148,18 +148,6 @@ static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } -/** - * @brief Get alarm value - * - * @param hw Timer Group register base address - * @param timer_num Timer number in the group - * @return Counter value to trigger the alarm event - */ -static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) -{ - return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); -} - /** * @brief Set reload value * diff --git a/components/hal/esp32s3/include/hal/timer_ll.h b/components/hal/esp32s3/include/hal/timer_ll.h index 2f5481c0fa..9a3994a5e3 100644 --- a/components/hal/esp32s3/include/hal/timer_ll.h +++ b/components/hal/esp32s3/include/hal/timer_ll.h @@ -147,18 +147,6 @@ static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, hw->hw_timer[timer_num].alarmlo.tn_alarm_lo = (uint32_t)alarm_value; } -/** - * @brief Get alarm value - * - * @param hw Timer Group register base address - * @param timer_num Timer number in the group - * @return Counter value to trigger the alarm event - */ -static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) -{ - return ((uint64_t)hw->hw_timer[timer_num].alarmhi.tn_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tn_alarm_lo); -} - /** * @brief Set reload value * diff --git a/components/hal/esp8684/include/hal/timer_ll.h b/components/hal/esp8684/include/hal/timer_ll.h index d28c0d7925..f35de704a8 100644 --- a/components/hal/esp8684/include/hal/timer_ll.h +++ b/components/hal/esp8684/include/hal/timer_ll.h @@ -12,7 +12,6 @@ #include "hal/assert.h" #include "hal/misc.h" #include "hal/timer_types.h" -#include "soc/timer_periph.h" #include "soc/timer_group_struct.h" #ifdef __cplusplus @@ -148,18 +147,6 @@ static inline void timer_ll_set_alarm_value(timg_dev_t *hw, uint32_t timer_num, hw->hw_timer[timer_num].alarmlo.tx_alarm_lo = (uint32_t) alarm_value; } -/** - * @brief Get alarm value - * - * @param hw Timer Group register base address - * @param timer_num Timer number in the group - * @return Counter value to trigger the alarm event - */ -static inline uint64_t timer_ll_get_alarm_value(timg_dev_t *hw, uint32_t timer_num) -{ - return ((uint64_t) hw->hw_timer[timer_num].alarmhi.tx_alarm_hi << 32) | (hw->hw_timer[timer_num].alarmlo.tx_alarm_lo); -} - /** * @brief Set reload value * diff --git a/components/hal/include/hal/timer_types.h b/components/hal/include/hal/timer_types.h index 19e72418bd..4b339c9f29 100644 --- a/components/hal/include/hal/timer_types.h +++ b/components/hal/include/hal/timer_types.h @@ -6,6 +6,8 @@ #pragma once +#include "soc/soc_caps.h" + #ifdef __cplusplus extern "C" { #endif @@ -14,17 +16,21 @@ extern "C" { * @brief GPTimer clock source * @note The clock source listed here is not supported on all targets * @note User should select the clock source based on real requirements: - * ╔══════════════════════╦══════════════════════════════════╦══════════════════════════╗ - * ║ GPTimer clock source ║ Features ║ Power Management ║ - * ╠══════════════════════╬══════════════════════════════════╬══════════════════════════╣ - * ║ GPTIMER_CLK_SRC_APB ║ High resolution ║ ESP_PM_APB_FREQ_MAX lock ║ - * ╠══════════════════════╬══════════════════════════════════╬══════════════════════════╣ - * ║ GPTIMER_CLK_SRC_XTAL ║ Medium resolution, high accuracy ║ No PM lock ║ - * ╚══════════════════════╩══════════════════════════════════╩══════════════════════════╝ + * @verbatim embed:rst:leading-asterisk + * +----------------------+----------------------------------+--------------------------+ + * | GPTimer clock source | Features | Power Management | + * +======================+==================================+==========================+ + * | GPTIMER_CLK_SRC_APB | High resolution | ESP_PM_APB_FREQ_MAX lock | + * +----------------------+----------------------------------+--------------------------+ + * | GPTIMER_CLK_SRC_XTAL | Medium resolution, high accuracy | No PM lock | + * +----------------------+----------------------------------+--------------------------+ + * @endverbatim */ typedef enum { GPTIMER_CLK_SRC_APB, /*!< Select APB as the source clock */ +#if SOC_TIMER_GROUP_SUPPORT_XTAL GPTIMER_CLK_SRC_XTAL, /*!< Select XTAL as the source clock */ +#endif } gptimer_clock_source_t; /** @@ -35,15 +41,6 @@ typedef enum { GPTIMER_COUNT_UP, /*!< Increase count value */ } gptimer_count_direction_t; -/** - * @brief GPTimer actions on alarm event - */ -typedef enum { - GPTIMER_ALARM_ACTION_CONTINUE, /*!< Counter will pass through the alarm point and continue counting */ - GPTIMER_ALARM_ACTION_STOP, /*!< Counter will stop on alarm event */ - GPTIMER_ALARM_ACTION_RELOAD, /*!< Counter will do reload on alarm event */ -} gptimer_alarm_action_t; - #ifdef __cplusplus } #endif From 4ed33afc3fc8f849b2741f1f718010289a83fccc Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 17 Dec 2021 10:02:33 +0800 Subject: [PATCH 3/5] timer: stop alarm if alarm value doesn't change in ISR handler Alarm will be disabled by hardware when alarm event happend. In the ISR, if auto-reload is enabled, we should re-enable the alarm. If the alarm target value is changed in user's callback, the alarm will be reenabled as well. Closes https://github.com/espressif/esp-idf/issues/7001 Closes https://github.com/espressif/esp-idf/issues/8095 --- components/driver/timer.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/driver/timer.c b/components/driver/timer.c index 55705d346d..b9cc2e1a81 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -212,12 +212,16 @@ static void IRAM_ATTR timer_isr_default(void *arg) timer_hal_context_t *hal = &timer_obj->hal; TIMER_ENTER_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]); uint32_t intr_status = timer_ll_get_intr_status(hal->dev); + uint64_t old_alarm_value = timer_obj->alarm_value; if (intr_status & TIMER_LL_EVENT_ALARM(timer_id)) { - //Clear intrrupt status + // Clear interrupt status timer_ll_clear_intr_status(hal->dev, TIMER_LL_EVENT_ALARM(timer_id)); + // call user registered callback is_awoken = timer_obj->timer_isr_fun.fn(timer_obj->timer_isr_fun.args); - //If the timer is set to auto reload, we need enable it again, so it is triggered the next time - timer_ll_enable_alarm(hal->dev, timer_id, timer_obj->auto_reload_en); + // reenable alarm if required + uint64_t new_alarm_value = timer_obj->alarm_value; + bool reenable_alarm = (new_alarm_value != old_alarm_value) || timer_obj->auto_reload_en; + timer_ll_enable_alarm(hal->dev, timer_id, reenable_alarm); } TIMER_EXIT_CRITICAL(&timer_spinlock[timer_obj->timer_isr_fun.isr_timer_group]); From f2d3a18f434a9d94bfe3f638fade13d0862d92e2 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 17 Dec 2021 13:19:20 +0800 Subject: [PATCH 4/5] timer: example migrate to pytest --- examples/peripherals/timer_group/README.md | 47 ++--- .../peripherals/timer_group/example_test.py | 42 ----- .../main/timer_group_example_main.c | 168 ++++++++---------- .../timer_group/pytest_timer_group.py | 24 +++ 4 files changed, 119 insertions(+), 162 deletions(-) delete mode 100644 examples/peripherals/timer_group/example_test.py create mode 100644 examples/peripherals/timer_group/pytest_timer_group.py diff --git a/examples/peripherals/timer_group/README.md b/examples/peripherals/timer_group/README.md index 7fb754c47a..1da4ef74d3 100644 --- a/examples/peripherals/timer_group/README.md +++ b/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 diff --git a/examples/peripherals/timer_group/example_test.py b/examples/peripherals/timer_group/example_test.py deleted file mode 100644 index f7fc541ab9..0000000000 --- a/examples/peripherals/timer_group/example_test.py +++ /dev/null @@ -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() diff --git a/examples/peripherals/timer_group/main/timer_group_example_main.c b/examples/peripherals/timer_group/main/timer_group_example_main.c index fbc23c144f..5b90ab190e 100644 --- a/examples/peripherals/timer_group/main/timer_group_example_main.c +++ b/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); + .auto_reload = user_data->auto_reload, + }; + ESP_ERROR_CHECK(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); + // 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)); +} - /* 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); +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_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; - 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); + ESP_LOGI(TAG, "Init timer with auto-reload"); + user_data->auto_reload = true; + example_tg_timer_init(user_data); - /* 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_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); } diff --git a/examples/peripherals/timer_group/pytest_timer_group.py b/examples/peripherals/timer_group/pytest_timer_group.py new file mode 100644 index 0000000000..b715ec81ea --- /dev/null +++ b/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) From 8f2199cd88d930a8d04a91d5f3580d1ffc2baeba Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 23 Dec 2021 11:34:27 +0800 Subject: [PATCH 5/5] timer: unit test and doc update for esp8684 --- components/driver/test/test_timer.c | 225 ++++++++++---------- docs/docs_not_updated/esp8684.txt | 1 - docs/en/api-reference/peripherals/timer.rst | 9 +- 3 files changed, 115 insertions(+), 120 deletions(-) diff --git a/components/driver/test/test_timer.c b/components/driver/test/test_timer.c index f338cee4fb..c1eaeee4a9 100644 --- a/components/driver/test/test_timer.c +++ b/components/driver/test/test_timer.c @@ -15,12 +15,9 @@ #include "soc/soc_caps.h" #include "esp_rom_sys.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP8684) -// TODO: Timer support IDF-3825 - -#define TIMER_DIVIDER 16 -#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */ +#define TEST_TIMER_RESOLUTION_HZ 1000000 // 1MHz resolution #define TIMER_DELTA 0.001 + static bool alarm_flag; static xQueueHandle timer_queue; @@ -39,14 +36,16 @@ typedef struct { #define TIMER_INFO_INIT(TG, TID) {.timer_group = (TG), .timer_idx = (TID),} static timer_info_t timer_info[] = { -#if !CONFIG_IDF_TARGET_ESP32C3 +#if SOC_TIMER_GROUP_TOTAL_TIMERS >= 4 TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_0), TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_1), TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_0), TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_1), -#else +#elif SOC_TIMER_GROUP_TOTAL_TIMERS >= 2 TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_0), TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_0), +#else + TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_0), #endif }; @@ -248,7 +247,7 @@ static void timer_intr_enable_and_start(int timer_group, int timer_idx, double a { TEST_ESP_OK(timer_pause(timer_group, timer_idx)); TEST_ESP_OK(timer_set_counter_value(timer_group, timer_idx, 0x0)); - TEST_ESP_OK(timer_set_alarm_value(timer_group, timer_idx, alarm_time * TIMER_SCALE)); + TEST_ESP_OK(timer_set_alarm_value(timer_group, timer_idx, alarm_time * TEST_TIMER_RESOLUTION_HZ)); TEST_ESP_OK(timer_set_alarm(timer_group, timer_idx, TIMER_ALARM_EN)); TEST_ESP_OK(timer_enable_intr(timer_group, timer_idx)); TEST_ESP_OK(timer_start(timer_group, timer_idx)); @@ -300,9 +299,10 @@ TEST_CASE("Timer init", "[hw_timer]") // lack one parameter timer_config_t config2 = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_START, .intr_type = TIMER_INTR_LEVEL }; @@ -311,33 +311,20 @@ TEST_CASE("Timer init", "[hw_timer]") config2.counter_en = TIMER_PAUSE; all_timer_init(&config2, true); - // error config parameter - timer_config_t config3 = { - .alarm_en = 3, //error parameter - .auto_reload = TIMER_AUTORELOAD_EN, - .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, - .counter_en = TIMER_START, - .intr_type = TIMER_INTR_LEVEL - }; - all_timer_init(&config3, true); - timer_config_t get_config; - TEST_ESP_OK(timer_get_config(TIMER_GROUP_1, TIMER_0, &get_config)); - printf("Error config alarm_en is %d\n", get_config.alarm_en); - TEST_ASSERT_NOT_EQUAL(config3.alarm_en, get_config.alarm_en); - // Test init 2: init uint64_t set_timer_val = 0x0; timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_DIS, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_START, .intr_type = TIMER_INTR_LEVEL }; // judge get config parameters + timer_config_t get_config; TEST_ESP_OK(timer_init(TIMER_GROUP_0, TIMER_0, &config)); TEST_ESP_OK(timer_get_config(TIMER_GROUP_0, TIMER_0, &get_config)); TEST_ASSERT_EQUAL(config.alarm_en, get_config.alarm_en); @@ -355,8 +342,8 @@ TEST_CASE("Timer init", "[hw_timer]") // Test init 3: wrong parameter TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_init(-1, TIMER_0, &config)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_init(TIMER_GROUP_1, 2, &config)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_init(TIMER_GROUP_1, -1, &config)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_init(TIMER_GROUP_0, 2, &config)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_init(TIMER_GROUP_0, -1, &config)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_init(2, TIMER_0, &config)); all_timer_deinit(); } @@ -369,10 +356,11 @@ TEST_CASE("Timer init", "[hw_timer]") TEST_CASE("Timer read counter value", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_START, .intr_type = TIMER_INTR_LEVEL }; @@ -408,10 +396,11 @@ TEST_CASE("Timer read counter value", "[hw_timer]") TEST_CASE("Timer start", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_START, .intr_type = TIMER_INTR_LEVEL }; @@ -426,8 +415,8 @@ TEST_CASE("Timer start", "[hw_timer]") //Test start 2:wrong parameter TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_start(2, TIMER_0)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_start(-1, TIMER_0)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_start(TIMER_GROUP_1, 2)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_start(TIMER_GROUP_1, -1)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_start(TIMER_GROUP_0, 2)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_start(TIMER_GROUP_0, -1)); all_timer_deinit(); } @@ -439,10 +428,11 @@ TEST_CASE("Timer start", "[hw_timer]") TEST_CASE("Timer pause", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_START, .intr_type = TIMER_INTR_LEVEL }; @@ -458,7 +448,7 @@ TEST_CASE("Timer pause", "[hw_timer]") TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_pause(-1, TIMER_0)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_pause(TIMER_GROUP_0, -1)); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_pause(2, TIMER_0)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_pause(TIMER_GROUP_1, 2)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_pause(TIMER_GROUP_0, 2)); all_timer_deinit(); } @@ -466,10 +456,11 @@ TEST_CASE("Timer pause", "[hw_timer]") TEST_CASE("Timer counter mode (up / down)", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_START, .intr_type = TIMER_INTR_LEVEL }; @@ -486,7 +477,7 @@ TEST_CASE("Timer counter mode (up / down)", "[hw_timer]") // Test counter mode 2: TIMER_COUNT_DOWN all_timer_pause(); - set_timer_val = 0x00E4E1C0ULL; // 3s clock counter value + set_timer_val = TEST_TIMER_RESOLUTION_HZ * 3; // 3s clock counter value all_timer_set_counter_mode(TIMER_COUNT_DOWN); all_timer_set_counter_value(set_timer_val); all_timer_start(); @@ -499,24 +490,14 @@ TEST_CASE("Timer counter mode (up / down)", "[hw_timer]") all_timer_deinit(); } -/** - * divider case: - * 1. different divider, read value - * Note: divide 0 = divide max, divide 1 = divide 2 - * 2. error parameter - * - * the frequency(timer counts in one sec): - * 80M/divider = 800*100000 - * max divider value is 65536, its frequency is 1220 (nearly about 1KHz) - */ TEST_CASE("Timer divider", "[hw_timer]") { - int i; timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_START, .intr_type = TIMER_INTR_LEVEL }; @@ -532,41 +513,36 @@ TEST_CASE("Timer divider", "[hw_timer]") vTaskDelay(1000 / portTICK_PERIOD_MS); all_timer_get_counter_value(set_timer_val, false, time_val); - // compare divider 16 and 8, value should be double all_timer_pause(); - all_timer_set_divider(8); + all_timer_set_divider(config.divider / 2); // half of original divider all_timer_set_counter_value(set_timer_val); all_timer_start(); vTaskDelay(1000 / portTICK_PERIOD_MS); //delay the same time all_timer_get_counter_value(set_timer_val, false, comp_time_val); - for (i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { - TEST_ASSERT_INT_WITHIN(5000, 5000000, time_val[i]); - TEST_ASSERT_INT_WITHIN(10000, 10000000, comp_time_val[i]); + for (int i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { + TEST_ASSERT_INT_WITHIN(2000, 1000000, time_val[i]); + TEST_ASSERT_INT_WITHIN(2000, 2000000, comp_time_val[i]); } - // divider is 256, value should be 2^4 all_timer_pause(); all_timer_set_divider(256); all_timer_set_counter_value(set_timer_val); all_timer_start(); vTaskDelay(1000 / portTICK_PERIOD_MS); //delay the same time all_timer_get_counter_value(set_timer_val, false, comp_time_val); - for (i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { - TEST_ASSERT_INT_WITHIN(5000, 5000000, time_val[i]); - TEST_ASSERT_INT_WITHIN(3126, 312500, comp_time_val[i]); + for (int i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { + TEST_ASSERT_INT_WITHIN(100, APB_CLK_FREQ / 256, comp_time_val[i]); } - // extrem value test all_timer_pause(); all_timer_set_divider(2); all_timer_set_counter_value(set_timer_val); all_timer_start(); vTaskDelay(1000 / portTICK_PERIOD_MS); all_timer_get_counter_value(set_timer_val, false, comp_time_val); - for (i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { - TEST_ASSERT_INT_WITHIN(5000, 5000000, time_val[i]); - TEST_ASSERT_INT_WITHIN(40000, 40000000, comp_time_val[i]); + for (int i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { + TEST_ASSERT_INT_WITHIN(5000, APB_CLK_FREQ / 2, comp_time_val[i]); } all_timer_pause(); @@ -575,19 +551,13 @@ TEST_CASE("Timer divider", "[hw_timer]") all_timer_start(); vTaskDelay(1000 / portTICK_PERIOD_MS); //delay the same time all_timer_get_counter_value(set_timer_val, false, comp_time_val); - for (i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { - TEST_ASSERT_INT_WITHIN(5000, 5000000, time_val[i]); - TEST_ASSERT_INT_WITHIN(2, 1220, comp_time_val[i]); + for (int i = 0; i < TIMER_GROUP_MAX * TIMER_MAX; i++) { + TEST_ASSERT_INT_WITHIN(10, APB_CLK_FREQ / 65536, comp_time_val[i]); } - // divider is 1 should be equal with 2 all_timer_pause(); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_set_divider(TIMER_GROUP_0, TIMER_0, 1)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_set_divider(TIMER_GROUP_1, TIMER_0, 1)); - - all_timer_pause(); TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_set_divider(TIMER_GROUP_0, TIMER_0, 65537)); - TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, timer_set_divider(TIMER_GROUP_1, TIMER_0, 65537)); all_timer_deinit(); } @@ -599,10 +569,11 @@ TEST_CASE("Timer divider", "[hw_timer]") TEST_CASE("Timer enable alarm", "[hw_timer]") { timer_config_t config_test = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_DIS, .auto_reload = TIMER_AUTORELOAD_DIS, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL }; @@ -613,7 +584,7 @@ TEST_CASE("Timer enable alarm", "[hw_timer]") alarm_flag = false; TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_0, TIMER_0, TIMER_ALARM_EN)); timer_intr_enable_and_start(TIMER_GROUP_0, TIMER_0, 1.2); - timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TIMER_SCALE); + timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TEST_TIMER_RESOLUTION_HZ); TEST_ASSERT_EQUAL(true, alarm_flag); // disable alarm of tg0_timer1 @@ -623,11 +594,12 @@ TEST_CASE("Timer enable alarm", "[hw_timer]") vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT_EQUAL(false, alarm_flag); +#if SOC_TIMER_GROUPS > 1 // enable alarm of tg1_timer0 alarm_flag = false; TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_EN)); timer_intr_enable_and_start(TIMER_GROUP_1, TIMER_0, 1.2); - timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TIMER_SCALE); + timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TEST_TIMER_RESOLUTION_HZ); TEST_ASSERT_EQUAL(true, alarm_flag); // disable alarm of tg1_timer0 @@ -636,6 +608,7 @@ TEST_CASE("Timer enable alarm", "[hw_timer]") TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_DIS)); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT_EQUAL(false, alarm_flag); +#endif all_timer_isr_unreg(); all_timer_deinit(); } @@ -649,10 +622,11 @@ TEST_CASE("Timer set alarm value", "[hw_timer]") { uint64_t alarm_val[SOC_TIMER_GROUP_TOTAL_TIMERS]; timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_DIS, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL }; @@ -660,17 +634,19 @@ TEST_CASE("Timer set alarm value", "[hw_timer]") all_timer_isr_reg(); // set and get alarm value - all_timer_set_alarm_value(3 * TIMER_SCALE); + all_timer_set_alarm_value(3 * TEST_TIMER_RESOLUTION_HZ); all_timer_get_alarm_value(alarm_val); for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) { - TEST_ASSERT_EQUAL_UINT32(3 * TIMER_SCALE, (uint32_t)alarm_val[i]); + TEST_ASSERT_EQUAL_UINT32(3 * TEST_TIMER_RESOLUTION_HZ, (uint32_t)alarm_val[i]); } // set interrupt read alarm value timer_intr_enable_and_start(TIMER_GROUP_0, TIMER_0, 2.4); - timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 2.4 * TIMER_SCALE); + timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 2.4 * TEST_TIMER_RESOLUTION_HZ); +#if SOC_TIMER_GROUPS > 1 timer_intr_enable_and_start(TIMER_GROUP_1, TIMER_0, 1.4); - timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_DIS, 1.4 * TIMER_SCALE); + timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_DIS, 1.4 * TEST_TIMER_RESOLUTION_HZ); +#endif all_timer_isr_unreg(); all_timer_deinit(); } @@ -683,10 +659,11 @@ TEST_CASE("Timer set alarm value", "[hw_timer]") TEST_CASE("Timer auto reload", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_DIS, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL }; @@ -695,17 +672,21 @@ TEST_CASE("Timer auto reload", "[hw_timer]") // test disable auto_reload timer_intr_enable_and_start(TIMER_GROUP_0, TIMER_0, 1.14); - timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 1.14 * TIMER_SCALE); + timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 1.14 * TEST_TIMER_RESOLUTION_HZ); +#if SOC_TIMER_GROUPS > 1 timer_intr_enable_and_start(TIMER_GROUP_1, TIMER_0, 1.14); - timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_DIS, 1.14 * TIMER_SCALE); + timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_DIS, 1.14 * TEST_TIMER_RESOLUTION_HZ); +#endif //test enable auto_reload TEST_ESP_OK(timer_set_auto_reload(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_EN)); timer_intr_enable_and_start(TIMER_GROUP_0, TIMER_0, 1.4); timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_EN, 0); +#if SOC_TIMER_GROUPS > 1 TEST_ESP_OK(timer_set_auto_reload(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_EN)); timer_intr_enable_and_start(TIMER_GROUP_1, TIMER_0, 1.4); timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_EN, 0); +#endif all_timer_isr_unreg(); all_timer_deinit(); } @@ -718,30 +699,33 @@ TEST_CASE("Timer auto reload", "[hw_timer]") TEST_CASE("Timer enable timer interrupt", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_DIS, .counter_dir = TIMER_COUNT_UP, .auto_reload = TIMER_AUTORELOAD_DIS, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL }; all_timer_init(&config, true); all_timer_pause(); - all_timer_set_alarm_value(1.2 * TIMER_SCALE); + all_timer_set_alarm_value(1.2 * TEST_TIMER_RESOLUTION_HZ); all_timer_set_counter_value(0); all_timer_isr_reg(); - timer_intr_enable_disable_test(TIMER_GROUP_0, TIMER_0, 1.2 * TIMER_SCALE); - timer_intr_enable_disable_test(TIMER_GROUP_1, TIMER_0, 1.2 * TIMER_SCALE); + timer_intr_enable_disable_test(TIMER_GROUP_0, TIMER_0, 1.2 * TEST_TIMER_RESOLUTION_HZ); +#if SOC_TIMER_GROUPS > 1 + timer_intr_enable_disable_test(TIMER_GROUP_1, TIMER_0, 1.2 * TEST_TIMER_RESOLUTION_HZ); +#endif - // enable interrupt of tg1_timer0 again + // enable interrupt of tg0_timer0 again alarm_flag = false; - TEST_ESP_OK(timer_pause(TIMER_GROUP_1, TIMER_0)); - TEST_ESP_OK(timer_set_counter_value(TIMER_GROUP_1, TIMER_0, 0)); - TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_EN)); - TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_1, TIMER_0)); - TEST_ESP_OK(timer_start(TIMER_GROUP_1, TIMER_0)); - timer_isr_check(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TIMER_SCALE); + TEST_ESP_OK(timer_pause(TIMER_GROUP_0, TIMER_0)); + TEST_ESP_OK(timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0)); + TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_0, TIMER_0, TIMER_ALARM_EN)); + TEST_ESP_OK(timer_enable_intr(TIMER_GROUP_0, TIMER_0)); + TEST_ESP_OK(timer_start(TIMER_GROUP_0, TIMER_0)); + timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TEST_TIMER_RESOLUTION_HZ); TEST_ASSERT_EQUAL(true, alarm_flag); all_timer_isr_unreg(); all_timer_deinit(); @@ -757,10 +741,11 @@ TEST_CASE("Timer enable timer group interrupt", "[hw_timer][ignore]") intr_handle_t isr_handle = NULL; alarm_flag = false; timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_DIS, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL }; @@ -768,14 +753,14 @@ TEST_CASE("Timer enable timer group interrupt", "[hw_timer][ignore]") all_timer_init(&config, true); all_timer_pause(); all_timer_set_counter_value(set_timer_val); - all_timer_set_alarm_value(1.2 * TIMER_SCALE); + all_timer_set_alarm_value(1.2 * TEST_TIMER_RESOLUTION_HZ); // enable interrupt of tg0_timer0 TEST_ESP_OK(timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0)); TEST_ESP_OK(timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, &isr_handle)); TEST_ESP_OK(timer_start(TIMER_GROUP_0, TIMER_0)); - timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TIMER_SCALE); + timer_isr_check(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_DIS, 1.2 * TEST_TIMER_RESOLUTION_HZ); TEST_ASSERT_EQUAL(true, alarm_flag); // disable interrupt of tg0_timer0 @@ -795,10 +780,11 @@ TEST_CASE("Timer enable timer group interrupt", "[hw_timer][ignore]") TEST_CASE("Timer interrupt register", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_DIS, .auto_reload = TIMER_AUTORELOAD_DIS, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL }; @@ -815,15 +801,19 @@ TEST_CASE("Timer interrupt register", "[hw_timer]") TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_0, TIMER_0, TIMER_ALARM_EN)); timer_intr_enable_and_start(TIMER_GROUP_0, TIMER_0, 0.54); +#if SOC_TIMER_GROUPS > 1 TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_EN)); timer_intr_enable_and_start(TIMER_GROUP_1, TIMER_0, 0.34); +#endif TEST_ESP_OK(timer_set_auto_reload(TIMER_GROUP_0, TIMER_0, TIMER_AUTORELOAD_EN)); TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_0, TIMER_0, TIMER_ALARM_EN)); timer_intr_enable_and_start(TIMER_GROUP_0, TIMER_0, 0.4); +#if SOC_TIMER_GROUPS > 1 TEST_ESP_OK(timer_set_auto_reload(TIMER_GROUP_1, TIMER_0, TIMER_AUTORELOAD_EN)); TEST_ESP_OK(timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_EN)); timer_intr_enable_and_start(TIMER_GROUP_1, TIMER_0, 0.6); +#endif vTaskDelay(1000 / portTICK_PERIOD_MS); // ISR hanlde function should be free before next ISR register. @@ -845,34 +835,37 @@ TEST_CASE("Timer interrupt register", "[hw_timer]") TEST_CASE("Timer clock source", "[hw_timer]") { // configure clock source as APB clock - uint32_t timer_scale = rtc_clk_apb_freq_get() / TIMER_DIVIDER; timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_DIS, .auto_reload = TIMER_AUTORELOAD_DIS, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL, - .clk_src = TIMER_SRC_CLK_APB }; all_timer_init(&config, true); all_timer_pause(); - all_timer_set_alarm_value(1.2 * timer_scale); + all_timer_set_alarm_value(1.2 * TEST_TIMER_RESOLUTION_HZ); all_timer_set_counter_value(0); all_timer_isr_reg(); - timer_intr_enable_disable_test(TIMER_GROUP_0, TIMER_0, 1.2 * timer_scale); - timer_intr_enable_disable_test(TIMER_GROUP_1, TIMER_0, 1.2 * timer_scale ); + timer_intr_enable_disable_test(TIMER_GROUP_0, TIMER_0, 1.2 * TEST_TIMER_RESOLUTION_HZ); +#if SOC_TIMER_GROUPS > 1 + timer_intr_enable_disable_test(TIMER_GROUP_1, TIMER_0, 1.2 * TEST_TIMER_RESOLUTION_HZ); +#endif // configure clock source as XTAL clock all_timer_pause(); - timer_scale = rtc_clk_xtal_freq_get() * 1000000 / TIMER_DIVIDER; config.clk_src = TIMER_SRC_CLK_XTAL; + config.divider = rtc_clk_xtal_freq_get() * 1000000 / TEST_TIMER_RESOLUTION_HZ; all_timer_init(&config, true); - all_timer_set_alarm_value(1.2 * timer_scale); + all_timer_set_alarm_value(1.2 * TEST_TIMER_RESOLUTION_HZ); - timer_intr_enable_disable_test(TIMER_GROUP_0, TIMER_0, 1.2 * timer_scale); - timer_intr_enable_disable_test(TIMER_GROUP_1, TIMER_0, 1.2 * timer_scale ); + timer_intr_enable_disable_test(TIMER_GROUP_0, TIMER_0, 1.2 * TEST_TIMER_RESOLUTION_HZ); +#if SOC_TIMER_GROUPS > 1 + timer_intr_enable_disable_test(TIMER_GROUP_1, TIMER_0, 1.2 * TEST_TIMER_RESOLUTION_HZ); +#endif all_timer_isr_unreg(); all_timer_deinit(); @@ -886,15 +879,15 @@ TEST_CASE("Timer ISR callback", "[hw_timer]") { alarm_flag = false; timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_DIS, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL, }; - uint32_t timer_scale = rtc_clk_apb_freq_get() / TIMER_DIVIDER; - uint64_t alarm_cnt_val = 1.2 * timer_scale; + uint64_t alarm_cnt_val = 1.2 * TEST_TIMER_RESOLUTION_HZ; uint64_t set_timer_val = 0x0; all_timer_init(&config, true); all_timer_pause(); @@ -918,6 +911,7 @@ TEST_CASE("Timer ISR callback", "[hw_timer]") vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT_EQUAL(false, alarm_flag); +#if SOC_TIMER_GROUPS > 1 // add isr callback for tg1_timer0 TEST_ESP_OK(timer_pause(TIMER_GROUP_1, TIMER_0)); TEST_ESP_OK(timer_isr_callback_add(TIMER_GROUP_1, TIMER_0, test_timer_group_isr_cb, @@ -935,19 +929,21 @@ TEST_CASE("Timer ISR callback", "[hw_timer]") TEST_ESP_OK(timer_start(TIMER_GROUP_1, TIMER_0)); vTaskDelay(2000 / portTICK_PERIOD_MS); TEST_ASSERT_EQUAL(false, alarm_flag); +#endif all_timer_deinit(); } /** * Timer memory test */ -TEST_CASE("Timer memory test", "[hw_timer]") +TEST_CASE("Timer init/deinit stress test", "[hw_timer]") { timer_config_t config = { + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .alarm_en = TIMER_ALARM_EN, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, - .divider = TIMER_DIVIDER, .counter_en = TIMER_PAUSE, .intr_type = TIMER_INTR_LEVEL, }; @@ -964,10 +960,10 @@ TEST_CASE("Timer memory test", "[hw_timer]") static void timer_group_test_init(void) { 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); + static const uint32_t ste_val = time_ms * TEST_TIMER_RESOLUTION_HZ / 1000; timer_config_t config = { - .divider = timer_div, + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .counter_dir = TIMER_COUNT_UP, .counter_en = TIMER_PAUSE, .alarm_en = TIMER_ALARM_EN, @@ -1028,7 +1024,8 @@ TEST_CASE("Timer check reinitialization sequence", "[hw_timer]") // 3 - deinit timer driver TEST_ESP_OK(timer_deinit(TIMER_GROUP_0, TIMER_0)); timer_config_t config = { - .divider = TIMER_DIVIDER, + .clk_src = TIMER_SRC_CLK_APB, + .divider = APB_CLK_FREQ / TEST_TIMER_RESOLUTION_HZ, .counter_dir = TIMER_COUNT_UP, .counter_en = TIMER_START, .alarm_en = TIMER_ALARM_EN, @@ -1043,5 +1040,3 @@ TEST_CASE("Timer check reinitialization sequence", "[hw_timer]") // 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); } - -#endif // #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP8684) diff --git a/docs/docs_not_updated/esp8684.txt b/docs/docs_not_updated/esp8684.txt index f3abea91d7..0819164aa1 100644 --- a/docs/docs_not_updated/esp8684.txt +++ b/docs/docs_not_updated/esp8684.txt @@ -102,7 +102,6 @@ api-reference/storage/index api-reference/peripherals/adc api-reference/peripherals/usb_host api-reference/peripherals/sigmadelta -api-reference/peripherals/timer api-reference/peripherals/twai api-reference/peripherals/hmac api-reference/peripherals/usb_device diff --git a/docs/en/api-reference/peripherals/timer.rst b/docs/en/api-reference/peripherals/timer.rst index e05e738af2..f2b2903cbc 100644 --- a/docs/en/api-reference/peripherals/timer.rst +++ b/docs/en/api-reference/peripherals/timer.rst @@ -4,13 +4,14 @@ General Purpose Timer :link_to_translation:`zh_CN:[中文]` {IDF_TARGET_TIMER_COUNTER_BIT_WIDTH:default="54", esp32="64", esp32s2="64"} -{IDF_TARGET_TIMERS_PER_GROUP:default="two", esp32c3="one"} -{IDF_TARGET_TIMERS_TOTAL:default="four", esp32c3="two"} +{IDF_TARGET_TIMER_GROUPS:default="two", esp8684="one"} +{IDF_TARGET_TIMERS_PER_GROUP:default="two", esp32c3="one", esp8684="one"} +{IDF_TARGET_TIMERS_TOTAL:default="four", esp32c3="two", esp8684="one"} Introduction ------------ -The {IDF_TARGET_NAME} chip contains two hardware timer groups. Each group has {IDF_TARGET_TIMERS_PER_GROUP} general-purpose hardware timer(s). They are all {IDF_TARGET_TIMER_COUNTER_BIT_WIDTH}-bit generic timers based on 16-bit pre-scalers and {IDF_TARGET_TIMER_COUNTER_BIT_WIDTH}-bit up / down counters which are capable of being auto-reloaded. +The {IDF_TARGET_NAME} chip contains {IDF_TARGET_TIMER_GROUPS} hardware timer group(s). Each group has {IDF_TARGET_TIMERS_PER_GROUP} general-purpose hardware timer(s). They are all {IDF_TARGET_TIMER_COUNTER_BIT_WIDTH}-bit generic timers based on 16-bit pre-scalers and {IDF_TARGET_TIMER_COUNTER_BIT_WIDTH}-bit up / down counters which are capable of being auto-reloaded. Functional Overview @@ -29,7 +30,7 @@ The following sections of this document cover the typical steps to configure and Timer Initialization ^^^^^^^^^^^^^^^^^^^^ -The two {IDF_TARGET_NAME} timer groups, with {IDF_TARGET_TIMERS_PER_GROUP} timer(s) in each, provide the total of {IDF_TARGET_TIMERS_TOTAL} individual timers for use. An {IDF_TARGET_NAME} timer group should be identified using :cpp:type:`timer_group_t`. An individual timer in a group should be identified with :cpp:type:`timer_idx_t`. +The {IDF_TARGET_TIMER_GROUPS} {IDF_TARGET_NAME} timer group(s), with {IDF_TARGET_TIMERS_PER_GROUP} timer(s) in each, provide the total of {IDF_TARGET_TIMERS_TOTAL} individual timers for use. An {IDF_TARGET_NAME} timer group should be identified using :cpp:type:`timer_group_t`. An individual timer in a group should be identified with :cpp:type:`timer_idx_t`. First of all, the timer should be initialized by calling the function :cpp:func:`timer_init` and passing a structure :cpp:type:`timer_config_t` to it to define how the timer should operate. In particular, the following timer parameters can be set: