feat(adc): support ADC single ended oneshot and continuous mode on ESP32-S31

This commit is contained in:
gaoxu
2026-05-14 16:31:29 +08:00
parent 315b6547ff
commit 03c8862a9f
40 changed files with 1315 additions and 105 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2016-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -512,6 +512,7 @@ esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_contin
uint32_t adc1_chan_mask = 0;
uint32_t adc2_chan_mask = 0;
for (int i = 0; i < config->pattern_num; i++) {
ESP_RETURN_ON_FALSE(config->adc_pattern[i].atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, ADC_TAG, "invalid pattern attenuation");
const adc_digi_pattern_config_t *pat = &config->adc_pattern[i];
if (pat->unit == ADC_UNIT_1) {
handle->use_adc1 = 1;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -200,7 +200,7 @@ esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_chann
ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth");
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
s_adc_io_init(handle->unit_id, channel);
ESP_RETURN_ON_ERROR(s_adc_io_init(handle->unit_id, channel), TAG, "adc io init failed");
adc_oneshot_hal_ctx_t *hal = &(handle->hal);
adc_oneshot_hal_chan_cfg_t cfg = {
@@ -268,7 +268,7 @@ esp_err_t adc_oneshot_read_isr(adc_oneshot_unit_handle_t handle, adc_channel_t c
adc_hal_calibration_init(handle->unit_id);
adc_set_hw_calibration_code(handle->unit_id, atten);
#endif
adc_oneshot_hal_convert(&(handle->hal), out_raw);
bool valid = adc_oneshot_hal_convert(&(handle->hal), out_raw);
ANALOG_CLOCK_DISABLE();
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)(handle->hal.clk_src), false));
@@ -276,7 +276,7 @@ esp_err_t adc_oneshot_read_isr(adc_oneshot_unit_handle_t handle, adc_channel_t c
portEXIT_CRITICAL_SAFE(&rtc_spinlock);
return ESP_OK;
return valid ? ESP_OK : ESP_ERR_TIMEOUT;
}
esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle)

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -33,7 +33,12 @@ esp_err_t adc_dma_init(adc_dma_t *adc_dma)
.flags.isr_cache_safe = true,
#endif
};
#if ADC_LL_DMA_USE_LP_AHB_GDMA
ret = gdma_new_lp_ahb_channel(&rx_alloc_config, NULL, &(adc_dma->gdma_chan));
#else
ret = gdma_new_ahb_channel(&rx_alloc_config, NULL, &(adc_dma->gdma_chan));
#endif
if (ret != ESP_OK) {
return ret;
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -161,6 +161,14 @@ esp_err_t adc_continuous_start(adc_continuous_handle_t handle);
/**
* @brief Read bytes from ADC under continuous mode.
*
* @note Raw ADC codes are intended for further processing. To obtain a voltage in mV, it is recommended to use
* :cpp:func:`adc_cali_raw_to_voltage` instead of interpreting the raw value directly.
*
* @note On targets with :c:macro:`SOC_ADC_DIFF_SUPPORTED`, N-side channels can be used in single-ended mode,
* but their raw data polarity is inverted. For an input range of -2 V to 2 V, the N-side raw code is
* 4393 to 0. Use the ADC calibration APIs to convert the raw result to voltage instead of interpreting the raw
* code directly.
*
* @param[in] handle ADC continuous mode driver handle
* @param[out] buf Conversion result buffer to read from ADC. Suggest convert to `adc_digi_output_data_t` for `ADC Conversion Results`.
* See the subsection `Driver Backgrounds` in this header file to learn about this concept.
@@ -244,7 +252,7 @@ esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel
typedef struct {
adc_unit_t unit; ///< ADC unit (ADC_UNIT_1 or ADC_UNIT_2)
adc_channel_t channel; ///< ADC channel number (0-9)
uint32_t raw_data; ///< ADC raw data value (0-4095, 12-bit resolution)
uint32_t raw_data; ///< ADC raw data value.
bool valid; ///< Whether the data is valid
} adc_continuous_data_t;

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
*/
@@ -76,6 +76,13 @@ esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_chann
*
* @note This API is thread-safe. For more details, see ADC programming guide
* @note This API should NOT be called in an ISR context
* @note Raw ADC codes are intended for further processing. To obtain a voltage in mV, it is recommended to use
* :cpp:func:`adc_cali_raw_to_voltage` instead of interpreting the raw value directly.
* :cpp:func:`adc_oneshot_get_calibrated_result` is a convenience function that does both.
* @note On targets with :c:macro:`SOC_ADC_DIFF_SUPPORTED`, N-side channels can be used in single-ended mode,
* but their raw data polarity is inverted. For an input range of -2 V to 2 V, the N-side raw code is
* 4393 to 0. Use the ADC calibration APIs to convert the raw result to voltage instead of interpreting the raw
* code directly.
*
* @param[in] handle ADC handle
* @param[in] chan ADC channel

View File

@@ -17,4 +17,4 @@ components/esp_adc/test_apps/adc:
disable_test:
- if: IDF_TARGET in ["esp32h4"]
temporary: true
reason: no runners for esp32h4 ADC test
reason: no runners

View File

@@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | -------- | --------- |

View File

@@ -92,4 +92,14 @@
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_16 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_64 10
#define IDF_PERFORMANCE_MAX_ADC_ONESHOT_STD_ATTEN3 10
#elif CONFIG_IDF_TARGET_ESP32S31
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_2 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_4 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_8 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_16 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_64 10
#define IDF_PERFORMANCE_MAX_ADC_ONESHOT_STD_ATTEN3 10
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -27,12 +27,10 @@ const __attribute__((unused)) static char *TAG = "TEST_ADC";
#define ADC1_TEST_CHAN0 ADC_CHANNEL_4
#define ADC1_TEST_CHAN1 ADC_CHANNEL_5
#define ADC2_TEST_CHAN0 ADC_CHANNEL_0
static const char *TAG_CH[2][10] = {{"ADC1_CH4", "ADC1_CH5"}, {"ADC2_CH0"}};
#else
#define ADC1_TEST_CHAN0 ADC_CHANNEL_2
#define ADC1_TEST_CHAN1 ADC_CHANNEL_3
#define ADC2_TEST_CHAN0 ADC_CHANNEL_0
static const char *TAG_CH[2][10] = {{"ADC1_CH2", "ADC1_CH3"}, {"ADC2_CH0"}};
#endif
/*---------------------------------------------------------------
@@ -69,7 +67,7 @@ static void adc_oneshot_init_test(void)
//-------------ADC1 TEST Channel 0 Config---------------//
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
.atten = TEST_ADC_DRIVER_DEFAULT_ATTEN,
};
TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, ADC1_TEST_CHAN0, &config));
@@ -86,36 +84,30 @@ static void adc_oneshot_read_test(void)
{
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0);
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN0, &adc_raw[0][0]));
ESP_LOGI(TAG_CH[0][0], "low raw data: %d", adc_raw[0][0]);
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[0][0]);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, false, adc_raw[0][0], false, false);
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN1, 0);
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN1, &adc_raw[0][1]));
ESP_LOGI(TAG_CH[0][1], "low raw data: %d", adc_raw[0][1]);
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[0][1]);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN1, false, adc_raw[0][1], false, false);
#if ADC_TEST_ONESHOT_HIGH_LOW_TEST_ADC2
test_adc_set_io_level(ADC_UNIT_2, ADC2_TEST_CHAN0, 0);
TEST_ESP_OK(adc_oneshot_read(adc2_handle, ADC2_TEST_CHAN0, &adc_raw[1][0]));
ESP_LOGI(TAG_CH[1][0], "low raw data: %d", adc_raw[1][0]);
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[1][0]);
test_assert_adc_raw(ADC_UNIT_2, ADC2_TEST_CHAN0, false, adc_raw[1][0], false, false);
#endif //#if ADC_TEST_ONESHOT_HIGH_LOW_TEST_ADC2
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1);
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN0, &adc_raw[0][0]));
ESP_LOGI(TAG_CH[0][0], "high raw data: %d", adc_raw[0][0]);
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[0][0]);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, true, adc_raw[0][0], false, false);
test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN1, 1);
TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN1, &adc_raw[0][1]));
ESP_LOGI(TAG_CH[0][1], "high raw data: %d", adc_raw[0][1]);
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[0][1]);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN1, true, adc_raw[0][1], false, false);
#if ADC_TEST_ONESHOT_HIGH_LOW_TEST_ADC2
test_adc_set_io_level(ADC_UNIT_2, ADC2_TEST_CHAN0, 1);
TEST_ESP_OK(adc_oneshot_read(adc2_handle, ADC2_TEST_CHAN0, &adc_raw[1][0]));
ESP_LOGI(TAG_CH[1][0], "high raw data: %d", adc_raw[1][0]);
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[1][0]);
test_assert_adc_raw(ADC_UNIT_2, ADC2_TEST_CHAN0, true, adc_raw[1][0], false, false);
#endif //#if ADC_TEST_ONESHOT_HIGH_LOW_TEST_ADC2
}
@@ -147,7 +139,7 @@ TEST_CASE("ADC oneshot stress test that get zero even if convent done", "[adc_on
int test_num = 100;
adc_channel_t channel = ADC1_TEST_CHAN1;
adc_atten_t atten = ADC_ATTEN_DB_12;
adc_atten_t atten = TEST_ADC_DRIVER_DEFAULT_ATTEN;
adc_unit_t unit_id = ADC_UNIT_1;
adc_oneshot_unit_handle_t adc1_handle;
@@ -345,7 +337,7 @@ TEST_CASE("ADC continuous monitor init_deinit", "[adc]")
adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
for (int i = 0; i < 1; i++) {
adc_pattern[i].atten = ADC_ATTEN_DB_12;
adc_pattern[i].atten = TEST_ADC_DRIVER_DEFAULT_ATTEN;
adc_pattern[i].channel = i;
adc_pattern[i].unit = ADC_UNIT_1;
adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
@@ -445,7 +437,7 @@ TEST_CASE("ADC continuous monitor functionary", "[adc]")
adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
for (int i = 0; i < 2; i++) {
adc_pattern[i].atten = ADC_ATTEN_DB_12;
adc_pattern[i].atten = TEST_ADC_DRIVER_DEFAULT_ATTEN;
adc_pattern[i].channel = TEST_ADC_CHANNEL;
adc_pattern[i].unit = ADC_UNIT_1;
adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -52,12 +52,7 @@ static bool IRAM_ATTR s_alarm_callback(gptimer_handle_t timer, const gptimer_ala
esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value);
TEST_ESP_OK(adc_oneshot_read_isr(test_ctx->oneshot_handle, ADC1_TEST_CHAN0, &adc_raw));
esp_rom_printf("adc raw: %d\r\n", adc_raw);
if (test_ctx->level) {
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw);
} else {
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw);
}
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, test_ctx->level, adc_raw, false, false);
// check the count value at alarm event
vTaskNotifyGiveFromISR(test_ctx->task_handle, &high_task_wakeup);
@@ -80,7 +75,7 @@ TEST_CASE("ADC oneshot fast work with ISR", "[adc_oneshot]")
//-------------ADC1 TEST Channel 0 Config---------------//
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
.atten = TEST_ADC_DRIVER_DEFAULT_ATTEN,
};
TEST_ESP_OK(adc_oneshot_config_channel(isr_test_ctx.oneshot_handle, ADC1_TEST_CHAN0, &config));
@@ -170,7 +165,7 @@ TEST_CASE("ADC continuous big conv_frame_size test", "[adc_continuous]")
.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_12;
adc_pattern[0].atten = TEST_ADC_DRIVER_DEFAULT_ATTEN;
adc_pattern[0].channel = ADC1_TEST_CHAN0;
adc_pattern[0].unit = ADC_UNIT_1;
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
@@ -202,7 +197,7 @@ TEST_CASE("ADC continuous big conv_frame_size test", "[adc_continuous]")
cnt++;
}
esp_rom_printf("avg: %" PRIu32 "\n", sum / cnt);
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, sum / cnt);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, false, sum / cnt, false, false);
}
TEST_ESP_OK(adc_continuous_stop(handle));
@@ -227,7 +222,7 @@ TEST_CASE("ADC continuous flush internal pool", "[adc_continuous][manual][ignore
.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_12;
adc_pattern[0].atten = TEST_ADC_DRIVER_DEFAULT_ATTEN;
adc_pattern[0].channel = ADC1_TEST_CHAN0;
adc_pattern[0].unit = ADC_UNIT_1;
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
@@ -279,7 +274,7 @@ TEST_CASE("ADC continuous test after restarting", "[adc_continuous][ignore]")
.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_12;
adc_pattern[0].atten = TEST_ADC_DRIVER_DEFAULT_ATTEN;
adc_pattern[0].channel = ADC1_TEST_CHAN0;
adc_pattern[0].unit = ADC_UNIT_1;
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;

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
*/
@@ -84,7 +84,7 @@ TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]")
//-------------ADC1 TEST Channel 0 Config---------------//
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
.atten = TEST_ADC_DRIVER_DEFAULT_ATTEN,
};
TEST_ESP_OK(adc_oneshot_config_channel(oneshot_handle, ADC1_TEST_CHAN0, &config));
@@ -117,7 +117,7 @@ TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]")
s_test_cache_disable_period_us(&isr_test_ctx, 100 * 1000);
TEST_ESP_OK(gptimer_stop(timer));
//Checks
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, isr_test_ctx.adc_raw_low);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, false, isr_test_ctx.adc_raw_low, false, false);
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_low);
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_low);
@@ -131,7 +131,7 @@ TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]")
s_test_cache_disable_period_us(&isr_test_ctx, 100 * 1000);
TEST_ESP_OK(gptimer_stop(timer));
//Checks
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, isr_test_ctx.adc_raw_high);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, true, isr_test_ctx.adc_raw_high, false, false);
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_high);
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_high);
@@ -225,7 +225,7 @@ TEST_CASE("ADC continuous work with ISR and Flash", "[adc_continuous]")
s_test_cache_disable_period_us(&isr_test_ctx, wait_time_us);
TEST_ESP_OK(adc_continuous_stop(handle));
//Checks
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, isr_test_ctx.adc_raw_low);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, false, isr_test_ctx.adc_raw_low, false, false);
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_low);
//At least 1 time conv_done callback happens during this period is ok
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_low);
@@ -240,7 +240,7 @@ TEST_CASE("ADC continuous work with ISR and Flash", "[adc_continuous]")
s_test_cache_disable_period_us(&isr_test_ctx, wait_time_us);
TEST_ESP_OK(adc_continuous_stop(handle));
//Checks
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL_DMA, isr_test_ctx.adc_raw_high);
test_assert_adc_raw(ADC_UNIT_1, ADC1_TEST_CHAN0, true, isr_test_ctx.adc_raw_high, true, false);
esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_high);
//At least 1 time conv_done callback happens during this period is ok
TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_high);

View File

@@ -13,6 +13,7 @@
#include "esp_cpu.h"
#include "esp_heap_caps.h"
#include "hal/adc_periph.h"
#include "hal/adc_ll.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_adc/adc_oneshot.h"
@@ -34,20 +35,25 @@ static int s_adc_count_size;
static int *s_p_adc_count;
static int s_adc_offset = -1;
#ifndef ADC_LL_RAW_DATA_WEIGHTED_SUM
#define ADC_TEST_RAW_BUCKET_SIZE(bitwidth) (1 << (bitwidth))
#else
#define ADC_TEST_RAW_BUCKET_SIZE(bitwidth) (ADC_TEST_HIGH_VAL + 1)
#endif
static int s_insert_point(uint32_t value)
{
const bool fixed_size = true;
if (s_adc_offset < 0) {
if (fixed_size) {
TEST_ASSERT_GREATER_OR_EQUAL(4096, s_adc_count_size);
s_adc_offset = 0; //Fixed to 0 because the array can hold all the data in 12 bits
s_adc_offset = 0; // Fixed to 0 because the array can hold the full raw code range
} else {
s_adc_offset = MAX((int)value - s_adc_count_size / 2, 0);
}
}
if (!fixed_size && (value < s_adc_offset || value >= s_adc_offset + s_adc_count_size)) {
if (value < s_adc_offset || value >= s_adc_offset + s_adc_count_size) {
TEST_ASSERT_GREATER_OR_EQUAL(s_adc_offset, value);
TEST_ASSERT_LESS_THAN(s_adc_offset + s_adc_count_size, value);
}
@@ -217,7 +223,7 @@ static float test_adc_continuous_std(adc_atten_t atten, bool filter_en, int filt
ESP_LOGI("TEST_ADC", "Test with atten: %d, no filter", atten);
}
s_reset_array((1 << SOC_ADC_DIGI_MAX_BITWIDTH));
s_reset_array(ADC_TEST_RAW_BUCKET_SIZE(SOC_ADC_DIGI_MAX_BITWIDTH));
TEST_ESP_OK(adc_continuous_start(handle));
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
@@ -271,29 +277,29 @@ TEST_CASE("ADC1 continuous raw average and std_deviation", "[adc_continuous][man
TEST_CASE("ADC1 continuous std deviation performance, no filter", "[adc_continuous][performance]")
{
float std = test_adc_continuous_std(ADC_ATTEN_DB_12, false, 0, true);
float std = test_adc_continuous_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, false, 0, true);
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER, "%.2f", std);
}
#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED
TEST_CASE("ADC1 continuous std deviation performance, with filter", "[adc_continuous][performance]")
{
float std = test_adc_continuous_std(ADC_ATTEN_DB_12, false, 0, true);
float std = test_adc_continuous_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, false, 0, true);
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER, "%.2f", std);
std = test_adc_continuous_std(ADC_ATTEN_DB_12, true, ADC_DIGI_IIR_FILTER_COEFF_2, true);
std = test_adc_continuous_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, true, ADC_DIGI_IIR_FILTER_COEFF_2, true);
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_FILTER_2, "%.2f", std);
std = test_adc_continuous_std(ADC_ATTEN_DB_12, true, ADC_DIGI_IIR_FILTER_COEFF_4, true);
std = test_adc_continuous_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, true, ADC_DIGI_IIR_FILTER_COEFF_4, true);
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_FILTER_4, "%.2f", std);
std = test_adc_continuous_std(ADC_ATTEN_DB_12, true, ADC_DIGI_IIR_FILTER_COEFF_8, true);
std = test_adc_continuous_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, true, ADC_DIGI_IIR_FILTER_COEFF_8, true);
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_FILTER_8, "%.2f", std);
std = test_adc_continuous_std(ADC_ATTEN_DB_12, true, ADC_DIGI_IIR_FILTER_COEFF_16, true);
std = test_adc_continuous_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, true, ADC_DIGI_IIR_FILTER_COEFF_16, true);
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_FILTER_16, "%.2f", std);
std = test_adc_continuous_std(ADC_ATTEN_DB_12, true, ADC_DIGI_IIR_FILTER_COEFF_64, true);
std = test_adc_continuous_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, true, ADC_DIGI_IIR_FILTER_COEFF_64, true);
TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_FILTER_64, "%.2f", std);
}
#endif //#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED
@@ -421,7 +427,7 @@ static float test_adc_oneshot_std(adc_atten_t atten, bool is_performance_test)
TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, channel, &config));
ESP_LOGI("TEST_ADC", "Test with atten: %d", atten);
s_reset_array((1 << SOC_ADC_RTC_MAX_BITWIDTH));
s_reset_array(ADC_TEST_RAW_BUCKET_SIZE(SOC_ADC_RTC_MAX_BITWIDTH));
if (is_performance_test) {
test_adc_set_io_middle(ADC_UNIT_1, TEST_STD_ADC1_CHANNEL0);
@@ -463,7 +469,7 @@ TEST_CASE("ADC1 oneshot raw average and std_deviation", "[adc_oneshot][manual]")
TEST_CASE("ADC1 oneshot std_deviation performance", "[adc_oneshot][performance]")
{
float std = test_adc_oneshot_std(ADC_ATTEN_DB_12, true);
float std = test_adc_oneshot_std(TEST_ADC_DRIVER_DEFAULT_ATTEN, true);
TEST_PERFORMANCE_LESS_THAN(ADC_ONESHOT_STD_ATTEN3, "%.2f", std);
}
/*---------------------------------------------------------------
@@ -513,7 +519,7 @@ static void s_adc_cali_speed(adc_unit_t unit_id, adc_channel_t channel)
} else {
ESP_LOGI(TAG, "CPU FREQ is %dMHz", CPU_FREQ_MHZ);
uint32_t adc_time_record[4][TIMES_PER_ATTEN] = {};
uint32_t adc_time_record[TEST_ATTEN_NUMS][TIMES_PER_ATTEN] = {};
int adc_raw = 0;
//-------------ADC Init---------------//

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
*/
@@ -25,7 +25,7 @@
static const char *TAG = "adc_tsens";
#define TEST_ADC1_CHAN0 ADC_CHANNEL_2
#define TEST_ADC_ATTEN ADC_ATTEN_DB_12
#define TEST_ADC_ATTEN TEST_ADC_DRIVER_DEFAULT_ATTEN
static int adc_raw;
static float tsens_value;
@@ -45,13 +45,11 @@ static void adc_oneshot_test(adc_oneshot_unit_handle_t adc_handle)
{
test_adc_set_io_level(ADC_UNIT_1, TEST_ADC1_CHAN0, 0);
TEST_ESP_OK(adc_oneshot_read(adc_handle, TEST_ADC1_CHAN0, &adc_raw));
ESP_LOGI(TAG, "low raw data: %d", adc_raw);
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw);
test_assert_adc_raw(ADC_UNIT_1, TEST_ADC1_CHAN0, false, adc_raw, false, false);
test_adc_set_io_level(ADC_UNIT_1, TEST_ADC1_CHAN0, 1);
TEST_ESP_OK(adc_oneshot_read(adc_handle, TEST_ADC1_CHAN0, &adc_raw));
ESP_LOGI(TAG, "high raw data: %d", adc_raw);
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw);
test_assert_adc_raw(ADC_UNIT_1, TEST_ADC1_CHAN0, true, adc_raw, false, false);
}
TEST_CASE("Test temperature sensor work with ADC oneshot", "[adc]")
@@ -118,7 +116,7 @@ TEST_CASE("Test temperature sensor work with ADC continuous", "[adc]")
.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_12;
adc_pattern[0].atten = TEST_ADC_DRIVER_DEFAULT_ATTEN;
adc_pattern[0].channel = TEST_ADC1_CHAN0;
adc_pattern[0].unit = ADC_UNIT_1;
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -34,14 +34,12 @@ static const char* TAG = "test_adc_wifi";
#define ADC2_WIFI_TEST_CHAN0 ADC_CHANNEL_0
#endif
#define ADC_ERROR_THRES 200
#define TEST_NUM 8
#define MINUS_UNTIL_ZERO(a, b) ( ((a) > (b)) ? ((a)-(b)): 0)
#define TIME_REMAIN(start, now, timeout) ((now) >= (start) ? MINUS_UNTIL_ZERO((timeout), (now)-(start)) : -1)
static int read_raw;
static int target_value;
static int test_adc_io;
static bool test_list[TEST_NUM] = {0, 1, 0, 0, 1, 0, 1, 0};
@@ -98,7 +96,7 @@ static int event_deinit(void)
return ESP_OK;
}
static void s_test_adc_work_when_wifi_on(adc_oneshot_unit_handle_t adc_handle, adc_channel_t channel)
static void s_test_adc_work_when_wifi_on(adc_oneshot_unit_handle_t adc_handle, adc_unit_t unit_id, adc_channel_t channel, bool level)
{
esp_err_t ret = ESP_FAIL;
int32_t start = xTaskGetTickCount();
@@ -110,8 +108,8 @@ static void s_test_adc_work_when_wifi_on(adc_oneshot_unit_handle_t adc_handle, a
remain_wait_ms = pdTICKS_TO_MS(TIME_REMAIN(start, now, timeout));
ret = adc_oneshot_read(adc_handle, channel, &read_raw);
if (ret == ESP_OK) {
printf("When WiFi is ON, ADC read: %d (target_value: %d)\n", read_raw, target_value);
TEST_ASSERT_INT_WITHIN(ADC_ERROR_THRES, target_value, read_raw);
printf("When WiFi is ON, ADC read: %d\n", read_raw);
test_assert_adc_raw(unit_id, channel, level, read_raw, false, true);
break;
} else if (ret == ESP_ERR_TIMEOUT) {
continue;
@@ -170,19 +168,18 @@ __attribute__((unused)) static void adc_work_with_wifi(adc_unit_t unit_id, adc_c
//-------------ADC TEST Channel Config---------------//
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
.atten = TEST_ADC_DRIVER_DEFAULT_ATTEN,
};
TEST_ESP_OK(adc_oneshot_config_channel(adc_handle, channel, &config));
for (int i = 0; i < TEST_NUM; i++) {
/* Tune test ADC channel level */
test_adc_set_io_level(unit_id, channel, test_list[i]);
target_value = test_list[i] ? ADC_TEST_HIGH_VAL : ADC_TEST_LOW_VAL;
/* ADC single read before WIFI start */
TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &read_raw));
printf("Before WiFi starts, ADC read: %d (target_value: %d)\n", read_raw, target_value);
TEST_ASSERT_INT_WITHIN(ADC_ERROR_THRES, target_value, read_raw);
printf("Before WiFi starts, ADC read: %d\n", read_raw);
test_assert_adc_raw(unit_id, channel, test_list[i], read_raw, false, true);
/* ADC single read when WIFI is on */
TEST_ESP_OK(esp_wifi_start());
@@ -193,16 +190,16 @@ __attribute__((unused)) static void adc_work_with_wifi(adc_unit_t unit_id, adc_c
// After SAR ADC2 is released by Wi-Fi, users can use SAR ADC2 normally.
TEST_ASSERT_EQUAL(ESP_ERR_TIMEOUT, adc_oneshot_read(adc_handle, channel, &read_raw));
} else {
s_test_adc_work_when_wifi_on(adc_handle, channel);
s_test_adc_work_when_wifi_on(adc_handle, unit_id, channel, test_list[i]);
}
#else
s_test_adc_work_when_wifi_on(adc_handle, channel);
s_test_adc_work_when_wifi_on(adc_handle, unit_id, channel, test_list[i]);
#endif
/* ADC single read after WIFI is off */
TEST_ESP_OK(esp_wifi_stop());
TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &read_raw));
printf("After WiFi is OFF, ADC read: %d (target_value: %d)\n\n", read_raw, target_value);
TEST_ASSERT_INT_WITHIN(ADC_ERROR_THRES, target_value, read_raw);
printf("After WiFi is OFF, ADC read: %d\n\n", read_raw);
test_assert_adc_raw(unit_id, channel, test_list[i], read_raw, false, true);
}
TEST_ESP_OK(adc_oneshot_del_unit(adc_handle));

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -22,6 +22,8 @@ __attribute__((unused)) static const char *TAG = "TEST_ADC";
---------------------------------------------------------------*/
#if CONFIG_IDF_TARGET_ESP32C2
adc_atten_t g_test_atten[TEST_ATTEN_NUMS] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_12};
#elif CONFIG_IDF_TARGET_ESP32S31
adc_atten_t g_test_atten[TEST_ATTEN_NUMS] = {ADC_ATTEN_DB_0};
#else
adc_atten_t g_test_atten[TEST_ATTEN_NUMS] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_2_5, ADC_ATTEN_DB_6, ADC_ATTEN_DB_12};
#endif
@@ -128,3 +130,32 @@ void test_adc_set_io_middle(adc_unit_t unit, adc_channel_t channel)
#endif
vTaskDelay(10 / portTICK_PERIOD_MS);
}
void test_assert_adc_raw(adc_unit_t unit, adc_channel_t channel, bool level, int raw, bool dma_mode, bool loose_thresh)
{
TEST_ASSERT(channel < SOC_ADC_CHANNEL_NUM(unit) && "invalid channel");
#if defined ADC_TEST_HIGH_VAL_DMA
int expected_value = level ? (dma_mode ? ADC_TEST_HIGH_VAL_DMA : ADC_TEST_HIGH_VAL) : ADC_TEST_LOW_VAL;
#else
int expected_value = level ? ADC_TEST_HIGH_VAL : ADC_TEST_LOW_VAL;
#endif
int expected_thresh = level ? ADC_TEST_HIGH_THRESH : ADC_TEST_LOW_THRESH;
int io_num = adc_channel_io_map[unit][channel];
#if SOC_ADC_DIFF_SUPPORTED
if ((((unsigned)channel) & 0x1U) == 0U) {
// N-side input's raw value is inverted.
expected_value = level ? 0 : ADC_TEST_LOW_VAL;
expected_thresh = ADC_TEST_LOW_THRESH;
}
#endif
if (loose_thresh) {
expected_thresh = ADC_TEST_LOOSE_THRESH;
}
ESP_EARLY_LOGI(TAG, "ADC%d channel %d (GPIO%d) set=%d, raw=%d, expected=%d",
unit + 1, channel, io_num, level, raw, expected_value);
TEST_ASSERT_INT_WITHIN(expected_thresh, expected_value, raw);
}

View File

@@ -119,19 +119,41 @@ extern "C" {
#define ADC_TEST_HIGH_VAL_DMA 4095
#define ADC_TEST_HIGH_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32S31
#define ADC_TEST_LOW_VAL 2196
#define ADC_TEST_LOW_THRESH 100
#define ADC_TEST_HIGH_VAL 4393
#define ADC_TEST_HIGH_VAL_DMA 4393
#define ADC_TEST_HIGH_THRESH 100
#endif
/**
* Loose threshold used in noisy scenarios (e.g. ADC reading while WiFi is on),
*/
#define ADC_TEST_LOOSE_THRESH 200
/*---------------------------------------------------------------
ADC Attenuation
---------------------------------------------------------------*/
#if CONFIG_IDF_TARGET_ESP32C2
#define TEST_ATTEN_NUMS 2
extern adc_atten_t g_test_atten[TEST_ATTEN_NUMS];
#elif CONFIG_IDF_TARGET_ESP32S31
#define TEST_ATTEN_NUMS 1
extern adc_atten_t g_test_atten[TEST_ATTEN_NUMS];
#else
#define TEST_ATTEN_NUMS 4
extern adc_atten_t g_test_atten[TEST_ATTEN_NUMS];
#endif
#if SOC_ADC_ATTEN_NUM <= 1
#define TEST_ADC_DRIVER_DEFAULT_ATTEN ADC_ATTEN_DB_0
#else
#define TEST_ADC_DRIVER_DEFAULT_ATTEN ADC_ATTEN_DB_12
#endif
/*---------------------------------------------------------------
ADC Filter
---------------------------------------------------------------*/
@@ -188,6 +210,18 @@ void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level);
*/
void test_adc_set_io_middle(adc_unit_t unit, adc_channel_t channel);
/**
* @brief Assert ADC raw value against test expectation
*
* @param[in] unit ADC unit
* @param[in] channel ADC channel
* @param[in] level IO level. True: high; False: low
* @param[in] raw ADC raw value
* @param[in] dma_mode Whether to use DMA-mode high-level expectation
* @param[in] loose_thresh When true, use for noisy scenarios such as ADC reading while WiFi is on.
*/
void test_assert_adc_raw(adc_unit_t unit, adc_channel_t channel, bool level, int raw, bool dma_mode, bool loose_thresh);
#ifdef __cplusplus
}
#endif

View File

@@ -9,7 +9,7 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.parametrize('config', ['iram_safe', 'release', 'pm_enable'], indirect=True)
@idf_parametrize(
'target',
['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32c5', 'esp32p4', 'esp32c61'],
['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32c5', 'esp32p4', 'esp32c61', 'esp32s31'],
indirect=['target'],
)
def test_adc(dut: Dut) -> None:

View File

@@ -117,7 +117,16 @@ 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)
#if ADC_LL_DIGI_SAMPLE_FREQ_DYNAMIC_CLK_DIV
uint64_t max_ctrl_clk_hz = MIN((uint64_t)clk_src_freq_hz, (uint64_t)sample_freq_hz * 2 * 4095);
uint32_t ctrl_div = (uint32_t)(((uint64_t)clk_src_freq_hz + max_ctrl_clk_hz - 1) / max_ctrl_clk_hz);
ctrl_div = MAX(ctrl_div, 1U);
uint32_t interval = (uint32_t)((uint64_t)clk_src_freq_hz / ((uint64_t)ctrl_div * 2 * sample_freq_hz));
adc_ll_digi_controller_clk_div(ctrl_div - 1, 1, 0);
adc_ll_digi_clk_sel(clk_src);
adc_ll_digi_set_trigger_interval(interval);
#elif !SOC_IS(ESP32)
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));

View File

@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "hal/adc_periph.h"
/* Store the GPIO number for each public ADC channel. */
const int adc_channel_io_map[SOC_ADC_PERIPH_NUM][SOC_ADC_MAX_CHANNEL_NUM] = {
/* ADC1 */
{
ADC1_CHANNEL_0_GPIO_NUM, ADC1_CHANNEL_1_GPIO_NUM, ADC1_CHANNEL_2_GPIO_NUM, ADC1_CHANNEL_3_GPIO_NUM,
ADC1_CHANNEL_4_GPIO_NUM, ADC1_CHANNEL_5_GPIO_NUM, ADC1_CHANNEL_6_GPIO_NUM, ADC1_CHANNEL_7_GPIO_NUM
},
/* ADC2 */
{
ADC2_CHANNEL_0_GPIO_NUM, ADC2_CHANNEL_1_GPIO_NUM, ADC2_CHANNEL_2_GPIO_NUM, ADC2_CHANNEL_3_GPIO_NUM,
ADC2_CHANNEL_4_GPIO_NUM, ADC2_CHANNEL_5_GPIO_NUM, ADC2_CHANNEL_6_GPIO_NUM, ADC2_CHANNEL_7_GPIO_NUM
}
};

View File

@@ -0,0 +1,699 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "hal/adc_periph.h"
#include "soc/adc_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/lp_peri_clkrst_struct.h"
#include "hal/misc.h"
#include "hal/assert.h"
#include "hal/adc_types.h"
#include "hal/regi2c_ctrl.h"
#include "soc/regi2c_saradc.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
Macros
---------------------------------------------------------------*/
#define ADC_LL_EVENT_ADC1_ONESHOT_DONE BIT(31)
#define ADC_LL_EVENT_ADC2_ONESHOT_DONE BIT(30)
#define ADC_LL_FORCE_XPD_SAR_FSM 0 // Use FSM to control power
#define ADC_LL_FORCE_XPD_SAR_PD 2 // Force power down
#define ADC_LL_FORCE_XPD_SAR_PU 3 // Force power up
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1)
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION (0)
#define ADC_LL_DMA_USE_LP_AHB_GDMA 1
#define ADC_LL_DIGI_SAMPLE_FREQ_DYNAMIC_CLK_DIV 1
#define ADC_LL_RAW_DATA_WEIGHTED_SUM (1)
/*---------------------------------------------------------------
Differential
---------------------------------------------------------------*/
#define ADC_LL_ZERO_DIFF_CODE (2198)
/*---------------------------------------------------------------
Oneshot
---------------------------------------------------------------*/
#define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (0)
#define ADC_LL_DELAY_CYCLE_AFTER_DONE_SIGNAL (0)
#define ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT (1)
#define ADC_LL_CLKM_DIV_NUM_DEFAULT 4
#define ADC_LL_CLKM_DIV_B_DEFAULT 1
#define ADC_LL_CLKM_DIV_A_DEFAULT 0
#define ADC_LL_POWER_MANAGE_SUPPORTED 1
#define ADC_LL_DIGI_DATA_INVERT_DEFAULT(PERIPH_NUM) (0)
#define ADC_LL_FSM_RSTB_WAIT_DEFAULT (8)
#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_DEFAULT_CONV_LIMIT_EN (0)
#define ADC_LL_DEFAULT_CONV_LIMIT_NUM (255)
#define ADC_LL_WORKAROUND_CLEAR_EOF_COUNTER (0)
#define ADC_LL_PWDET_CCT_DEFAULT (4)
typedef enum {
ADC_LL_CTRL_DIG = 0, ///< S31 uses unified digital controller
} adc_ll_controller_t;
typedef enum {
ADC_LL_POWER_BY_FSM = ADC_LL_FORCE_XPD_SAR_FSM, /*!< ADC XPD controlled by FSM. Used for polling mode */
ADC_LL_POWER_SW_ON = ADC_LL_FORCE_XPD_SAR_PU, /*!< ADC XPD controlled by SW. power on. */
ADC_LL_POWER_SW_OFF = ADC_LL_FORCE_XPD_SAR_PD, /*!< ADC XPD controlled by SW. power off. */
} adc_ll_power_t;
typedef enum {
ADC_LL_TRIGGER_MODE_OFF = 0, /*!< Trigger disabled */
ADC_LL_TRIGGER_MODE_SCAN = 1, /*!< Timer/scan trigger mode */
ADC_LL_TRIGGER_MODE_SW = 2, /*!< Software trigger mode for oneshot */
ADC_LL_TRIGGER_MODE_ETM = 3, /*!< External ETM trigger mode */
} adc_ll_trigger_mode_t;
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/**
* @brief Set SAR ADC module clock division factor.
* S31 clock is controlled through LP_PERI_CLKRST divider.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_set_clk_div(uint32_t div)
{
(void)div;
}
/**
* @brief Set ADC digital controller clock division factor.
* S31 uses LP_PERI_CLKRST.adc_ctrl.lp_adc_div_num for clock division.
* Division factor = lp_adc_div_num + 1
*/
__attribute__((always_inline))
static inline void adc_ll_digi_controller_clk_div(uint32_t div_num, uint32_t div_b, uint32_t div_a)
{
(void)div_b;
(void)div_a;
HAL_FORCE_MODIFY_U32_REG_FIELD(LP_PERI_CLKRST.adc_ctrl, lp_adc_div_num, div_num);
}
/**
* @brief Select the digital clock source for ADC.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_clk_sel(adc_continuous_clk_src_t clk_src)
{
switch (clk_src) {
case ADC_DIGI_CLK_SRC_XTAL:
LP_PERI_CLKRST.adc_ctrl.lp_adc_clk_sel = 1;
break;
case ADC_DIGI_CLK_SRC_RC_FAST:
LP_PERI_CLKRST.adc_ctrl.lp_adc_clk_sel = 0;
break;
default:
HAL_ASSERT(false && "unsupported clock");
}
ADC.ctrl_date.clk_en = 1;
}
/*---------------------------------------------------------------
DMA continuous mode
---------------------------------------------------------------*/
typedef enum {
ADC_LL_DIGI_CONV_ONLY_ADC1 = 0,
ADC_LL_DIGI_CONV_ONLY_ADC2 = 1,
ADC_LL_DIGI_CONV_BOTH_UNIT = 2,
ADC_LL_DIGI_CONV_ALTER_UNIT = 3,
} adc_ll_digi_convert_mode_t;
/**
* Set ADC FSM interval parameters for digital controller.
*
* @param rst_wait cycles between DIG ADC controller reset ADC sensor and start ADC sensor.
* @param start_wait Delay time after opening XPD.
* @param standby_wait Delay time to close XPD.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_set_fsm_time(uint32_t rst_wait, uint32_t start_wait, uint32_t standby_wait)
{
(void)rst_wait;
(void)start_wait;
(void)standby_wait;
}
/**
* Set ADC sample cycle for digital controller.
*
* @note Normally, please use the default value.
* @param sample_cycle Cycles between DIG ADC controller start ADC sensor and beginning to receive data from sensor.
*/
__attribute__((always_inline))
static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle)
{
REGI2C_WRITE_MASK(I2C_SARADC, ADC_SAR1_SAMPLE_CYCLE_ADDR, sample_cycle);
REGI2C_WRITE_MASK(I2C_SARADC, ADC_SAR2_SAMPLE_CYCLE_ADDR, sample_cycle);
}
/**
* Set ADC CCT for PWDET controller.
*
* @note Capacitor tuning of the PA power monitor. CCT is set to the same value as PHY.
* @param cct CCT value.
*/
__attribute__((always_inline))
static inline void adc_ll_pwdet_set_cct(uint32_t cct)
{
(void)cct;
}
/**
* Get ADC CCT for PWDET controller.
*
* @return CCT value.
*/
__attribute__((always_inline))
static inline uint32_t adc_ll_pwdet_get_cct(void)
{
return ADC_LL_PWDET_CCT_DEFAULT;
}
/**
* Configure ADC digital controller output data inversion.
*
* @param adc_n ADC unit.
* @param inv_en true to invert output data, false otherwise.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_output_invert(adc_unit_t adc_n, bool inv_en)
{
(void)adc_n;
(void)inv_en;
}
/**
* Enable max conversion number detection for digital controller.
* If the number of ADC conversions reaches the maximum, the conversion is stopped.
*
* @param enable true to enable, false to disable.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_convert_limit_enable(bool enable)
{
(void)enable;
}
/**
* Set ADC max conversion number for digital controller.
* If the number of ADC conversions reaches the maximum, the conversion is stopped.
*
* @param meas_num Max conversion number.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num)
{
(void)meas_num;
}
/**
* Disable clock for ADC digital controller.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_controller_clk_disable(void)
{
// For compatibility
}
/**
* Set ADC conversion mode for digital controller.
*
* @param mode Conversion mode select.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_set_convert_mode(adc_ll_digi_convert_mode_t mode)
{
switch (mode) {
case ADC_LL_DIGI_CONV_ONLY_ADC1:
ADC.ctrl0.sar1_trigger_mode = ADC_LL_TRIGGER_MODE_SCAN;
ADC.ctrl1.sar2_trigger_mode = ADC_LL_TRIGGER_MODE_OFF;
ADC.ctrl0.sar1_continue_mode_en = 0;
ADC.ctrl1.sar2_continue_mode_en = 0;
break;
case ADC_LL_DIGI_CONV_ONLY_ADC2:
ADC.ctrl0.sar1_trigger_mode = ADC_LL_TRIGGER_MODE_OFF;
ADC.ctrl1.sar2_trigger_mode = ADC_LL_TRIGGER_MODE_SCAN;
ADC.ctrl0.sar1_continue_mode_en = 0;
ADC.ctrl1.sar2_continue_mode_en = 0;
break;
case ADC_LL_DIGI_CONV_BOTH_UNIT:
case ADC_LL_DIGI_CONV_ALTER_UNIT:
ADC.ctrl0.sar1_trigger_mode = ADC_LL_TRIGGER_MODE_SCAN;
ADC.ctrl1.sar2_trigger_mode = ADC_LL_TRIGGER_MODE_SCAN;
ADC.ctrl0.sar1_continue_mode_en = 0;
ADC.ctrl1.sar2_continue_mode_en = 0;
break;
default:
HAL_ASSERT(false && "bad convert mode");
break;
}
/* Update pattern index after each completed conversion; single-ended uses model bit 0 in each entry. */
ADC.ctrl0.sar1_patt_type = 0;
ADC.ctrl1.sar2_patt_type = 0;
ADC.ctrl0.sar1_clk_pos_sel = 1;
ADC.ctrl1.sar2_clk_pos_sel = 1;
}
/**
* Set pattern table length for digital controller.
* The pattern table defines the conversion rules for each SAR ADC.
*
* @param adc_n ADC unit.
* @param patt_len Pattern items. Range: 1 ~ 16.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_set_pattern_table_len(adc_unit_t adc_n, uint32_t patt_len)
{
if (adc_n == ADC_UNIT_1) {
ADC.ctrl0.sar1_patt_len = patt_len - 1;
} else {
ADC.ctrl1.sar2_patt_len = patt_len - 1;
}
}
/**
* Set pattern table for digital controller.
* The pattern table stores channel selection, attenuation and model bits for scan conversion.
*
* @param adc_n ADC unit.
* @param pattern_index Pattern item index. Range: 0 ~ 15.
* @param table Stored conversion rule.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_set_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_config_t table)
{
HAL_ASSERT(pattern_index < 16);
uint32_t tab = 0;
uint8_t index = pattern_index / 4;
uint8_t offset = (pattern_index % 4) * 6;
(void)table.atten;
const uint32_t six_bits = (((uint32_t)table.channel & 0xFU) << 2) | 0U;
if (adc_n == ADC_UNIT_1) {
switch (index) {
case 0: tab = ADC.sar1_patt_tab1.sar1_patt_tab1; break;
case 1: tab = ADC.sar1_patt_tab2.sar1_patt_tab2; break;
case 2: tab = ADC.sar1_patt_tab3.sar1_patt_tab3; break;
default: tab = ADC.sar1_patt_tab4.sar1_patt_tab4; break;
}
tab &= ~(0xFC0000U >> offset);
tab |= (six_bits << 18) >> offset;
tab &= 0xffffff;
switch (index) {
case 0: ADC.sar1_patt_tab1.sar1_patt_tab1 = tab; break;
case 1: ADC.sar1_patt_tab2.sar1_patt_tab2 = tab; break;
case 2: ADC.sar1_patt_tab3.sar1_patt_tab3 = tab; break;
default: ADC.sar1_patt_tab4.sar1_patt_tab4 = tab; break;
}
} else {
switch (index) {
case 0: tab = ADC.sar2_patt_tab1.sar2_patt_tab1; break;
case 1: tab = ADC.sar2_patt_tab2.sar2_patt_tab2; break;
case 2: tab = ADC.sar2_patt_tab3.sar2_patt_tab3; break;
default: tab = ADC.sar2_patt_tab4.sar2_patt_tab4; break;
}
tab &= ~(0xFC0000U >> offset);
tab |= (six_bits << 18) >> offset;
tab &= 0xffffff;
switch (index) {
case 0: ADC.sar2_patt_tab1.sar2_patt_tab1 = tab; break;
case 1: ADC.sar2_patt_tab2.sar2_patt_tab2 = tab; break;
case 2: ADC.sar2_patt_tab3.sar2_patt_tab3 = tab; break;
default: ADC.sar2_patt_tab4.sar2_patt_tab4 = tab; break;
}
}
}
/**
* Reset the pattern table pointer, then take the measurement rule from table header in next measurement.
*
* @param adc_n ADC unit.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_clear_pattern_table(adc_unit_t adc_n)
{
if (adc_n == ADC_UNIT_1) {
ADC.ctrl0.sar1_patt_p_clear = 1;
ADC.ctrl0.sar1_patt_p_clear = 0;
} else {
ADC.ctrl1.sar2_patt_p_clear = 1;
ADC.ctrl1.sar2_patt_p_clear = 0;
}
}
/**
* Set the interval clock cycle for the digital controller to trigger the measurement.
*
* @note The trigger interval should not be smaller than the sampling time of the SAR ADC.
* @param cycle The clock cycle of the measurement trigger interval.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_set_trigger_interval(uint32_t cycle)
{
HAL_ASSERT(cycle <= 4095);
ADC.ctrl2.timer_target = cycle & 0xFFFU;
}
/**
* Enable digital controller timer to trigger the measurement.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_trigger_enable(void)
{
ADC.ctrl2.timer_en = 1;
}
/**
* Disable digital controller timer to trigger the measurement.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_trigger_disable(void)
{
ADC.ctrl2.timer_en = 0;
}
/**
* Set DMA EOF number of ADC digital controller.
* If the number of measurements reaches this value, then DMA EOF signal is generated.
*
* @param num EOF number of DMA.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_dma_set_eof_num(uint32_t num)
{
ADC.dma_conf.apb_adc_eof_num = num & 0xFFFFU;
}
/**
* Enable output data to DMA from ADC digital controller.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_dma_enable(void)
{
ADC.dma_conf.apb_adc_trans = 1;
}
/**
* Disable output data to DMA from ADC digital controller.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_dma_disable(void)
{
ADC.dma_conf.apb_adc_trans = 0;
}
/**
* Reset ADC digital controller.
*/
__attribute__((always_inline))
static inline void adc_ll_digi_reset(void)
{
ADC.dma_conf.dma_eof_num_clr = 1;
ADC.dma_conf.dma_eof_num_clr = 0;
}
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* @brief Enable the ADC bus clock
*/
__attribute__((always_inline))
static inline void _adc_ll_enable_bus_clock(bool enable)
{
LP_PERI_CLKRST.adc_ctrl.lp_adc_clk_en = enable;
}
#define adc_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_adc_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Enable the ADC function clock (for chips with independent RCC)
*/
__attribute__((always_inline))
static inline void _adc_ll_enable_func_clock(bool enable)
{
ADC.ctrl_date.clk_en = enable;
}
#define adc_ll_enable_func_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_adc_ll_enable_func_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset ADC module
*/
__attribute__((always_inline))
static inline void _adc_ll_reset_register(void)
{
LP_PERI_CLKRST.adc_ctrl.lp_adc_rst_en = 1;
LP_PERI_CLKRST.adc_ctrl.lp_adc_rst_en = 0;
}
#define adc_ll_reset_register(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_adc_ll_reset_register(__VA_ARGS__); \
} while(0)
/**
* @brief Enable ADC reference generator.
*/
__attribute__((always_inline))
static inline void adc_ll_enable_refgen(void)
{
ADC.ref_control.rtc_xpd_refgen = 1;
ADC.ref_control.rtc_pre_charge = 1;
ADC.ref_control.rtc_ref_delay = 1;
}
/**
* @brief Set ADC power management.
* S31 uses ADC_XPD_SAR1_FORCE / ADC_XPD_SAR2_FORCE directly.
* 0x=auto(FSM), 10=force off, 11=force on
*/
__attribute__((always_inline))
static inline void adc_ll_set_power_manage(adc_unit_t adc_n, adc_ll_power_t manage)
{
if (manage != ADC_LL_POWER_SW_OFF) {
adc_ll_enable_refgen();
}
if (adc_n == ADC_UNIT_1) {
ADC.ctrl0.xpd_sar1_force = manage;
} else {
ADC.ctrl1.xpd_sar2_force = manage;
}
}
/**
* @brief Set ADC module controller.
* S31 has a unified controller, this is a no-op.
*/
__attribute__((always_inline))
static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t ctrl)
{
(void)adc_n;
(void)ctrl;
}
/*---------------------------------------------------------------
Oneshot Read
---------------------------------------------------------------*/
/**
* @brief Validate the requested output width.
*/
static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth_t bits)
{
(void)adc_n;
HAL_ASSERT(bits == SOC_ADC_RTC_MAX_BITWIDTH || bits == ADC_BITWIDTH_DEFAULT);
}
/**
* Program the first pattern entry for oneshot conversion.
*
* @param adc_n ADC unit.
* @param channel ADC channel number for each ADCn.
*/
static inline void adc_oneshot_ll_program_pattern(adc_unit_t adc_n, uint32_t channel)
{
const uint32_t patt_val = ((channel & 0xFU) << 2);
if (adc_n == ADC_UNIT_1) {
ADC.ctrl0.sar1_patt_type = 1;
ADC.ctrl0.sar1_patt_len = 0;
ADC.sar1_patt_tab1.sar1_patt_tab1 = (patt_val << 18);
ADC.ctrl0.sar1_patt_p_clear = 1;
ADC.ctrl0.sar1_patt_p_clear = 0;
ADC.ctrl0.sar1_trigger_mode = ADC_LL_TRIGGER_MODE_SW;
} else {
ADC.ctrl1.sar2_patt_type = 1;
ADC.ctrl1.sar2_patt_len = 0;
ADC.sar2_patt_tab1.sar2_patt_tab1 = (patt_val << 18);
ADC.ctrl1.sar2_patt_p_clear = 1;
ADC.ctrl1.sar2_patt_p_clear = 0;
ADC.ctrl1.sar2_trigger_mode = ADC_LL_TRIGGER_MODE_SW;
}
}
/**
* Enable ADC channel to start convert.
*
* @note Only one channel can be selected for measurement.
*
* @param adc_n ADC unit.
* @param channel ADC channel number for each ADCn.
*/
static inline void adc_oneshot_ll_set_channel(adc_unit_t adc_n, adc_channel_t channel)
{
adc_oneshot_ll_program_pattern(adc_n, (uint32_t)channel);
}
/**
* @brief Disable adc channel to start convert.
* Return the selected SAR trigger source to OFF.
*/
static inline void adc_oneshot_ll_disable_channel(adc_unit_t adc_n)
{
if (adc_n == ADC_UNIT_1) {
ADC.ctrl0.sar1_trigger_mode = ADC_LL_TRIGGER_MODE_OFF;
} else {
ADC.ctrl1.sar2_trigger_mode = ADC_LL_TRIGGER_MODE_OFF;
}
}
/**
* @brief Start one conversion by software trigger.
*/
static inline void adc_oneshot_ll_start(adc_unit_t adc_n)
{
if (adc_n == ADC_UNIT_1) {
ADC.ctrl0.sar1_trigger_start = 1;
} else {
ADC.ctrl1.sar2_trigger_start = 1;
}
}
/**
* @brief Clear the event for each ADCn for Oneshot mode
*/
static inline void adc_oneshot_ll_clear_event(uint32_t event_mask)
{
ADC.int_clr.val = event_mask;
}
/**
* @brief Check the event for each ADCn for Oneshot mode
*
* @return
* -true : The conversion process is finished.
* -false : The conversion process is not finished.
*/
static inline bool adc_oneshot_ll_get_event(uint32_t event)
{
if (event == ADC_LL_EVENT_ADC1_ONESHOT_DONE) {
return (bool)ADC.int_raw.sar1_done_int_raw;
} else if (event == ADC_LL_EVENT_ADC2_ONESHOT_DONE) {
return (bool)ADC.int_raw.sar2_done_int_raw;
}
HAL_ASSERT(false);
return false;
}
/**
* @brief Get the converted value for each ADCn.
* S31 output: 22-bit [21:17]=channel, [16:0]=17-bit data.
* Returns the 17-bit data portion.
*/
static inline uint32_t adc_oneshot_ll_get_raw_result(adc_unit_t adc_n)
{
if (adc_n == ADC_UNIT_1) {
return HAL_FORCE_READ_U32_REG_FIELD(ADC.sar1_data_status, apb_saradc1_data) & 0x1FFFF;
} else {
return HAL_FORCE_READ_U32_REG_FIELD(ADC.sar2_data_status, apb_saradc2_data) & 0x1FFFF;
}
}
/**
* @brief Check whether the raw result is valid.
*/
static inline bool adc_oneshot_ll_raw_check_valid(adc_unit_t adc_n, uint32_t raw)
{
(void)adc_n;
(void)raw;
return true;
}
/**
* @brief Configure oneshot output inversion.
*/
static inline void adc_oneshot_ll_output_invert(adc_unit_t adc_n, bool inv_en)
{
(void)adc_n;
(void)inv_en;
}
/**
* @brief Prepare the hardware for oneshot conversion.
*/
static inline void adc_oneshot_ll_enable(adc_unit_t adc_n)
{
ADC.ctrl2.timer_en = 0;
adc_ll_enable_refgen();
if (adc_n == ADC_UNIT_1) {
ADC.ctrl0.sar1_continue_mode_en = 0;
ADC.ctrl0.sar1_trigger_stop = 1;
} else {
ADC.ctrl1.sar2_continue_mode_en = 0;
ADC.ctrl1.sar2_trigger_stop = 1;
}
}
/**
* @brief Disable oneshot conversion trigger for all the ADC units
* Both SAR trigger sources are returned to OFF state.
*/
static inline void adc_oneshot_ll_disable_all_unit(void)
{
ADC.ctrl0.sar1_trigger_mode = ADC_LL_TRIGGER_MODE_OFF;
ADC.ctrl1.sar2_trigger_mode = ADC_LL_TRIGGER_MODE_OFF;
}
/**
* @brief Set attenuation for the first oneshot pattern entry.
*/
static inline void adc_oneshot_ll_set_atten(adc_unit_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
(void)adc_n;
(void)channel;
(void)atten;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -241,6 +241,35 @@ typedef struct {
uint32_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#elif SOC_IS(ESP32S31)
/**
* @brief ADC digital controller (DMA mode) output data format.
* Used to analyze the acquired ADC (DMA) data.
* @note ESP32-S31: 22-bit result: [16:0]=17-bit unsigned data, [20:17]=channel, bit 21=`unit` (0=SAR1, 1=SAR2).
*/
typedef struct {
union {
struct {
uint32_t data: 17; /*!<ADC conversion data. 17-bit field stores the weighted sum of
17 SAR comparator bits (non-uniform weights), max value 4393.
+-----+--------+-----+--------+-----+--------+
| bit | weight | bit | weight | bit | weight |
+-----+--------+-----+--------+-----+--------+
| 16 | 2^11 | 10 | 2^6 | 4 | 2^2 |
| 15 | 2^10 | 9 | 2^5 | 3 | 2 |
| 14 | 2^9 | 8 | 2^5 | 2 | 2 |
| 13 | 2^8 | 7 | 2^4 | 1 | 0 |
| 12 | 2^8 | 6 | 2^3 | 0 | 1 |
| 11 | 2^7 | 5 | 2^3 | | |
+-----+--------+-----+--------+-----+--------+ */
uint32_t channel: 4; /*!<Channel index within the SAR (maps to HW channel field bit[3:0]). */
uint32_t unit: 1; /*!<ADC unit: 0=SAR1 (ADC1), 1=SAR2 (ADC2). HW channel field bit[4]. */
uint32_t reserved22_31: 10; /*!<Reserved. */
} type2; /*!<When the configured output format is 17bit.*/
uint32_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#endif
#ifdef __cplusplus

View File

@@ -10,6 +10,10 @@ set(srcs
"pmu_sleep.c"
)
if(NOT BOOTLOADER_BUILD)
list(APPEND srcs "sar_periph_ctrl.c")
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
target_sources(${COMPONENT_LIB} PRIVATE "${srcs}")

View File

@@ -0,0 +1,128 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Shared SAR power/reset control for ADC and PWDET. */
#include "sdkconfig.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "esp_private/sar_periph_ctrl.h"
#include "esp_private/regi2c_ctrl.h"
#include "esp_private/critical_section.h"
#include "esp_private/adc_share_hw_ctrl.h"
#include "hal/sar_ctrl_ll.h"
#include "hal/adc_ll.h"
ESP_LOG_ATTR_TAG(TAG, "sar_periph_ctrl");
extern portMUX_TYPE rtc_spinlock;
void sar_periph_ctrl_init(void)
{
sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_FSM);
}
void sar_periph_ctrl_power_enable(void)
{
esp_os_enter_critical_safe(&rtc_spinlock);
sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_FSM);
esp_os_exit_critical_safe(&rtc_spinlock);
}
void sar_periph_ctrl_power_disable(void)
{
esp_os_enter_critical_safe(&rtc_spinlock);
sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_OFF);
esp_os_exit_critical_safe(&rtc_spinlock);
}
/**
* This gets incremented when s_sar_power_acquire() is called,
* and decremented when s_sar_power_release() is called.
* PWDET and REG_I2C are powered down when the value reaches zero.
* Should be modified within critical section.
*/
static int s_sar_power_on_cnt;
static void s_sar_power_acquire(void)
{
esp_os_enter_critical_safe(&rtc_spinlock);
regi2c_saradc_enable();
s_sar_power_on_cnt++;
if (s_sar_power_on_cnt == 1) {
sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_ON);
}
esp_os_exit_critical_safe(&rtc_spinlock);
}
static void s_sar_power_release(void)
{
esp_os_enter_critical_safe(&rtc_spinlock);
s_sar_power_on_cnt--;
if (s_sar_power_on_cnt < 0) {
esp_os_exit_critical_safe(&rtc_spinlock);
ESP_LOGE(TAG, "%s called, but s_sar_power_on_cnt == 0", __func__);
abort();
} else if (s_sar_power_on_cnt == 0) {
sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_FSM);
}
regi2c_saradc_disable();
esp_os_exit_critical_safe(&rtc_spinlock);
}
/*------------------------------------------------------------------------------
* PWDET power
*----------------------------------------------------------------------------*/
void sar_periph_ctrl_pwdet_power_acquire(void)
{
s_sar_power_acquire();
}
void sar_periph_ctrl_pwdet_power_release(void)
{
s_sar_power_release();
}
/*------------------------------------------------------------------------------
* ADC power
*----------------------------------------------------------------------------*/
void sar_periph_ctrl_adc_oneshot_power_acquire(void)
{
s_sar_power_acquire();
}
void sar_periph_ctrl_adc_oneshot_power_release(void)
{
s_sar_power_release();
}
void sar_periph_ctrl_adc_continuous_power_acquire(void)
{
s_sar_power_acquire();
}
void sar_periph_ctrl_adc_continuous_power_release(void)
{
s_sar_power_release();
}
/*------------------------------------------------------------------------------
* ADC reset
*----------------------------------------------------------------------------*/
void sar_periph_ctrl_adc_reset(void)
{
PERIPH_RCC_ATOMIC() {
adc_ll_reset_register();
}
}
void adc_reset_lock_acquire(void)
{
}
void adc_reset_lock_release(void)
{
}

View File

@@ -0,0 +1,82 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* SAR related peripherals are interdependent.
* Related peripherals are:
* - ADC
* - PWDET
*
* All of above peripherals require SAR to work correctly.
* As SAR has some registers that will influence above mentioned peripherals.
* This file gives an abstraction for such registers
*/
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/adc_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
SAR_CTRL_LL_POWER_FSM, //SAR power controlled by FSM
SAR_CTRL_LL_POWER_ON, //SAR power on
SAR_CTRL_LL_POWER_OFF, //SAR power off
} sar_ctrl_ll_power_t;
/*---------------------------------------------------------------
SAR power control
---------------------------------------------------------------*/
/**
* Set SAR power mode
*
* S31 uses xpd_sar1_force / xpd_sar2_force in ADC ctrl registers:
* 0 = FSM (auto), 2 = force power down, 3 = force power up
*
* @param mode See `sar_ctrl_ll_power_t`
*/
__attribute__((always_inline))
static inline void sar_ctrl_ll_set_power_mode(sar_ctrl_ll_power_t mode)
{
uint32_t force_val;
if (mode == SAR_CTRL_LL_POWER_FSM) {
force_val = 0;
} else if (mode == SAR_CTRL_LL_POWER_ON) {
force_val = 3;
} else {
force_val = 2;
}
ADC.ctrl0.xpd_sar1_force = force_val;
ADC.ctrl1.xpd_sar2_force = force_val;
}
/**
* @brief Set SAR power mode when controlled by PWDET
* S31 does not have separate PWDET power control, use unified SAR power mode.
*/
static inline void sar_ctrl_ll_set_power_mode_from_pwdet(sar_ctrl_ll_power_t mode)
{
sar_ctrl_ll_set_power_mode(mode);
}
/**
* @brief Set SAR power ctrl source
* S31 does not have PWDET-based SAR power mux, no-op.
*/
static inline void sar_ctrl_ll_force_power_ctrl_from_pwdet(bool force)
{
(void)force;
}
#ifdef __cplusplus
}
#endif

View File

@@ -3,6 +3,10 @@
# using gen_soc_caps_kconfig.py, do not edit manually
#####################################################
config SOC_ADC_SUPPORTED
bool
default y
config SOC_ANA_CMPR_SUPPORTED
bool
default y
@@ -331,14 +335,78 @@ config SOC_XTAL_CLOCK_PATH_DEPENDS_ON_TOP_DOMAIN
bool
default y
config SOC_ADC_MAX_CHANNEL_NUM
int
default 10
config SOC_ADC_DIG_CTRL_SUPPORTED
bool
default y
config SOC_ADC_PERIPH_NUM
int
default 2
config SOC_ADC_MAX_CHANNEL_NUM
int
default 8
config SOC_ADC_ATTEN_NUM
int
default 1
config SOC_ADC_RTC_MIN_BITWIDTH
int
default 17
config SOC_ADC_RTC_MAX_BITWIDTH
int
default 17
config SOC_ADC_DMA_SUPPORTED
bool
default y
config SOC_ADC_DIGI_CONTROLLER_NUM
int
default 2
config SOC_ADC_PATT_LEN_MAX
int
default 16
config SOC_ADC_DIGI_MIN_BITWIDTH
int
default 17
config SOC_ADC_DIGI_MAX_BITWIDTH
int
default 17
config SOC_ADC_DIGI_RESULT_BYTES
int
default 4
config SOC_ADC_DIGI_DATA_BYTES_PER_CONV
int
default 4
config SOC_ADC_SAMPLE_FREQ_THRES_HIGH
int
default 83333
config SOC_ADC_SAMPLE_FREQ_THRES_LOW
int
default 611
config SOC_ADC_DIGI_MONITOR_NUM
int
default 2
config SOC_ADC_DIFF_SUPPORTED
bool
default y
config SOC_ADC_SHARED_POWER
bool
default y
config SOC_CACHE_WRITEBACK_SUPPORTED
bool
default y

View File

@@ -3,4 +3,41 @@
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#pragma once
/* Public ADC channels map directly to each analog pad (single-ended). */
#define ADC1_GPIO42_CHANNEL 0
#define ADC1_CHANNEL_0_GPIO_NUM 42
#define ADC1_GPIO43_CHANNEL 1
#define ADC1_CHANNEL_1_GPIO_NUM 43
#define ADC1_GPIO44_CHANNEL 2
#define ADC1_CHANNEL_2_GPIO_NUM 44
#define ADC1_GPIO45_CHANNEL 3
#define ADC1_CHANNEL_3_GPIO_NUM 45
#define ADC1_GPIO46_CHANNEL 4
#define ADC1_CHANNEL_4_GPIO_NUM 46
#define ADC1_GPIO47_CHANNEL 5
#define ADC1_CHANNEL_5_GPIO_NUM 47
#define ADC1_GPIO48_CHANNEL 6
#define ADC1_CHANNEL_6_GPIO_NUM 48
#define ADC1_GPIO49_CHANNEL 7
#define ADC1_CHANNEL_7_GPIO_NUM 49
#define ADC2_GPIO50_CHANNEL 0
#define ADC2_CHANNEL_0_GPIO_NUM 50
#define ADC2_GPIO51_CHANNEL 1
#define ADC2_CHANNEL_1_GPIO_NUM 51
#define ADC2_GPIO52_CHANNEL 2
#define ADC2_CHANNEL_2_GPIO_NUM 52
#define ADC2_GPIO53_CHANNEL 3
#define ADC2_CHANNEL_3_GPIO_NUM 53
#define ADC2_GPIO54_CHANNEL 4
#define ADC2_CHANNEL_4_GPIO_NUM 54
#define ADC2_GPIO55_CHANNEL 5
#define ADC2_CHANNEL_5_GPIO_NUM 55
#define ADC2_GPIO56_CHANNEL 6
#define ADC2_CHANNEL_6_GPIO_NUM 56
#define ADC2_GPIO57_CHANNEL 7
#define ADC2_CHANNEL_7_GPIO_NUM 57

View File

@@ -680,6 +680,19 @@ typedef enum {
PCNT_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */
} soc_periph_pcnt_clk_src_t;
//////////////////////////////////////////////////ADC///////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of ADC
*/
#define SOC_ADC_DIGI_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST}
typedef enum {
ADC_DIGI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select FOSC (internal RC oscillator) as ADC source clock */
ADC_DIGI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as ADC source clock */
ADC_DIGI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */
} soc_periph_adc_digi_clk_src_t;
#ifdef __cplusplus
}
#endif

View File

@@ -23,7 +23,7 @@
#define _SOC_CAPS_TARGET_IS_ESP32S31 1 // [gen_soc_caps:ignore]
/*-------------------------- COMMON CAPS ---------------------------------------*/
// #define SOC_ADC_SUPPORTED 1 // TODO: [ESP32S31] IDF-14741
#define SOC_ADC_SUPPORTED 1
#define SOC_ANA_CMPR_SUPPORTED 1
#define SOC_DEDICATED_GPIO_SUPPORTED 1
#define SOC_UART_SUPPORTED 1
@@ -128,8 +128,30 @@
/*-------------------------- ADC CAPS ----------------------------------------*/
/*!< SAR ADC Module*/
#define SOC_ADC_MAX_CHANNEL_NUM (10)
#define SOC_ADC_DIG_CTRL_SUPPORTED 1
#define SOC_ADC_PERIPH_NUM (2)
#define SOC_ADC_MAX_CHANNEL_NUM (8)
#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (8)
#define SOC_ADC_ATTEN_NUM (1U)
#define SOC_ADC_RTC_MIN_BITWIDTH (17)
#define SOC_ADC_RTC_MAX_BITWIDTH (17)
#define SOC_ADC_DMA_SUPPORTED 1
#define SOC_ADC_DIGI_CONTROLLER_NUM (2)
#define SOC_ADC_PATT_LEN_MAX (16)
#define SOC_ADC_DIGI_MIN_BITWIDTH (17)
#define SOC_ADC_DIGI_MAX_BITWIDTH (17)
#define SOC_ADC_DIGI_RESULT_BYTES (4)
#define SOC_ADC_DIGI_DATA_BYTES_PER_CONV (4)
#define SOC_ADC_DIG_SUPPORTED_UNIT(UNIT) (1)
#define SOC_ADC_SAMPLE_FREQ_THRES_HIGH (83333U)
#define SOC_ADC_SAMPLE_FREQ_THRES_LOW (611U)
#define SOC_ADC_DIGI_MONITOR_NUM (2)
#define SOC_ADC_DIFF_SUPPORTED (1)
/*!< ADC power control is shared by PWDET, TempSensor */
#define SOC_ADC_SHARED_POWER 1
/*-------------------------- CACHE CAPS --------------------------------------*/
#define SOC_CACHE_WRITEBACK_SUPPORTED 1

View File

@@ -711,6 +711,7 @@ typedef struct {
volatile adc_ctrl_date_reg_t ctrl_date;
} adc_dev_t;
extern adc_dev_t ADC;
#ifndef __cplusplus
_Static_assert(sizeof(adc_dev_t) == 0x400, "Invalid size of adc_dev_t structure");

View File

@@ -352,7 +352,7 @@ The parsed data structure :cpp:type:`adc_continuous_data_t` contains the followi
- :cpp:member:`adc_continuous_data_t::unit`ADC unit (ADC_UNIT_1 or ADC_UNIT_2)
- :cpp:member:`adc_continuous_data_t::channel`ADC channel number (0-9)
- :cpp:member:`adc_continuous_data_t::raw_data`ADC raw data value (0-4095, 12-bit resolution)
- :cpp:member:`adc_continuous_data_t::raw_data`ADC raw data value
- :cpp:member:`adc_continuous_data_t::valid`Whether the data is valid
Read and Parse ADC Data
@@ -389,6 +389,7 @@ Hardware Limitations
- A specific ADC unit can only work under one operating mode at any one time, either continuous mode or one-shot mode. :cpp:func:`adc_continuous_start` has provided the protection.
:not esp32s31: - Random Number Generator (RNG) uses ADC as an input source. When ADC continuous mode driver works, the random number generated from RNG will be less random.
:SOC_ADC_DIFF_SUPPORTED: - In single-ended mode, if the N-side channel is used as the input interface, its raw-data polarity is inverted. For an input range of -2 V to 2 V, the N-side raw code is 4393 to 0. Please use the ADC calibration APIs.
:esp32 or esp32s2: - ADC2 is also used by Wi-Fi. :cpp:func:`adc_continuous_start` has provided the protection between Wi-Fi driver and ADC continuous mode driver.
:esp32: - ADC continuous mode driver uses I2S0 peripheral as hardware DMA FIFO. Therefore, if I2S0 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`.
:esp32: - ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits.

View File

@@ -137,7 +137,7 @@ where:
* - Dmax
- Maximum of the output ADC raw digital reading result, which is 2^bitwidth, where bitwidth is the :cpp:member:`adc_oneshot_chan_cfg_t::bitwidth` configured before.
To do further calibration to convert the ADC raw result to voltage in mV, please refer to calibration doc :doc:`adc_calibration`.
For further calibration to convert the ADC raw result to voltage in mV, please refer to :doc:`adc_calibration`.
Read Raw Result
@@ -161,6 +161,7 @@ Hardware Limitations
:not esp32s31: - Random Number Generator (RNG) uses ADC as an input source. When ADC :cpp:func:`adc_oneshot_read` works, the random number generated from RNG will be less random.
:SOC_ADC_DMA_SUPPORTED: - A specific ADC unit can only work under one operating mode at any one time, either continuous mode or oneshot mode. :cpp:func:`adc_oneshot_read` has provided the protection.
:SOC_ADC_DIFF_SUPPORTED: - In single-ended mode, if the N-side channel is used as the input interface, its raw-data polarity is inverted. For an input range of -2 to 2, the N-side raw code is 4393 to 0. Please use the ADC calibration APIs.
:esp32 or esp32s2 or esp32s3: - ADC2 is also used by Wi-Fi. :cpp:func:`adc_oneshot_read` has provided protection between the Wi-Fi driver and ADC oneshot mode driver.
:esp32c3: - ADC2 oneshot mode is no longer supported, due to hardware limitations. The results are not stable. This issue can be found in `ESP32-C3 Series SoC Errata <https://www.espressif.com/sites/default/files/documentation/esp32-c3_errata_en.pdf>`_. For compatibility, you can enable :ref:`CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3` to force use ADC2.
:esp32: - ESP32-DevKitC: GPIO0 cannot be used in oneshot mode, because the DevKit has used it for auto-flash.

View File

@@ -352,7 +352,7 @@ ADC 连续转换模式读取的原始数据需要进一步解析才能获得可
- :cpp:member:`adc_continuous_data_t::unit`ADC 单元ADC_UNIT_1 或 ADC_UNIT_2
- :cpp:member:`adc_continuous_data_t::channel`ADC 通道号0-9
- :cpp:member:`adc_continuous_data_t::raw_data`ADC 原始数据值0-409512位分辨率
- :cpp:member:`adc_continuous_data_t::raw_data`ADC 原始数据值
- :cpp:member:`adc_continuous_data_t::valid`:数据是否有效
读取并解析 ADC 数据
@@ -389,6 +389,7 @@ ADC 连续转换模式读取的原始数据需要进一步解析才能获得可
- 一个 ADC 单元一次只能运行一种操作模式,即连续模式或单次模式。:cpp:func:`adc_continuous_start` 提供了保护措施。
:not esp32s31: - 随机数生成器 (RNG) 以 ADC 为输入源。使用 ADC 连续转换模式驱动从 RNG 生成随机数时,随机性会减弱。
:SOC_ADC_DIFF_SUPPORTED: - 在单端模式下,如果使用 N 端通道作为输入接口,其原始数据极性是反向的。输入电压范围为 -2 V ~ 2 V 时N 端 raw 值为 4393~0。请使用 ADC 校准 API。
:esp32 or esp32s2: - Wi-Fi 也使用 ADC2:cpp:func:`adc_continuous_start` 提供了 Wi-Fi 驱动和 ADC 连续转换模式驱动之间的保护。
:esp32: - ADC 连续转换模式驱动使用 I2S0 外设作为硬件 DMA FIFO。因此如果 I2S0 已在使用中,:cpp:func:`adc_continuous_new_handle` 将返回 :c:macro:`ESP_ERR_NOT_FOUND`。
:esp32: - ESP32 DevKitC由于存在外部自动烧录电路GPIO 0 不能用于 ADC 连续转换模式。

View File

@@ -161,6 +161,7 @@ ADC 单次转换模式驱动基于 {IDF_TARGET_NAME} SAR ADC 模块实现,不
:not esp32s31: - 随机数生成器 (RNG) 以 ADC 为输入源。使用 ADC 单次转换模式驱动从 RNG 生成随机数时,随机性会减弱。
:SOC_ADC_DMA_SUPPORTED: - 一个 ADC 单元每次只能在一种操作模式下运行,可以是连续模式或单次模式。:cpp:func:`adc_oneshot_start` 提供了保护措施。
:SOC_ADC_DIFF_SUPPORTED: - 在单端模式下,如果使用 N 端通道作为输入接口,其原始数据极性是反向的。输入电压范围为 -2 V ~ 2 V 时N 端 raw 值为 4393~0。请使用 ADC 校准 API。
:esp32 or esp32s2 or esp32s3: - Wi-Fi 也使用 ADC2:cpp:func:`adc_oneshot_read` 提供了 Wi-Fi 驱动与 ADC 单次转换模式驱动间的保护。
:esp32c3: - 由于硬件限制,现已不再支持使用 ADC2 DMA 功能获取 ADC 转换结果。使用 ADC2 单次转换的结果可能不稳定,具体可参考 `ESP32-C3 系列芯片勘误表 <https://www.espressif.com/sites/default/files/documentation/esp32-c3_errata_cn.pdf>`__。出于兼容性考虑可以启用 :ref:`CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3`,强制使用 ADC2。
:esp32: - ESP32-DevKitCGPIO0 已用于自动烧录功能,不能用于 ADC 单次转换模式。

View File

@@ -16,7 +16,7 @@ examples/peripherals/adc/continuous_read:
disable_test:
- if: IDF_TARGET in ["esp32h4"]
temporary: true
reason: no runners for esp32h4 ADC test
reason: no runners
<<: *adc_dependencies
examples/peripherals/adc/oneshot_read:
@@ -25,7 +25,7 @@ examples/peripherals/adc/oneshot_read:
disable_test:
- if: IDF_TARGET in ["esp32h4"]
temporary: true
reason: no runners for esp32h4 ADC test
reason: no runners
<<: *adc_dependencies
examples/peripherals/analog_comparator/auto_scan:

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | -------- | --------- |
# ADC DMA Example

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -7,6 +7,7 @@
#include <string.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -15,7 +16,11 @@
#define EXAMPLE_ADC_UNIT ADC_UNIT_1
#define EXAMPLE_ADC_CONV_MODE ADC_CONV_SINGLE_UNIT_1
#if SOC_ADC_ATTEN_NUM <= 1
#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_0
#else
#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_12
#endif
#define EXAMPLE_ADC_BIT_WIDTH SOC_ADC_DIGI_MAX_BITWIDTH
#define EXAMPLE_READ_LEN 256

View File

@@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.adc
@idf_parametrize(
'target',
['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32c5', 'esp32p4', 'esp32c61'],
['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32c5', 'esp32p4', 'esp32c61', 'esp32s31'],
indirect=['target'],
)
def test_adc_continuous(dut: Dut) -> None:

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | -------- | --------- |
# ADC Single Read Example

View File

@@ -41,7 +41,11 @@ const static char *TAG = "EXAMPLE";
#define EXAMPLE_ADC2_CHAN0 ADC_CHANNEL_0
#endif //#if EXAMPLE_USE_ADC2
#if SOC_ADC_ATTEN_NUM <= 1
#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_0
#else
#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_12
#endif
static int adc_raw[2][10];
static int voltage[2][10];

View File

@@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.adc
@idf_parametrize(
'target',
['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32c5', 'esp32p4', 'esp32c61'],
['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32c5', 'esp32p4', 'esp32c61', 'esp32s31'],
indirect=['target'],
)
def test_adc_oneshot(dut: Dut) -> None: