From 24361f232d1a884594fcfd2f8014f7329656ce3f Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 7 Mar 2023 12:09:07 +0800 Subject: [PATCH] ana_cmpr: add an example and test cases --- components/driver/.build-test-rules.yml | 4 + .../driver/analog_comparator/ana_cmpr.c | 27 +++- .../include/driver/ana_cmpr_types.h | 2 +- .../analog_comparator/CMakeLists.txt | 18 +++ .../test_apps/analog_comparator/README.md | 2 + .../analog_comparator/main/CMakeLists.txt | 11 ++ .../analog_comparator/main/test_ana_cmpr.c | 86 +++++++++++ .../analog_comparator/main/test_ana_cmpr.h | 43 ++++++ .../main/test_ana_cmpr_common.c | 39 +++++ .../main/test_ana_cmpr_iram.c | 76 +++++++++ .../analog_comparator/main/test_app_main.c | 54 +++++++ .../analog_comparator/pytest_ana_cmpr.py | 19 +++ .../analog_comparator/sdkconfig.ci.iram_safe | 7 + .../analog_comparator/sdkconfig.ci.release | 5 + .../analog_comparator/sdkconfig.defaults | 2 + .../hal/esp32h2/include/hal/ana_cmpr_ll.h | 4 + examples/peripherals/.build-test-rules.yml | 4 + .../analog_comparator/CMakeLists.txt | 8 + .../peripherals/analog_comparator/README.md | 144 ++++++++++++++++++ .../peripherals/analog_comparator/ext_ref.png | Bin 0 -> 9204 bytes .../analog_comparator/hysteresis_ref.png | Bin 0 -> 8042 bytes .../analog_comparator/main/CMakeLists.txt | 2 + .../analog_comparator/main/Kconfig.projbuild | 28 ++++ .../main/ana_cmpr_example_main.c | 140 +++++++++++++++++ .../pytest_ana_cmpr_example.py | 26 ++++ .../analog_comparator/sdkconfig.ci.ext | 2 + .../analog_comparator/sdkconfig.ci.intl | 2 + .../analog_comparator/static_50p_ref.png | Bin 0 -> 9600 bytes 28 files changed, 747 insertions(+), 8 deletions(-) create mode 100644 components/driver/test_apps/analog_comparator/CMakeLists.txt create mode 100644 components/driver/test_apps/analog_comparator/README.md create mode 100644 components/driver/test_apps/analog_comparator/main/CMakeLists.txt create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c create mode 100644 components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c create mode 100644 components/driver/test_apps/analog_comparator/main/test_app_main.c create mode 100644 components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py create mode 100644 components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe create mode 100644 components/driver/test_apps/analog_comparator/sdkconfig.ci.release create mode 100644 components/driver/test_apps/analog_comparator/sdkconfig.defaults create mode 100644 examples/peripherals/analog_comparator/CMakeLists.txt create mode 100644 examples/peripherals/analog_comparator/README.md create mode 100644 examples/peripherals/analog_comparator/ext_ref.png create mode 100644 examples/peripherals/analog_comparator/hysteresis_ref.png create mode 100644 examples/peripherals/analog_comparator/main/CMakeLists.txt create mode 100644 examples/peripherals/analog_comparator/main/Kconfig.projbuild create mode 100644 examples/peripherals/analog_comparator/main/ana_cmpr_example_main.c create mode 100644 examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py create mode 100644 examples/peripherals/analog_comparator/sdkconfig.ci.ext create mode 100644 examples/peripherals/analog_comparator/sdkconfig.ci.intl create mode 100644 examples/peripherals/analog_comparator/static_50p_ref.png diff --git a/components/driver/.build-test-rules.yml b/components/driver/.build-test-rules.yml index 7aefd1f0ab..fc4e3f03bd 100644 --- a/components/driver/.build-test-rules.yml +++ b/components/driver/.build-test-rules.yml @@ -1,5 +1,9 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps +components/driver/test_apps/analog_comparator: + disable: + - if: SOC_ANA_CMPR_SUPPORTED != 1 + components/driver/test_apps/dac_test_apps/dac: disable: - if: SOC_DAC_SUPPORTED != 1 diff --git a/components/driver/analog_comparator/ana_cmpr.c b/components/driver/analog_comparator/ana_cmpr.c index c042455668..1054550bb8 100644 --- a/components/driver/analog_comparator/ana_cmpr.c +++ b/components/driver/analog_comparator/ana_cmpr.c @@ -20,6 +20,7 @@ #include "esp_pm.h" #include "esp_heap_caps.h" #include "esp_intr_alloc.h" +#include "esp_memory_utils.h" #include "soc/periph_defs.h" #include "soc/ana_cmpr_periph.h" #include "hal/ana_cmpr_ll.h" @@ -30,6 +31,7 @@ struct ana_cmpr_t { ana_cmpr_unit_t unit; /*!< Analog comparator unit id */ analog_cmpr_dev_t *dev; /*!< Analog comparator unit device address */ + ana_cmpr_ref_source_t ref_src; /*!< Analog comparator reference source, internal or external */ bool is_enabled; /*!< Whether the Analog comparator unit is enabled */ ana_cmpr_event_callbacks_t cbs; /*!< The callback group that set by user */ intr_handle_t intr_handle; /*!< Interrupt handle */ @@ -46,9 +48,11 @@ struct ana_cmpr_t { /* Memory allocation caps which decide the section that memory supposed to allocate */ #if CONFIG_ANA_CMPR_ISR_IRAM_SAFE -#define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM) #else -#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#define ANA_CMPR_INTR_FLAG ESP_INTR_FLAG_LEVEL1 #endif /* Driver tag */ @@ -99,6 +103,7 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * /* Assign analog comparator unit */ s_ana_cmpr[unit]->dev = ANALOG_CMPR_LL_GET_HW(); + s_ana_cmpr[unit]->ref_src = config->ref_src; s_ana_cmpr[unit]->is_enabled = false; s_ana_cmpr[unit]->pm_lock = NULL; @@ -124,7 +129,7 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * portEXIT_CRITICAL(&s_spinlock); /* Allocate the interrupt, currently the interrupt source of Analog Comparator is shared with GPIO interrupt source */ - esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, + esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ANA_CMPR_INTR_FLAG, s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle); if (config->ref_src == ANA_CMPR_REF_SRC_INTERNAL) { @@ -183,11 +188,13 @@ esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_int { ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr); ANA_CMPR_NULL_POINTER_CHECK_ISR(ref_cfg); + ESP_RETURN_ON_FALSE_ISR(cmpr->ref_src == ANA_CMPR_REF_SRC_INTERNAL, ESP_ERR_INVALID_STATE, + TAG, "the reference channel is not internal, no need to configure internal reference"); /* Set internal reference voltage */ - portENTER_CRITICAL_ISR(&s_spinlock); + portENTER_CRITICAL_SAFE(&s_spinlock); analog_cmpr_ll_set_internal_ref_voltage(cmpr->dev, ref_cfg->ref_volt); - portEXIT_CRITICAL_ISR(&s_spinlock); + portEXIT_CRITICAL_SAFE(&s_spinlock); ESP_EARLY_LOGD(TAG, "unit %d internal voltage level %"PRIu32, (int)cmpr->unit, ref_cfg->ref_volt); @@ -202,9 +209,9 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_ /* Transfer the time to clock cycles */ uint32_t wait_cycle = (uint32_t)(dbc_cfg->wait_us * cmpr->src_clk_freq_hz) / 1000000; /* Set the waiting clock cycles */ - portENTER_CRITICAL_ISR(&s_spinlock); + portENTER_CRITICAL_SAFE(&s_spinlock); analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle); - portEXIT_CRITICAL_ISR(&s_spinlock); + portEXIT_CRITICAL_SAFE(&s_spinlock); ESP_EARLY_LOGD(TAG, "unit %d debounce wait cycle %"PRIu32, (int)cmpr->unit, wait_cycle); @@ -217,6 +224,12 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm ANA_CMPR_NULL_POINTER_CHECK(cbs); ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, "please disable the analog comparator before registering the callbacks"); +#if CONFIG_ANA_CMPR_ISR_IRAM_SAFE + if (cbs->on_cross) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_cross), ESP_ERR_INVALID_ARG, TAG, + "ANA_CMPR_ISR_IRAM_SAFE enabled but the callback function not in IRAM"); + } +#endif /* Save the callback group */ memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t)); diff --git a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h index d2ea26fc74..8f96c25a3c 100644 --- a/components/driver/analog_comparator/include/driver/ana_cmpr_types.h +++ b/components/driver/analog_comparator/include/driver/ana_cmpr_types.h @@ -90,7 +90,7 @@ typedef int ana_cmpr_clk_src_t; * */ typedef struct { - // Currently no data + // No data for now } ana_cmpr_cross_event_data_t; /** diff --git a/components/driver/test_apps/analog_comparator/CMakeLists.txt b/components/driver/test_apps/analog_comparator/CMakeLists.txt new file mode 100644 index 0000000000..1b4500c607 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/CMakeLists.txt @@ -0,0 +1,18 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_ana_cmpr) + +if(CONFIG_COMPILER_DUMP_RTL_FILES) + add_custom_target(check_test_app_sections ALL + COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py + --rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/driver/ + --elf-file ${CMAKE_BINARY_DIR}/test_ana_cmpr.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/driver/test_apps/analog_comparator/README.md b/components/driver/test_apps/analog_comparator/README.md new file mode 100644 index 0000000000..8161d00f6d --- /dev/null +++ b/components/driver/test_apps/analog_comparator/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32-H2 | +| ----------------- | -------- | diff --git a/components/driver/test_apps/analog_comparator/main/CMakeLists.txt b/components/driver/test_apps/analog_comparator/main/CMakeLists.txt new file mode 100644 index 0000000000..beb627afb1 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/CMakeLists.txt @@ -0,0 +1,11 @@ +set(srcs "test_app_main.c" + "test_ana_cmpr_common.c" + "test_ana_cmpr.c") + +if(CONFIG_ANA_CMPR_ISR_IRAM_SAFE) + list(APPEND srcs "test_ana_cmpr_iram.c") +endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + WHOLE_ARCHIVE) diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c new file mode 100644 index 0000000000..18389f407b --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_ana_cmpr.h" + +TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]") +{ + ana_cmpr_handle_t cmpr = NULL; + ana_cmpr_config_t config = { + .unit = SOC_ANA_CMPR_NUM, // Set a wrong unit + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + /* Allocate a wrong unit */ + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ana_cmpr_new_unit(&config, &cmpr)); + /* Allocate a correct unit */ + config.unit = ANA_CMPR_UNIT_0; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + /* Try to allocate a existed unit */ + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_new_unit(&config, &cmpr)); + /* Set the internal reference before enable */ + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + /* Enable the unit */ + TEST_ESP_OK(ana_cmpr_enable(cmpr)); + /* Set the internal reference after enable */ + ref_cfg.ref_volt = ANA_CMPR_REF_VOLT_30_PCT_VDD; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + /* Try tp delete unit after enable */ + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_del_unit(cmpr)); + /* Disable the unit */ + TEST_ESP_OK(ana_cmpr_disable(cmpr)); + /* Try to delete the unit with a wrong handle */ + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_del_unit((void *)&cmpr)); + /* Delete the unit */ + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); + + /* Try to set internal reference for a external unit */ + config.ref_src = ANA_CMPR_REF_SRC_EXTERNAL; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); +} + +TEST_CASE("ana_cmpr_internal_reference", "[ana_cmpr]") +{ + int src_chan = test_init_src_chan_gpio(); + uint32_t cnt = 0; + + ana_cmpr_handle_t cmpr = NULL; + ana_cmpr_config_t config = { + .unit = ANA_CMPR_UNIT_0, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + ana_cmpr_debounce_config_t dbc_cfg = { + .wait_us = 10.0, + }; + TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &dbc_cfg)); + ana_cmpr_event_callbacks_t cbs = { + .on_cross = test_ana_cmpr_on_cross_callback, + }; + + TEST_ESP_OK(ana_cmpr_register_event_callbacks(cmpr, &cbs, &cnt)); + TEST_ESP_OK(ana_cmpr_enable(cmpr)); + cnt = 0; + for (int i = 1; i <= 10; i++) { + test_simulate_src_signal(src_chan, i % 2); + esp_rom_delay_us(100); + TEST_ASSERT(cnt == i); + } + TEST_ESP_OK(ana_cmpr_disable(cmpr)); + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); +} diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h new file mode 100644 index 0000000000..13566bfc84 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr.h @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_rom_sys.h" +#include "soc/soc_caps.h" +#include "driver/ana_cmpr.h" + +/** + * @brief Test default on cross callback + * + * @param cmpr Analog Comparator handle + * @param edata Event data + * @param user_ctx User context, need to input a unint32_t counter + * @return + * - true Need to yield + * - false Don't need yield + */ +bool test_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana_cmpr_cross_event_data_t *edata, void *user_ctx); + +/** + * @brief Initialize Analog Comparator source channel GPIO + * + * @return + * - int Source channel GPIO number + */ +int test_init_src_chan_gpio(void); + +/** + * @brief Simulate source channel signal + * + * @param src_chan Source channel GPIO number + * @param val 0 to set low, others to set high + */ +void test_simulate_src_signal(int src_chan, uint32_t val); diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c new file mode 100644 index 0000000000..9db12a0d07 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_common.c @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_ana_cmpr.h" +#include "hal/gpio_ll.h" +#include "driver/gpio.h" +#include "esp_attr.h" + +bool IRAM_ATTR test_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana_cmpr_cross_event_data_t *edata, void *user_ctx) +{ + uint32_t *count = (uint32_t *)user_ctx; + (*count)++; + return false; +} + +int test_init_src_chan_gpio(void) +{ + int src_chan_num = -1; + TEST_ESP_OK(ana_cmpr_get_gpio(ANA_CMPR_UNIT_0, ANA_CMPR_SOURCE_CHAN, &src_chan_num)); + TEST_ASSERT(src_chan_num > 0); + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << src_chan_num), + .pull_down_en = false, + .pull_up_en = false, + }; + TEST_ESP_OK(gpio_config(&io_conf)); + TEST_ESP_OK(gpio_set_level(src_chan_num, 0)); + return src_chan_num; +} + +void IRAM_ATTR test_simulate_src_signal(int src_chan, uint32_t val) +{ + gpio_set_level(src_chan, val); +} diff --git a/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c new file mode 100644 index 0000000000..3b929fb267 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_ana_cmpr_iram.c @@ -0,0 +1,76 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_ana_cmpr.h" +#include "unity_test_utils.h" +#include "unity_test_utils_cache.h" + +typedef struct { + ana_cmpr_handle_t handle; + uint32_t count; + int src_chan; +} test_ana_cmpr_data_t; + +/** + * @brief Global debounce configuration + * @note Why it is global? + * If we declare a local variable in 'float' type when cache disabled, + * it may be allocated in the flash, which can lead crash when trying to access it. + */ +static ana_cmpr_debounce_config_t IRAM_ATTR s_dbc_cfg = { + .wait_us = 1.0, +}; + +static void IRAM_ATTR test_ana_cmpr_iram_safety(void *args) +{ + test_ana_cmpr_data_t *data = (test_ana_cmpr_data_t *)args; + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + ana_cmpr_set_intl_reference(data->handle, &ref_cfg); + ana_cmpr_set_debounce(data->handle, &s_dbc_cfg); + data->count = 0; + for (int i = 1; i <= 10; i++) { + test_simulate_src_signal(data->src_chan, i % 2); + esp_rom_delay_us(100); + } +} + +TEST_CASE("ana_cmpr_internal_reference_iram_safe", "[ana_cmpr]") +{ + test_ana_cmpr_data_t test_data = { + .handle = NULL, + .count = 0, + .src_chan = -1, + }; + test_data.src_chan = test_init_src_chan_gpio(); + + ana_cmpr_handle_t cmpr = NULL; + ana_cmpr_config_t config = { + .unit = ANA_CMPR_UNIT_0, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr)); + test_data.handle = cmpr; + ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, + }; + TEST_ESP_OK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); + TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &s_dbc_cfg)); + ana_cmpr_event_callbacks_t cbs = { + .on_cross = test_ana_cmpr_on_cross_callback, + }; + TEST_ESP_OK(ana_cmpr_register_event_callbacks(cmpr, &cbs, &test_data.count)); + TEST_ESP_OK(ana_cmpr_enable(cmpr)); + + unity_utils_run_cache_disable_stub(test_ana_cmpr_iram_safety, &test_data); + TEST_ASSERT_EQUAL_INT(test_data.count, 10); + + TEST_ESP_OK(ana_cmpr_disable(cmpr)); + TEST_ESP_OK(ana_cmpr_del_unit(cmpr)); +} diff --git a/components/driver/test_apps/analog_comparator/main/test_app_main.c b/components/driver/test_apps/analog_comparator/main/test_app_main.c new file mode 100644 index 0000000000..9b6762fcc8 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/main/test_app_main.c @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +// Some resources are lazy allocated in analog comparator driver, the threshold is left for that case +#define TEST_MEMORY_LEAK_THRESHOLD (-300) + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + +// _ _ _ _ ____ __ __ ____ ____ _____ _ +// / \ | \ | | / \ / ___| \/ | _ \| _ \ |_ _|__ ___| |_ +// / _ \ | \| | / _ \ | | | |\/| | |_) | |_) | | |/ _ \/ __| __| +// / ___ \| |\ |/ ___ \ | |___| | | | __/| _ < | | __/\__ \ |_ +// /_/ \_\_| \_/_/ \_\ \____|_| |_|_| |_| \_\ |_|\___||___/\__| + + printf(" _ _ _ _ ____ __ __ ____ ____ _____ _ \n"); + printf(" / \\ | \\ | | / \\ / ___| \\/ | _ \\| _ \\ |_ _|__ ___| |_ \n"); + printf(" / _ \\ | \\| | / _ \\ | | | |\\/| | |_) | |_) | | |/ _ \\/ __| __|\n"); + printf(" / ___ \\| |\\ |/ ___ \\ | |___| | | | __/| _ < | | __/\\__ \\ |_ \n"); + printf(" /_/ \\_\\_| \\_/_/ \\_\\ \\____|_| |_|_| |_| \\_\\ |_|\\___||___/\\__|\n"); + printf("\n"); + unity_run_menu(); +} diff --git a/components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py b/components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py new file mode 100644 index 0000000000..1cc5cf4971 --- /dev/null +++ b/components/driver/test_apps/analog_comparator/pytest_ana_cmpr.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32h2 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'iram_safe', + 'release', + ], + indirect=True, +) +def test_ana_cmpr(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe b/components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe new file mode 100644 index 0000000000..9d68c306bf --- /dev/null +++ b/components/driver/test_apps/analog_comparator/sdkconfig.ci.iram_safe @@ -0,0 +1,7 @@ +CONFIG_COMPILER_DUMP_RTL_FILES=y +CONFIG_ANA_CMPR_ISR_IRAM_SAFE=y +CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM=y +CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y +CONFIG_COMPILER_OPTIMIZATION_NONE=y +# place non-ISR FreeRTOS functions in Flash +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y diff --git a/components/driver/test_apps/analog_comparator/sdkconfig.ci.release b/components/driver/test_apps/analog_comparator/sdkconfig.ci.release new file mode 100644 index 0000000000..91d93f163e --- /dev/null +++ b/components/driver/test_apps/analog_comparator/sdkconfig.ci.release @@ -0,0 +1,5 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/driver/test_apps/analog_comparator/sdkconfig.defaults b/components/driver/test_apps/analog_comparator/sdkconfig.defaults new file mode 100644 index 0000000000..b308cb2ddd --- /dev/null +++ b/components/driver/test_apps/analog_comparator/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n diff --git a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h index 31e0026cd2..ffedbfde61 100644 --- a/components/hal/esp32h2/include/hal/ana_cmpr_ll.h +++ b/components/hal/esp32h2/include/hal/ana_cmpr_ll.h @@ -38,6 +38,7 @@ static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en) * @param hw Analog comparator register base address * @param volt_level The voltage level of the internal reference, range [0.0V, 0.7VDD], step 0.1VDD */ +__attribute__((always_inline)) static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, uint32_t volt_level) { hw->pad_comp_config.dref_comp = volt_level; @@ -90,6 +91,7 @@ static inline void analog_cmpr_ll_set_cross_intr_type(analog_cmpr_dev_t *hw, uin * @param hw Analog comparator register base address * @param cycle The debounce cycle */ +__attribute__((always_inline)) static inline void analog_cmpr_ll_set_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle) { hw->pad_comp_filter.zero_det_filter_cnt = cycle; @@ -116,6 +118,7 @@ static inline void analog_cmpr_ll_enable_intr(analog_cmpr_dev_t *hw, uint32_t ma * * @param hw Analog comparator register base address */ +__attribute__((always_inline)) static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) { return hw->int_st.val; @@ -127,6 +130,7 @@ static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw) * @param hw Analog comparator register base address * @param mask Interrupt status word */ +__attribute__((always_inline)) static inline void analog_cmpr_ll_clear_intr(analog_cmpr_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 6d8c66f57d..28b1931547 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -8,6 +8,10 @@ examples/peripherals/adc/oneshot_read: disable: - if: SOC_ADC_SUPPORTED != 1 +examples/peripherals/analog_comparator: + disable: + - if: SOC_ANA_CMPR_SUPPORTED != 1 + examples/peripherals/dac: disable: - if: SOC_DAC_SUPPORTED != 1 diff --git a/examples/peripherals/analog_comparator/CMakeLists.txt b/examples/peripherals/analog_comparator/CMakeLists.txt new file mode 100644 index 0000000000..fa9f99dcd0 --- /dev/null +++ b/examples/peripherals/analog_comparator/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(analog_comparator_example) diff --git a/examples/peripherals/analog_comparator/README.md b/examples/peripherals/analog_comparator/README.md new file mode 100644 index 0000000000..8a6adb523c --- /dev/null +++ b/examples/peripherals/analog_comparator/README.md @@ -0,0 +1,144 @@ +| Supported Targets | ESP32-H2 | +| ----------------- | -------- | + +# Analog Comparator Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example is going to show how to use the Analog Comparator. + +## How to Use Example + +### Hardware Requirement + +* A development board with any supported Espressif SOC chip (see `Supported Targets` table above) +* A USB cable for power supply and programming +* A device to generate the source signal. For example, you can use a ESP SoC that support DAC peripheral (like ESP32 or ESP32S2) to generate source signal, or just use a signal generator. + +#### Required Additionally for External Reference + +* One more external signal for the reference. You can input a static voltage or a wave, for example, the static voltage can be gotten by the resistor divider, and the wave can be generated by either ESP SoC or a signal generator. + +### Example Connection + +Let's take ESP32-H2 and ESP32 for example, and we use the DAC on ESP32 as the signal generator (you can use a real signal generator instead if you have one). + +#### Internal Reference + +Download this example into ESP32-H2 and any DAC examples in `examples/peripherals/dac` directory into ESP32. + +``` + ┌──────────────┐ ┌──────────────┐ + │ ESP32-H2 │ │ ESP32 │ + │ │ source signal │ │ +┌────┤GPIO0 GPIO11│◄────┬──────────┤GPIO25 │ +│ │ │ │ │ │ +│ │ GND├─────┼────┬─────┤GND │ +│ │ │ │ │ │ │ +│ └──────────────┘ │ │ └──────────────┘ +│ │ │ +│ ┌──────────────┐ │ │ +│ │ Oscilloscope │ │ │ +│ │ │ │ │ +└───►│Probe1 Probe2│◄────┘ │ + │ │ │ + │ GND├──────────┘ + │ │ + └──────────────┘ +``` + +#### External Reference + +For the static external reference, we can use resistor divider to get the static voltage. + +``` + ┌──────────────┐ ┌──────────────┐ + │ ESP32-H2 │ │ ESP32 │ + │ │ source signal │ │ +┌────┤GPIO0 GPIO11│◄────┬──────────┤GPIO25 │ +│ │ │ ref│signal │ │ +│ │ GPIO10│◄────┼──────┐ ┌─┤GND │ +│ │ │ │ │ │ │ │ +│ │ GND├─────┼─┬────┼─┘ └──────────────┘ +│ │ │ │ │ │ VDD +│ └──────────────┘ │ │ │ ─┬─ +│ │ │ │ │ +│ │ │ │ ├┐ +│ ┌──────────────┐ │ │ │ ││R1 +│ │ Oscilloscope │ │ │ │ ├┘ +│ │ │ │ │ └──────────┤ +└───►│Probe1 Probe2│◄────┘ │ │ + │ │ │ ├┐ + │ GND├───────┤ ││R2 + │ │ │ ├┘ + └──────────────┘ │ │ + └───────────────┤ + │ + ─┴─ + GND +``` + +Also, we can generate a different signal on another DAC channel on ESP32, you can customize your DAC wave using `examples/peripherals/dac/dac_continuous/signal_generator` example. + +``` + ┌──────────────┐ ┌──────────────┐ + │ ESP32-H2 │ │ ESP32 │ + │ │ source signal │ │ +┌────┤GPIO0 GPIO11│◄────┬──────────┤GPIO25 │ +│ │ │ ref│signal │ │ +│ │ GPIO10│◄────┼──────────┤GPIO26 │ +│ │ │ │ │ │ +│ │ GND├─────┼───┬──────┤GND │ +│ │ │ │ │ │ │ +│ └──────────────┘ │ │ └──────────────┘ +│ │ │ +│ │ │ +│ ┌──────────────┐ │ │ +│ │ Oscilloscope │ │ │ +│ │ │ │ │ +└───►│Probe1 Probe2│◄────┘ │ + │ │ │ + │ GND├─────────┘ + │ │ + └──────────────┘ +``` + +### Configure the Project + +You can decide to adopt internal reference or external reference in the example menu config, and you can also enable hysteresis comparator for the internal reference in the menu config. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT build flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +### Static Internal Reference + +The internal voltage is set to 50% VDD, and input a 50 Hz sine wave as source signal (blue line), the output GPIO toggles every time the sine wave crossing the reference voltage (yellow line) + +![static_intl_ref](./static_50p_ref.png) + +### Hysteresis Internal Reference + +The internal voltage is set to 30% VDD and 70% VDD alternately in this case, the source signal is a 100 Hz sine wave (blue line), the output GPIO toggles every time the source signal exceed 70% VDD and lower than 30% VDD. + +![hysteresis_cmpr](./hysteresis_ref.png) + +### External Reference + +Here we input a 100 Hz sine wave (blue line) as the source signal and input a 1 KHz triangle wave as the reference signal, the output wave (yellow line) can be regarded as a SPWM (Sinusoidal PWM) wave. + +![ext_ref](./ext_ref.png) + +## Troubleshooting + +For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/analog_comparator/ext_ref.png b/examples/peripherals/analog_comparator/ext_ref.png new file mode 100644 index 0000000000000000000000000000000000000000..e73485331ea13356dbb79aa9ffd6bcbd21e8dac2 GIT binary patch literal 9204 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 CLS@+i literal 0 HcmV?d00001 diff --git a/examples/peripherals/analog_comparator/hysteresis_ref.png b/examples/peripherals/analog_comparator/hysteresis_ref.png new file mode 100644 index 0000000000000000000000000000000000000000..e2707f6db71b95aa01354f9fe820e903846fc323 GIT binary patch literal 8042 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 +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "driver/ana_cmpr.h" +#include "esp_log.h" + +#define EXAMPLE_ANA_CMPR_UNIT ANA_CMPR_UNIT_0 // Analog Comparator unit +#define EXAMPLE_WAIT_TIME_PROP (0.1) // The wait time proportion in one relative signal period +#define EXAMPLE_WAITE_TIME_US(freq_approx) (1000000.0 * EXAMPLE_WAIT_TIME_PROP / (freq_approx)) + +#define EXAMPLE_MONITOR_GPIO_NUM (0) // The gpio to monitor the on cross callback + +static const char *TAG = "ana_cmpr_example"; + +static bool IRAM_ATTR example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, + const ana_cmpr_cross_event_data_t *edata, + void *user_ctx) +{ +#if CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR + static ana_cmpr_intl_ref_config_t ref_cfg = { + .ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD, + }; + bool is_70p = ref_cfg.ref_volt == ANA_CMPR_REF_VOLT_70_PCT_VDD; + /* Toggle the GPIO, monitor the gpio on a oscilloscope. */ + gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, is_70p); + /* Set the internal reference voltage to 30% VDD and 70 %VDD alternately */ + ana_cmpr_set_intl_reference(cmpr, &ref_cfg); + ref_cfg.ref_volt = is_70p ? ANA_CMPR_REF_VOLT_30_PCT_VDD : ANA_CMPR_REF_VOLT_70_PCT_VDD; +#else + static int lvl = 0; + /* Toggle the GPIO, monitor the gpio on a oscilloscope. */ + gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, lvl); + lvl = !lvl; +#endif + return false; +} + +void example_init_analog_comparator(void) +{ + /* Step 0: Show the source channel and reference channel GPIO */ + int src_gpio = -1; + int ext_ref_gpio = -1; + ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio)); + ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio)); + ESP_LOGI(TAG, "Analog Comparator source gpio %d, external reference gpio %d", src_gpio, ext_ref_gpio); + + ana_cmpr_handle_t cmpr = NULL; + +#if CONFIG_EXAMPLE_INTERNAL_REF + /* Step 1: Allocate the new analog comparator unit */ + ana_cmpr_config_t config = { + .unit = EXAMPLE_ANA_CMPR_UNIT, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_INTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); + ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference"); + + /* Step 1.1: As we are using the internal reference source, we need to configure the internal reference */ + ana_cmpr_intl_ref_config_t ref_cfg = { +#if CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR + /* Set the initial internal reference voltage to 70% VDD, it will be updated in the callback every time the interrupt triggered */ + .ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD +#else + .ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD, +#endif + }; + ESP_ERROR_CHECK(ana_cmpr_set_intl_reference(cmpr, &ref_cfg)); +#else + /* Step 1: Allocate the new analog comparator unit */ + ana_cmpr_config_t config = { + .unit = EXAMPLE_ANA_CMPR_UNIT, + .clk_src = ANA_CMPR_CLK_SRC_DEFAULT, + .ref_src = ANA_CMPR_REF_SRC_EXTERNAL, + .intr_type = ANA_CMPR_INTR_ANY_CROSS, + }; + ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr)); + ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference"); +#endif + + /* Step 2: (Optional) Set the debounce configuration + * It's an optional configuration, if the wait time is set in debounce configuration, + * the cross interrupt will be disabled temporary after it is triggered, and it will be enabled + * automatically enabled after `wait_us`, so that the duplicate interrupts + * can be suppressed while the source signal crossing the reference signal. */ + ana_cmpr_debounce_config_t dbc_cfg = { + /* Normally the `wait_us` is related to how fast the source signal or reference signal changes + * comparing to another one. This example adopts an approximate frequency as the relative signal + * frequency, and set the default wait time to EXAMPLE_WAIT_TIME_PROP of the relative signal period. + * We need to estimate an appropriate `freq_approx` and EXAMPLE_WAIT_TIME_PROP + * to make sure the interrupt neither triggers duplicate interrupts, nor misses the next crossing interrupt. + * Here we take 1 KHz for example */ + .wait_us = EXAMPLE_WAITE_TIME_US(1000), + }; + ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg)); + + /* Step 3: Register the event callbacks */ + ana_cmpr_event_callbacks_t cbs = { + .on_cross = example_ana_cmpr_on_cross_callback, + }; + ESP_ERROR_CHECK(ana_cmpr_register_event_callbacks(cmpr, &cbs, NULL)); + + /* Step 4: Enable the analog comparator unit */ + ESP_ERROR_CHECK(ana_cmpr_enable(cmpr)); + +#if CONFIG_EXAMPLE_INTERNAL_REF + ESP_LOGI(TAG, "Analog comparator enabled, reference voltage: %d%% * VDD", (int)ref_cfg.ref_volt * 10); +#else + ESP_LOGI(TAG, "Analog comparator enabled, external reference selected"); +#endif +} + +void example_init_monitor_gpio(void) +{ + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << EXAMPLE_MONITOR_GPIO_NUM), + .pull_down_en = false, + .pull_up_en = false, + }; + gpio_config(&io_conf); + gpio_set_level(EXAMPLE_MONITOR_GPIO_NUM, 0); +} + +void app_main(void) +{ + /* Initialize GPIO to monitor the comparator interrupt */ + example_init_monitor_gpio(); + /* Initialize Analog Comparator */ + example_init_analog_comparator(); +} diff --git a/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py b/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py new file mode 100644 index 0000000000..a5bba766e5 --- /dev/null +++ b/examples/peripherals/analog_comparator/pytest_ana_cmpr_example.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32h2 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'intl', + 'ext', + ], + indirect=True, +) +def test_ana_cmpr_example(dut: Dut) -> None: + sdkconfig = dut.app.sdkconfig + dut.expect('ana_cmpr_example: Analog Comparator source gpio 11, external reference gpio 10', timeout=10) + if sdkconfig['EXAMPLE_INTERNAL_REF']: + dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10) + dut.expect(r'ana_cmpr_example: Analog comparator enabled, reference voltage: [0-9]+% \* VDD', timeout=10) + elif sdkconfig['EXAMPLE_EXTERNAL_REF']: + dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10) + dut.expect('ana_cmpr_example: Analog comparator enabled, external reference selected', timeout=10) diff --git a/examples/peripherals/analog_comparator/sdkconfig.ci.ext b/examples/peripherals/analog_comparator/sdkconfig.ci.ext new file mode 100644 index 0000000000..3ec04884ce --- /dev/null +++ b/examples/peripherals/analog_comparator/sdkconfig.ci.ext @@ -0,0 +1,2 @@ +CONFIG_EXAMPLE_INTERNAL_REF=n +CONFIG_EXAMPLE_EXTERNAL_REF=y diff --git a/examples/peripherals/analog_comparator/sdkconfig.ci.intl b/examples/peripherals/analog_comparator/sdkconfig.ci.intl new file mode 100644 index 0000000000..ae9cdfdb82 --- /dev/null +++ b/examples/peripherals/analog_comparator/sdkconfig.ci.intl @@ -0,0 +1,2 @@ +CONFIG_EXAMPLE_INTERNAL_REF=y +CONFIG_EXAMPLE_EXTERNAL_REF=n diff --git a/examples/peripherals/analog_comparator/static_50p_ref.png b/examples/peripherals/analog_comparator/static_50p_ref.png new file mode 100644 index 0000000000000000000000000000000000000000..202b0ad680ad86c5867791f4c6e460a544c98cd9 GIT binary patch literal 9600 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 V}>F7L*K5?Rlakk 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 z z47Kqq?|l^=0d{@`GrOY)!Cl@7q6%hqwkH%8z9>HmnxN>Y@M6&Y6^Ny8$#P+lyePz3 znvyCxiW?VpH}guWm>f~mcF3uzn&9Yk@qHJjm8uP5e^+2}p^?W8(DWfYXjY}eIjrHv zk1q<%EsO5MtYF;o!kvJNUhxT8wR17ce%SP)TTEA}UuE$=CmE@U#S{7bI~TZGMkVe0 z`fv3mV|Syjwfh!juv}P_QtNuwE^LPDq`)&r_cwq9KCZvk?#=L5^ijM6Q%2yXkgajo zOSiJ^?3sD4R4RLJ;@tAIX@9a$vwhj+=DX4T%Ou0gJ7>L*PoBKE%k!=IvS%&VJ#7!% zXWe4sxni}kbi~@PWlO~*jpx2LnWnVTG2*ZL$^Cwk4c|6e%)V&W#+1V~<>%o}zl3Hm}e%wi1i(AY*%@o42~wTS}%Y{N8To&c^8~>%|z=-%zu0 z!@u{6u`(YdZ@;qV$ltvB?$L)lW^YU1$nV=!kXO<1D7#O#;i_cK*1Y!nj4l{ZIC{#!1svYg_j%%1D{8p>@}m z#J&3hw|E-8(!R20=@U;jPFGi}UA3Jqu2#DkT|F6ePhH%8C4b_HnV~dISbF_=o~HYPrc*sR>wW-{0zIxamOQWxlKAb^$D{{ zJDYZM%OW4$qvzvg&hbs1HJSC52Gi>a(VskxcFwCaZ?gNf!>rIk*s0uX+NSF=w{hoUE>SIHJR3B>)fGW}zr zIx{AeDWjcWMhWAMS>g)QUi}I5^}J9zMw_c zPkqwKuU~dIOk4SQrN9L*_DzRp{>b~0nI9KD>160uozoB3W|l8v-{Mp2f0kkGwpABn z=61d|ep~y<@UpDo_o;lgrA>u>B=N!!EaGsU)E zG!M&|ctX9$v%hTOn$$>^3rg)Q7Z%OC!nuHR_klUt@A_WdT72nFN!0Zjnp$g98Fycj zFn(Lwv$QmY*=lPZOP;}ns|%*=U!j$jQsjBuWap%J_cLZbw`G`BAP}jqe*eq|s{=w8 z7{%0$qe8{i3qHD6$Y!v==-DM0Ic2N&&+b)8iE8qCcQ?#R{-6CPZ}M}t1=qu0tyZh8 zeJ+!J%HsZXznyP+FHB5-dBxc5f0&@Y{M=r7%fc;xXA3X*{HiT>N>%6WFDrGQ>*cII z_x1J-?K3G`m;IG~^?dWYc7Y2a+e8=e_E=SB>F`bnKfC{9Wv;CT)G|Y~p>H>QpC( z{X!+ow-&73cV*tn^?#-|luZ)Hl z3+5WX7Tpzh_C}a%ltc4#hT9CcwtxR%^~3+Bq6+I@vDKWLr#f`h^QOrPrm z5?R#C9gMF9)y$4{*dNo%ly!lj-t0EB;Fi1Wxo5VB|9lqyrn&B|a@Ma@)<;kCUhs(U zuj()gv7TJNt%1j(zI$5g#ObP?KDzV7Z*{udU-8sB{$K01r=^RPg1<#CbY1lR>h!QQ clRx}