From 3afa671069ecafe7329f1442faeb4d28b33c034d Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 7 Feb 2023 16:01:26 +0800 Subject: [PATCH 1/2] esp_adc: added adc digital filter feature --- components/esp_adc/CMakeLists.txt | 4 + components/esp_adc/adc_continuous.c | 35 +- components/esp_adc/adc_continuous_internal.h | 87 +++++ components/esp_adc/adc_filter.c | 158 +++++++++ .../esp_adc/include/esp_adc/adc_continuous.h | 5 +- .../esp_adc/include/esp_adc/adc_filter.h | 88 +++++ .../test_apps/adc/main/test_adc_driver_iram.c | 4 +- .../test_apps/adc/main/test_adc_performance.c | 329 ++++++++++++++---- .../test_apps/adc/main/test_common_adc.c | 32 +- .../test_apps/adc/main/test_common_adc.h | 18 + components/hal/esp32c2/include/hal/adc_ll.h | 77 ++-- components/hal/esp32c3/include/hal/adc_ll.h | 93 ++--- components/hal/esp32c6/include/hal/adc_ll.h | 93 ++--- components/hal/esp32h4/include/hal/adc_ll.h | 94 ++--- components/hal/esp32s2/include/hal/adc_ll.h | 59 ++-- components/hal/esp32s3/include/hal/adc_ll.h | 91 +++-- components/hal/include/hal/adc_types.h | 19 + .../hal/include/hal/adc_types_private.h | 49 --- .../include/esp32/idf_performance_target.h | 3 + .../include/esp32c2/idf_performance_target.h | 2 + .../include/esp32c3/idf_performance_target.h | 8 + .../include/esp32c6/idf_performance_target.h | 7 + .../include/esp32s2/idf_performance_target.h | 8 + .../include/esp32s3/idf_performance_target.h | 8 + .../esp32c2/include/soc/Kconfig.soc_caps.in | 4 +- components/soc/esp32c2/include/soc/soc_caps.h | 4 +- .../esp32c3/include/soc/Kconfig.soc_caps.in | 4 +- components/soc/esp32c3/include/soc/soc_caps.h | 4 +- .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 +- components/soc/esp32c6/include/soc/soc_caps.h | 4 +- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 +- components/soc/esp32h2/include/soc/soc_caps.h | 4 +- .../esp32h4/include/soc/Kconfig.soc_caps.in | 4 +- components/soc/esp32h4/include/soc/soc_caps.h | 4 +- .../esp32s2/include/soc/Kconfig.soc_caps.in | 10 +- components/soc/esp32s2/include/soc/soc_caps.h | 4 +- .../esp32s3/include/soc/Kconfig.soc_caps.in | 6 +- components/soc/esp32s3/include/soc/soc_caps.h | 3 +- 38 files changed, 1032 insertions(+), 402 deletions(-) create mode 100644 components/esp_adc/adc_continuous_internal.h create mode 100644 components/esp_adc/adc_filter.c create mode 100644 components/esp_adc/include/esp_adc/adc_filter.h diff --git a/components/esp_adc/CMakeLists.txt b/components/esp_adc/CMakeLists.txt index fc17397748..2f53681010 100644 --- a/components/esp_adc/CMakeLists.txt +++ b/components/esp_adc/CMakeLists.txt @@ -17,6 +17,10 @@ if(CONFIG_SOC_ADC_DMA_SUPPORTED) list(APPEND srcs "adc_continuous.c") endif() +if(CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED) + list(APPEND srcs "adc_filter.c") +endif() + # line fitting scheme if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/adc_cali_line_fitting.c") list(APPEND srcs "${target}/adc_cali_line_fitting.c") diff --git a/components/esp_adc/adc_continuous.c b/components/esp_adc/adc_continuous.c index 7f21de5d68..b4bc9ab319 100644 --- a/components/esp_adc/adc_continuous.c +++ b/components/esp_adc/adc_continuous.c @@ -28,6 +28,7 @@ #include "hal/adc_hal.h" #include "hal/dma_types.h" #include "esp_memory_utils.h" +#include "adc_continuous_internal.h" //For DMA #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" @@ -51,40 +52,6 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi #define INTERNAL_BUF_NUM 5 -typedef enum { - ADC_FSM_INIT, - ADC_FSM_STARTED, -} adc_fsm_t; - -/*--------------------------------------------------------------- - Continuous Mode Driverr Context ----------------------------------------------------------------*/ -typedef struct adc_continuous_ctx_t { - uint8_t *rx_dma_buf; //dma buffer - adc_hal_dma_ctx_t hal; //hal context -#if SOC_GDMA_SUPPORTED - gdma_channel_handle_t rx_dma_channel; //dma rx channel handle -#elif CONFIG_IDF_TARGET_ESP32S2 - spi_host_device_t spi_host; //ADC uses this SPI DMA -#elif CONFIG_IDF_TARGET_ESP32 - i2s_port_t i2s_host; //ADC uses this I2S DMA -#endif - intr_handle_t dma_intr_hdl; //DMA Interrupt handler - RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler - void* ringbuf_storage; //Ringbuffer storage buffer - void* ringbuf_struct; //Ringbuffer structure buffer - intptr_t rx_eof_desc_addr; //eof descriptor address of RX channel - adc_fsm_t fsm; //ADC continuous mode driver internal states - bool use_adc1; //1: ADC unit1 will be used; 0: ADC unit1 won't be used. - bool use_adc2; //1: ADC unit2 will be used; 0: ADC unit2 won't be used. This determines whether to acquire sar_adc2_mutex lock or not. - adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation. - adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation. - adc_hal_digi_ctrlr_cfg_t hal_digi_ctrlr_cfg; //Hal digital controller configuration - adc_continuous_evt_cbs_t cbs; //Callbacks - void *user_data; //User context - esp_pm_lock_handle_t pm_lock; //For power management -} adc_continuous_ctx_t; - #ifdef CONFIG_PM_ENABLE //Only for deprecated API extern esp_pm_lock_handle_t adc_digi_arbiter_lock; diff --git a/components/esp_adc/adc_continuous_internal.h b/components/esp_adc/adc_continuous_internal.h new file mode 100644 index 0000000000..e352c300e7 --- /dev/null +++ b/components/esp_adc/adc_continuous_internal.h @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "esp_pm.h" +#include "freertos/FreeRTOS.h" +#include "freertos/ringbuf.h" +#include "hal/adc_types.h" +#include "hal/adc_hal.h" +//For DMA +#if SOC_GDMA_SUPPORTED +#include "esp_private/gdma.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "hal/spi_types.h" +#elif CONFIG_IDF_TARGET_ESP32 +#include "driver/i2s_types.h" +#endif + +#include "esp_adc/adc_filter.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ADC_FSM_INIT, + ADC_FSM_STARTED, +} adc_fsm_t; + +/*--------------------------------------------------------------- + Driver Context +---------------------------------------------------------------*/ +typedef struct adc_iir_filter_t adc_iir_filter_t; +typedef struct adc_continuous_ctx_t adc_continuous_ctx_t; + +/** + * @brief ADC iir filter context + */ +struct adc_iir_filter_t { + adc_digi_iir_filter_t filter_id; // Filter ID + adc_continuous_iir_filter_config_t cfg; //filter configuration + adc_continuous_ctx_t *continuous_ctx; //ADC continuous driver context +}; + +/** + * @brief ADC continuous driver context + */ +struct adc_continuous_ctx_t { + uint8_t *rx_dma_buf; //dma buffer + adc_hal_dma_ctx_t hal; //hal context +#if SOC_GDMA_SUPPORTED + gdma_channel_handle_t rx_dma_channel; //dma rx channel handle +#elif CONFIG_IDF_TARGET_ESP32S2 + spi_host_device_t spi_host; //ADC uses this SPI DMA +#elif CONFIG_IDF_TARGET_ESP32 + i2s_port_t i2s_host; //ADC uses this I2S DMA +#endif + intr_handle_t dma_intr_hdl; //DMA Interrupt handler + RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler + void* ringbuf_storage; //Ringbuffer storage buffer + void* ringbuf_struct; //Ringbuffer structure buffer + intptr_t rx_eof_desc_addr; //eof descriptor address of RX channel + adc_fsm_t fsm; //ADC continuous mode driver internal states + bool use_adc1; //1: ADC unit1 will be used; 0: ADC unit1 won't be used. + bool use_adc2; //1: ADC unit2 will be used; 0: ADC unit2 won't be used. This determines whether to acquire sar_adc2_mutex lock or not. + adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation. + adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation. + adc_hal_digi_ctrlr_cfg_t hal_digi_ctrlr_cfg; //Hal digital controller configuration + adc_continuous_evt_cbs_t cbs; //Callbacks + void *user_data; //User context + esp_pm_lock_handle_t pm_lock; //For power management +#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED + adc_iir_filter_t *iir_filter[SOC_ADC_DIGI_IIR_FILTER_NUM]; //ADC IIR filter context +#endif +}; + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/adc_filter.c b/components/esp_adc/adc_filter.c new file mode 100644 index 0000000000..f27216cd08 --- /dev/null +++ b/components/esp_adc/adc_filter.c @@ -0,0 +1,158 @@ +/* + * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_types.h" +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "hal/adc_types.h" +#include "hal/adc_hal.h" +#include "adc_continuous_internal.h" +#include "esp_adc/adc_filter.h" + +static const char *TAG = "adc_filter"; +static portMUX_TYPE s_filter_spinlock = portMUX_INITIALIZER_UNLOCKED; + + +#if SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED +static atomic_bool s_adc_filter_claimed[SOC_ADC_PERIPH_NUM] = {ATOMIC_VAR_INIT(false), +#if (SOC_ADC_PERIPH_NUM >= 2) +ATOMIC_VAR_INIT(false) +#endif +}; + +static esp_err_t s_adc_filter_claim(adc_continuous_handle_t handle, adc_iir_filter_t *filter_ctx, adc_unit_t unit) +{ + assert(handle && filter_ctx); + esp_err_t ret = ESP_ERR_NOT_FOUND; + bool false_var = false; + if (atomic_compare_exchange_strong(&s_adc_filter_claimed[unit], &false_var, true)) { + ret = ESP_OK; + filter_ctx->filter_id = unit; + handle->iir_filter[unit] = filter_ctx; + } + + return ret; +} + +static esp_err_t s_adc_filter_free(adc_iir_filter_t *filter_ctx) +{ + assert(filter_ctx); + esp_err_t ret = ESP_ERR_NOT_FOUND; + bool true_var = true; + if (atomic_compare_exchange_strong(&s_adc_filter_claimed[filter_ctx->cfg.unit], &true_var, false)) { + ret = ESP_OK; + filter_ctx->continuous_ctx->iir_filter[filter_ctx->filter_id] = NULL; + } + + return ret; +} + +#else +static esp_err_t s_adc_filter_claim(adc_continuous_handle_t handle, adc_iir_filter_t *filter_ctx, adc_unit_t unit) +{ + (void)unit; + assert(handle && filter_ctx); + for (int i = 0; i < SOC_ADC_DIGI_IIR_FILTER_NUM; i++) { + portENTER_CRITICAL(&s_filter_spinlock); + bool found = !handle->iir_filter[i]; + handle->iir_filter[i] = filter_ctx; + filter_ctx->filter_id = i; + portEXIT_CRITICAL(&s_filter_spinlock); + if (found) { + return ESP_OK; + } + } + + return ESP_ERR_NOT_FOUND; +} + +static esp_err_t s_adc_filter_free(adc_iir_filter_t *filter_ctx) +{ + assert(filter_ctx); + portENTER_CRITICAL(&s_filter_spinlock); + filter_ctx->continuous_ctx->iir_filter[filter_ctx->filter_id] = NULL; + portEXIT_CRITICAL(&s_filter_spinlock); + + return ESP_OK; +} +#endif + + + + +esp_err_t adc_new_continuous_iir_filter(adc_continuous_handle_t handle, const adc_continuous_iir_filter_config_t *config, adc_iir_filter_handle_t *ret_hdl) +{ + esp_err_t ret = ESP_FAIL; + ESP_RETURN_ON_FALSE(handle && config && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "ADC continuous driver should be in init state"); + ESP_RETURN_ON_FALSE(config->unit < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid unit"); + + adc_iir_filter_t *filter_ctx = heap_caps_calloc(1, sizeof(adc_iir_filter_t), MALLOC_CAP_DEFAULT); + ESP_RETURN_ON_FALSE(filter_ctx, ESP_ERR_NO_MEM, TAG, "no mem"); + + //claim a filter +#if SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED + ESP_GOTO_ON_ERROR(s_adc_filter_claim(handle, filter_ctx, config->unit), err, TAG, "filter already in use"); +#else + ESP_GOTO_ON_ERROR(s_adc_filter_claim(handle, filter_ctx, config->unit), err, TAG, "no free filter"); +#endif + + filter_ctx->cfg.unit = config->unit; + filter_ctx->cfg.channel = config->channel; + filter_ctx->cfg.coeff = config->coeff; + filter_ctx->continuous_ctx = handle; + + *ret_hdl = filter_ctx; + + return ESP_OK; + +err: + free(filter_ctx); + + return ret; +} + +esp_err_t adc_continuous_iir_filter_enable(adc_iir_filter_handle_t filter_hdl) +{ + ESP_RETURN_ON_FALSE(filter_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(filter_hdl->continuous_ctx->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "ADC continuous driver should be in init state"); + + portENTER_CRITICAL(&s_filter_spinlock); + adc_ll_digi_filter_reset(filter_hdl->filter_id, filter_hdl->cfg.unit); + adc_ll_digi_filter_set_factor(filter_hdl->filter_id, filter_hdl->cfg.unit, filter_hdl->cfg.channel, filter_hdl->cfg.coeff); + adc_ll_digi_filter_enable(filter_hdl->filter_id, filter_hdl->cfg.unit, true); + portEXIT_CRITICAL(&s_filter_spinlock); + + return ESP_OK; +} + +esp_err_t adc_continuous_iir_filter_disable(adc_iir_filter_handle_t filter_hdl) +{ + ESP_RETURN_ON_FALSE(filter_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(filter_hdl->continuous_ctx->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "ADC continuous driver should be in init state"); + + portENTER_CRITICAL(&s_filter_spinlock); + adc_ll_digi_filter_enable(filter_hdl->filter_id, filter_hdl->cfg.unit, false); + portEXIT_CRITICAL(&s_filter_spinlock); + + return ESP_OK; +} + +esp_err_t adc_del_continuous_iir_filter(adc_iir_filter_handle_t filter_hdl) +{ + ESP_RETURN_ON_FALSE(filter_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(filter_hdl->continuous_ctx->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "ADC continuous driver should be in init state"); + + ESP_RETURN_ON_ERROR(s_adc_filter_free(filter_hdl), TAG, "filter isn't in use"); + + free(filter_hdl); + + return ESP_OK; +} diff --git a/components/esp_adc/include/esp_adc/adc_continuous.h b/components/esp_adc/include/esp_adc/adc_continuous.h index 8db0f53135..d4827669e9 100644 --- a/components/esp_adc/include/esp_adc/adc_continuous.h +++ b/components/esp_adc/include/esp_adc/adc_continuous.h @@ -16,7 +16,6 @@ extern "C" { #endif -#if SOC_ADC_DMA_SUPPORTED /** * @brief Driver Backgrounds @@ -130,7 +129,7 @@ esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_contin /** * @brief Register callbacks * - * @note User can deregister a previously registered callback by calling this function and setting the to-be-deregistered callback member int + * @note User can deregister a previously registered callback by calling this function and setting the to-be-deregistered callback member in * the `cbs` structure to NULL. * @note When CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. * Involved variables (including `user_data`) should be in internal RAM as well. @@ -224,8 +223,6 @@ esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t *unit_id, adc_chan */ esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num); -#endif // #if SOC_ADC_DMA_SUPPORTED - #ifdef __cplusplus } diff --git a/components/esp_adc/include/esp_adc/adc_filter.h b/components/esp_adc/include/esp_adc/adc_filter.h new file mode 100644 index 0000000000..de4a12074c --- /dev/null +++ b/components/esp_adc/include/esp_adc/adc_filter.h @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_adc/adc_continuous.h" +#include "hal/adc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of adc iir filter handle + */ +typedef struct adc_iir_filter_t *adc_iir_filter_handle_t; + +/** + * @brief Filter Configuration + */ +typedef struct { + adc_unit_t unit; ///< ADC unit + adc_channel_t channel; ///< An ADC channel to be filtered. Note for ESP32S2, you should only set only one channel in pattern table, per ADC unit. See programming guide for more details. + adc_digi_iir_filter_coeff_t coeff; ///< ADC filter coefficient +} adc_continuous_iir_filter_config_t; + + +/** + * @brief New a ADC continuous mode IIR filter + * + * @param[in] handle ADC continuous mode driver handle + * @param[in] config Filter configuration + * @param[out] ret_hdl Returned IIR filter handle + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid state + * - ESP_ERR_NO_MEM: No memory + */ +esp_err_t adc_new_continuous_iir_filter(adc_continuous_handle_t handle, const adc_continuous_iir_filter_config_t *config, adc_iir_filter_handle_t *ret_hdl); + +/** + * @brief Enable an IIR filter + * + * @param[in] filter_hdl ADC IIR filter handle + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid state + */ +esp_err_t adc_continuous_iir_filter_enable(adc_iir_filter_handle_t filter_hdl); + +/** + * @brief Disable an IIR filter + * + * @param[in] filter_hdl ADC IIR filter handle + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid state + */ +esp_err_t adc_continuous_iir_filter_disable(adc_iir_filter_handle_t filter_hdl); + +/** + * @brief Delete the IIR filter + * + * @param[in] filter_hdl ADC IIR filter handle + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid state + */ +esp_err_t adc_del_continuous_iir_filter(adc_iir_filter_handle_t filter_hdl); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c b/components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c index c48fc746a1..a258a5b743 100644 --- a/components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c +++ b/components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -156,7 +156,7 @@ TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]") #endif #define ADC_TEST_FREQ_HZ (50 * 1000) -#define ADC_TEST_PKG_SIZE 100 +#define ADC_TEST_PKG_SIZE 512 static bool IRAM_ATTR NOINLINE_ATTR s_conv_done_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data) { test_adc_iram_ctx_t *test_ctx = (test_adc_iram_ctx_t *)user_data; diff --git a/components/esp_adc/test_apps/adc/main/test_adc_performance.c b/components/esp_adc/test_apps/adc/main/test_adc_performance.c index 314b59aef9..366c288bac 100644 --- a/components/esp_adc/test_apps/adc/main/test_adc_performance.c +++ b/components/esp_adc/test_apps/adc/main/test_adc_performance.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,19 +15,21 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_adc/adc_oneshot.h" +#include "esp_adc/adc_continuous.h" +#include "esp_adc/adc_filter.h" #include "test_common_adc.h" - -#if CONFIG_IDF_TARGET_ESP32 || SOC_ADC_CALIBRATION_V1_SUPPORTED +#include "idf_performance.h" __attribute__((unused)) static const char *TAG = "TEST_ADC"; -/*--------------------------------------------------------------- - ADC Oneshot Average / STD_Deviation Test ----------------------------------------------------------------*/ -#define TEST_COUNT (1<= s_adc_offset + MAX_ARRAY_SIZE)) { + if (!fixed_size && (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 + MAX_ARRAY_SIZE, value); + TEST_ASSERT_LESS_THAN(s_adc_offset + s_adc_count_size, value); } - s_adc_count[value - s_adc_offset] ++; + s_p_adc_count[value - s_adc_offset] ++; return value - s_adc_offset; } -static void s_reset_array(void) +static void s_reset_array(int array_size) { - memset(s_adc_count, 0, sizeof(s_adc_count)); + s_adc_count_size = array_size; + s_p_adc_count = (int *)heap_caps_calloc(1, s_adc_count_size * sizeof(int), MALLOC_CAP_INTERNAL); + TEST_ASSERT(s_p_adc_count); s_adc_offset = -1; } +static void s_destroy_array(void) +{ + free(s_p_adc_count); + s_p_adc_count = NULL; + s_adc_count_size = 0; +} + +__attribute__((unused)) static uint32_t s_get_average(void) { uint32_t sum = 0; int count = 0; - for (int i = 0; i < MAX_ARRAY_SIZE; i++) { - sum += s_adc_count[i] * (s_adc_offset+i); - count += s_adc_count[i]; + for (int i = 0; i < s_adc_count_size; i++) { + sum += s_p_adc_count[i] * (s_adc_offset+i); + count += s_p_adc_count[i]; } return sum/count; } -static void s_print_summary(bool figure) +static float s_print_summary(bool figure) { const int MAX_WIDTH=20; int max_count = 0; @@ -77,53 +89,220 @@ static void s_print_summary(bool figure) int end = -1; uint32_t sum = 0; int count = 0; - for (int i = 0; i < MAX_ARRAY_SIZE; i++) { - if (s_adc_count[i] > max_count) { - max_count = s_adc_count[i]; + for (int i = 0; i < s_adc_count_size; i++) { + if (s_p_adc_count[i] > max_count) { + max_count = s_p_adc_count[i]; } - if (s_adc_count[i] > 0 && start < 0) { + if (s_p_adc_count[i] > 0 && start < 0) { start = i; } - if (s_adc_count[i] > 0) { + if (s_p_adc_count[i] > 0) { end = i; } - count += s_adc_count[i]; - sum += s_adc_count[i] * (s_adc_offset+i); + count += s_p_adc_count[i]; + sum += s_p_adc_count[i] * (s_adc_offset+i); } if (figure) { for (int i = start; i <= end; i++) { printf("%4d ", i+s_adc_offset); - int count = s_adc_count[i] * MAX_WIDTH / max_count; + int count = s_p_adc_count[i] * MAX_WIDTH / max_count; for (int j = 0; j < count; j++) { putchar('|'); } - printf(" %d\n", s_adc_count[i]); + printf(" %d\n", s_p_adc_count[i]); } } float average = (float)sum/count; float variation_square = 0; for (int i = start; i <= end; i ++) { - if (s_adc_count[i] == 0) { + if (s_p_adc_count[i] == 0) { continue; } float delta = i + s_adc_offset - average; - variation_square += (delta * delta) * s_adc_count[i]; + variation_square += (delta * delta) * s_p_adc_count[i]; } printf("%d points.\n", count); printf("average: %.1f\n", (float)sum/count); printf("std: %.2f\n", sqrt(variation_square/count)); + + return sqrt(variation_square/count); } -#if CONFIG_IDF_TARGET_ESP32 -#define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_6 +#if SOC_ADC_DMA_SUPPORTED +/*--------------------------------------------------------------- + ADC Continuous Average / STD_Deviation Test +---------------------------------------------------------------*/ +#if (SOC_ADC_DIGI_RESULT_BYTES == 2) +#define ADC_TEST_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1 +#define EXAMPLE_ADC_GET_CHANNEL(result) ((result).type1.channel) +#define EXAMPLE_ADC_GET_DATA(result) ((result).type1.data) #else -#define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_2 +#define ADC_TEST_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 +#define EXAMPLE_ADC_GET_CHANNEL(result) ((result).type2.channel) +#define EXAMPLE_ADC_GET_DATA(result) ((result).type2.data) +#endif +#define ADC_TEST_FREQ_HZ (50 * 1000) +#define ADC_TEST_PKG_SIZE 512 +#define ADC_TEST_CNT 4096 + + +static bool IRAM_ATTR s_conv_done_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data) +{ + BaseType_t mustYield = pdFALSE; + TaskHandle_t task_handle = *(TaskHandle_t *)(user_data); + //Notify that ADC continuous driver has done enough number of conversions + vTaskNotifyGiveFromISR(task_handle, &mustYield); + + return (mustYield == pdTRUE); +} + +static float test_adc_continuous_std(adc_atten_t atten, bool filter_en, int filter_coeff, bool is_performance_test) +{ + uint8_t *result = heap_caps_calloc(1, ADC_TEST_CNT * SOC_ADC_DIGI_RESULT_BYTES, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_32BIT); + TEST_ASSERT(result); + bool print_figure = false; + TaskHandle_t task_handle = xTaskGetCurrentTaskHandle(); + + //-------------ADC Init---------------// + adc_continuous_handle_t handle = NULL; + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = 4096, + .conv_frame_size = ADC_TEST_PKG_SIZE, + }; + TEST_ESP_OK(adc_continuous_new_handle(&adc_config, &handle)); + + 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)); + + //-------------ADC Config---------------// + adc_continuous_config_t dig_cfg = { + .sample_freq_hz = ADC_TEST_FREQ_HZ, + .conv_mode = ADC_CONV_SINGLE_UNIT_1, + .format = ADC_TEST_OUTPUT_TYPE, + }; + adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0}; + adc_pattern[0].atten = atten; + 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)); + +#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED + adc_iir_filter_handle_t filter_hdl = NULL; + if (filter_en) { + adc_continuous_iir_filter_config_t filter_config = { + .unit = ADC_UNIT_1, + .channel = TEST_STD_ADC1_CHANNEL0, + .coeff = filter_coeff, + }; + TEST_ESP_OK(adc_new_continuous_iir_filter(handle, &filter_config, &filter_hdl)); + TEST_ESP_OK(adc_continuous_iir_filter_enable(filter_hdl)); + } #endif -TEST_CASE("ADC1 oneshot raw average / std_deviation", "[adc_oneshot][ignore][manual]") + if (is_performance_test) { + test_adc_set_io_middle(ADC_UNIT_1, TEST_STD_ADC1_CHANNEL0); + } + + if (filter_en) { + ESP_LOGI("TEST_ADC", "Test with atten: %d, filter coeff: %d", atten, filter_coeff); + } else { + ESP_LOGI("TEST_ADC", "Test with atten: %d, no filter", atten); + } + + s_reset_array((1 << SOC_ADC_DIGI_MAX_BITWIDTH)); + TEST_ESP_OK(adc_continuous_start(handle)); + + int remain_count = ADC_TEST_CNT; + while (remain_count) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + int already_got = ADC_TEST_CNT - remain_count; + uint32_t ret_num = 0; + TEST_ESP_OK(adc_continuous_read(handle, result + already_got * SOC_ADC_DIGI_RESULT_BYTES, ADC_TEST_PKG_SIZE, &ret_num, 0)); + remain_count -= ret_num / SOC_ADC_DIGI_RESULT_BYTES; + } + + adc_digi_output_data_t *p = (void*)result; + for (int i = 0; i < ADC_TEST_CNT; i++) { + TEST_ASSERT_EQUAL(TEST_STD_ADC1_CHANNEL0, EXAMPLE_ADC_GET_CHANNEL(p[i])); + s_insert_point(EXAMPLE_ADC_GET_DATA(p[i])); + } + float std = s_print_summary(print_figure); + + TEST_ESP_OK(adc_continuous_stop(handle)); +#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED + if (filter_en) { + TEST_ESP_OK(adc_continuous_iir_filter_disable(filter_hdl)); + TEST_ESP_OK(adc_del_continuous_iir_filter(filter_hdl)); + } +#endif + TEST_ESP_OK(adc_continuous_deinit(handle)); + ulTaskNotifyTake(pdTRUE, 0); + s_destroy_array(); + free(result); + + return std; +} + +TEST_CASE("ADC1 continuous raw average and std_deviation", "[adc_continuous][manual]") +{ + for (int i = 0; i < TEST_ATTEN_NUMS; i ++) { +#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED + //filter disabled + test_adc_continuous_std(g_test_atten[i], false, 0, false); + //filter with different coeffs + for (int j = 0; j < TEST_FILTER_COEFF_NUMS; j ++) { + test_adc_continuous_std(g_test_atten[i], true, g_test_filter_coeff[j], false); + } +#else + //filter disabled + test_adc_continuous_std(g_test_atten[i], false, 0, false); +#endif + } +} + +TEST_CASE("ADC1 continuous std deviation performance, no filter", "[adc_continuous][performance]") +{ + float std = test_adc_continuous_std(ADC_ATTEN_DB_11, 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_11, false, 0, true); + TEST_PERFORMANCE_LESS_THAN(ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER, "%.2f", std); + + std = test_adc_continuous_std(ADC_ATTEN_DB_11, 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_11, 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_11, 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_11, 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_11, 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 +#endif //#if SOC_ADC_DMA_SUPPORTED + +#if CONFIG_IDF_TARGET_ESP32 || SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Oneshot Average / STD_Deviation Test +---------------------------------------------------------------*/ +static float test_adc_oneshot_std(adc_atten_t atten, bool is_performance_test) { adc_channel_t channel = TEST_STD_ADC1_CHANNEL0; int raw = 0; @@ -144,50 +323,62 @@ TEST_CASE("ADC1 oneshot raw average / std_deviation", "[adc_oneshot][ignore][man //-------------ADC Calibration Init---------------// bool do_calibration = false; - adc_cali_handle_t cali_handle[TEST_ATTEN_NUMS] = {}; - for (int i = 0; i < TEST_ATTEN_NUMS; i++) { - do_calibration = test_adc_calibration_init(ADC_UNIT_1, g_test_atten[i], ADC_BITWIDTH_DEFAULT, &cali_handle[i]); - } + adc_cali_handle_t cali_handle = NULL; + do_calibration = test_adc_calibration_init(ADC_UNIT_1, atten, ADC_BITWIDTH_DEFAULT, &cali_handle); if (!do_calibration) { ESP_LOGW(TAG, "calibration fail, jump calibration\n"); } - for (int i = 0; i < TEST_ATTEN_NUMS; i++) { + //-------------ADC1 Channel Config---------------// + config.atten = atten; + TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, channel, &config)); + ESP_LOGI("TEST_ADC", "Test with atten: %d", atten); - //-------------ADC1 Channel Config---------------// - config.atten = g_test_atten[i]; - TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, channel, &config)); - ESP_LOGI("TEST_ADC", "Test with atten: %d", g_test_atten[i]); + s_reset_array((1 << SOC_ADC_RTC_MAX_BITWIDTH)); - while (1) { - - s_reset_array(); - - for (int i = 0; i < TEST_COUNT; i++) { - TEST_ESP_OK(adc_oneshot_read(adc1_handle, channel, &raw)); - s_insert_point(raw); - } - s_print_summary(print_figure); - break; - } - - if (do_calibration) { - uint32_t raw = s_get_average(); - int voltage_mv = 0; - TEST_ESP_OK(adc_cali_raw_to_voltage(cali_handle[i], raw, &voltage_mv)); - printf("Voltage = %d mV\n", voltage_mv); - } + if (is_performance_test) { + test_adc_set_io_middle(ADC_UNIT_1, TEST_STD_ADC1_CHANNEL0); } - TEST_ESP_OK(adc_oneshot_del_unit(adc1_handle)); - for (int i = 0; i < TEST_ATTEN_NUMS; i++) { - if (cali_handle[i]) { - test_adc_calibration_deinit(cali_handle[i]); + float std; + while (1) { + for (int i = 0; i < s_adc_count_size; i++) { + TEST_ESP_OK(adc_oneshot_read(adc1_handle, channel, &raw)); + s_insert_point(raw); } + std = s_print_summary(print_figure); + break; + } + + if (do_calibration) { + uint32_t raw = s_get_average(); + int voltage_mv = 0; + TEST_ESP_OK(adc_cali_raw_to_voltage(cali_handle, raw, &voltage_mv)); + printf("Voltage = %d mV\n", voltage_mv); + } + + s_destroy_array(); + + TEST_ESP_OK(adc_oneshot_del_unit(adc1_handle)); + if (cali_handle) { + test_adc_calibration_deinit(cali_handle); + } + + return std; +} + +TEST_CASE("ADC1 oneshot raw average and std_deviation", "[adc_oneshot][manual]") +{ + for (int i = 0; i < TEST_ATTEN_NUMS; i++) { + test_adc_oneshot_std(g_test_atten[i], false); } } - +TEST_CASE("ADC1 oneshot std_deviation performance", "[adc_oneshot][performance]") +{ + float std = test_adc_oneshot_std(ADC_ATTEN_DB_11, true); + TEST_PERFORMANCE_LESS_THAN(ADC_ONESHOT_STD_ATTEN3, "%.2f", std); +} /*--------------------------------------------------------------- ADC Calibration Speed ---------------------------------------------------------------*/ @@ -277,14 +468,14 @@ static void s_adc_cali_speed(adc_unit_t unit_id, adc_channel_t channel) } } -TEST_CASE("ADC1 Calibration Speed", "[adc][ignore][manual]") +TEST_CASE("ADC1 Calibration Speed", "[adc][manual]") { s_adc_cali_speed(ADC_UNIT_1, ADC1_CALI_SPEED_TEST_CHAN0); } #if (SOC_ADC_PERIPH_NUM >= 2) && !CONFIG_IDF_TARGET_ESP32C3 //ESP32C3 ADC2 oneshot mode is not supported anymore -TEST_CASE("ADC2 Calibration Speed", "[adc][ignore][manual]") +TEST_CASE("ADC2 Calibration Speed", "[adc][manual]") { s_adc_cali_speed(ADC_UNIT_2, ADC2_CALI_SPEED_TEST_CHAN0); } diff --git a/components/esp_adc/test_apps/adc/main/test_common_adc.c b/components/esp_adc/test_apps/adc/main/test_common_adc.c index aff057286e..f9cc81ebf1 100644 --- a/components/esp_adc/test_apps/adc/main/test_common_adc.c +++ b/components/esp_adc/test_apps/adc/main/test_common_adc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -7,6 +7,8 @@ #include #include "unity.h" #include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "driver/gpio.h" #include "driver/rtc_io.h" #include "soc/adc_periph.h" @@ -23,6 +25,16 @@ adc_atten_t g_test_atten[TEST_ATTEN_NUMS] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_11}; 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_11}; #endif +#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED +adc_digi_iir_filter_coeff_t g_test_filter_coeff[TEST_FILTER_COEFF_NUMS] = { + ADC_DIGI_IIR_FILTER_COEFF_2, + ADC_DIGI_IIR_FILTER_COEFF_4, + ADC_DIGI_IIR_FILTER_COEFF_8, + ADC_DIGI_IIR_FILTER_COEFF_16, + ADC_DIGI_IIR_FILTER_COEFF_64, +}; +#endif + /*--------------------------------------------------------------- ADC Calibration @@ -102,3 +114,21 @@ void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level) TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY: GPIO_PULLDOWN_ONLY))); #endif } + + +void test_adc_set_io_middle(adc_unit_t unit, adc_channel_t channel) +{ + TEST_ASSERT(channel < SOC_ADC_CHANNEL_NUM(unit) && "invalid channel"); + + uint32_t io_num = ADC_GET_IO_NUM(unit, channel); + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + TEST_ESP_OK(gpio_set_pull_mode(io_num, GPIO_PULLUP_PULLDOWN)); +#else + TEST_ESP_OK(rtc_gpio_init(io_num)); + TEST_ESP_OK(rtc_gpio_pullup_en(io_num)); + TEST_ESP_OK(rtc_gpio_pulldown_en(io_num)); + TEST_ESP_OK(rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_DISABLED)); +#endif + vTaskDelay(10 / portTICK_PERIOD_MS); +} diff --git a/components/esp_adc/test_apps/adc/main/test_common_adc.h b/components/esp_adc/test_apps/adc/main/test_common_adc.h index d822404a3f..d443d33235 100644 --- a/components/esp_adc/test_apps/adc/main/test_common_adc.h +++ b/components/esp_adc/test_apps/adc/main/test_common_adc.h @@ -92,6 +92,13 @@ extern adc_atten_t g_test_atten[TEST_ATTEN_NUMS]; extern adc_atten_t g_test_atten[TEST_ATTEN_NUMS]; #endif +/*--------------------------------------------------------------- + ADC Filter +---------------------------------------------------------------*/ +#if SOC_ADC_DIG_IIR_FILTER_SUPPORTED +#define TEST_FILTER_COEFF_NUMS 5 +extern adc_digi_iir_filter_coeff_t g_test_filter_coeff[TEST_FILTER_COEFF_NUMS]; +#endif /*--------------------------------------------------------------- ADC Calibration @@ -127,6 +134,17 @@ void test_adc_calibration_deinit(adc_cali_handle_t handle); */ void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level); +/** + * @brief Set ADC IO to a middle level + * + * @note We don't expect this IO to have a fixed level among different chips. + * We just need the IO to be stable at a certain level, which is neither 0 nor overflow. + * + * @param[in] unit ADC unit + * @param[in] channel ADC channel + */ +void test_adc_set_io_middle(adc_unit_t unit, adc_channel_t channel); + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c2/include/hal/adc_ll.h b/components/hal/esp32c2/include/hal/adc_ll.h index 15376463b2..a1d51689d7 100644 --- a/components/hal/esp32c2/include/hal/adc_ll.h +++ b/components/hal/esp32c2/include/hal/adc_ll.h @@ -161,46 +161,77 @@ static inline void adc_ll_digi_controller_clk_disable(void) /** * Reset adc digital controller filter. * + * @param idx Filter index * @param adc_n ADC unit. */ -static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) +static inline void adc_ll_digi_filter_reset(adc_digi_iir_filter_t idx, adc_unit_t adc_n) { + (void)adc_n; APB_SARADC.saradc_filter_ctrl0.saradc_filter_reset = 1; + APB_SARADC.saradc_filter_ctrl0.saradc_filter_reset = 0; } /** - * Set adc digital controller filter factor. + * Set adc digital controller filter coeff. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param idx ADC filter unit. - * @param filter Filter config. Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). + * @param idx filter index + * @param adc_n adc unit + * @param channel adc channel + * @param coeff filter coeff */ -static inline void adc_ll_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) +static inline void adc_ll_digi_filter_set_factor(adc_digi_iir_filter_t idx, adc_unit_t adc_n, adc_channel_t channel, adc_digi_iir_filter_coeff_t coeff) { - abort(); + uint32_t factor_reg_val = 0; + switch (coeff) { + case ADC_DIGI_IIR_FILTER_COEFF_2: + factor_reg_val = 1; + break; + case ADC_DIGI_IIR_FILTER_COEFF_4: + factor_reg_val = 2; + break; + case ADC_DIGI_IIR_FILTER_COEFF_8: + factor_reg_val = 3; + break; + case ADC_DIGI_IIR_FILTER_COEFF_16: + factor_reg_val = 4; + break; + case ADC_DIGI_IIR_FILTER_COEFF_64: + factor_reg_val = 6; + break; + default: + HAL_ASSERT(false); + } + + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.saradc_filter_ctrl0.saradc_filter_channel0 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.saradc_filter_ctrl1.saradc_filter_factor0 = factor_reg_val; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.saradc_filter_ctrl0.saradc_filter_channel1 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.saradc_filter_ctrl1.saradc_filter_factor1 = factor_reg_val; + } } /** - * Get adc digital controller filter factor. - * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). - */ -static inline void adc_ll_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) -{ - abort(); -} - -/** - * Disable adc digital controller filter. + * Enable adc digital controller filter. * Filtering the ADC data to obtain smooth data at higher sampling rates. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param adc_n ADC unit. + * @param idx filter index + * @param adc_n ADC unit + * @param enable Enable / Disable */ -static inline void adc_ll_digi_filter_disable(adc_digi_filter_idx_t idx) +static inline void adc_ll_digi_filter_enable(adc_digi_iir_filter_t idx, adc_unit_t adc_n, bool enable) { - abort(); + (void)adc_n; + if (!enable) { + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.saradc_filter_ctrl0.saradc_filter_channel0 = 0xF; + APB_SARADC.saradc_filter_ctrl1.saradc_filter_factor0 = 0; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.saradc_filter_ctrl0.saradc_filter_channel1 = 0xF; + APB_SARADC.saradc_filter_ctrl1.saradc_filter_factor1 = 0; + } + } + //nothing to do to enable, after adc_ll_digi_filter_set_factor, it's enabled. } /** diff --git a/components/hal/esp32c3/include/hal/adc_ll.h b/components/hal/esp32c3/include/hal/adc_ll.h index 81966cb01c..c102b72abd 100644 --- a/components/hal/esp32c3/include/hal/adc_ll.h +++ b/components/hal/esp32c3/include/hal/adc_ll.h @@ -304,66 +304,77 @@ static inline void adc_ll_digi_controller_clk_disable(void) /** * Reset adc digital controller filter. * + * @param idx Filter index * @param adc_n ADC unit. */ -static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) +static inline void adc_ll_digi_filter_reset(adc_digi_iir_filter_t idx, adc_unit_t adc_n) { + (void)adc_n; APB_SARADC.filter_ctrl0.filter_reset = 1; + APB_SARADC.filter_ctrl0.filter_reset = 0; } /** - * Set adc digital controller filter factor. + * Set adc digital controller filter coeff. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param idx ADC filter unit. - * @param filter Filter config. Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). + * @param idx filter index + * @param adc_n adc unit + * @param channel adc channel + * @param coeff filter coeff */ -static inline void adc_ll_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) +static inline void adc_ll_digi_filter_set_factor(adc_digi_iir_filter_t idx, adc_unit_t adc_n, adc_channel_t channel, adc_digi_iir_filter_coeff_t coeff) { - if (idx == ADC_DIGI_FILTER_IDX0) { - APB_SARADC.filter_ctrl0.filter_channel0 = (filter->adc_unit << 3) | (filter->channel & 0x7); - APB_SARADC.filter_ctrl1.filter_factor0 = filter->mode; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - APB_SARADC.filter_ctrl0.filter_channel1 = (filter->adc_unit << 3) | (filter->channel & 0x7); - APB_SARADC.filter_ctrl1.filter_factor1 = filter->mode; + uint32_t factor_reg_val = 0; + switch (coeff) { + case ADC_DIGI_IIR_FILTER_COEFF_2: + factor_reg_val = 1; + break; + case ADC_DIGI_IIR_FILTER_COEFF_4: + factor_reg_val = 2; + break; + case ADC_DIGI_IIR_FILTER_COEFF_8: + factor_reg_val = 3; + break; + case ADC_DIGI_IIR_FILTER_COEFF_16: + factor_reg_val = 4; + break; + case ADC_DIGI_IIR_FILTER_COEFF_64: + factor_reg_val = 6; + break; + default: + HAL_ASSERT(false); + } + + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.filter_ctrl0.filter_channel0 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.filter_ctrl1.filter_factor0 = factor_reg_val; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.filter_ctrl0.filter_channel1 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.filter_ctrl1.filter_factor1 = factor_reg_val; } } /** - * Get adc digital controller filter factor. - * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). - */ -static inline void adc_ll_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) -{ - if (idx == ADC_DIGI_FILTER_IDX0) { - filter->adc_unit = (APB_SARADC.filter_ctrl0.filter_channel0 >> 3) & 0x1; - filter->channel = APB_SARADC.filter_ctrl0.filter_channel0 & 0x7; - filter->mode = APB_SARADC.filter_ctrl1.filter_factor0; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - filter->adc_unit = (APB_SARADC.filter_ctrl0.filter_channel1 >> 3) & 0x1; - filter->channel = APB_SARADC.filter_ctrl0.filter_channel1 & 0x7; - filter->mode = APB_SARADC.filter_ctrl1.filter_factor1; - } -} - -/** - * Disable adc digital controller filter. + * Enable adc digital controller filter. * Filtering the ADC data to obtain smooth data at higher sampling rates. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param adc_n ADC unit. + * @param idx filter index + * @param adc_n ADC unit + * @param enable Enable / Disable */ -static inline void adc_ll_digi_filter_disable(adc_digi_filter_idx_t idx) +static inline void adc_ll_digi_filter_enable(adc_digi_iir_filter_t idx, adc_unit_t adc_n, bool enable) { - if (idx == ADC_DIGI_FILTER_IDX0) { - APB_SARADC.filter_ctrl0.filter_channel0 = 0xF; - APB_SARADC.filter_ctrl1.filter_factor0 = 0; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - APB_SARADC.filter_ctrl0.filter_channel1 = 0xF; - APB_SARADC.filter_ctrl1.filter_factor1 = 0; + (void)adc_n; + if (!enable) { + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.filter_ctrl0.filter_channel0 = 0xF; + APB_SARADC.filter_ctrl1.filter_factor0 = 0; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.filter_ctrl0.filter_channel1 = 0xF; + APB_SARADC.filter_ctrl1.filter_factor1 = 0; + } } + //nothing to do to enable, after adc_ll_digi_filter_set_factor, it's enabled. } /** diff --git a/components/hal/esp32c6/include/hal/adc_ll.h b/components/hal/esp32c6/include/hal/adc_ll.h index 9dd051b716..5ed2db486a 100644 --- a/components/hal/esp32c6/include/hal/adc_ll.h +++ b/components/hal/esp32c6/include/hal/adc_ll.h @@ -313,66 +313,77 @@ static inline void adc_ll_digi_controller_clk_disable(void) /** * Reset adc digital controller filter. * + * @param idx Filter index * @param adc_n ADC unit. */ -static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) +static inline void adc_ll_digi_filter_reset(adc_digi_iir_filter_t idx, adc_unit_t adc_n) { + (void)adc_n; APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_reset = 1; + APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_reset = 0; } /** - * Set adc digital controller filter factor. + * Set adc digital controller filter coeff. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param idx ADC filter unit. - * @param filter Filter config. Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). + * @param idx filter index + * @param adc_n adc unit + * @param channel adc channel + * @param coeff filter coeff */ -static inline void adc_ll_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) +static inline void adc_ll_digi_filter_set_factor(adc_digi_iir_filter_t idx, adc_unit_t adc_n, adc_channel_t channel, adc_digi_iir_filter_coeff_t coeff) { - if (idx == ADC_DIGI_FILTER_IDX0) { - APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel0 = (filter->adc_unit << 3) | (filter->channel & 0x7); - APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor0 = filter->mode; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel1 = (filter->adc_unit << 3) | (filter->channel & 0x7); - APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor1 = filter->mode; + uint32_t factor_reg_val = 0; + switch (coeff) { + case ADC_DIGI_IIR_FILTER_COEFF_2: + factor_reg_val = 1; + break; + case ADC_DIGI_IIR_FILTER_COEFF_4: + factor_reg_val = 2; + break; + case ADC_DIGI_IIR_FILTER_COEFF_8: + factor_reg_val = 3; + break; + case ADC_DIGI_IIR_FILTER_COEFF_16: + factor_reg_val = 4; + break; + case ADC_DIGI_IIR_FILTER_COEFF_64: + factor_reg_val = 6; + break; + default: + HAL_ASSERT(false); + } + + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel0 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor0 = factor_reg_val; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel1 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor1 = factor_reg_val; } } /** - * Get adc digital controller filter factor. - * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). - */ -static inline void adc_ll_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) -{ - if (idx == ADC_DIGI_FILTER_IDX0) { - filter->adc_unit = (APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel0 >> 3) & 0x1; - filter->channel = APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel0 & 0x7; - filter->mode = APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor0; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - filter->adc_unit = (APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel1 >> 3) & 0x1; - filter->channel = APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel1 & 0x7; - filter->mode = APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor1; - } -} - -/** - * Disable adc digital controller filter. + * Enable adc digital controller filter. * Filtering the ADC data to obtain smooth data at higher sampling rates. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param adc_n ADC unit. + * @param idx filter index + * @param adc_n ADC unit + * @param enable Enable / Disable */ -static inline void adc_ll_digi_filter_disable(adc_digi_filter_idx_t idx) +static inline void adc_ll_digi_filter_enable(adc_digi_iir_filter_t idx, adc_unit_t adc_n, bool enable) { - if (idx == ADC_DIGI_FILTER_IDX0) { - APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel0 = 0xF; - APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor0 = 0; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel1 = 0xF; - APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor1 = 0; + (void)adc_n; + if (!enable) { + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel0 = 0xF; + APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor0 = 0; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.saradc_filter_ctrl0.saradc_apb_saradc_filter_channel1 = 0xF; + APB_SARADC.saradc_filter_ctrl1.saradc_apb_saradc_filter_factor1 = 0; + } } + //nothing to do to enable, after adc_ll_digi_filter_set_factor, it's enabled. } /** diff --git a/components/hal/esp32h4/include/hal/adc_ll.h b/components/hal/esp32h4/include/hal/adc_ll.h index b131fda5fa..aa23ec8bb2 100644 --- a/components/hal/esp32h4/include/hal/adc_ll.h +++ b/components/hal/esp32h4/include/hal/adc_ll.h @@ -18,6 +18,7 @@ #include "soc/rtc_cntl_reg.h" #include "soc/clk_tree_defs.h" #include "hal/misc.h" +#include "hal/assert.h" #include "hal/regi2c_ctrl.h" #include "soc/regi2c_saradc.h" @@ -310,66 +311,77 @@ static inline void adc_ll_digi_controller_clk_disable(void) /** * Reset adc digital controller filter. * + * @param idx Filter index * @param adc_n ADC unit. */ -static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) +static inline void adc_ll_digi_filter_reset(adc_digi_iir_filter_t idx, adc_unit_t adc_n) { + (void)adc_n; APB_SARADC.filter_ctrl0.filter_reset = 1; + APB_SARADC.filter_ctrl0.filter_reset = 0; } /** - * Set adc digital controller filter factor. + * Set adc digital controller filter coeff. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param idx ADC filter unit. - * @param filter Filter config. Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). + * @param idx filter index + * @param adc_n adc unit + * @param channel adc channel + * @param coeff filter coeff */ -static inline void adc_ll_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) +static inline void adc_ll_digi_filter_set_factor(adc_digi_iir_filter_t idx, adc_unit_t adc_n, adc_channel_t channel, adc_digi_iir_filter_coeff_t coeff) { - if (idx == ADC_DIGI_FILTER_IDX0) { - APB_SARADC.filter_ctrl0.filter_channel0 = (filter->adc_unit << 3) | (filter->channel & 0x7); - APB_SARADC.filter_ctrl1.filter_factor0 = filter->mode; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - APB_SARADC.filter_ctrl0.filter_channel1 = (filter->adc_unit << 3) | (filter->channel & 0x7); - APB_SARADC.filter_ctrl1.filter_factor1 = filter->mode; + uint32_t factor_reg_val = 0; + switch (coeff) { + case ADC_DIGI_IIR_FILTER_COEFF_2: + factor_reg_val = 1; + break; + case ADC_DIGI_IIR_FILTER_COEFF_4: + factor_reg_val = 2; + break; + case ADC_DIGI_IIR_FILTER_COEFF_8: + factor_reg_val = 3; + break; + case ADC_DIGI_IIR_FILTER_COEFF_16: + factor_reg_val = 4; + break; + case ADC_DIGI_IIR_FILTER_COEFF_64: + factor_reg_val = 6; + break; + default: + HAL_ASSERT(false); + } + + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.filter_ctrl0.filter_channel0 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.filter_ctrl1.filter_factor0 = factor_reg_val; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.filter_ctrl0.filter_channel1 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.filter_ctrl1.filter_factor1 = factor_reg_val; } } /** - * Get adc digital controller filter factor. - * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). - */ -static inline void adc_ll_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) -{ - if (idx == ADC_DIGI_FILTER_IDX0) { - filter->adc_unit = (APB_SARADC.filter_ctrl0.filter_channel0 >> 3) & 0x1; - filter->channel = APB_SARADC.filter_ctrl0.filter_channel0 & 0x7; - filter->mode = APB_SARADC.filter_ctrl1.filter_factor0; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - filter->adc_unit = (APB_SARADC.filter_ctrl0.filter_channel1 >> 3) & 0x1; - filter->channel = APB_SARADC.filter_ctrl0.filter_channel1 & 0x7; - filter->mode = APB_SARADC.filter_ctrl1.filter_factor1; - } -} - -/** - * Disable adc digital controller filter. + * Enable adc digital controller filter. * Filtering the ADC data to obtain smooth data at higher sampling rates. * - * @note If the channel info is not supported, the filter function will not be enabled. - * @param adc_n ADC unit. + * @param idx filter index + * @param adc_n ADC unit + * @param enable Enable / Disable */ -static inline void adc_ll_digi_filter_disable(adc_digi_filter_idx_t idx) +static inline void adc_ll_digi_filter_enable(adc_digi_iir_filter_t idx, adc_unit_t adc_n, bool enable) { - if (idx == ADC_DIGI_FILTER_IDX0) { - APB_SARADC.filter_ctrl0.filter_channel0 = 0xF; - APB_SARADC.filter_ctrl1.filter_factor0 = 0; - } else if (idx == ADC_DIGI_FILTER_IDX1) { - APB_SARADC.filter_ctrl0.filter_channel1 = 0xF; - APB_SARADC.filter_ctrl1.filter_factor1 = 0; + (void)adc_n; + if (!enable) { + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.filter_ctrl0.filter_channel0 = 0xF; + APB_SARADC.filter_ctrl1.filter_factor0 = 0; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.filter_ctrl0.filter_channel1 = 0xF; + APB_SARADC.filter_ctrl1.filter_factor1 = 0; + } } + //nothing to do to enable, after adc_ll_digi_filter_set_factor, it's enabled. } /** diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index aacb604209..e09a07f54c 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -357,10 +357,12 @@ static inline void adc_ll_digi_controller_clk_disable(void) /** * Reset adc digital controller filter. * + * @param idx Filter index * @param adc_n ADC unit. */ -static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) +static inline void adc_ll_digi_filter_reset(adc_digi_iir_filter_t idx, adc_unit_t adc_n) { + (void)idx; if (adc_n == ADC_UNIT_1) { APB_SARADC.filter_ctrl.adc1_filter_reset = 1; APB_SARADC.filter_ctrl.adc1_filter_reset = 0; @@ -371,20 +373,24 @@ static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) } /** - * Set adc digital controller filter factor. + * Set adc digital controller filter coeff. * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). + * @param idx filter index + * @param adc_n adc unit + * @param channel adc channel + * @param coeff filter coeff */ -static inline void adc_ll_digi_filter_set_factor(adc_unit_t adc_n, adc_digi_filter_mode_t factor) +static inline void adc_ll_digi_filter_set_factor(adc_digi_iir_filter_t idx, adc_unit_t adc_n, adc_channel_t channel, adc_digi_iir_filter_coeff_t coeff) { + (void)idx; + (void)channel; int mode = 0; - switch (factor) { - case ADC_DIGI_FILTER_IIR_2: mode = 2; break; - case ADC_DIGI_FILTER_IIR_4: mode = 4; break; - case ADC_DIGI_FILTER_IIR_8: mode = 8; break; - case ADC_DIGI_FILTER_IIR_16: mode = 16; break; - case ADC_DIGI_FILTER_IIR_64: mode = 64; break; + switch (coeff) { + case ADC_DIGI_IIR_FILTER_COEFF_2: mode = 2; break; + case ADC_DIGI_IIR_FILTER_COEFF_4: mode = 4; break; + case ADC_DIGI_IIR_FILTER_COEFF_8: mode = 8; break; + case ADC_DIGI_IIR_FILTER_COEFF_16: mode = 16; break; + case ADC_DIGI_IIR_FILTER_COEFF_64: mode = 64; break; default: mode = 8; break; } if (adc_n == ADC_UNIT_1) { @@ -394,39 +400,18 @@ static inline void adc_ll_digi_filter_set_factor(adc_unit_t adc_n, adc_digi_filt } } -/** - * Get adc digital controller filter factor. - * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). - */ -static inline void adc_ll_digi_filter_get_factor(adc_unit_t adc_n, adc_digi_filter_mode_t *factor) -{ - int mode = 0; - if (adc_n == ADC_UNIT_1) { - mode = APB_SARADC.filter_ctrl.adc1_filter_factor; - } else { // adc_n == ADC_UNIT_2 - mode = APB_SARADC.filter_ctrl.adc2_filter_factor; - } - switch (mode) { - case 2: *factor = ADC_DIGI_FILTER_IIR_2; break; - case 4: *factor = ADC_DIGI_FILTER_IIR_4; break; - case 8: *factor = ADC_DIGI_FILTER_IIR_8; break; - case 16: *factor = ADC_DIGI_FILTER_IIR_16; break; - case 64: *factor = ADC_DIGI_FILTER_IIR_64; break; - default: *factor = ADC_DIGI_FILTER_IIR_MAX; break; - } -} - /** * Enable/disable adc digital controller filter. * Filtering the ADC data to obtain smooth data at higher sampling rates. * * @note The filter will filter all the enabled channel data of the each ADC unit at the same time. - * @param adc_n ADC unit. + * @param idx Filter index + * @param adc_n ADC unit + * @param enable Enable / Disable */ -static inline void adc_ll_digi_filter_enable(adc_unit_t adc_n, bool enable) +static inline void adc_ll_digi_filter_enable(adc_digi_iir_filter_t idx, adc_unit_t adc_n, bool enable) { + (void)idx; if (adc_n == ADC_UNIT_1) { APB_SARADC.filter_ctrl.adc1_filter_en = enable; } else { // adc_n == ADC_UNIT_2 diff --git a/components/hal/esp32s3/include/hal/adc_ll.h b/components/hal/esp32s3/include/hal/adc_ll.h index c1526aebc6..19a5c9aea3 100644 --- a/components/hal/esp32s3/include/hal/adc_ll.h +++ b/components/hal/esp32s3/include/hal/adc_ll.h @@ -362,58 +362,77 @@ static inline void adc_ll_digi_controller_clk_disable(void) /** * Reset adc digital controller filter. * + * @param idx Filter index * @param adc_n ADC unit. */ -static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) +static inline void adc_ll_digi_filter_reset(adc_digi_iir_filter_t idx, adc_unit_t adc_n) { - abort(); + (void)adc_n; + APB_SARADC.filter_ctrl0.filter_reset = 1; + APB_SARADC.filter_ctrl0.filter_reset = 0; } /** - * Set adc digital controller filter factor. + * Set adc digital controller filter coeff. * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). + * @param idx filter index + * @param adc_n adc unit + * @param channel adc channel + * @param coeff filter coeff */ -static inline void adc_ll_digi_filter_set_factor(adc_unit_t adc_n, adc_digi_filter_mode_t factor) +static inline void adc_ll_digi_filter_set_factor(adc_digi_iir_filter_t idx, adc_unit_t adc_n, adc_channel_t channel, adc_digi_iir_filter_coeff_t coeff) { - abort(); + uint32_t factor_reg_val = 0; + switch (coeff) { + case ADC_DIGI_IIR_FILTER_COEFF_2: + factor_reg_val = 1; + break; + case ADC_DIGI_IIR_FILTER_COEFF_4: + factor_reg_val = 2; + break; + case ADC_DIGI_IIR_FILTER_COEFF_8: + factor_reg_val = 3; + break; + case ADC_DIGI_IIR_FILTER_COEFF_16: + factor_reg_val = 4; + break; + case ADC_DIGI_IIR_FILTER_COEFF_64: + factor_reg_val = 6; + break; + default: + HAL_ASSERT(false); + } + + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.filter_ctrl0.filter_channel0 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.filter_ctrl1.filter_factor0 = factor_reg_val; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.filter_ctrl0.filter_channel1 = ((adc_n + 1) << 3) | (channel & 0x7); + APB_SARADC.filter_ctrl1.filter_factor1 = factor_reg_val; + } } /** - * Get adc digital controller filter factor. - * - * @param adc_n ADC unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). - */ -static inline void adc_ll_digi_filter_get_factor(adc_unit_t adc_n, adc_digi_filter_mode_t *factor) -{ - abort(); -} - -/** - * Enable/disable adc digital controller filter. + * Enable adc digital controller filter. * Filtering the ADC data to obtain smooth data at higher sampling rates. * - * @note The filter will filter all the enabled channel data of the each ADC unit at the same time. - * @param adc_n ADC unit. + * @param idx filter index + * @param adc_n ADC unit + * @param enable Enable / Disable */ -static inline void adc_ll_digi_filter_enable(adc_unit_t adc_n, bool enable) +static inline void adc_ll_digi_filter_enable(adc_digi_iir_filter_t idx, adc_unit_t adc_n, bool enable) { - abort(); -} - -/** - * Get the filtered data of adc digital controller filter. - * The data after each measurement and filtering is updated to the DMA by the digital controller. But it can also be obtained manually through this API. - * - * @note The filter will filter all the enabled channel data of the each ADC unit at the same time. - * @param adc_n ADC unit. - * @return Filtered data. - */ -static inline uint32_t adc_ll_digi_filter_read_data(adc_unit_t adc_n) -{ - abort(); + (void)adc_n; + if (!enable) { + if (idx == ADC_DIGI_IIR_FILTER_0) { + APB_SARADC.filter_ctrl0.filter_channel0 = 0xF; + APB_SARADC.filter_ctrl1.filter_factor0 = 0; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + APB_SARADC.filter_ctrl0.filter_channel1 = 0xF; + APB_SARADC.filter_ctrl1.filter_factor1 = 0; + } + } + //nothing to do to enable, after adc_ll_digi_filter_set_factor, it's enabled. } /** diff --git a/components/hal/include/hal/adc_types.h b/components/hal/include/hal/adc_types.h index 8568c195c5..b8cc83b245 100644 --- a/components/hal/include/hal/adc_types.h +++ b/components/hal/include/hal/adc_types.h @@ -97,6 +97,25 @@ typedef struct { uint8_t bit_width; ///< ADC output bit width } adc_digi_pattern_config_t; +/** + * @brief ADC IIR Filter ID + */ +typedef enum { + ADC_DIGI_IIR_FILTER_0, ///< Filter 0 + ADC_DIGI_IIR_FILTER_1, ///< Filter 1 +} adc_digi_iir_filter_t; + +/** + * @brief IIR Filter Coefficient + */ +typedef enum { + ADC_DIGI_IIR_FILTER_COEFF_2, ///< The filter coefficient is 2 + ADC_DIGI_IIR_FILTER_COEFF_4, ///< The filter coefficient is 4 + ADC_DIGI_IIR_FILTER_COEFF_8, ///< The filter coefficient is 8 + ADC_DIGI_IIR_FILTER_COEFF_16, ///< The filter coefficient is 16 + ADC_DIGI_IIR_FILTER_COEFF_64, ///< The filter coefficient is 64 +} adc_digi_iir_filter_coeff_t; + /*--------------------------------------------------------------- Output Format ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/adc_types_private.h b/components/hal/include/hal/adc_types_private.h index 63c210261b..aa65371465 100644 --- a/components/hal/include/hal/adc_types_private.h +++ b/components/hal/include/hal/adc_types_private.h @@ -47,55 +47,6 @@ typedef struct { } #endif //#if SOC_ADC_ARBITER_SUPPORTED - -#if SOC_ADC_FILTER_SUPPORTED -/*--------------------------------------------------------------- - Filter ----------------------------------------------------------------*/ -/** - * @brief ADC digital controller (DMA mode) filter index options. - * - * @note For ESP32-S2, The filter object of the ADC is fixed. - */ -typedef enum { - ADC_DIGI_FILTER_IDX0 = 0, /*! Date: Tue, 7 Feb 2023 16:18:07 +0800 Subject: [PATCH 2/2] esp_adc: added adc filter doc, and filter migration guides --- components/esp_adc/adc_filter.c | 2 -- .../esp_adc/include/esp_adc/adc_filter.h | 2 +- .../peripherals/adc_continuous.rst | 24 +++++++++++++++++++ .../release-5.x/5.0/peripherals.rst | 1 + .../release-5.x/5.0/peripherals.rst | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/components/esp_adc/adc_filter.c b/components/esp_adc/adc_filter.c index f27216cd08..ea397dee1f 100644 --- a/components/esp_adc/adc_filter.c +++ b/components/esp_adc/adc_filter.c @@ -85,8 +85,6 @@ static esp_err_t s_adc_filter_free(adc_iir_filter_t *filter_ctx) #endif - - esp_err_t adc_new_continuous_iir_filter(adc_continuous_handle_t handle, const adc_continuous_iir_filter_config_t *config, adc_iir_filter_handle_t *ret_hdl) { esp_err_t ret = ESP_FAIL; diff --git a/components/esp_adc/include/esp_adc/adc_filter.h b/components/esp_adc/include/esp_adc/adc_filter.h index de4a12074c..973ccf0d26 100644 --- a/components/esp_adc/include/esp_adc/adc_filter.h +++ b/components/esp_adc/include/esp_adc/adc_filter.h @@ -33,7 +33,7 @@ typedef struct { /** - * @brief New a ADC continuous mode IIR filter + * @brief New an ADC continuous mode IIR filter * * @param[in] handle ADC continuous mode driver handle * @param[in] config Filter configuration diff --git a/docs/en/api-reference/peripherals/adc_continuous.rst b/docs/en/api-reference/peripherals/adc_continuous.rst index b67a5bd895..cd65795f26 100644 --- a/docs/en/api-reference/peripherals/adc_continuous.rst +++ b/docs/en/api-reference/peripherals/adc_continuous.rst @@ -71,6 +71,26 @@ After setting up above configurations for the ADC, call :cpp:func:`adc_continuou If the ADC continuous mode driver is no longer used, you should deinitialize the driver by calling :cpp:func:`adc_continuous_deinit`. +.. only:: SOC_ADC_DIG_IIR_FILTER_SUPPORTED + + Two IIR filters are available when ADC is working under continuous mode. To create an ADC IIR filter, you should set up the :cpp:type:`adc_continuous_iir_filter_config_t`, and call :cpp:func:`adc_new_continuous_iir_filter`. + + - :cpp:member:`adc_digi_filter_config_t::unit`, ADC unit. + - :cpp:member:`adc_digi_filter_config_t::channel`, ADC channel to be filtered. + - :cpp:member:`adc_digi_filter_config_t::coeff`, filter coefficient. + + .. only:: SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED + + On ESP32S2, the filter is per ADC unit. Once a filter is enabled, all the enabled ADC channels in this ADC unit will be filtered. However, we suggest only enabling one ADC channel per unit, when using the filter feature. Because the filtered results depend on the previous filtered result. So you should not enable multiple ADC channels, to avoid mixing the filtered results. + + To recycle a filter, you should call :cpp:func:`adc_del_continuous_iir_filter`. + + .. only:: not SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED + + .. note:: + + If you use both the filters on a same ADC channel, then only the first one will take effect. + Initialize the ADC Continuous Mode Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -120,6 +140,10 @@ This API may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. When it re See ADC continuous mode example :example:`peripherals/adc/continuous_read` to see configuration codes. +.. only:: SOC_ADC_DIG_IIR_FILTER_SUPPORTED + + To enable / disable the ADC IIR filter, you should call :cpp:func:`adc_continuous_iir_filter_enable` / :cpp:func:`adc_continuous_iir_filter_disable`. + ADC Control ^^^^^^^^^^^ diff --git a/docs/en/migration-guides/release-5.x/5.0/peripherals.rst b/docs/en/migration-guides/release-5.x/5.0/peripherals.rst index 352550fc49..900100c58f 100644 --- a/docs/en/migration-guides/release-5.x/5.0/peripherals.rst +++ b/docs/en/migration-guides/release-5.x/5.0/peripherals.rst @@ -70,6 +70,7 @@ API Changes - API ``hall_sensor_read`` on ESP32 has been removed. Hall sensor is no longer supported on ESP32. - API ``adc_set_i2s_data_source`` and ``adc_i2s_mode_init`` have been deprecated. Related enum ``adc_i2s_source_t`` has been deprecated. Please migrate to use ``esp_adc/adc_continuous.h``. +- API ``adc_digi_filter_reset``, ``adc_digi_filter_set_config``, ``adc_digi_filter_get_config`` and ``adc_digi_filter_enable`` have been removed. These APIs behaviours are not guaranteed. Enum ``adc_digi_filter_idx_t``, ``adc_digi_filter_mode_t`` and structure ``adc_digi_iir_filter_t`` have been removed as well. GPIO ---- diff --git a/docs/zh_CN/migration-guides/release-5.x/5.0/peripherals.rst b/docs/zh_CN/migration-guides/release-5.x/5.0/peripherals.rst index 837a2cc9b6..bcd3a34224 100644 --- a/docs/zh_CN/migration-guides/release-5.x/5.0/peripherals.rst +++ b/docs/zh_CN/migration-guides/release-5.x/5.0/peripherals.rst @@ -70,6 +70,7 @@ API 更新 - ESP32 中的 API ``hall_sensor_read`` 已被删除,因此 ESP32 不再支持霍尔传感器。 - API ``adc_set_i2s_data_source`` 和 ``adc_i2s_mode_init`` 已被弃用,相关的枚举 ``adc_i2s_source_t`` 也已被弃用,请使用 ``esp_adc/adc_continuous.h`` 进行迁移。 +- API ``adc_digi_filter_reset`` , ``adc_digi_filter_set_config`` , ``adc_digi_filter_get_config`` 和 ``adc_digi_filter_enable`` 已被移除. 这些接口的行为不被保证。 枚举 ``adc_digi_filter_idx_t`` , ``adc_digi_filter_mode_t`` 和结构体 ``adc_digi_iir_filter_t`` 已被移除。 GPIO ----------