Merge branch 'fix/update_dfs_compensate_table_v5.4' into 'release/v5.4'

fix(esp_hw_support): update esp32 dfs table to make the timing drift always negative (v5.4)

See merge request espressif/esp-idf!39839
This commit is contained in:
Jiang Jiang Jian
2025-06-16 20:42:34 +08:00
5 changed files with 40 additions and 26 deletions

View File

@ -965,7 +965,7 @@ static void btdm_sleep_enter_phase1_wrapper(uint32_t lpcycles)
assert(us_to_sleep > BTDM_MIN_TIMER_UNCERTAINTY_US);
// allow a maximum time uncertainty to be about 488ppm(1/2048) at least as clock drift
// and set the timer in advance
uint32_t uncertainty = (us_to_sleep >> 11);
uint32_t uncertainty = (us_to_sleep / 1000);
if (uncertainty < BTDM_MIN_TIMER_UNCERTAINTY_US) {
uncertainty = BTDM_MIN_TIMER_UNCERTAINTY_US;
}

View File

@ -403,16 +403,16 @@ static void rtc_clk_cpu_freq_to_8m(void)
}
#ifndef BOOTLOADER_BUILD
static const DRAM_ATTR int16_t dfs_lact_conpensate_table[3][3] = { \
static const DRAM_ATTR int16_t dfs_lact_compensate_table[3][3] = { \
/* From / To 80 160 240*/ \
/* 10 */ {138, 220, 18}, \
/* 20 */ {128, 205, -3579}, \
/* 40 */ {34, 100, 0}, \
/* 10 */ {78, 172, -1}, \
/* 20 */ {2, 105, -90}, \
/* 40 */ {-190, -18, -372}, \
};
__attribute__((weak)) IRAM_ATTR int16_t rtc_clk_get_lact_compensation_delay(uint32_t cur_freq, uint32_t tar_freq)
{
return dfs_lact_conpensate_table[(cur_freq == 10) ? 0 : (cur_freq == 20) ? 1 : 2][(tar_freq == 80) ? 0 : (tar_freq == 160) ? 1 : 2];
return dfs_lact_compensate_table[(cur_freq == 10) ? 0 : (cur_freq == 20) ? 1 : 2][(tar_freq == 80) ? 0 : (tar_freq == 160) ? 1 : 2];
}
#endif
@ -437,6 +437,12 @@ NOINLINE_ATTR static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
}
#endif
clk_ll_cpu_set_freq_mhz_from_pll(cpu_freq_mhz);
/* adjust ref_tick */
clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_PLL, cpu_freq_mhz);
/* switch clock source */
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
rtc_clk_apb_freq_update(80 * MHZ);
esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz);
#ifndef BOOTLOADER_BUILD
if (cur_freq <= 40 && delay_cycle < 0) {
for (int i = 0; i > delay_cycle; --i) {
@ -445,12 +451,6 @@ NOINLINE_ATTR static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
timer_ll_set_lact_clock_prescale(TIMER_LL_GET_HW(LACT_MODULE), 80 / LACT_TICKS_PER_US);
}
#endif
/* adjust ref_tick */
clk_ll_ref_tick_set_divider(SOC_CPU_CLK_SRC_PLL, cpu_freq_mhz);
/* switch clock source */
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
rtc_clk_apb_freq_update(80 * MHZ);
esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz);
rtc_clk_wait_for_slow_cycle();
esp_rom_delay_us(30);
}

View File

@ -665,7 +665,10 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
esp_clk_utils_mspi_speed_mode_sync_before_cpu_freq_switching(new_config.source_freq_mhz, new_config.freq_mhz);
#endif
extern portMUX_TYPE s_time_update_lock;
portENTER_CRITICAL_SAFE(&s_time_update_lock);
rtc_clk_cpu_freq_set_config_fast(&new_config);
portEXIT_CRITICAL_SAFE(&s_time_update_lock);
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
esp_clk_utils_mspi_speed_mode_sync_after_cpu_freq_switching(new_config.source_freq_mhz, new_config.freq_mhz);
#endif

View File

@ -273,7 +273,9 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
* will not cause issues in practice.
*/
REG_SET_BIT(INT_ENA_REG, TIMG_LACT_INT_ENA);
portENTER_CRITICAL_SAFE(&s_time_update_lock);
timer_ll_set_lact_clock_prescale(TIMER_LL_GET_HW(LACT_MODULE), esp_clk_apb_freq() / MHZ / LACT_TICKS_PER_US);
portEXIT_CRITICAL_SAFE(&s_time_update_lock);
// Set the step for the sleep mode when the timer will work
// from a slow_clk frequency instead of the APB frequency.
uint32_t slowclk_ticks_per_us = esp_clk_slowclk_cal_get() * LACT_TICKS_PER_US;

View File

@ -83,15 +83,19 @@ static IRAM_ATTR void periodic_timer_callback(void* arg)
static int64_t measuring_periodic_timer_accuracy(uint64_t alarm_records[])
{
int64_t sum_jitter_us = 0;
int64_t max_jitter_us = 0;
int64_t max_jitter_us = -(ALARM_PERIOD_MS * 1000);
int64_t min_jitter_us = ALARM_PERIOD_MS * 1000;
int64_t jitter_array[ALARM_TIMES] = {0};
for (int i = 1; i <= ALARM_TIMES; ++i) {
int64_t jitter_us = (int64_t)alarm_records[i] - (int64_t)alarm_records[i - 1] - ALARM_PERIOD_MS * 1000;
jitter_array[i - 1] = jitter_us;
if (llabs(jitter_us) > llabs(max_jitter_us)) {
if (jitter_us > max_jitter_us) {
max_jitter_us = jitter_us;
}
if (jitter_us < min_jitter_us) {
min_jitter_us = jitter_us;
}
sum_jitter_us += jitter_us;
}
int64_t avg_jitter_us = sum_jitter_us / ALARM_TIMES;
@ -106,14 +110,19 @@ static int64_t measuring_periodic_timer_accuracy(uint64_t alarm_records[])
double stddev = sqrt(variance);
printf("Average jitter us: %"PRIi64"\n", avg_jitter_us);
printf("Max jitter us: %"PRIi64"\n", max_jitter_us);
if (max_jitter_us > 0) {
printf("\e[1;31mMax jitter us: %"PRIi64"\n\e[0m", max_jitter_us);
} else {
printf("Max jitter us: %"PRIi64"\n", max_jitter_us);
}
printf("Min jitter us: %"PRIi64"\n", min_jitter_us);
printf("Standard Deviation: %.3f\n", stddev);
printf("Drift Percentage: %.3f%%\n", (double)avg_jitter_us / (ALARM_PERIOD_MS * 10));
// Reset measurement
s_current_alarm = 0;
bzero(s_alarm_records, sizeof(s_alarm_records));
return avg_jitter_us;
return max_jitter_us;
}
static int64_t test_periodic_timer_accuracy_on_dfs(esp_timer_handle_t timer)
@ -129,9 +138,9 @@ static int64_t test_periodic_timer_accuracy_on_dfs(esp_timer_handle_t timer)
// Each FreeRTOS tick will perform a min_freq_mhz->max_freq_mhz -> min_freq_mhz frequency switch
xSemaphoreTake(s_alarm_finished, portMAX_DELAY);
ESP_ERROR_CHECK(esp_timer_stop(timer));
int64_t avg_jitter_us = measuring_periodic_timer_accuracy(s_alarm_records);
int64_t max_jitter_us = measuring_periodic_timer_accuracy(s_alarm_records);
vSemaphoreDelete(s_alarm_finished);
return avg_jitter_us;
return max_jitter_us;
}
// The results of this test are meaningful only if `CONFIG_ESP_SYSTEM_RTC_EXT_XTAL` is enabled
@ -203,7 +212,7 @@ TEST_CASE("Test DFS lact conpensate magic table ", "[esp_timer][manual][ignore]"
esp_pm_configure(&pm_config);
int32_t max_delay = 300;
int32_t min_delay = (pm_config.max_freq_mhz == 240) ? -4000 : 0;
int32_t min_delay = (pm_config.max_freq_mhz == 240) ? -4000 : -300;
int32_t test_delay = (max_delay + min_delay) / 2;
int32_t last_delay = 0;
int32_t best_delay = 0;
@ -212,19 +221,19 @@ TEST_CASE("Test DFS lact conpensate magic table ", "[esp_timer][manual][ignore]"
do {
printf("Test delay %ld\n", test_delay);
test_lact_compensation_delay = test_delay;
int64_t avg = test_periodic_timer_accuracy_on_dfs(periodic_timer);
int64_t max_jitter_us = test_periodic_timer_accuracy_on_dfs(periodic_timer);
last_delay = test_delay;
if (avg < 0) {
test_delay = (test_delay + max_delay) / 2;
min_delay = last_delay;
} else {
if (max_jitter_us > 0) {
test_delay = (test_delay + min_delay) / 2;
max_delay = last_delay;
} else {
test_delay = (test_delay + max_delay) / 2;
min_delay = last_delay;
}
if (llabs(avg) < llabs(min_avg)) {
if (llabs(max_jitter_us) < llabs(min_avg)) {
best_delay = last_delay;
min_avg = avg;
min_avg = max_jitter_us;
}
} while (test_delay != last_delay);