Skip to content

Commit

Permalink
gptimer: add example with various use cases
Browse files Browse the repository at this point in the history
  • Loading branch information
suda-morris committed Jan 7, 2022
1 parent 5deb83b commit 25490dd
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 3 deletions.
6 changes: 6 additions & 0 deletions examples/peripherals/timer_group/gptimer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(gptimer)
46 changes: 46 additions & 0 deletions examples/peripherals/timer_group/gptimer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Example: General Purpose Timer

This example illustrates how to use gptimer APIs to generate periodic alarm events and how different alarm actions behave on events.

## How to Use Example

### Hardware Required

* A development board with ESP SOC chip
* A USB cable for Power supply and programming

### Build and Flash

Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.

(To exit the serial monitor, type ``Ctrl-]``.)

See the [ESP-IDF Getting Started Guide](https://idf.espressif.com/) for all the steps to configure and use the ESP-IDF to build projects.
## Example Output

```
I (0) cpu_start: Starting scheduler on APP CPU.
I (323) example: Create timer handle
I (323) example: Start timer, stop it at alarm event
I (1333) example: Timer stopped, count=1000002
I (1333) example: Set count value
I (1333) example: Get count value
I (1333) example: Timer count value=100
I (1343) example: Start timer, auto-reload at alarm event
I (2343) example: Timer reloaded, count=2
I (3343) example: Timer reloaded, count=2
I (4343) example: Timer reloaded, count=2
I (5343) example: Timer reloaded, count=2
I (5343) example: Stop timer
I (5343) example: Update alarm value dynamically
I (6353) example: Timer alarmed, count=1000002
I (7353) example: Timer alarmed, count=2000002
I (8353) example: Timer alarmed, count=3000002
I (9353) example: Timer alarmed, count=4000002
I (9353) example: Stop timer
I (9353) example: Delete timer
```

## Troubleshooting

For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
2 changes: 2 additions & 0 deletions examples/peripherals/timer_group/gptimer/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRCS "gptimer_example_main.c"
INCLUDE_DIRS ".")
155 changes: 155 additions & 0 deletions examples/peripherals/timer_group/gptimer/main/gptimer_example_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gptimer.h"
#include "esp_log.h"

static const char *TAG = "example";

typedef struct {
uint64_t event_count;
} example_queue_element_t;

static bool IRAM_ATTR example_timer_on_alarm_cb_v1(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
BaseType_t high_task_awoken = pdFALSE;
QueueHandle_t queue = (QueueHandle_t)user_data;
// stop timer immediately
gptimer_stop(timer);
// Retrieve count value and send to queue
example_queue_element_t ele = {
.event_count = edata->count_value
};
xQueueSendFromISR(queue, &ele, &high_task_awoken);
// return whether we need to yield at the end of ISR
return (high_task_awoken == pdTRUE);
}

static bool IRAM_ATTR example_timer_on_alarm_cb_v2(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
BaseType_t high_task_awoken = pdFALSE;
QueueHandle_t queue = (QueueHandle_t)user_data;
// Retrieve count value and send to queue
example_queue_element_t ele = {
.event_count = edata->count_value
};
xQueueSendFromISR(queue, &ele, &high_task_awoken);
// return whether we need to yield at the end of ISR
return (high_task_awoken == pdTRUE);
}

static bool IRAM_ATTR example_timer_on_alarm_cb_v3(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
{
BaseType_t high_task_awoken = pdFALSE;
QueueHandle_t queue = (QueueHandle_t)user_data;
// Retrieve count value and send to queue
example_queue_element_t ele = {
.event_count = edata->count_value
};
xQueueSendFromISR(queue, &ele, &high_task_awoken);
// reconfigure alarm value
gptimer_alarm_config_t alarm_config = {
.alarm_count = edata->alarm_value + 1000000, // alarm in next 1s
};
gptimer_set_alarm_action(timer, &alarm_config);
// return whether we need to yield at the end of ISR
return (high_task_awoken == pdTRUE);
}

void app_main(void)
{
example_queue_element_t ele;
QueueHandle_t queue = xQueueCreate(10, sizeof(example_queue_element_t));
if (!queue) {
ESP_LOGE(TAG, "Creating queue failed");
return;
}

ESP_LOGI(TAG, "Create timer handle");
gptimer_handle_t gptimer = NULL;
gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_APB,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = 1000000, // 1MHz, 1 tick=1us
};
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));

gptimer_event_callbacks_t cbs = {
.on_alarm = example_timer_on_alarm_cb_v1,
};
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));

ESP_LOGI(TAG, "Start timer, stop it at alarm event");
gptimer_alarm_config_t alarm_config1 = {
.alarm_count = 1000000, // period = 1s
};
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config1));
ESP_ERROR_CHECK(gptimer_start(gptimer));
if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) {
ESP_LOGI(TAG, "Timer stopped, count=%llu", ele.event_count);
} else {
ESP_LOGW(TAG, "Missed one count event");
}

ESP_LOGI(TAG, "Set count value");
ESP_ERROR_CHECK(gptimer_set_raw_count(gptimer, 100));
ESP_LOGI(TAG, "Get count value");
uint64_t count;
ESP_ERROR_CHECK(gptimer_get_raw_count(gptimer, &count));
ESP_LOGI(TAG, "Timer count value=%llu", count);

ESP_LOGI(TAG, "Start timer, auto-reload at alarm event");
cbs.on_alarm = example_timer_on_alarm_cb_v2;
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
gptimer_alarm_config_t alarm_config2 = {
.reload_count = 0,
.alarm_count = 1000000, // period = 1s
.flags.auto_reload_on_alarm = true,
};
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config2));
ESP_ERROR_CHECK(gptimer_start(gptimer));
int record = 4;
while (record) {
if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) {
ESP_LOGI(TAG, "Timer reloaded, count=%llu", ele.event_count);
record--;
} else {
ESP_LOGW(TAG, "Missed one count event");
}
}

ESP_LOGI(TAG, "Stop timer");
ESP_ERROR_CHECK(gptimer_stop(gptimer));

ESP_LOGI(TAG, "Update alarm value dynamically");
cbs.on_alarm = example_timer_on_alarm_cb_v3;
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
gptimer_alarm_config_t alarm_config3 = {
.alarm_count = 1000000, // period = 1s
};
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config3));
ESP_ERROR_CHECK(gptimer_start(gptimer));
record = 4;
while (record) {
if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) {
ESP_LOGI(TAG, "Timer alarmed, count=%llu", ele.event_count);
record--;
} else {
ESP_LOGW(TAG, "Missed one count event");
}
}

ESP_LOGI(TAG, "Stop timer");
ESP_ERROR_CHECK(gptimer_stop(gptimer));
ESP_LOGI(TAG, "Delete timer");
ESP_ERROR_CHECK(gptimer_del_timer(gptimer));

vQueueDelete(queue);
}
39 changes: 39 additions & 0 deletions examples/peripherals/timer_group/gptimer/pytest_gptimer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-FileCopyrightText: 2021-2022 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_gptimer_example(dut: Dut) -> None:
dut.expect(r'Create timer handle', timeout=5)
dut.expect(r'Start timer, stop it at alarm event', timeout=5)
res = dut.expect(r'Timer stopped, count=(\d+)', timeout=30)
stopped_count = res.group(1).decode('utf8')
assert (1000000 - 10) < int(stopped_count) < (1000000 + 10)

dut.expect(r'Set count value')
dut.expect(r'Get count value')
res = dut.expect(r'Timer count value=(\d+)', timeout=5)
count_val = res.group(1).decode('utf8')
assert int(count_val) == 100

dut.expect(r'Start timer, auto-reload at alarm event', timeout=5)
res = dut.expect(r'Timer reloaded, count=(\d+)', timeout=5)
reloaded_count = res.group(1).decode('utf8')
assert 0 <= int(reloaded_count) < 10

dut.expect(r'Stop timer')
dut.expect(r'Update alarm value dynamically')
for i in range(1,5):
res = dut.expect(r'Timer alarmed, count=(\d+)', timeout=5)
alarm_count = res.group(1).decode('utf8')
assert (i * 1000000 - 10) < int(alarm_count) < (i * 1000000 + 10)

dut.expect(r'Stop timer')
dut.expect(r'Delete timer')
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2010-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0

import pytest
Expand All @@ -10,7 +10,7 @@
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.generic
def test_timer_group_example(dut: Dut): # type: ignore
def test_timer_group_example(dut: Dut) -> None:
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')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN=y

0 comments on commit 25490dd

Please sign in to comment.