diff --git a/components/driver/.build-test-rules.yml b/components/driver/.build-test-rules.yml index 23ed2a0ee6..ed8967bd8a 100644 --- a/components/driver/.build-test-rules.yml +++ b/components/driver/.build-test-rules.yml @@ -8,12 +8,6 @@ components/driver/test_apps/dac_test_apps/legacy_dac_driver: disable: - if: SOC_DAC_SUPPORTED != 1 -components/driver/test_apps/gptimer: - disable_test: - - if: IDF_TARGET == "esp32c6" - temporary: true - reason: target esp32c6 is not supported yet - components/driver/test_apps/i2s_test_apps: disable: - if: SOC_I2S_SUPPORTED != 1 @@ -64,12 +58,6 @@ components/driver/test_apps/legacy_rtc_temp_driver: disable: - if: SOC_TEMP_SENSOR_SUPPORTED != 1 -components/driver/test_apps/legacy_timer_driver: - disable_test: - - if: IDF_TARGET == "esp32c6" - temporary: true - reason: target esp32c6 is not supported yet - components/driver/test_apps/mcpwm: disable: - if: SOC_MCPWM_SUPPORTED != 1 diff --git a/components/driver/gptimer/gptimer.c b/components/driver/gptimer/gptimer.c index b70f6bc96e..d9c1ac0db3 100644 --- a/components/driver/gptimer/gptimer.c +++ b/components/driver/gptimer/gptimer.c @@ -26,6 +26,7 @@ #include "esp_memory_utils.h" #include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" +#include "clk_ctrl_os.h" #include "gptimer_priv.h" static const char *TAG = "gptimer"; @@ -153,12 +154,23 @@ esp_err_t gptimer_del_timer(gptimer_handle_t timer) ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(timer->fsm == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state"); gptimer_group_t *group = timer->group; + gptimer_clock_source_t clk_src = timer->clk_src; int group_id = group->group_id; int timer_id = timer->timer_id; ESP_LOGD(TAG, "del timer (%d,%d)", group_id, timer_id); timer_hal_deinit(&timer->hal); // recycle memory resource ESP_RETURN_ON_ERROR(gptimer_destory(timer), TAG, "destory gptimer failed"); + + switch (clk_src) { +#if SOC_TIMER_GROUP_SUPPORT_RC_FAST + case GPTIMER_CLK_SRC_RC_FAST: + periph_rtc_dig_clk8m_disable(); + break; +#endif // SOC_TIMER_GROUP_SUPPORT_RC_FAST + default: + break; + } return ESP_OK; } @@ -182,6 +194,13 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *valu return ESP_OK; } +esp_err_t gptimer_get_resolution(gptimer_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 gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value) { ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); @@ -404,7 +423,7 @@ static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_sou counter_src_hz = 40 * 1000 * 1000; #if CONFIG_PM_ENABLE sprintf(timer->pm_lock_name, "gptimer_%d_%d", timer->group->group_id, timer_id); // e.g. gptimer_0_0 - // PLL_F40M will be turned off when DFS switches CPU clock source to XTAL + // on ESP32C2, PLL_F40M is unavailable when CPU clock source switches from PLL to XTAL, so we're acquiring a "APB" lock here to prevent the clock switch ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, timer->pm_lock_name, &timer->pm_lock); ESP_RETURN_ON_ERROR(ret, TAG, "create APB_FREQ_MAX lock failed"); ESP_LOGD(TAG, "install APB_FREQ_MAX lock for timer (%d,%d)", timer->group->group_id, timer_id); @@ -416,7 +435,7 @@ static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_sou counter_src_hz = 80 * 1000 * 1000; #if CONFIG_PM_ENABLE sprintf(timer->pm_lock_name, "gptimer_%d_%d", timer->group->group_id, timer_id); // e.g. gptimer_0_0 - // ESP32C6 PLL_F80M is available when SOC_ROOT_CLK switchs to XTAL + // ESP32C6 PLL_F80M is available when SOC_ROOT_CLK switches to XTAL ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, timer->pm_lock_name, &timer->pm_lock); ESP_RETURN_ON_ERROR(ret, TAG, "create NO_LIGHT_SLEEP lock failed"); ESP_LOGD(TAG, "install NO_LIGHT_SLEEP lock for timer (%d,%d)", timer->group->group_id, timer_id); @@ -434,6 +453,12 @@ static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_sou counter_src_hz = esp_clk_xtal_freq(); break; #endif // SOC_TIMER_GROUP_SUPPORT_XTAL +#if SOC_TIMER_GROUP_SUPPORT_RC_FAST + case GPTIMER_CLK_SRC_RC_FAST: + periph_rtc_dig_clk8m_enable(); + counter_src_hz = periph_rtc_dig_clk8m_get_freq(); + break; +#endif // SOC_TIMER_GROUP_SUPPORT_RC_FAST default: ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "clock source %d is not support", src_clk); break; diff --git a/components/driver/include/driver/gptimer.h b/components/driver/include/driver/gptimer.h index b24f38ab77..31a761a891 100644 --- a/components/driver/include/driver/gptimer.h +++ b/components/driver/include/driver/gptimer.h @@ -80,7 +80,7 @@ esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, uint64_t value); * @brief Get GPTimer raw count value * * @note This function will trigger a software capture event and then return the captured count value. - * @note With the raw count value and the resolution set in the `gptimer_config_t`, you can convert the count value into seconds. + * @note With the raw count value and the resolution returned from `gptimer_get_resolution`, you can convert the count value into seconds. * @note This function is allowed to run within ISR context * @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` * @@ -93,6 +93,20 @@ esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, uint64_t value); */ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, uint64_t *value); +/** + * @brief Return the real resolution of the timer + * + * @note usually the timer resolution is same as what you configured in the `gptimer_config_t::resolution_hz`, but for some unstable clock source (e.g. RC_FAST), which needs a calibration, the real resolution may be different from the configured one. + * + * @param[in] timer Timer handle created by `gptimer_new_timer` + * @param[out] out_resolution Returned timer resolution, in Hz + * @return + * - ESP_OK: Get GPTimer resolution successfully + * - ESP_ERR_INVALID_ARG: Get GPTimer resolution failed because of invalid argument + * - ESP_FAIL: Get GPTimer resolution failed because of other error + */ +esp_err_t gptimer_get_resolution(gptimer_handle_t timer, uint32_t *out_resolution); + /** * @brief Get GPTimer captured count value * diff --git a/components/driver/test_apps/gptimer/main/test_gptimer.c b/components/driver/test_apps/gptimer/main/test_gptimer.c index b74bc93274..79b5b9bdcc 100644 --- a/components/driver/test_apps/gptimer/main/test_gptimer.c +++ b/components/driver/test_apps/gptimer/main/test_gptimer.c @@ -60,6 +60,7 @@ TEST_CASE("gptimer_set_get_raw_count", "[gptimer]") TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]") { gptimer_clock_source_t test_clk_srcs[] = SOC_GPTIMER_CLKS; + uint32_t timer_resolution_hz[SOC_TIMER_GROUP_TOTAL_TIMERS]; // test with various clock sources for (size_t i = 0; i < sizeof(test_clk_srcs) / sizeof(test_clk_srcs[0]); i++) { @@ -71,6 +72,7 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]") 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_get_resolution(timers[i], &timer_resolution_hz[i])); } // start timer before enable should fail TEST_ESP_ERR(ESP_ERR_INVALID_STATE, gptimer_start(timers[0])); @@ -83,9 +85,11 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]") TEST_ESP_OK(gptimer_start(timers[i])); } vTaskDelay(pdMS_TO_TICKS(20)); // 20ms = 20_000 ticks - unsigned long long value = 0; + uint64_t value = 0; for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) { TEST_ESP_OK(gptimer_get_raw_count(timers[i], &value)); + // convert the raw count to us + value = value * 1000000 / timer_resolution_hz[i]; TEST_ASSERT_UINT_WITHIN(1000, 20000, value); } printf("stop timers\r\n"); @@ -97,6 +101,8 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]") 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); + // convert the raw count to us + value = value * 1000000 / timer_resolution_hz[i]; TEST_ASSERT_UINT_WITHIN(1000, 20000, value); } printf("restart timers\r\n"); @@ -113,6 +119,8 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]") 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); + // convert the raw count to us + value = value * 1000000 / timer_resolution_hz[i]; TEST_ASSERT_UINT_WITHIN(2000, 40000, value); } printf("disable timers\r\n"); diff --git a/components/driver/test_apps/gptimer/pytest_gptimer.py b/components/driver/test_apps/gptimer/pytest_gptimer.py index 7ab67b6b5c..05d8f9639a 100644 --- a/components/driver/test_apps/gptimer/pytest_gptimer.py +++ b/components/driver/test_apps/gptimer/pytest_gptimer.py @@ -6,7 +6,6 @@ from pytest_embedded import Dut @pytest.mark.supported_targets -@pytest.mark.temp_skip_ci(targets=['esp32c6'], reason='iram_safe test failed') @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py b/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py index 5ee4c5074f..93ae72d934 100644 --- a/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py +++ b/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py @@ -6,7 +6,6 @@ from pytest_embedded import Dut @pytest.mark.supported_targets -@pytest.mark.temp_skip_ci(targets=['esp32c6'], reason='test failed') @pytest.mark.generic @pytest.mark.parametrize('config', [ 'release', diff --git a/components/hal/esp32c6/include/hal/timer_ll.h b/components/hal/esp32c6/include/hal/timer_ll.h index 37eadf5ed2..a9403c4bd4 100644 --- a/components/hal/esp32c6/include/hal/timer_ll.h +++ b/components/hal/esp32c6/include/hal/timer_ll.h @@ -68,6 +68,9 @@ static inline void timer_ll_set_clock_source(timg_dev_t *hw, uint32_t timer_num, case GPTIMER_CLK_SRC_PLL_F80M: clk_id = 1; break; + case GPTIMER_CLK_SRC_RC_FAST: + clk_id = 2; + break; default: HAL_ASSERT(false); break; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index c5b217ac7d..29851ed91d 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -771,6 +771,10 @@ config SOC_TIMER_GROUP_SUPPORT_PLL_F80M bool default y +config SOC_TIMER_GROUP_SUPPORT_RC_FAST + bool + default y + config SOC_TIMER_GROUP_TOTAL_TIMERS int default 2 diff --git a/components/soc/esp32c6/include/soc/clk_tree_defs.h b/components/soc/esp32c6/include/soc/clk_tree_defs.h index 8fa92582e9..008eab1dcf 100644 --- a/components/soc/esp32c6/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c6/include/soc/clk_tree_defs.h @@ -149,15 +149,16 @@ typedef enum { * } * @endcode */ -#define SOC_GPTIMER_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL} +#define SOC_GPTIMER_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} /** * @brief Type of GPTimer clock source */ typedef enum { - GPTIMER_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ - GPTIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ + GPTIMER_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ + GPTIMER_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + GPTIMER_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ } soc_periph_gptimer_clk_src_t; /** diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 942e17be30..53510b05f0 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -359,6 +359,7 @@ #define SOC_TIMER_GROUP_COUNTER_BIT_WIDTH (54) #define SOC_TIMER_GROUP_SUPPORT_XTAL (1) #define SOC_TIMER_GROUP_SUPPORT_PLL_F80M (1) +#define SOC_TIMER_GROUP_SUPPORT_RC_FAST (1) #define SOC_TIMER_GROUP_TOTAL_TIMERS (2) #define SOC_TIMER_SUPPORT_ETM (1) diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 6ccf051edc..5792670e50 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -183,12 +183,6 @@ examples/peripherals/timer_group/gptimer_capture_hc_sr04: disable: - if: SOC_TIMER_SUPPORT_ETM != 1 -examples/peripherals/timer_group/legacy_driver: - disable_test: - - if: IDF_TARGET == "esp32c6" - temporary: true - reason: target esp32c6 is not supported yet - examples/peripherals/touch_sensor: disable: - if: SOC_TOUCH_SENSOR_SUPPORTED != 1 diff --git a/examples/peripherals/timer_group/legacy_driver/pytest_timer_group.py b/examples/peripherals/timer_group/legacy_driver/pytest_timer_group.py index 7caa9adf39..058638029d 100644 --- a/examples/peripherals/timer_group/legacy_driver/pytest_timer_group.py +++ b/examples/peripherals/timer_group/legacy_driver/pytest_timer_group.py @@ -6,7 +6,6 @@ from pytest_embedded import Dut @pytest.mark.supported_targets -@pytest.mark.temp_skip_ci(targets=['esp32c6'], reason='test failed') @pytest.mark.generic def test_timer_group_example(dut: Dut) -> None: dut.expect(r'Init timer with auto-reload', timeout=5)