forked from espressif/esp-idf
timer: example migrate to pytest
This commit is contained in:
@@ -19,40 +19,27 @@ See the [ESP-IDF Getting Started Guide](https://idf.espressif.com/) for all the
|
|||||||
## Example Output
|
## Example Output
|
||||||
|
|
||||||
```
|
```
|
||||||
Timer Group with auto reload
|
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||||
Group[0], timer[0] alarm event
|
I (325) example: Init timer with auto-reload
|
||||||
------- EVENT TIME --------
|
I (835) example: Timer auto reloaded, count value in ISR: 3
|
||||||
Counter: 0x0000000000000008
|
I (1335) example: Timer auto reloaded, count value in ISR: 3
|
||||||
Time : 0.00000160 s
|
I (1835) example: Timer auto reloaded, count value in ISR: 3
|
||||||
-------- TASK TIME --------
|
I (2335) example: Timer auto reloaded, count value in ISR: 3
|
||||||
Counter: 0x0000000000004ed8
|
I (2335) example: Init timer without auto-reload
|
||||||
Time : 0.00403680 s
|
I (2835) example: Timer alarmed at 500003
|
||||||
Timer Group without auto reload
|
I (3335) example: Timer alarmed at 1000003
|
||||||
Group[1], timer[0] alarm event
|
I (3835) example: Timer alarmed at 1500003
|
||||||
------- EVENT TIME --------
|
I (4335) example: Timer alarmed at 2000003
|
||||||
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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Functionality Overview
|
## Functionality Overview
|
||||||
|
|
||||||
* Two timers are configured
|
* Configure one timer with auto-reload enabled, alarm period set to 0.5s
|
||||||
* Each timer is set with some sample alarm interval
|
* On reaching the interval value the timer will generate an alarm
|
||||||
* On reaching the interval value each timer will generate an alarm
|
* The timer will reload with initial count value on alarm, by hardware
|
||||||
* One of the timers is configured to automatically reload it's counter value on the alarm
|
* Reconfigure the timer with auto-reload disabled, initial alarm value set to 0.5s
|
||||||
* The other timer is configured to keep incrementing and is reloaded by the application each time the alarm happens
|
* The timer keeps incrementing and in the alarm callback, the software reconfigures its alarm value by increasing 0.5s
|
||||||
* Alarms trigger subsequent interrupts, that is tracked with messages printed on the terminal:
|
* The main task will print the count value that captured in the alarm callback
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
@@ -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()
|
|
@@ -9,131 +9,119 @@
|
|||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include "driver/timer.h"
|
#include "driver/timer.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
#define TIMER_DIVIDER (16) // Hardware timer clock divider
|
#define TIMER_RESOLUTION_HZ 1000000 // 1MHz resolution
|
||||||
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
|
#define TIMER_ALARM_PERIOD_S 0.5 // Alarm period 0.5s
|
||||||
|
|
||||||
typedef struct {
|
static const char *TAG = "example";
|
||||||
int timer_group;
|
|
||||||
int timer_idx;
|
|
||||||
int alarm_interval;
|
|
||||||
bool auto_reload;
|
|
||||||
} example_timer_info_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A sample structure to pass events from the timer ISR to task
|
* @brief A sample structure to pass events from the timer ISR to task
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
example_timer_info_t info;
|
uint64_t timer_count_value;
|
||||||
uint64_t timer_counter_value;
|
|
||||||
} example_timer_event_t;
|
} example_timer_event_t;
|
||||||
|
|
||||||
static xQueueHandle s_timer_queue;
|
/**
|
||||||
|
* @brief Timer user data, will be pass to timer alarm callback
|
||||||
/*
|
|
||||||
* A simple helper function to print the raw timer counter value
|
|
||||||
* and the counter value converted to seconds
|
|
||||||
*/
|
*/
|
||||||
static void inline print_timer_counter(uint64_t counter_value)
|
typedef struct {
|
||||||
{
|
xQueueHandle user_queue;
|
||||||
printf("Counter: 0x%08x%08x\r\n", (uint32_t) (counter_value >> 32),
|
int timer_group;
|
||||||
(uint32_t) (counter_value));
|
int timer_idx;
|
||||||
printf("Time : %.8f s\r\n", (double) counter_value / TIMER_SCALE);
|
int alarm_value;
|
||||||
}
|
bool auto_reload;
|
||||||
|
} example_timer_user_data_t;
|
||||||
|
|
||||||
static bool IRAM_ATTR timer_group_isr_callback(void *args)
|
static bool IRAM_ATTR timer_group_isr_callback(void *args)
|
||||||
{
|
{
|
||||||
BaseType_t high_task_awoken = pdFALSE;
|
BaseType_t high_task_awoken = pdFALSE;
|
||||||
example_timer_info_t *info = (example_timer_info_t *) args;
|
example_timer_user_data_t *user_data = (example_timer_user_data_t *) args;
|
||||||
|
// fetch current count value
|
||||||
uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(info->timer_group, info->timer_idx);
|
uint64_t timer_count_value = timer_group_get_counter_value_in_isr(user_data->timer_group, user_data->timer_idx);
|
||||||
|
|
||||||
/* Prepare basic event data that will be then sent back to task */
|
|
||||||
example_timer_event_t evt = {
|
example_timer_event_t evt = {
|
||||||
.info.timer_group = info->timer_group,
|
.timer_count_value = timer_count_value,
|
||||||
.info.timer_idx = info->timer_idx,
|
|
||||||
.info.auto_reload = info->auto_reload,
|
|
||||||
.info.alarm_interval = info->alarm_interval,
|
|
||||||
.timer_counter_value = timer_counter_value
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!info->auto_reload) {
|
// set new alarm value if necessary
|
||||||
timer_counter_value += info->alarm_interval * TIMER_SCALE;
|
if (!user_data->auto_reload) {
|
||||||
timer_group_set_alarm_value_in_isr(info->timer_group, info->timer_idx, timer_counter_value);
|
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 */
|
// Send the event data back to the main program task
|
||||||
xQueueSendFromISR(s_timer_queue, &evt, &high_task_awoken);
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void example_tg_timer_init(example_timer_user_data_t *user_data)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
/* Select and initialize basic parameters of the timer */
|
int group = user_data->timer_group;
|
||||||
|
int timer = user_data->timer_idx;
|
||||||
|
|
||||||
timer_config_t config = {
|
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_dir = TIMER_COUNT_UP,
|
||||||
.counter_en = TIMER_PAUSE,
|
.counter_en = TIMER_PAUSE,
|
||||||
.alarm_en = TIMER_ALARM_EN,
|
.alarm_en = TIMER_ALARM_EN,
|
||||||
.auto_reload = auto_reload,
|
.auto_reload = user_data->auto_reload,
|
||||||
}; // default clock source is APB
|
};
|
||||||
timer_init(group, timer, &config);
|
ESP_ERROR_CHECK(timer_init(group, timer, &config));
|
||||||
|
|
||||||
/* Timer's counter will initially start from value below.
|
// For the timer counter to a initial value
|
||||||
Also, if auto_reload is set, this value will be automatically reload on alarm */
|
ESP_ERROR_CHECK(timer_set_counter_value(group, timer, 0));
|
||||||
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. */
|
static void example_tg_timer_deinit(int group, int timer)
|
||||||
timer_set_alarm_value(group, timer, timer_interval_sec * TIMER_SCALE);
|
{
|
||||||
timer_enable_intr(group, timer);
|
ESP_ERROR_CHECK(timer_isr_callback_remove(group, timer));
|
||||||
|
ESP_ERROR_CHECK(timer_deinit(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_main(void)
|
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) {
|
ESP_LOGI(TAG, "Init timer with auto-reload");
|
||||||
|
user_data->auto_reload = true;
|
||||||
|
example_tg_timer_init(user_data);
|
||||||
|
|
||||||
example_timer_event_t evt;
|
example_timer_event_t evt;
|
||||||
xQueueReceive(s_timer_queue, &evt, portMAX_DELAY);
|
uint32_t test_count = 4;
|
||||||
|
while (test_count--) {
|
||||||
/* Print information that the timer reported an event */
|
xQueueReceive(user_data->user_queue, &evt, portMAX_DELAY);
|
||||||
if (evt.info.auto_reload) {
|
ESP_LOGI(TAG, "Timer auto reloaded, count value in ISR: %llu", evt.timer_count_value);
|
||||||
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);
|
example_tg_timer_deinit(user_data->timer_group, user_data->timer_idx);
|
||||||
|
|
||||||
/* Print the timer values passed by event */
|
ESP_LOGI(TAG, "Init timer without auto-reload");
|
||||||
printf("------- EVENT TIME --------\n");
|
user_data->auto_reload = false;
|
||||||
print_timer_counter(evt.timer_counter_value);
|
example_tg_timer_init(user_data);
|
||||||
|
|
||||||
/* Print the timer values as visible by this task */
|
test_count = 4;
|
||||||
printf("-------- TASK TIME --------\n");
|
while (test_count--) {
|
||||||
uint64_t task_counter_value;
|
xQueueReceive(user_data->user_queue, &evt, portMAX_DELAY);
|
||||||
timer_get_counter_value(evt.info.timer_group, evt.info.timer_idx, &task_counter_value);
|
ESP_LOGI(TAG, "Timer alarmed at %llu", evt.timer_count_value);
|
||||||
print_timer_counter(task_counter_value);
|
|
||||||
}
|
}
|
||||||
|
example_tg_timer_deinit(user_data->timer_group, user_data->timer_idx);
|
||||||
|
|
||||||
|
vQueueDelete(user_data->user_queue);
|
||||||
|
free(user_data);
|
||||||
}
|
}
|
||||||
|
24
examples/peripherals/timer_group/pytest_timer_group.py
Normal file
24
examples/peripherals/timer_group/pytest_timer_group.py
Normal file
@@ -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)
|
Reference in New Issue
Block a user