mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
gptimer: new driver for previous timer group
This commit is contained in:
18
components/driver/test_apps/gptimer/CMakeLists.txt
Normal file
18
components/driver/test_apps/gptimer/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(gptimer_test)
|
||||
|
||||
if(CONFIG_GPTIMER_ISR_IRAM_SAFE)
|
||||
add_custom_target(check_test_app_sections ALL
|
||||
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
|
||||
--rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/driver/
|
||||
--elf-file ${CMAKE_BINARY_DIR}/gptimer_test.elf
|
||||
find-refs
|
||||
--from-sections=.iram0.text
|
||||
--to-sections=.flash.text,.flash.rodata
|
||||
--exit-code
|
||||
DEPENDS ${elf}
|
||||
)
|
||||
endif()
|
2
components/driver/test_apps/gptimer/README.md
Normal file
2
components/driver/test_apps/gptimer/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
30
components/driver/test_apps/gptimer/app_test.py
Normal file
30
components/driver/test_apps/gptimer/app_test.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import glob
|
||||
import os
|
||||
|
||||
import ttfw_idf
|
||||
from tiny_test_fw import Utility
|
||||
|
||||
|
||||
@ttfw_idf.idf_component_unit_test(env_tag='COMPONENT_UT_GENERIC', target=['esp32', 'esp32s2', 'esp32s3', 'esp32c3'])
|
||||
def test_component_ut_gptimer(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
|
||||
# Get the names of all configs (sdkconfig.ci.* files)
|
||||
config_files = glob.glob(os.path.join(os.path.dirname(__file__), 'sdkconfig.ci.*'))
|
||||
config_names = [os.path.basename(s).replace('sdkconfig.ci.', '') for s in config_files]
|
||||
|
||||
# Run test once with binaries built for each config
|
||||
for name in config_names:
|
||||
Utility.console_log(f'Checking config "{name}"... ', end='')
|
||||
dut = env.get_dut('gptimer', 'components/driver/test_apps/gptimer', app_config_name=name)
|
||||
dut.start_app()
|
||||
stdout = dut.expect('Press ENTER to see the list of tests', full_stdout=True)
|
||||
dut.write('*')
|
||||
stdout = dut.expect("Enter next test, or 'enter' to see menu", full_stdout=True, timeout=30)
|
||||
ttfw_idf.ComponentUTResult.parse_result(stdout,ttfw_idf.TestFormat.UNITY_BASIC)
|
||||
env.close_dut(dut.name)
|
||||
Utility.console_log(f'Test config "{name}" done')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_component_ut_gptimer()
|
8
components/driver/test_apps/gptimer/main/CMakeLists.txt
Normal file
8
components/driver/test_apps/gptimer/main/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_gptimer.c"
|
||||
"test_gptimer_iram.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_REQUIRES driver unity spi_flash)
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u test_app_include_gptimer" "-u test_app_include_gptimer_iram")
|
51
components/driver/test_apps/gptimer/main/test_app_main.c
Normal file
51
components/driver/test_apps/gptimer/main/test_app_main.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// Some resources are lazy allocated in GPTimer driver, the threshold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// ____ ____ _____ _ _____ _
|
||||
// / ___| _ \_ _(_)_ __ ___ ___ _ __ |_ _|__ ___| |_
|
||||
// | | _| |_) || | | | '_ ` _ \ / _ \ '__| | |/ _ \/ __| __|
|
||||
// | |_| | __/ | | | | | | | | | __/ | | | __/\__ \ |_
|
||||
// \____|_| |_| |_|_| |_| |_|\___|_| |_|\___||___/\__|
|
||||
printf(" ____ ____ _____ _ _____ _\r\n");
|
||||
printf(" / ___| _ \\_ _(_)_ __ ___ ___ _ __ |_ _|__ ___| |_\r\n");
|
||||
printf("| | _| |_) || | | | '_ ` _ \\ / _ \\ '__| | |/ _ \\/ __| __|\r\n");
|
||||
printf("| |_| | __/ | | | | | | | | | __/ | | | __/\\__ \\ |_\r\n");
|
||||
printf(" \\____|_| |_| |_|_| |_| |_|\\___|_| |_|\\___||___/\\__|\r\n");
|
||||
unity_run_menu();
|
||||
}
|
487
components/driver/test_apps/gptimer/main/test_gptimer.c
Normal file
487
components/driver/test_apps/gptimer/main/test_gptimer.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
||||
#define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR
|
||||
#else
|
||||
#define TEST_ALARM_CALLBACK_ATTR
|
||||
#endif // CONFIG_GPTIMER_ISR_IRAM_SAFE
|
||||
|
||||
void test_app_include_gptimer(void)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_set_get_raw_count", "[gptimer]")
|
||||
{
|
||||
gptimer_config_t config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&config, &timers[i]));
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gptimer_new_timer(&config, &timers[0]));
|
||||
unsigned long long get_value = 0;
|
||||
printf("check gptimer initial count value\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &get_value));
|
||||
TEST_ASSERT_EQUAL(0, get_value);
|
||||
}
|
||||
unsigned long long set_values[] = {100, 500, 666};
|
||||
for (size_t j = 0; j < sizeof(set_values) / sizeof(set_values[0]); j++) {
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
printf("set raw count to %llu for gptimer %d\r\n", set_values[j], i);
|
||||
TEST_ESP_OK(gptimer_set_raw_count(timers[i], set_values[j]));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &get_value));
|
||||
printf("get raw count of gptimer %d: %llu\r\n", i, get_value);
|
||||
TEST_ASSERT_EQUAL(set_values[j], get_value);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]")
|
||||
{
|
||||
gptimer_clock_source_t test_clk_srcs[] = {
|
||||
GPTIMER_CLK_SRC_APB,
|
||||
#if SOC_TIMER_GROUP_SUPPORT_XTAL
|
||||
GPTIMER_CLK_SRC_XTAL,
|
||||
#endif // SOC_TIMER_GROUP_SUPPORT_XTAL
|
||||
};
|
||||
|
||||
// test with various clock sources
|
||||
for (size_t i = 0; i < sizeof(test_clk_srcs) / sizeof(test_clk_srcs[0]); i++) {
|
||||
gptimer_config_t timer_config = {
|
||||
.clk_src = test_clk_srcs[i],
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
printf("start timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // 20ms = 20_000 ticks
|
||||
unsigned long long value = 0;
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value));
|
||||
TEST_ASSERT_UINT_WITHIN(1000, 20000, value);
|
||||
}
|
||||
printf("stop timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
printf("check whether timers have stopped\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value));
|
||||
printf("get raw count of gptimer %d: %llu\r\n", i, value);
|
||||
TEST_ASSERT_UINT_WITHIN(1000, 20000, value);
|
||||
}
|
||||
printf("restart timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
printf("stop timers again\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
printf("check whether timers have stopped\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value));
|
||||
printf("get raw count of gptimer %d: %llu\r\n", i, value);
|
||||
TEST_ASSERT_UINT_WITHIN(2000, 40000, value);
|
||||
}
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_stop_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
xTaskHandle task_handle = (xTaskHandle)user_data;
|
||||
BaseType_t high_task_wakeup;
|
||||
gptimer_stop(timer);
|
||||
esp_rom_printf("count=%lld @alarm\n", edata->count_value);
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_stop_on_alarm", "[gptimer]")
|
||||
{
|
||||
xTaskHandle task_handle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = test_gptimer_alarm_stop_callback,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {};
|
||||
|
||||
printf("start timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
alarm_config.alarm_count = 100000 * (i + 1);
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
printf("alarm value for gptimer %d: %llu\r\n", i, alarm_config.alarm_count);
|
||||
}
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
}
|
||||
|
||||
printf("check whether the timers have stopped in the ISR\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
unsigned long long value = 0;
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value));
|
||||
printf("get raw count of gptimer %d: %llu\r\n", i, value);
|
||||
TEST_ASSERT_UINT_WITHIN(40, 100000 * (i + 1), value);
|
||||
}
|
||||
|
||||
printf("restart timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
alarm_config.alarm_count = 100000 * (i + 1);
|
||||
// reset counter value to zero
|
||||
TEST_ESP_OK(gptimer_set_raw_count(timers[i], 0));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
}
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
}
|
||||
printf("check whether the timers have stopped in the ISR\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value));
|
||||
printf("get raw count of gptimer %d: %llu\r\n", i, value);
|
||||
TEST_ASSERT_UINT_WITHIN(40, 100000 * (i + 1), value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_reload_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
xTaskHandle task_handle = (xTaskHandle)user_data;
|
||||
BaseType_t high_task_wakeup;
|
||||
esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value);
|
||||
// check if the count value has been reloaded
|
||||
TEST_ASSERT_UINT_WITHIN(20, 100, edata->count_value);
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_auto_reload_on_alarm", "[gptimer]")
|
||||
{
|
||||
xTaskHandle task_handle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = test_gptimer_alarm_reload_callback,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 100,
|
||||
.alarm_count = 100000,
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
|
||||
printf("start timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
// delete should fail if timer is not stopped
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, gptimer_del_timer(timers[i]));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_normal_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
xTaskHandle task_handle = (xTaskHandle)user_data;
|
||||
BaseType_t high_task_wakeup;
|
||||
esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value);
|
||||
// check the count value at alarm event
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_one_shot_alarm", "[gptimer]")
|
||||
{
|
||||
xTaskHandle task_handle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = test_gptimer_alarm_normal_callback,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 0,
|
||||
.alarm_count = 100000, // 100ms
|
||||
};
|
||||
|
||||
printf("start timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
// no alarm event should trigger again, as auto-reload is not enabled and alarm value hasn't changed in the isr
|
||||
TEST_ASSERT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
// the alarm is stopped, but the counter should still work
|
||||
uint64_t value = 0;
|
||||
TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value));
|
||||
TEST_ASSERT_UINT_WITHIN(1000, 1100000, value); // 1100000 = 100ms alarm + 1s delay
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
printf("restart timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
// alarm should be triggered immediately as the counter value has across the target alarm value already
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, 0));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_alarm_update_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
xTaskHandle task_handle = (xTaskHandle)user_data;
|
||||
BaseType_t high_task_wakeup;
|
||||
esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value);
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.alarm_count = edata->count_value + 100000, // alarm in next 100ms again
|
||||
};
|
||||
gptimer_set_alarm_action(timer, &alarm_config);
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_update_alarm_dynamically", "[gptimer]")
|
||||
{
|
||||
xTaskHandle task_handle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = test_gptimer_alarm_update_callback,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.alarm_count = 100000, // initial alarm count, 100ms
|
||||
};
|
||||
printf("start timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
// check the alarm event for multiple times
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
// check there won't be more interrupts triggered than expected
|
||||
TEST_ASSERT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
}
|
||||
|
||||
printf("restart timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
// check the alarm event for multiple times
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
// check there won't be more interrupts triggered than expected
|
||||
TEST_ASSERT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_count_down_reload_alarm_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
xTaskHandle task_handle = (xTaskHandle)user_data;
|
||||
BaseType_t high_task_wakeup;
|
||||
esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value);
|
||||
// check if the count value has been reloaded
|
||||
TEST_ASSERT_UINT_WITHIN(20, 200000, edata->count_value);
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_count_down_reload", "[gptimer]")
|
||||
{
|
||||
xTaskHandle task_handle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_DOWN,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
TEST_ESP_OK(gptimer_set_raw_count(timers[i], 200000));
|
||||
}
|
||||
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = test_gptimer_count_down_reload_alarm_callback,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 200000, // 200ms
|
||||
.alarm_count = 0,
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
// check twice, as it's a period event
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
printf("restart gptimer with previous configuration\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
// check twice, as it's a period event
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ALARM_CALLBACK_ATTR static bool test_gptimer_overflow_reload_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data)
|
||||
{
|
||||
xTaskHandle task_handle = (xTaskHandle)user_data;
|
||||
BaseType_t high_task_wakeup;
|
||||
// Note: esp_rom_printf can't print value with 64 bit length, so the following print result is meaningless, but as an incidator for test that the alarm has fired
|
||||
esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value);
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_overflow", "[gptimer]")
|
||||
{
|
||||
xTaskHandle task_handle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
};
|
||||
gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS];
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
#if SOC_TIMER_GROUP_COUNTER_BIT_WIDTH == 64
|
||||
uint64_t reload_at = UINT64_MAX - 100000;
|
||||
#else
|
||||
uint64_t reload_at = (1ULL << SOC_TIMER_GROUP_COUNTER_BIT_WIDTH) - 100000;
|
||||
#endif
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = test_gptimer_overflow_reload_callback,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = reload_at,
|
||||
.alarm_count = 100000, // 100ms
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
// The counter should start from [COUNTER_MAX-100000] and overflows to [0] and continue, then reached to alarm value [100000], reloaded to [COUNTER_MAX-100000] automatically
|
||||
// thus the period should be 200ms
|
||||
printf("start timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
// we start from the reload value
|
||||
TEST_ESP_OK(gptimer_set_raw_count(timers[i], reload_at));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(400)));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
107
components/driver/test_apps/gptimer/main/test_gptimer_iram.c
Normal file
107
components/driver/test_apps/gptimer/main/test_gptimer_iram.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
void test_app_include_gptimer_iram(void)
|
||||
{
|
||||
}
|
||||
|
||||
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
|
||||
|
||||
typedef struct {
|
||||
size_t buf_size;
|
||||
uint8_t *buf;
|
||||
size_t flash_addr;
|
||||
size_t repeat_count;
|
||||
SemaphoreHandle_t done_sem;
|
||||
} read_task_arg_t;
|
||||
|
||||
typedef struct {
|
||||
size_t delay_time_us;
|
||||
size_t repeat_count;
|
||||
} block_task_arg_t;
|
||||
|
||||
static bool IRAM_ATTR on_gptimer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
block_task_arg_t *arg = (block_task_arg_t *)user_ctx;
|
||||
esp_rom_delay_us(arg->delay_time_us);
|
||||
arg->repeat_count++;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void flash_read_task(void *varg)
|
||||
{
|
||||
read_task_arg_t *arg = (read_task_arg_t *)varg;
|
||||
for (size_t i = 0; i < arg->repeat_count; i++) {
|
||||
TEST_ESP_OK(spi_flash_read(arg->flash_addr, arg->buf, arg->buf_size));
|
||||
}
|
||||
xSemaphoreGive(arg->done_sem);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("gptimer_iram_interrupt_safe", "[gptimer]")
|
||||
{
|
||||
gptimer_handle_t gptimer = NULL;
|
||||
const size_t size = 128;
|
||||
uint8_t *buf = malloc(size);
|
||||
TEST_ASSERT_NOT_NULL(buf);
|
||||
SemaphoreHandle_t done_sem = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL(done_sem);
|
||||
read_task_arg_t read_arg = {
|
||||
.buf_size = size,
|
||||
.buf = buf,
|
||||
.flash_addr = 0,
|
||||
.repeat_count = 1000,
|
||||
.done_sem = done_sem,
|
||||
};
|
||||
|
||||
block_task_arg_t block_arg = {
|
||||
.repeat_count = 0,
|
||||
.delay_time_us = 100,
|
||||
};
|
||||
|
||||
gptimer_config_t timer_config = {
|
||||
.clk_src = GPTIMER_CLK_SRC_APB,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer));
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = on_gptimer_alarm_cb,
|
||||
};
|
||||
gptimer_alarm_config_t alarm_config = {
|
||||
.reload_count = 0,
|
||||
.alarm_count = 120,
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, &block_arg));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
xTaskCreatePinnedToCore(flash_read_task, "read_flash", 2048, &read_arg, 3, NULL, portNUM_PROCESSORS - 1);
|
||||
// wait for task done
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY);
|
||||
printf("alarm callback runs %d times\r\n", block_arg.repeat_count);
|
||||
TEST_ASSERT_GREATER_THAN(1000, block_arg.repeat_count);
|
||||
// delete gptimer
|
||||
TEST_ESP_OK(gptimer_stop(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
vSemaphoreDelete(done_sem);
|
||||
free(buf);
|
||||
// leave time for IDLE task to recycle deleted task
|
||||
vTaskDelay(2);
|
||||
}
|
||||
|
||||
#endif // CONFIG_GPTIMER_ISR_IRAM_SAFE
|
@@ -0,0 +1,5 @@
|
||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y
|
||||
CONFIG_GPTIMER_ISR_IRAM_SAFE=y
|
||||
# disable log as most of log access rodata string on error, causing RTL check failure
|
||||
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
|
5
components/driver/test_apps/gptimer/sdkconfig.ci.release
Normal file
5
components/driver/test_apps/gptimer/sdkconfig.ci.release
Normal file
@@ -0,0 +1,5 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
2
components/driver/test_apps/gptimer/sdkconfig.defaults
Normal file
2
components/driver/test_apps/gptimer/sdkconfig.defaults
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
Reference in New Issue
Block a user