Merge branch 'fix/adc_clk_div_error_v6.0' into 'release/v6.0'

Fix ADC continuous sample frequency and clock divide error on H2/C5/C61 (v6.0)

See merge request espressif/esp-idf!47974
This commit is contained in:
morris
2026-04-30 14:30:34 +08:00
7 changed files with 103 additions and 14 deletions

View File

@@ -11,5 +11,5 @@ set(srcs "test_app_main.c"
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES esp_driver_gptimer esp_driver_gpio esp_wifi nvs_flash esp_adc test_utils efuse
esp_driver_tsens
esp_driver_tsens esp_timer
WHOLE_ARCHIVE)

View File

@@ -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
*/
@@ -19,6 +19,7 @@
#include "esp_adc/adc_filter.h"
#include "test_common_adc.h"
#include "idf_performance.h"
#include "esp_timer.h"
__attribute__((unused)) static const char *TAG = "TEST_ADC";
@@ -295,6 +296,92 @@ TEST_CASE("ADC1 continuous std deviation performance, with filter", "[adc_contin
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_FILTER_64, "%.2f", std);
}
#endif //#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED
/*---------------------------------------------------------------
ADC Continuous Sample Count Test
---------------------------------------------------------------*/
static void test_adc_continuous_sample_freq(uint32_t sample_freq_hz)
{
adc_continuous_handle_t handle = NULL;
uint8_t result[256] = {0};
uint32_t ret_num = 0;
esp_err_t ret;
int64_t samples = 0;
int64_t current_us;
int64_t previous_us;
TaskHandle_t task_handle = xTaskGetCurrentTaskHandle();
printf("\n\nTesting ADC continuous with sample frequency: %"PRIu32" Hz\n", sample_freq_hz);
adc_continuous_handle_cfg_t adc_config = {
.max_store_buf_size = 1024,
.conv_frame_size = 256,
};
TEST_ESP_OK(adc_continuous_new_handle(&adc_config, &handle));
adc_continuous_config_t dig_cfg = {
.sample_freq_hz = sample_freq_hz,
.conv_mode = ADC_CONV_SINGLE_UNIT_1,
};
adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
adc_pattern[0].atten = ADC_ATTEN_DB_0;
adc_pattern[0].channel = TEST_STD_ADC1_CHANNEL0;
adc_pattern[0].unit = ADC_UNIT_1;
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
dig_cfg.adc_pattern = adc_pattern;
dig_cfg.pattern_num = 1;
TEST_ESP_OK(adc_continuous_config(handle, &dig_cfg));
adc_continuous_evt_cbs_t cbs = {
.on_conv_done = s_conv_done_cb,
};
TEST_ESP_OK(adc_continuous_register_event_callbacks(handle, &cbs, &task_handle));
TEST_ESP_OK(adc_continuous_start(handle));
for (int test_round = 0; test_round < 2; test_round++) {
samples = 0;
previous_us = esp_timer_get_time();
while (samples < sample_freq_hz) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
while (1) {
ret = adc_continuous_read(handle, result, 256, &ret_num, 0);
if (ret == ESP_OK) {
samples += (ret_num / SOC_ADC_DIGI_RESULT_BYTES);
if (samples >= sample_freq_hz) {
current_us = esp_timer_get_time();
int64_t samples_per_second = samples * 1000000 / (current_us - previous_us);
printf("samples = %lld, time = %lld us, samples_per_second = %lld (target: %"PRIu32" Hz)\n",
samples, (current_us - previous_us), samples_per_second, sample_freq_hz);
uint32_t tolerance = sample_freq_hz / 1000;
if (test_round != 0) {
//For first read, ADC is not stable, the count is not accurate, so ignore it
TEST_ASSERT_INT_WITHIN(tolerance, sample_freq_hz, samples_per_second);
}
break;
}
} else if (ret == ESP_ERR_TIMEOUT) {
break;
}
}
}
}
TEST_ESP_OK(adc_continuous_stop(handle));
TEST_ESP_OK(adc_continuous_deinit(handle));
}
TEST_CASE("ADC continuous sample frequency test", "[adc_continuous][performance]")
{
// Test minimum frequency
test_adc_continuous_sample_freq(SOC_ADC_SAMPLE_FREQ_THRES_LOW);
// Test maximum frequency
test_adc_continuous_sample_freq(SOC_ADC_SAMPLE_FREQ_THRES_HIGH);
}
#endif //#if SOC_ADC_DMA_SUPPORTED
#if CONFIG_IDF_TARGET_ESP32 || SOC_ADC_CALIBRATION_V1_SUPPORTED

View File

@@ -118,7 +118,9 @@ static adc_ll_digi_convert_mode_t get_convert_mode(adc_digi_convert_mode_t conve
static void adc_hal_digi_sample_freq_config(adc_hal_dma_ctx_t *hal, adc_continuous_clk_src_t clk_src, uint32_t clk_src_freq_hz, uint32_t sample_freq_hz)
{
#if !SOC_IS(ESP32)
uint32_t interval = clk_src_freq_hz / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1) / 2 / sample_freq_hz;
uint64_t clkm_div_denom = ((uint64_t)(ADC_LL_CLKM_DIV_NUM_DEFAULT + 1) * ADC_LL_CLKM_DIV_B_DEFAULT) + ADC_LL_CLKM_DIV_A_DEFAULT;
uint32_t interval = (uint32_t)(((uint64_t)clk_src_freq_hz * ADC_LL_CLKM_DIV_B_DEFAULT) /
(clkm_div_denom * 2 * sample_freq_hz));
//set sample interval
adc_ll_digi_set_trigger_interval(interval);
//Here we set the clock divider factor to make the digital clock to 5M Hz

View File

@@ -66,7 +66,7 @@ void adc_oneshot_hal_setup(adc_oneshot_hal_ctx_t *hal, adc_channel_t chan)
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
adc_ll_digi_clk_sel(hal->clk_src);
adc_ll_digi_controller_clk_div(ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT);
adc_ll_digi_controller_clk_div(ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT);
adc_ll_digi_set_clk_div(ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT);
#else
#if SOC_LP_ADC_SUPPORTED

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -147,7 +147,7 @@ __attribute__((always_inline))
static inline void adc_ll_digi_set_clk_div(uint32_t div)
{
/* ADC clock divided from digital controller clock clk */
HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_ctrl, saradc_saradc_sar_clk_div, div);
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.sar_clk_div, sar1_clk_div_num, div);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -147,7 +147,7 @@ __attribute__((always_inline))
static inline void adc_ll_digi_set_clk_div(uint32_t div)
{
/* ADC clock divided from digital controller clock clk */
HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.saradc_ctrl, saradc_sar_clk_div, div);
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.sar_clk_div, sar1_clk_div_num, div);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -56,11 +56,11 @@ extern "C" {
#define ADC_LL_FSM_START_WAIT_DEFAULT (5)
#define ADC_LL_FSM_STANDBY_WAIT_DEFAULT (100)
#define ADC_LL_SAMPLE_CYCLE_DEFAULT (2)
#define ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT (2)
#define ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT (1)
#define ADC_LL_CLKM_DIV_NUM_DEFAULT 19
#define ADC_LL_CLKM_DIV_B_DEFAULT 1
#define ADC_LL_CLKM_DIV_A_DEFAULT 0
#define ADC_LL_CLKM_DIV_NUM_DEFAULT 18
#define ADC_LL_CLKM_DIV_B_DEFAULT 5
#define ADC_LL_CLKM_DIV_A_DEFAULT 1
#define ADC_LL_DEFAULT_CONV_LIMIT_EN 0
#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 255
@@ -147,7 +147,7 @@ __attribute__((always_inline))
static inline void adc_ll_digi_set_clk_div(uint32_t div)
{
/* ADC clock divided from digital controller clock clk */
HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_ctrl, saradc_saradc_sar_clk_div, div);
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.sar_clk_div, sar1_clk_div_num, div);
}
/**