Skip to content

Commit

Permalink
Merge branch 'feature/gptimer_rc_fast_c6' into 'master'
Browse files Browse the repository at this point in the history
gptimer: support RC_FAST clock source

See merge request espressif/esp-idf!21601
  • Loading branch information
suda-morris committed Dec 27, 2022
2 parents 77d220c + bc2a2d3 commit 080328a
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 29 deletions.
12 changes: 0 additions & 12 deletions components/driver/.build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
29 changes: 27 additions & 2 deletions components/driver/gptimer/gptimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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;
}

Expand All @@ -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");
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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;
Expand Down
16 changes: 15 additions & 1 deletion components/driver/include/driver/gptimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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`
*
Expand All @@ -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
*
Expand Down
10 changes: 9 additions & 1 deletion components/driver/test_apps/gptimer/main/test_gptimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand All @@ -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]));
Expand All @@ -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");
Expand All @@ -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");
Expand All @@ -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");
Expand Down
1 change: 0 additions & 1 deletion components/driver/test_apps/gptimer/pytest_gptimer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@


@pytest.mark.supported_targets
@pytest.mark.temp_skip_ci(targets=['esp32c6'], reason='iram_safe test failed')
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@


@pytest.mark.supported_targets
@pytest.mark.temp_skip_ci(targets=['esp32c6'], reason='test failed')
@pytest.mark.generic
@pytest.mark.parametrize('config', [
'release',
Expand Down
3 changes: 3 additions & 0 deletions components/hal/esp32c6/include/hal/timer_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions components/soc/esp32c6/include/soc/Kconfig.soc_caps.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions components/soc/esp32c6/include/soc/clk_tree_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down
1 change: 1 addition & 0 deletions components/soc/esp32c6/include/soc/soc_caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 0 additions & 6 deletions examples/peripherals/.build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@


@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)
Expand Down

0 comments on commit 080328a

Please sign in to comment.