From d3ffd6ba8ed84bbb7581b17ae3195972cfb8b248 Mon Sep 17 00:00:00 2001 From: Steven Yang Date: Thu, 10 Sep 2026 17:34:20 +0800 Subject: [PATCH] fix(mcpwm): account for adjusted timer resolution in test --- .../include/driver/mcpwm_timer.h | 13 ++++- components/esp_driver_mcpwm/src/mcpwm_timer.c | 7 +++ .../test_apps/mcpwm/main/test_mcpwm_timer.c | 55 +++++++++++-------- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h b/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h index 6e7a816c14a..623b91d3ba3 100644 --- a/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h +++ b/components/esp_driver_mcpwm/include/driver/mcpwm_timer.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -61,6 +61,17 @@ typedef struct { */ esp_err_t mcpwm_new_timer(const mcpwm_timer_config_t *config, mcpwm_timer_handle_t *ret_timer); +/** + * @brief Get MCPWM timer resolution, in Hz + * + * @param[in] timer MCPWM timer handle, allocated by `mcpwm_new_timer()` + * @param[out] out_resolution Returned timer resolution, in Hz + * @return + * - ESP_OK: Get timer resolution successfully + * - ESP_ERR_INVALID_ARG: Get timer resolution failed because of invalid argument + */ +esp_err_t mcpwm_timer_get_resolution(mcpwm_timer_handle_t timer, uint32_t *out_resolution); + /** * @brief Delete MCPWM timer * diff --git a/components/esp_driver_mcpwm/src/mcpwm_timer.c b/components/esp_driver_mcpwm/src/mcpwm_timer.c index b44ad756b6b..1c2abf69e78 100644 --- a/components/esp_driver_mcpwm/src/mcpwm_timer.c +++ b/components/esp_driver_mcpwm/src/mcpwm_timer.c @@ -145,6 +145,13 @@ err: return ret; } +esp_err_t mcpwm_timer_get_resolution(mcpwm_timer_handle_t timer, uint32_t *out_resolution) +{ + ESP_RETURN_ON_FALSE(timer && out_resolution, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + *out_resolution = timer->resolution_hz; + return ESP_OK; +} + esp_err_t mcpwm_del_timer(mcpwm_timer_handle_t timer) { ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); diff --git a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_timer.c b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_timer.c index 7ee2ae4f922..6864ea3cb14 100644 --- a/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_timer.c +++ b/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_timer.c @@ -1,8 +1,9 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" @@ -90,19 +91,24 @@ TEST_CASE("mcpwm_timer_start_stop", "[mcpwm]") } } +#define TOLERANCE_PERCENT_RC_FAST 10 // 10% error allowed +#define TARGET_TIMER_RESOLUTION_HZ 1000000U +#define TIMER_RESOLUTION_TEST_DELAY_US 5000U +#define TARGET_TIMER_PERIOD_TICKS \ + (2ULL * TARGET_TIMER_RESOLUTION_HZ * TIMER_RESOLUTION_TEST_DELAY_US / 1000000ULL) // nominal period should be >= 2x measurement window + TEST_CASE("mcpwm_timer_various_clk_src", "[mcpwm]") { mcpwm_timer_clock_source_t clk_srcs[] = SOC_MCPWM_TIMER_CLKS; const int num_timers = MCPWM_LL_GET(TIMERS_PER_GROUP) * MCPWM_LL_GET(GROUP_NUM); - const uint32_t resolution_test_duration_us = 5000; for (size_t clk_src_idx = 0; clk_src_idx < sizeof(clk_srcs) / sizeof(clk_srcs[0]); clk_src_idx++) { mcpwm_timer_clock_source_t clk_src = clk_srcs[clk_src_idx]; - const uint32_t tolerance_percent = (soc_module_clk_t)clk_src == SOC_MOD_CLK_RC_FAST ? 10 : 1; + const uint32_t tolerance_percent = (soc_module_clk_t)clk_src == SOC_MOD_CLK_RC_FAST ? TOLERANCE_PERCENT_RC_FAST : 1; mcpwm_timer_config_t config = { .clk_src = clk_src, - .resolution_hz = 1000000, // 1MHz - .period_ticks = 12000, + .resolution_hz = TARGET_TIMER_RESOLUTION_HZ, + .period_ticks = TARGET_TIMER_PERIOD_TICKS, .count_mode = MCPWM_TIMER_COUNT_MODE_UP, }; @@ -123,31 +129,36 @@ TEST_CASE("mcpwm_timer_various_clk_src", "[mcpwm]") printf("check timer resolution\r\n"); for (int i = 0; i < num_timers; i++) { + uint32_t timer_resolution_hz = 0; // determined by mcpwm_new_timer() + TEST_ESP_OK(mcpwm_timer_get_resolution(timers[i], &timer_resolution_hz)); + TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_START_NO_STOP)); - uint32_t start_count = 0; - uint32_t end_count = 0; + uint32_t cnt_start = 0; + uint32_t cnt_end = 0; mcpwm_timer_direction_t direction; - TEST_ESP_OK(mcpwm_timer_get_phase(timers[i], &start_count, &direction)); - int64_t start_time_us = esp_timer_get_time(); - esp_rom_delay_us(resolution_test_duration_us); + TEST_ESP_OK(mcpwm_timer_get_phase(timers[i], &cnt_start, &direction)); + int64_t time_start_us = esp_timer_get_time(); + esp_rom_delay_us(TIMER_RESOLUTION_TEST_DELAY_US); + TEST_ESP_OK(mcpwm_timer_get_phase(timers[i], &cnt_end, &direction)); + int64_t time_end_us = esp_timer_get_time(); - TEST_ESP_OK(mcpwm_timer_get_phase(timers[i], &end_count, &direction)); - int64_t elapsed_time_us = esp_timer_get_time() - start_time_us; - uint32_t expected_ticks = (uint64_t)config.resolution_hz * elapsed_time_us / 1000000; - uint32_t actual_ticks; - if (end_count >= start_count) { - actual_ticks = end_count - start_count; - } else { - actual_ticks = config.period_ticks - start_count + end_count; - } + int64_t time_delta_us = time_end_us - time_start_us; + uint32_t expected_ticks = (uint64_t)timer_resolution_hz * time_delta_us / 1000000; uint32_t tolerance_ticks = expected_ticks * tolerance_percent / 100; - TEST_ASSERT_EQUAL(MCPWM_TIMER_DIRECTION_UP, direction); - TEST_ASSERT_UINT32_WITHIN(tolerance_ticks, expected_ticks, actual_ticks); + uint32_t measured_ticks; + if (cnt_end >= cnt_start) { + measured_ticks = cnt_end - cnt_start; + } else { + measured_ticks = config.period_ticks - cnt_start + cnt_end; + } - // make sure the timer has stopped + TEST_ASSERT_EQUAL(MCPWM_TIMER_DIRECTION_UP, direction); + TEST_ASSERT_UINT32_WITHIN(tolerance_ticks, expected_ticks, measured_ticks); + + // ensure timer has stopped TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_STOP_EMPTY)); vTaskDelay(pdMS_TO_TICKS(20)); check_mcpwm_timer_phase(&timers[i], 1, 0, MCPWM_TIMER_DIRECTION_UP);