From: krzychb Date: Mon, 25 Sep 2017 04:20:12 +0000 (+0200) Subject: Timer API docs update, refactored example X-Git-Tag: v3.1-dev~127^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9b7d5d76a7a6328399b267aa23a721238c8bd3eb;p=esp-idf Timer API docs update, refactored example --- diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index 2914a90a35..6b43eb4704 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -26,7 +26,8 @@ extern "C" { #endif -#define TIMER_BASE_CLK (APB_CLK_FREQ) +#define TIMER_BASE_CLK (APB_CLK_FREQ) /*!< Frequency of the clock on the input of the timer groups */ + /** * @brief Selects a Timer-Group out of 2 available groups */ @@ -90,15 +91,15 @@ typedef enum { } timer_autoreload_t; /** - * @brief timer configure struct + * @brief Data structure with timer's configuration settings */ typedef struct { - bool alarm_en; /*!< Timer alarm enable */ - bool counter_en; /*!< Counter enable */ + bool alarm_en; /*!< Timer alarm enable */ + bool counter_en; /*!< Counter enable */ timer_intr_mode_t intr_type; /*!< Interrupt mode */ timer_count_dir_t counter_dir; /*!< Counter direction */ - bool auto_reload; /*!< Timer auto-reload */ - uint16_t divider; /*!< Counter clock divider*/ + bool auto_reload; /*!< Timer auto-reload */ + uint32_t divider; /*!< Counter clock divider. The divider's range is from from 2 to 65536. */ } timer_config_t; @@ -202,13 +203,13 @@ esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, * * @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1 * @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1] - * @param divider Timer clock divider value. + * @param divider Timer clock divider value. The divider's range is from from 2 to 65536. * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider); +esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint32_t divider); /** * @brief Set timer alarm value. @@ -249,27 +250,23 @@ esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, */ esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en); - /** - * @brief register Timer interrupt handler, the handler is an ISR. - * The handler will be attached to the same CPU core that this function is running on. + * @brief Register Timer interrupt handler, the handler is an ISR. + * The handler will be attached to the same CPU core that this function is running on. * * @param group_num Timer group number * @param timer_num Timer index of timer group * @param fn Interrupt handler function. - * @note - * In case the this is called with the INIRAM flag, code inside the handler function can - * only call functions in IRAM, so it cannot call other timer APIs. - * Use direct register access to access timers from inside the ISR in this case. - * * @param arg Parameter for handler function - * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) - * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. - * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will - * be returned here. - * @return - * - ESP_OK Success - * - ESP_ERR_INVALID_ARG Function pointer error. + * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) + * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will + * be returned here. + * + * @note If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set, + * the handler function must be declared with IRAM_ATTR attribute + * and can only call functions in IRAM or ROM. It cannot call other timer APIs. + * Use direct register access to configure timers from inside the ISR in this case. * * @return * - ESP_OK Success diff --git a/components/driver/timer.c b/components/driver/timer.c index b80ed643e9..8f881fc5a8 100644 --- a/components/driver/timer.c +++ b/components/driver/timer.c @@ -35,6 +35,7 @@ static const char* TIMER_TAG = "timer_group"; #define TIMER_AUTORELOAD_ERROR "HW TIMER AUTORELOAD ERROR" #define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR" #define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR" +#define DIVIDER_RANGE_ERROR "HW TIMER divider outside of [2, 65536] range error" static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1}; static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; @@ -123,14 +124,15 @@ esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, return ESP_OK; } -esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider) +esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint32_t divider) { TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); + TIMER_CHECK(divider > 1 && divider < 65537, DIVIDER_RANGE_ERROR, ESP_ERR_INVALID_ARG); TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); int timer_en = TG[group_num]->hw_timer[timer_num].config.enable; TG[group_num]->hw_timer[timer_num].config.enable = 0; - TG[group_num]->hw_timer[timer_num].config.divider = divider; + TG[group_num]->hw_timer[timer_num].config.divider = (uint16_t) divider; TG[group_num]->hw_timer[timer_num].config.enable = timer_en; TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; @@ -209,6 +211,7 @@ esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG); TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG); + TIMER_CHECK(config->divider > 1 && config->divider < 65537, DIVIDER_RANGE_ERROR, ESP_ERR_INVALID_ARG); if(group_num == 0) { periph_module_enable(PERIPH_TIMG0_MODULE); @@ -217,7 +220,7 @@ esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer } TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]); TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload; - TG[group_num]->hw_timer[timer_num].config.divider = config->divider; + TG[group_num]->hw_timer[timer_num].config.divider = (uint16_t) config->divider; TG[group_num]->hw_timer[timer_num].config.enable = config->counter_en; TG[group_num]->hw_timer[timer_num].config.increase = config->counter_dir; TG[group_num]->hw_timer[timer_num].config.alarm_en = config->alarm_en; @@ -236,10 +239,11 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer config->alarm_en = TG[group_num]->hw_timer[timer_num].config.alarm_en; config->auto_reload = TG[group_num]->hw_timer[timer_num].config.autoreload; config->counter_dir = TG[group_num]->hw_timer[timer_num].config.increase; - config->counter_dir = TG[group_num]->hw_timer[timer_num].config.divider; + config->divider = (TG[group_num]->hw_timer[timer_num].config.divider == 0 ? + 65536 : TG[group_num]->hw_timer[timer_num].config.divider); config->counter_en = TG[group_num]->hw_timer[timer_num].config.enable; if(TG[group_num]->hw_timer[timer_num].config.level_int_en) { - config->intr_type =TIMER_INTR_LEVEL; + config->intr_type = TIMER_INTR_LEVEL; } TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]); return ESP_OK; diff --git a/docs/api-reference/peripherals/timer.rst b/docs/api-reference/peripherals/timer.rst index 5c833ebc09..2d7a057cb0 100644 --- a/docs/api-reference/peripherals/timer.rst +++ b/docs/api-reference/peripherals/timer.rst @@ -1,20 +1,100 @@ TIMER -======== +===== -Overview --------- +Introduction +------------ -ESP32 chip contains two hardware timer groups, each containing two general-purpose hardware timers. +The ESP32 chip contains two hardware timer groups. Each group has two general-purpose hardware timers. They are all 64-bit generic timers based on 16-bit prescalers and 64-bit auto-reload-capable up / down counters. + + +Functional Overview +------------------- + +Typical steps to configure an operate the timer are described in the following sections: + +* :ref:`timer-api-timer-initialization` - what parameters should be set up to get the timer working and what specific functionality is provided depending on the set up. +* :ref:`timer-api-timer-control` - how to read the timer's value, pause / start the timer, and change how it operates. +* :ref:`timer-api-alarms` - setting and using alarms. +* :ref:`timer-api-interrupts`- how to enable and use interrupts. + + +.. _timer-api-timer-initialization: + +Timer Initialization +^^^^^^^^^^^^^^^^^^^^ + +The two timer groups on-board of the ESP32 are identified using :cpp:type:`timer_group_t`. Individual timers in a group are identified with :cpp:type:`timer_idx_t`. The two groups, each having two timers, provide the total of four individual timers to our disposal. + +Before starting the timer, it should be initialized by calling :cpp:func:`timer_init`. This function should be provided with a structure :cpp:type:`timer_config_t` to define how timer should operate. In particular the following timer's parameters may be set: + + * **Divider**: How quickly the timer's counter is "ticking". This depends on the setting of :cpp:member:`divider`, that will be used as divisor of the incoming 80 MHz APB_CLK clock. + * **Mode**: If the the counter is incrementing or decrementing, defined using :cpp:member:`counter_dir` by selecting one of values from :cpp:type:`timer_count_dir_t`. + * **Counter Enable**: If the counter is enabled, then it will start incrementing / decrementing immediately after calling :cpp:func:`timer_init`. This action is set using :cpp:member:`counter_en` by selecting one of vales from :cpp:type:`timer_start_t`. + * **Alarm Enable**: Determined by the setting of :cpp:member:`alarm_en`. + * **Auto Reload**: Whether the counter should :cpp:member:`auto_reload` a specific initial value on the timer's alarm, or continue incrementing or decrementing. + * **Interrupt Type**: Whether an interrupt is triggered on timer's alarm. Set the value defined in :cpp:type:`timer_intr_mode_t`. + +To get the current values of the timers settings, use function :cpp:func:`timer_get_config`. + + +.. _timer-api-timer-control: + +Timer Control +^^^^^^^^^^^^^ + +Once the timer is configured and enabled, it is already "ticking". To check it's current value call :cpp:func:`timer_get_counter_value` or :cpp:func:`timer_get_counter_time_sec`. To set the timer to specific starting value call :cpp:func:`timer_set_counter_value`. + +The timer may be paused at any time by calling :cpp:func:`timer_pause`. To start it again call :cpp:func:`timer_start`. + +To change how the timer operates you can call once more :cpp:func:`timer_init` described in section :ref:`timer-api-timer-initialization`. Another option is to use dedicated functions to change individual settings: + + * **Divider** value - :cpp:func:`timer_set_divider`. **Note:** the timer should be paused when changing the divider to avoid unpredictable results. If the timer is already running, :cpp:func:`timer_set_divider` will first pause the timer, change the divider, and finally start the timer again. + * **Mode** (whether the counter incrementing or decrementing) - :cpp:func:`timer_set_counter_mode` + * **Auto Reload** counter on alarm - :cpp:func:`timer_set_auto_reload` + + +.. _timer-api-alarms: + +Alarms +^^^^^^ + +To set an alarm, call function :cpp:func:`timer_set_alarm_value` and then enable it with :cpp:func:`timer_set_alarm`. The alarm may be also enabled during the timer initialization stage, when :cpp:func:`timer_init` is called. + +After the alarm is enabled and the timer reaches the alarm value, depending on configuration, the following two actions may happen: + + * An interrupt will be triggered, if previously configured. See section :ref:`timer-api-interrupts` how to configure interrupts. + * When :cpp:member:`auto_reload` is enabled, the timer's counter will be reloaded to start counting from specific initial value. The value to start should be set in advance with :cpp:func:`timer_set_counter_value`. + +.. note:: + + The alarm will be triggered immediately, if an alarm value is set and the timer has already passed this value. + +To check what alarm value has been set up, call :cpp:func:`timer_get_alarm_value`. + + +.. _timer-api-interrupts: + +Interrupts +^^^^^^^^^^ + +Registration of the interrupt handler for a specific timer group and timer is done be calling :cpp:func:`timer_isr_register`. + +To enable interrupts for a timer group call :cpp:func:`timer_group_intr_enable`. To do it for a specific timer, call :cpp:func:`timer_enable_intr`. Disabling of interrupts is done with corresponding functions :cpp:func:`timer_group_intr_disable` and :cpp:func:`timer_disable_intr`. + +When servicing an interrupt within an ISR, the interrupt need to explicitly cleared. To do so, set the ``TIMERGN.int_clr_timers.tM`` structure defined in :component_file:`soc/esp32/include/soc/timer_group_struct.h`, where N is the timer group number [0, 1] and M is the timer number [0, 1]. For example to clear an interrupt for the timer 1 in the timer group 0, call the following:: + + TIMERG0.int_clr_timers.t1 = 1 + +See the application example below how to use interrupts. -They are all 64-bit generic timers based on 16-bit prescalers and 64-bit auto-reload-capable up/down counters. Application Example ------------------- -64-bit hardware timer example: :example:`peripherals/timer_group`. +The 64-bit hardware timer example: :example:`peripherals/timer_group`. + API Reference ------------- .. include:: /_build/inc/timer.inc - diff --git a/examples/peripherals/timer_group/README.md b/examples/peripherals/timer_group/README.md index 0be2c847a8..08135b3a39 100644 --- a/examples/peripherals/timer_group/README.md +++ b/examples/peripherals/timer_group/README.md @@ -1,3 +1,33 @@ # Example: timer_group This example uses the timer group driver to generate timer interrupts at two specified alarm intervals. + +## 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: + +``` + Example timer with auto reload +Group[0], timer[1] alarm event +------- EVENT TIME -------- +Counter: 0x000000000000000a +Time : 0.00000200 s +-------- TASK TIME -------- +Counter: 0x00000000000107ff +Time : 0.01351660 s + + Example timer without reload +Group[0], timer[0] alarm event +------- EVENT TIME -------- +Counter: 0x00000000092ae316 +Time : 30.76111800 s +-------- TASK TIME -------- +Counter: 0x00000000092bd535 +Time : 30.77351460 s + +``` 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 97892e5dec..0e1ee36fc6 100644 --- a/examples/peripherals/timer_group/main/timer_group_example_main.c +++ b/examples/peripherals/timer_group/main/timer_group_example_main.c @@ -16,186 +16,159 @@ #include "driver/periph_ctrl.h" #include "driver/timer.h" -#define TIMER_INTR_SEL TIMER_INTR_LEVEL /*!< Timer level interrupt */ -#define TIMER_GROUP TIMER_GROUP_0 /*!< Test on timer group 0 */ -#define TIMER_DIVIDER 16 /*!< Hardware timer clock divider */ -#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) /*!< used to calculate counter value */ -#define TIMER_FINE_ADJ (1.4*(TIMER_BASE_CLK / TIMER_DIVIDER)/1000000) /*!< used to compensate alarm value */ -#define TIMER_INTERVAL0_SEC (3.4179) /*!< test interval for timer 0 */ -#define TIMER_INTERVAL1_SEC (5.78) /*!< test interval for timer 1 */ -#define TEST_WITHOUT_RELOAD 0 /*!< example of auto-reload mode */ -#define TEST_WITH_RELOAD 1 /*!< example without auto-reload mode */ +#define TIMER_DIVIDER 16 // Hardware timer clock divider +#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds +#define TIMER_INTERVAL0_SEC (3.4179) // sample test interval for the first timer +#define TIMER_INTERVAL1_SEC (5.78) // sample test interval for the second timer +#define TEST_WITHOUT_RELOAD 0 // testing will be done without auto reload +#define TEST_WITH_RELOAD 1 // testing will be done with auto reload +/* + * A sample structure to pass events + * from the timer interrupt handler to the main program. + */ typedef struct { - int type; /*!< event type */ - int group; /*!< timer group */ - int idx; /*!< timer number */ - uint64_t counter_val; /*!< timer counter value */ + int type; // the type of timer's event + int timer_group; + int timer_idx; + uint64_t timer_counter_value; } timer_event_t; xQueueHandle timer_queue; /* - * @brief Print a uint64_t value + * A simple helper function to print the raw timer counter value + * and the counter value converted to seconds */ -static void inline print_u64(uint64_t val) +static void inline print_timer_counter(uint64_t counter_value) { - printf("0x%08x%08x\n", (uint32_t) (val >> 32), (uint32_t) (val)); -} - -static void timer_example_evt_task(void *arg) -{ - while(1) { - timer_event_t evt; - xQueueReceive(timer_queue, &evt, portMAX_DELAY); - if(evt.type == TEST_WITHOUT_RELOAD) { - printf("\n\n example of count-up-timer \n"); - } else if(evt.type == TEST_WITH_RELOAD) { - printf("\n\n example of reload-timer \n"); - - } - /*Show timer event from interrupt*/ - printf("-------INTR TIME EVT--------\n"); - printf("TG[%d] timer[%d] alarm evt\n", evt.group, evt.idx); - printf("reg: "); - print_u64(evt.counter_val); - - double time = (double) evt.counter_val / (TIMER_BASE_CLK / TIMERG0.hw_timer[evt.idx].config.divider); - printf("time: %.8f S\n", time); - /*Read timer value from task*/ - printf("======TASK TIME======\n"); - uint64_t timer_val; - timer_get_counter_value(evt.group, evt.idx, &timer_val); - timer_get_counter_time_sec(evt.group, evt.idx, &time); - printf("TG[%d] timer[%d] alarm evt\n", evt.group, evt.idx); - printf("reg: "); - print_u64(timer_val); - printf("time: %.8f S\n", time); - } + printf("Counter: 0x%08x%08x\n", (uint32_t) (counter_value >> 32), + (uint32_t) (counter_value)); + printf("Time : %.8f s\n", (double) counter_value / TIMER_SCALE); } /* - * @brief timer group0 ISR handler + * Timer group0 ISR handler + * + * Note: + * We don't call the timer API here because they are not declared with IRAM_ATTR. + * If we're okay with the timer irq not being serviced while SPI flash cache is disabled, + * we can allocate this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API. */ void IRAM_ATTR timer_group0_isr(void *para) { int timer_idx = (int) para; + + /* Retrieve the interrupt status and the counter value + from the timer that reported the interrupt */ uint32_t intr_status = TIMERG0.int_st_timers.val; - timer_event_t evt; - if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) { - /*Timer0 is an example that doesn't reload counter value*/ - TIMERG0.hw_timer[timer_idx].update = 1; + TIMERG0.hw_timer[timer_idx].update = 1; + uint64_t timer_counter_value = + ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32 + | TIMERG0.hw_timer[timer_idx].cnt_low; - /* We don't call a API here because they are not declared with IRAM_ATTR. - If we're okay with the timer irq not being serviced while SPI flash cache is disabled, - we can alloc this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API. */ - TIMERG0.int_clr_timers.t0 = 1; - uint64_t timer_val = ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32 - | TIMERG0.hw_timer[timer_idx].cnt_low; + /* Prepare basic event data + that will be then sent back to the main program task */ + timer_event_t evt; + evt.timer_group = 0; + evt.timer_idx = timer_idx; + evt.timer_counter_value = timer_counter_value; - /*Post an event to out example task*/ + /* Clear the interrupt + and update the alarm time for the timer with without reload */ + if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) { evt.type = TEST_WITHOUT_RELOAD; - evt.group = 0; - evt.idx = timer_idx; - evt.counter_val = timer_val; - xQueueSendFromISR(timer_queue, &evt, NULL); - - /*For a timer that will not reload, we need to set the next alarm value each time. */ - timer_val += - (uint64_t) (TIMER_INTERVAL0_SEC * (TIMER_BASE_CLK / TIMERG0.hw_timer[timer_idx].config.divider)); - /*Fine adjust*/ - timer_val -= TIMER_FINE_ADJ; - TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_val >> 32); - TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_val; - /*After set alarm, we set alarm_en bit if we want to enable alarm again.*/ - TIMERG0.hw_timer[timer_idx].config.alarm_en = 1; - - } else if((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) { - /*Timer1 is an example that will reload counter value*/ - TIMERG0.hw_timer[timer_idx].update = 1; - /*We don't call a API here because they are not declared with IRAM_ATTR*/ - TIMERG0.int_clr_timers.t1 = 1; - uint64_t timer_val = ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32 - | TIMERG0.hw_timer[timer_idx].cnt_low; - /*Post an event to out example task*/ + TIMERG0.int_clr_timers.t0 = 1; + timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE); + TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_counter_value >> 32); + TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value; + } else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) { evt.type = TEST_WITH_RELOAD; - evt.group = 0; - evt.idx = timer_idx; - evt.counter_val = timer_val; - xQueueSendFromISR(timer_queue, &evt, NULL); - /*For a auto-reload timer, we still need to set alarm_en bit if we want to enable alarm again.*/ - TIMERG0.hw_timer[timer_idx].config.alarm_en = 1; + TIMERG0.int_clr_timers.t1 = 1; + } else { + evt.type = -1; // not supported even type } + + /* After the alarm has been triggered + we need enable it again, so it is triggered the next time */ + TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN; + + /* Now just send the event data back to the main program task */ + xQueueSendFromISR(timer_queue, &evt, NULL); } /* - * @brief timer group0 hardware timer0 init + * Initialize selected timer of the timer group 0 + * + * timer_idx - the timer number to initialize + * auto_reload - should the timer auto reload on alarm? + * timer_interval_sec - the interval of alarm to set */ -static void example_tg0_timer0_init() +static void example_tg0_timer_init(int timer_idx, + bool auto_reload, double timer_interval_sec) { - int timer_group = TIMER_GROUP_0; - int timer_idx = TIMER_0; + /* Select and initialize basic parameters of the timer */ timer_config_t config; - config.alarm_en = 1; - config.auto_reload = 0; - config.counter_dir = TIMER_COUNT_UP; config.divider = TIMER_DIVIDER; - config.intr_type = TIMER_INTR_SEL; + config.counter_dir = TIMER_COUNT_UP; config.counter_en = TIMER_PAUSE; - /*Configure timer*/ - timer_init(timer_group, timer_idx, &config); - /*Stop timer counter*/ - timer_pause(timer_group, timer_idx); - /*Load counter value */ - timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); - /*Set alarm value*/ - timer_set_alarm_value(timer_group, timer_idx, TIMER_INTERVAL0_SEC * TIMER_SCALE - TIMER_FINE_ADJ); - /*Enable timer interrupt*/ - timer_enable_intr(timer_group, timer_idx); - /*Set ISR handler*/ - timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL); - /*Start timer counter*/ - timer_start(timer_group, timer_idx); + config.alarm_en = TIMER_ALARM_EN; + config.intr_type = TIMER_INTR_LEVEL; + config.auto_reload = auto_reload; + timer_init(TIMER_GROUP_0, timer_idx, &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(TIMER_GROUP_0, timer_idx, 0x00000000ULL); + + /* Configure the alarm value and the interrupt on alarm. */ + timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE); + timer_enable_intr(TIMER_GROUP_0, timer_idx); + timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, + (void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL); + + timer_start(TIMER_GROUP_0, timer_idx); } /* - * @brief timer group0 hardware timer1 init + * The main task of this example program */ -static void example_tg0_timer1_init() +static void timer_example_evt_task(void *arg) { - int timer_group = TIMER_GROUP_0; - int timer_idx = TIMER_1; - timer_config_t config; - config.alarm_en = 1; - config.auto_reload = 1; - config.counter_dir = TIMER_COUNT_UP; - config.divider = TIMER_DIVIDER; - config.intr_type = TIMER_INTR_SEL; - config.counter_en = TIMER_PAUSE; - /*Configure timer*/ - timer_init(timer_group, timer_idx, &config); - /*Stop timer counter*/ - timer_pause(timer_group, timer_idx); - /*Load counter value */ - timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); - /*Set alarm value*/ - timer_set_alarm_value(timer_group, timer_idx, TIMER_INTERVAL1_SEC * TIMER_SCALE); - /*Enable timer interrupt*/ - timer_enable_intr(timer_group, timer_idx); - /*Set ISR handler*/ - timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL); - /*Start timer counter*/ - timer_start(timer_group, timer_idx); + while (1) { + timer_event_t evt; + xQueueReceive(timer_queue, &evt, portMAX_DELAY); + + /* Print information that the timer reported an event */ + if (evt.type == TEST_WITHOUT_RELOAD) { + printf("\n Example timer without reload\n"); + } else if (evt.type == TEST_WITH_RELOAD) { + printf("\n Example timer with auto reload\n"); + } else { + printf("\n UNKNOWN EVENT TYPE\n"); + } + printf("Group[%d], timer[%d] alarm event\n", evt.timer_group, evt.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.timer_group, evt.timer_idx, &task_counter_value); + print_timer_counter(task_counter_value); + } } -/** - * @brief In this test, we will test hardware timer0 and timer1 of timer group0. +/* + * In this example, we will test hardware timer0 and timer1 of timer group0. */ void app_main() { timer_queue = xQueueCreate(10, sizeof(timer_event_t)); - example_tg0_timer0_init(); - example_tg0_timer1_init(); + example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC); + example_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD, TIMER_INTERVAL1_SEC); xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL); }