From 5b523a33136a09fd0b1d98da34a1eae9d6fcf4da Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 15 Jul 2022 12:52:44 +0800 Subject: [PATCH] esp_adc: new esp_adc component and adc drivers --- .gitlab/CODEOWNERS | 2 +- components/driver/CMakeLists.txt | 21 +- components/driver/Kconfig | 59 +- components/driver/adc_deprecated.c | 640 ----------------- .../driver/{ => deprecated}/adc1_private.h | 0 .../{adc.c => deprecated/adc_dma_legacy.c} | 586 ++++------------ .../driver/deprecated/adc_i2s_deprecated.c | 252 +++++++ .../{adc_single.c => deprecated/adc_legacy.c} | 535 +++++++++----- .../{include => deprecated}/driver/adc.h | 322 +-------- .../driver/deprecated/driver/adc_deprecated.h | 163 ----- .../driver/deprecated/driver/adc_i2s_legacy.h | 51 ++ .../deprecated/driver/adc_types_deprecated.h | 203 ------ .../deprecated/driver/adc_types_legacy.h | 128 ++++ components/driver/deprecated/i2s_legacy.c | 6 +- components/driver/esp32/adc.c | 77 --- components/driver/esp32s2/adc.c | 135 ---- components/driver/i2s/i2s_common.c | 1 + components/driver/include/driver/adc_common.h | 11 - .../driver/include/esp_private/adc_cali.h | 32 - components/driver/test/CMakeLists.txt | 4 +- .../driver/test/adc_dma_test/test_esp32s2.c | 654 ------------------ .../driver/test/dac_dma_test/test_esp32s2.c | 1 - .../test/include/test/test_common_adc.h | 2 +- components/driver/test/test_adc.c | 608 ---------------- components/driver/test/test_adc2_with_wifi.c | 7 +- components/driver/test/test_adc_common.c | 394 ----------- components/driver/test/test_dac.c | 3 +- .../legacy_i2s_adc_dac/main/test_i2s_dac.c | 1 - .../legacy_i2s_adc_dac/sdkconfig.defaults | 1 + .../legacy_i2s_driver/sdkconfig.defaults | 1 + .../legacy_adc_driver/CMakeLists.txt | 5 + .../test_apps/legacy_adc_driver/README.md | 2 + .../legacy_adc_driver/main/CMakeLists.txt | 5 + .../legacy_adc_driver/main/test_app_main.c | 40 ++ .../legacy_adc_driver/main/test_legacy_adc.c | 129 ++++ .../legacy_adc_driver/pytest_legacy_adc.py | 24 + .../legacy_adc_driver/sdkconfig.ci.release | 5 + .../legacy_adc_driver/sdkconfig.defaults | 3 + .../efuse/esp32c3/esp_efuse_rtc_calib.c | 3 +- .../esp32c3/include/esp_efuse_rtc_calib.h | 3 +- components/esp_adc/CMakeLists.txt | 39 ++ components/esp_adc/Kconfig | 47 ++ components/esp_adc/adc_cali.c | 45 ++ components/esp_adc/adc_cali_curve_fitting.c | 247 +++++++ components/esp_adc/adc_common.c | 208 ++++++ components/esp_adc/adc_continuous.c | 630 +++++++++++++++++ components/esp_adc/adc_lock.c | 87 +++ components/esp_adc/adc_oneshot.c | 260 +++++++ .../esp_adc/curve_fitting_coefficients.h | 33 + .../deprecated/esp32/esp_adc_cal_legacy.c} | 7 +- .../deprecated/esp32c3/esp_adc_cal_legacy.c} | 18 +- .../deprecated/esp32s2/esp_adc_cal_legacy.c} | 5 +- .../deprecated/esp32s3/esp_adc_cal_legacy.c} | 7 +- .../deprecated/esp_adc_cal_common_legacy.c} | 11 +- .../deprecated/esp_adc_cal_internal_legacy.h} | 0 .../deprecated}/include/esp_adc_cal.h | 46 +- .../include/esp_adc_cal_types_legacy.h | 50 ++ .../esp_adc/esp32/adc_cali_line_fitting.c | 435 ++++++++++++ .../esp_adc/esp32/include/adc_cali_schemes.h | 15 + .../esp32c2/include/adc_cali_schemes.h | 15 + .../esp32c3/adc2_init_cal.c | 16 +- .../esp32c3/curve_fitting_coefficients.c | 36 + .../esp32c3/include/adc_cali_schemes.h | 15 + .../esp32h2/include/adc_cali_schemes.h | 15 + .../esp32s2/adc2_init_cal.c | 16 +- .../esp_adc/esp32s2/adc_cali_line_fitting.c | 255 +++++++ .../esp32s2/include/adc_cali_schemes.h | 15 + .../esp32s3/curve_fitting_coefficients.c | 48 ++ .../esp32s3/include/adc_cali_schemes.h | 15 + components/esp_adc/include/esp_adc/adc_cali.h | 59 ++ .../esp_adc/include/esp_adc/adc_cali_scheme.h | 135 ++++ .../esp_adc/include/esp_adc/adc_continuous.h | 232 +++++++ .../esp_adc/include/esp_adc/adc_oneshot.h | 130 ++++ .../include/esp_private/adc2_wifi.h | 9 +- .../esp_adc/include/esp_private/adc_lock.h | 60 ++ .../esp_adc/include/esp_private/adc_private.h | 130 ++++ .../esp_adc/interface/adc_cali_interface.h | 46 ++ components/esp_adc/linker.lf | 5 + .../esp_adc/test_apps/adc/CMakeLists.txt | 20 + components/esp_adc/test_apps/adc/README.md | 2 + .../esp_adc/test_apps/adc/main/CMakeLists.txt | 11 + .../esp_adc/test_apps/adc/main/test_adc.c | 260 +++++++ .../test_apps/adc/main/test_adc_driver.c | 128 ++++ .../test_apps/adc/main/test_adc_driver_iram.c | 266 +++++++ .../test_apps/adc/main/test_adc_performance.c | 298 ++++++++ .../test_apps/adc/main/test_app_main.c | 40 ++ .../test_apps/adc/main/test_common_adc.c | 94 +++ .../test_apps/adc/main/test_common_adc.h | 107 +++ .../esp_adc/test_apps/adc/pytest_adc.py | 21 + .../test_apps/adc/sdkconfig.ci.iram_safe | 6 + .../test_apps/adc/sdkconfig.ci.release | 3 + .../esp_adc/test_apps/adc/sdkconfig.defaults | 2 + components/esp_adc_cal/CMakeLists.txt | 12 - components/esp_adc_cal/Kconfig | 31 - components/esp_phy/CMakeLists.txt | 2 +- components/esp_phy/src/phy_override.c | 3 +- components/esp_wifi/CMakeLists.txt | 2 +- components/esp_wifi/src/wifi_init.c | 1 + components/hal/CMakeLists.txt | 8 +- components/hal/adc_hal.c | 94 +-- components/hal/adc_hal_common.c | 9 +- components/hal/adc_oneshot_hal.c | 180 +++++ components/hal/esp32/adc_hal.c | 30 - components/hal/esp32/include/hal/adc_hal.h | 38 - components/hal/esp32/include/hal/adc_ll.h | 25 +- components/hal/esp32c2/include/hal/adc_ll.h | 610 +++------------- components/hal/esp32c3/adc_hal.c | 86 --- components/hal/esp32c3/include/hal/adc_hal.h | 82 --- components/hal/esp32c3/include/hal/adc_ll.h | 39 +- components/hal/esp32h2/include/hal/adc_ll.h | 23 +- components/hal/esp32s2/include/hal/adc_ll.h | 19 +- components/hal/esp32s3/include/hal/adc_ll.h | 19 +- components/hal/include/hal/adc_hal.h | 24 - components/hal/include/hal/adc_hal_common.h | 4 +- components/hal/include/hal/adc_oneshot_hal.h | 86 +++ components/hal/include/hal/adc_types.h | 167 +---- .../hal/include/hal/adc_types_private.h | 103 +++ components/hal/linker.lf | 16 + components/newlib/test/test_time.c | 5 +- .../soc/esp32/include/soc/Kconfig.soc_caps.in | 14 +- components/soc/esp32/include/soc/soc_caps.h | 14 +- .../esp32c2/include/soc/Kconfig.soc_caps.in | 10 +- .../soc/esp32c2/include/soc/adc_channel.h | 10 +- components/soc/esp32c2/include/soc/soc_caps.h | 6 +- .../esp32c3/include/soc/Kconfig.soc_caps.in | 16 + components/soc/esp32c3/include/soc/soc_caps.h | 4 + .../esp32h2/include/soc/Kconfig.soc_caps.in | 16 + .../soc/esp32h2/include/soc/adc_channel.h | 10 +- components/soc/esp32h2/include/soc/soc_caps.h | 6 +- .../esp32s2/include/soc/Kconfig.soc_caps.in | 16 + components/soc/esp32s2/include/soc/soc_caps.h | 4 + .../esp32s3/include/soc/Kconfig.soc_caps.in | 18 +- components/soc/esp32s3/include/soc/soc_caps.h | 6 +- components/ulp/CMakeLists.txt | 2 +- .../ulp/ulp_riscv/include/ulp_riscv_adc.h | 2 +- components/ulp/ulp_riscv/ulp_riscv_adc.c | 30 +- .../diagrams/adc/adc_conversion_frame.png | Bin 0 -> 14426 bytes docs/conf_common.py | 6 + docs/doxygen/Doxyfile | 6 +- docs/en/api-reference/peripherals/adc.rst | 463 ------------- .../peripherals/adc_calibration.rst | 184 +++++ .../peripherals/adc_continuous.rst | 256 +++++++ .../api-reference/peripherals/adc_oneshot.rst | 210 ++++++ docs/en/api-reference/peripherals/index.rst | 6 +- docs/en/migration-guides/peripherals.rst | 14 +- docs/zh_CN/api-reference/peripherals/adc.rst | 1 - .../peripherals/adc_calibration.rst | 1 + .../peripherals/adc_continuous.rst | 1 + .../api-reference/peripherals/adc_oneshot.rst | 1 + .../zh_CN/api-reference/peripherals/index.rst | 6 +- examples/peripherals/.build-test-rules.yml | 22 +- .../adc2 => continuous_read}/CMakeLists.txt | 2 +- .../{dma_read => continuous_read}/README.md | 2 +- .../adc/continuous_read/main/CMakeLists.txt | 2 + .../main/continuous_read_main.c | 173 +++++ .../continuous_read/pytest_adc_continuous.py | 15 + .../peripherals/adc/dma_read/CMakeLists.txt | 6 - .../adc/dma_read/main/CMakeLists.txt | 2 - .../adc/dma_read/main/adc_dma_example_main.c | 176 ----- .../CMakeLists.txt | 2 +- .../peripherals/adc/oneshot_read/README.md | 62 ++ .../adc/oneshot_read/main/CMakeLists.txt | 2 + .../adc/oneshot_read/main/oneshot_read_main.c | 189 +++++ .../adc/oneshot_read/pytest_adc_oneshot.py | 14 + .../adc/single_read/adc/CMakeLists.txt | 6 - .../peripherals/adc/single_read/adc/README.md | 55 -- .../adc/single_read/adc/main/CMakeLists.txt | 2 - .../single_read/adc/main/adc1_example_main.c | 108 --- .../adc/single_read/adc2/README.md | 96 --- .../adc/single_read/adc2/main/CMakeLists.txt | 2 - .../single_read/adc2/main/Kconfig.projbuild | 105 --- .../single_read/adc2/main/adc2_example_main.c | 69 -- .../adc/single_read/single_read/README.md | 58 -- .../single_read/main/CMakeLists.txt | 2 - .../single_read/main/single_read.c | 110 --- .../i2s/i2s_adc_dac/main/app_main.c | 8 +- .../i2s/i2s_adc_dac/sdkconfig.defaults | 1 + examples/system/app_trace_to_host/README.md | 4 +- .../main/app_trace_to_host_example_main.c | 35 +- .../deep_sleep/main/deep_sleep_example_main.c | 1 - .../ulp_fsm/ulp_adc/main/CMakeLists.txt | 2 +- .../ulp_adc/main/ulp_adc_example_main.c | 27 +- .../system/ulp_riscv/adc/main/CMakeLists.txt | 2 +- .../ulp_riscv/adc/main/ulp/example_config.h | 2 +- .../system/g1_components/CMakeLists.txt | 5 + 185 files changed, 7783 insertions(+), 6462 deletions(-) delete mode 100644 components/driver/adc_deprecated.c rename components/driver/{ => deprecated}/adc1_private.h (100%) rename components/driver/{adc.c => deprecated/adc_dma_legacy.c} (54%) create mode 100644 components/driver/deprecated/adc_i2s_deprecated.c rename components/driver/{adc_single.c => deprecated/adc_legacy.c} (60%) rename components/driver/{include => deprecated}/driver/adc.h (52%) delete mode 100644 components/driver/deprecated/driver/adc_deprecated.h create mode 100644 components/driver/deprecated/driver/adc_i2s_legacy.h delete mode 100644 components/driver/deprecated/driver/adc_types_deprecated.h create mode 100644 components/driver/deprecated/driver/adc_types_legacy.h delete mode 100644 components/driver/esp32/adc.c delete mode 100644 components/driver/esp32s2/adc.c delete mode 100644 components/driver/include/driver/adc_common.h delete mode 100644 components/driver/include/esp_private/adc_cali.h delete mode 100644 components/driver/test/adc_dma_test/test_esp32s2.c delete mode 100644 components/driver/test/test_adc.c delete mode 100644 components/driver/test/test_adc_common.c create mode 100644 components/driver/test_apps/legacy_adc_driver/CMakeLists.txt create mode 100644 components/driver/test_apps/legacy_adc_driver/README.md create mode 100644 components/driver/test_apps/legacy_adc_driver/main/CMakeLists.txt create mode 100644 components/driver/test_apps/legacy_adc_driver/main/test_app_main.c create mode 100644 components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c create mode 100644 components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py create mode 100644 components/driver/test_apps/legacy_adc_driver/sdkconfig.ci.release create mode 100644 components/driver/test_apps/legacy_adc_driver/sdkconfig.defaults create mode 100644 components/esp_adc/CMakeLists.txt create mode 100644 components/esp_adc/Kconfig create mode 100644 components/esp_adc/adc_cali.c create mode 100644 components/esp_adc/adc_cali_curve_fitting.c create mode 100644 components/esp_adc/adc_common.c create mode 100644 components/esp_adc/adc_continuous.c create mode 100644 components/esp_adc/adc_lock.c create mode 100644 components/esp_adc/adc_oneshot.c create mode 100644 components/esp_adc/curve_fitting_coefficients.h rename components/{esp_adc_cal/esp32/esp_adc_cal.c => esp_adc/deprecated/esp32/esp_adc_cal_legacy.c} (99%) rename components/{esp_adc_cal/esp32c3/esp_adc_cal.c => esp_adc/deprecated/esp32c3/esp_adc_cal_legacy.c} (92%) rename components/{esp_adc_cal/esp32s2/esp_adc_cal.c => esp_adc/deprecated/esp32s2/esp_adc_cal_legacy.c} (98%) rename components/{esp_adc_cal/esp32s3/esp_adc_cal.c => esp_adc/deprecated/esp32s3/esp_adc_cal_legacy.c} (98%) rename components/{esp_adc_cal/esp_adc_cal_common.c => esp_adc/deprecated/esp_adc_cal_common_legacy.c} (89%) rename components/{esp_adc_cal/esp_adc_cal_internal.h => esp_adc/deprecated/esp_adc_cal_internal_legacy.h} (100%) rename components/{esp_adc_cal => esp_adc/deprecated}/include/esp_adc_cal.h (71%) create mode 100644 components/esp_adc/deprecated/include/esp_adc_cal_types_legacy.h create mode 100644 components/esp_adc/esp32/adc_cali_line_fitting.c create mode 100644 components/esp_adc/esp32/include/adc_cali_schemes.h create mode 100644 components/esp_adc/esp32c2/include/adc_cali_schemes.h rename components/{driver => esp_adc}/esp32c3/adc2_init_cal.c (69%) create mode 100644 components/esp_adc/esp32c3/curve_fitting_coefficients.c create mode 100644 components/esp_adc/esp32c3/include/adc_cali_schemes.h create mode 100644 components/esp_adc/esp32h2/include/adc_cali_schemes.h rename components/{driver => esp_adc}/esp32s2/adc2_init_cal.c (69%) create mode 100644 components/esp_adc/esp32s2/adc_cali_line_fitting.c create mode 100644 components/esp_adc/esp32s2/include/adc_cali_schemes.h create mode 100644 components/esp_adc/esp32s3/curve_fitting_coefficients.c create mode 100644 components/esp_adc/esp32s3/include/adc_cali_schemes.h create mode 100644 components/esp_adc/include/esp_adc/adc_cali.h create mode 100644 components/esp_adc/include/esp_adc/adc_cali_scheme.h create mode 100644 components/esp_adc/include/esp_adc/adc_continuous.h create mode 100644 components/esp_adc/include/esp_adc/adc_oneshot.h rename components/{driver => esp_adc}/include/esp_private/adc2_wifi.h (84%) create mode 100644 components/esp_adc/include/esp_private/adc_lock.h create mode 100644 components/esp_adc/include/esp_private/adc_private.h create mode 100644 components/esp_adc/interface/adc_cali_interface.h create mode 100644 components/esp_adc/linker.lf create mode 100644 components/esp_adc/test_apps/adc/CMakeLists.txt create mode 100644 components/esp_adc/test_apps/adc/README.md create mode 100644 components/esp_adc/test_apps/adc/main/CMakeLists.txt create mode 100644 components/esp_adc/test_apps/adc/main/test_adc.c create mode 100644 components/esp_adc/test_apps/adc/main/test_adc_driver.c create mode 100644 components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c create mode 100644 components/esp_adc/test_apps/adc/main/test_adc_performance.c create mode 100644 components/esp_adc/test_apps/adc/main/test_app_main.c create mode 100644 components/esp_adc/test_apps/adc/main/test_common_adc.c create mode 100644 components/esp_adc/test_apps/adc/main/test_common_adc.h create mode 100644 components/esp_adc/test_apps/adc/pytest_adc.py create mode 100644 components/esp_adc/test_apps/adc/sdkconfig.ci.iram_safe create mode 100644 components/esp_adc/test_apps/adc/sdkconfig.ci.release create mode 100644 components/esp_adc/test_apps/adc/sdkconfig.defaults delete mode 100644 components/esp_adc_cal/CMakeLists.txt delete mode 100644 components/esp_adc_cal/Kconfig create mode 100644 components/hal/adc_oneshot_hal.c delete mode 100644 components/hal/esp32/adc_hal.c delete mode 100644 components/hal/esp32/include/hal/adc_hal.h delete mode 100644 components/hal/esp32c3/adc_hal.c delete mode 100644 components/hal/esp32c3/include/hal/adc_hal.h create mode 100644 components/hal/include/hal/adc_oneshot_hal.h create mode 100644 docs/_static/diagrams/adc/adc_conversion_frame.png delete mode 100644 docs/en/api-reference/peripherals/adc.rst create mode 100644 docs/en/api-reference/peripherals/adc_calibration.rst create mode 100644 docs/en/api-reference/peripherals/adc_continuous.rst create mode 100644 docs/en/api-reference/peripherals/adc_oneshot.rst delete mode 100644 docs/zh_CN/api-reference/peripherals/adc.rst create mode 100644 docs/zh_CN/api-reference/peripherals/adc_calibration.rst create mode 100644 docs/zh_CN/api-reference/peripherals/adc_continuous.rst create mode 100644 docs/zh_CN/api-reference/peripherals/adc_oneshot.rst rename examples/peripherals/adc/{single_read/adc2 => continuous_read}/CMakeLists.txt (89%) rename examples/peripherals/adc/{dma_read => continuous_read}/README.md (98%) create mode 100644 examples/peripherals/adc/continuous_read/main/CMakeLists.txt create mode 100644 examples/peripherals/adc/continuous_read/main/continuous_read_main.c create mode 100644 examples/peripherals/adc/continuous_read/pytest_adc_continuous.py delete mode 100644 examples/peripherals/adc/dma_read/CMakeLists.txt delete mode 100644 examples/peripherals/adc/dma_read/main/CMakeLists.txt delete mode 100644 examples/peripherals/adc/dma_read/main/adc_dma_example_main.c rename examples/peripherals/adc/{single_read/single_read => oneshot_read}/CMakeLists.txt (90%) create mode 100644 examples/peripherals/adc/oneshot_read/README.md create mode 100644 examples/peripherals/adc/oneshot_read/main/CMakeLists.txt create mode 100644 examples/peripherals/adc/oneshot_read/main/oneshot_read_main.c create mode 100644 examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py delete mode 100644 examples/peripherals/adc/single_read/adc/CMakeLists.txt delete mode 100644 examples/peripherals/adc/single_read/adc/README.md delete mode 100644 examples/peripherals/adc/single_read/adc/main/CMakeLists.txt delete mode 100644 examples/peripherals/adc/single_read/adc/main/adc1_example_main.c delete mode 100644 examples/peripherals/adc/single_read/adc2/README.md delete mode 100644 examples/peripherals/adc/single_read/adc2/main/CMakeLists.txt delete mode 100644 examples/peripherals/adc/single_read/adc2/main/Kconfig.projbuild delete mode 100644 examples/peripherals/adc/single_read/adc2/main/adc2_example_main.c delete mode 100644 examples/peripherals/adc/single_read/single_read/README.md delete mode 100644 examples/peripherals/adc/single_read/single_read/main/CMakeLists.txt delete mode 100644 examples/peripherals/adc/single_read/single_read/main/single_read.c diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 68ea16e550..a55dbf8495 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -77,7 +77,7 @@ /components/cxx/ @esp-idf-codeowners/system /components/driver/ @esp-idf-codeowners/peripherals /components/efuse/ @esp-idf-codeowners/system -/components/esp_adc_cal/ @esp-idf-codeowners/peripherals +/components/esp_adc/ @esp-idf-codeowners/peripherals /components/esp_common/ @esp-idf-codeowners/system /components/esp_eth/ @esp-idf-codeowners/network /components/esp_event/ @esp-idf-codeowners/system diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index b8dd34318d..60e70f9cf9 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -24,9 +24,11 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${target}/include") endif() if(CONFIG_SOC_ADC_SUPPORTED) - list(APPEND srcs - "adc_single.c" - "adc.c") + list(APPEND srcs "deprecated/adc_legacy.c") +endif() + +if(CONFIG_SOC_ADC_DMA_SUPPORTED) + list(APPEND srcs "deprecated/adc_dma_legacy.c") endif() if(CONFIG_SOC_MCPWM_SUPPORTED) @@ -87,8 +89,7 @@ if(${target} STREQUAL "esp32") "sdio_slave.c" "touch_sensor_common.c" "esp32/touch_sensor.c" - "esp32/adc.c" - "adc_deprecated.c" + "deprecated/adc_i2s_deprecated.c" "esp32/dac.c") endif() @@ -96,9 +97,6 @@ if(${target} STREQUAL "esp32s2") list(APPEND srcs "dac_common.c" "touch_sensor_common.c" "esp32s2/touch_sensor.c" - "esp32s2/adc.c" - "adc_deprecated.c" - "esp32s2/adc2_init_cal.c" "esp32s2/dac.c") endif() @@ -107,19 +105,18 @@ if(${target} STREQUAL "esp32s3") "esp32s3/touch_sensor.c") endif() -if(${target} STREQUAL "esp32c3") - list(APPEND srcs "esp32c3/adc2_init_cal.c") -endif() if(BOOTLOADER_BUILD) # Bootloader shall NOT depend on the drivers idf_component_register() else() # (REQUIRES cannot hide soc headers, since many arguments in the driver headers are chip-dependent) + # (Legacy drivers requires `esp_adc`, due to ADC HW resource mutex logics are there. + # Can be removed together with legacy drivers) idf_component_register(SRCS "${srcs}" INCLUDE_DIRS ${includes} PRIV_INCLUDE_DIRS "include/driver" - PRIV_REQUIRES efuse esp_timer + PRIV_REQUIRES efuse esp_timer esp_adc REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support LDFRAGMENTS linker.lf) endif() diff --git a/components/driver/Kconfig b/components/driver/Kconfig index 1259bb75d3..e3afb0d64a 100644 --- a/components/driver/Kconfig +++ b/components/driver/Kconfig @@ -1,16 +1,9 @@ menu "Driver Configurations" - menu "ADC Configuration" - - config ADC_FORCE_XPD_FSM - bool "Use the FSM to control ADC power" - default n - help - ADC power can be controlled by the FSM instead of software. This allows the ADC to - be shut off when it is not working leading to lower power consumption. However - using the FSM control ADC power will increase the noise of ADC. + menu "Legacy ADC Configuration" config ADC_DISABLE_DAC + depends on SOC_DAC_SUPPORTED bool "Disable DAC when ADC2 is used on GPIO 25 and 26" default y help @@ -19,6 +12,54 @@ menu "Driver Configurations" For testing, disable this option so that we can measure the output of DAC by internal ADC. + config ADC_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + Wether to suppress the deprecation warnings when using legacy adc driver (driver/adc.h). + If you want to continue using the legacy driver, and don't want to see related deprecation warnings, + you can enable this option. + + menu "Legacy ADC Calibration Configuration" + + config ADC_CAL_EFUSE_TP_ENABLE + depends on IDF_TARGET_ESP32 + bool "Use Two Point Values" + default "y" + help + Some ESP32s have Two Point calibration values burned into eFuse BLOCK3. + This option will allow the ADC calibration component to characterize the + ADC-Voltage curve using Two Point values if they are available. + + config ADC_CAL_EFUSE_VREF_ENABLE + depends on IDF_TARGET_ESP32 + bool "Use eFuse Vref" + default "y" + help + Some ESP32s have Vref burned into eFuse BLOCK0. This option will allow + the ADC calibration component to characterize the ADC-Voltage curve using + eFuse Vref if it is available. + + config ADC_CAL_LUT_ENABLE + depends on IDF_TARGET_ESP32 + bool "Use Lookup Tables" + default "y" + help + This option will allow the ADC calibration component to use Lookup Tables + to correct for non-linear behavior in 11db attenuation. Other attenuations + do not exhibit non-linear behavior hence will not be affected by this option. + + config ADC_CALI_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + Wether to suppress the deprecation warnings when using legacy adc calibration + driver (esp_adc_cal.h). + If you want to continue using the legacy driver, and don't want to see related + deprecation warnings, you can enable this option. + + endmenu + endmenu # ADC Configuration menu "SPI Configuration" diff --git a/components/driver/adc_deprecated.c b/components/driver/adc_deprecated.c deleted file mode 100644 index 3f27a0c1ba..0000000000 --- a/components/driver/adc_deprecated.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/*---------------------------------------------------------------------------------- - This file contains ESP32 and ESP32S2 Depricated ADC APIs and functions ------------------------------------------------------------------------------------*/ - -#include "sdkconfig.h" -#include "esp_types.h" -#include "esp_log.h" -#include "esp_intr_alloc.h" -#include "driver/rtc_io.h" -#include "hal/adc_ll.h" -#include "hal/adc_types.h" -#include "hal/adc_hal_conf.h" -#ifdef CONFIG_PM_ENABLE -#include "esp_pm.h" -#endif -#include "adc.h" -#include "esp_private/adc_cali.h" -#include "freertos/FreeRTOS.h" - -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#include "deprecated/driver/adc_types_deprecated.h" - -static const char *ADC_TAG = "ADC"; - -#define ADC_CHECK_RET(fun_ret) ({ \ - if (fun_ret != ESP_OK) { \ - ESP_LOGE(ADC_TAG,"%s:%d\n",__FUNCTION__,__LINE__); \ - return ESP_FAIL; \ - } \ -}) - -#define ADC_CHECK(a, str, ret_val) ({ \ - if (!(a)) { \ - ESP_LOGE(ADC_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ - return (ret_val); \ - } \ -}) - -#define ADC_CHANNEL_CHECK(periph, channel) ADC_CHECK(channel < SOC_ADC_CHANNEL_NUM(periph), "ADC"#periph" channel error", ESP_ERR_INVALID_ARG) -#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel]) - -extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished. -#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock) -#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock) - -#ifdef CONFIG_PM_ENABLE -esp_pm_lock_handle_t adc_digi_arbiter_lock = NULL; -#endif //CONFIG_PM_ENABLE - - -#if CONFIG_IDF_TARGET_ESP32 -/*--------------------------------------------------------------- - ESP32 Depricated ADC APIs and functions ----------------------------------------------------------------*/ -#define ADC_MEAS_NUM_LIM_DEFAULT (1) -#define ADC_MAX_MEAS_NUM_DEFAULT (255) -#define DIG_ADC_OUTPUT_FORMAT_DEFUALT (ADC_DIGI_FORMAT_12BIT) -#define DIG_ADC_ATTEN_DEFUALT (ADC_ATTEN_DB_11) -#define DIG_ADC_BIT_WIDTH_DEFUALT (ADC_WIDTH_BIT_12) - -esp_err_t adc_digi_init(void) -{ - ADC_ENTER_CRITICAL(); - adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT, - ADC_HAL_FSM_STANDBY_WAIT_DEFAULT); - adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT); - adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); - adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1)); - adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2)); - adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_deinit(void) -{ - adc_power_release(); - ADC_ENTER_CRITICAL(); - adc_hal_digi_deinit(NULL); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/** - * Set adc output 16-bit-data format from digital controller. - * - * @param data_sel 1: [15] unit, [14:11] channel, [10:0] data, 11-bit-width at most. Only work under `ADC_LL_DIGI_CONV_BOTH_UNIT` or `ADC_LL_DIGI_CONV_ALTER_UNIT` mode. - * 0: [15:12] channel, [11:0] data, 12-bit-width at most. Only work under `ADC_LL_DIGI_CONV_ONLY_ADC1` or `ADC_LL_DIGI_CONV_ONLY_ADC2` mode - * @note see `adc_ll_digi_pattern_table_t` for more detail of data bit width - */ -static inline void adc_ll_digi_set_output_format(bool data_sel) -{ - SYSCON.saradc_ctrl.data_sar_sel = data_sel; -} - -static inline void adc_ll_digi_prepare_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern) -{ - uint32_t tab; - uint8_t index = pattern_index / 4; - uint8_t offset = (pattern_index % 4) * 8; - if (adc_n == ADC_UNIT_1) { - tab = SYSCON.saradc_sar1_patt_tab[index]; // Read old register value - tab &= (~(0xFF000000 >> offset)); // clear old data - tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data - SYSCON.saradc_sar1_patt_tab[index] = tab; // Write back - } else { // adc_n == ADC_UNIT_2 - tab = SYSCON.saradc_sar2_patt_tab[index]; // Read old register value - tab &= (~(0xFF000000 >> offset)); // clear old data - tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data - SYSCON.saradc_sar2_patt_tab[index] = tab; // Write back - } -} - -void adc_digi_controller_reg_set(const adc_digi_config_t *cfg) -{ - /* On ESP32, only support ADC1 */ - switch (cfg->conv_mode) { - case ADC_CONV_SINGLE_UNIT_1: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1); - break; - case ADC_CONV_SINGLE_UNIT_2: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC2); - break; - case ADC_CONV_BOTH_UNIT: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT); - break; - case ADC_CONV_ALTER_UNIT: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ALTER_UNIT); - break; - default: - abort(); - } - - if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) { - adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG); - if (cfg->adc1_pattern_len) { - adc_ll_digi_clear_pattern_table(ADC_UNIT_1); - adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, cfg->adc1_pattern_len); - for (uint32_t i = 0; i < cfg->adc1_pattern_len; i++) { - adc_ll_digi_prepare_pattern_table(ADC_UNIT_1, i, cfg->adc1_pattern[i]); - } - } - } - if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) { - adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_DIG); - if (cfg->adc2_pattern_len) { - adc_ll_digi_clear_pattern_table(ADC_UNIT_2); - adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, cfg->adc2_pattern_len); - for (uint32_t i = 0; i < cfg->adc2_pattern_len; i++) { - adc_ll_digi_prepare_pattern_table(ADC_UNIT_2, i, cfg->adc2_pattern[i]); - } - } - } - adc_ll_digi_set_output_format(cfg->format); - if (cfg->conv_limit_en) { - adc_ll_digi_set_convert_limit_num(cfg->conv_limit_num); - adc_ll_digi_convert_limit_enable(); - } else { - adc_ll_digi_convert_limit_disable(); - } - adc_ll_digi_set_data_source(ADC_I2S_DATA_SRC_ADC); -} - -esp_err_t adc_digi_controller_config(const adc_digi_config_t *config) -{ - adc_power_acquire(); - ADC_ENTER_CRITICAL(); - adc_digi_controller_reg_set(config); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src) -{ - ADC_CHECK(src < ADC_I2S_DATA_SRC_MAX, "ADC i2s data source error", ESP_ERR_INVALID_ARG); - ADC_ENTER_CRITICAL(); - adc_ll_digi_set_data_source(src); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -extern esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel); -esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel) -{ - if (adc_unit == ADC_UNIT_1) { - ADC_CHECK((SOC_ADC_SUPPORT_DMA_MODE(ADC_UNIT_1)), "ADC1 not support DMA for now.", ESP_ERR_INVALID_ARG); - ADC_CHANNEL_CHECK(ADC_UNIT_1, channel); - } else if (adc_unit == ADC_UNIT_2) { - //ADC2 does not support DMA mode - ADC_CHECK((SOC_ADC_SUPPORT_DMA_MODE(ADC_UNIT_2)), "ADC2 not support DMA for now.", ESP_ERR_INVALID_ARG); - ADC_CHANNEL_CHECK(ADC_UNIT_2, channel); - } - - adc_digi_pattern_table_t adc1_pattern[1]; - adc_digi_pattern_table_t adc2_pattern[1]; - adc_digi_config_t dig_cfg = { - .conv_limit_en = ADC_MEAS_NUM_LIM_DEFAULT, - .conv_limit_num = ADC_MAX_MEAS_NUM_DEFAULT, - .format = DIG_ADC_OUTPUT_FORMAT_DEFUALT, - .conv_mode = ADC_CONV_SINGLE_UNIT_1, - }; - - if (adc_unit == ADC_UNIT_1) { - adc1_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT; - adc1_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT; - adc1_pattern[0].channel = channel; - dig_cfg.adc1_pattern_len = 1; - dig_cfg.adc1_pattern = adc1_pattern; - } else if (adc_unit == ADC_UNIT_2) { - adc2_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT; - adc2_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT; - adc2_pattern[0].channel = channel; - dig_cfg.adc2_pattern_len = 1; - dig_cfg.adc2_pattern = adc2_pattern; - } - adc_common_gpio_init(adc_unit, channel); - ADC_ENTER_CRITICAL(); - adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT, - ADC_HAL_FSM_STANDBY_WAIT_DEFAULT); - adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT); - adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); - adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1)); - adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2)); - adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT); - adc_digi_controller_reg_set(&dig_cfg); - ADC_EXIT_CRITICAL(); - - return ESP_OK; -} - -#endif //#if CONFIG_IDF_TARGET_ESP32 - -#if CONFIG_IDF_TARGET_ESP32S2 -/*--------------------------------------------------------------- - ESP32S2 Depricated ADC functions and APIs ----------------------------------------------------------------*/ -esp_err_t adc_arbiter_config(adc_unit_t adc_unit, adc_arbiter_t *config) -{ - if (adc_unit == ADC_UNIT_1) { - return ESP_ERR_NOT_SUPPORTED; - } - ADC_ENTER_CRITICAL(); - adc_hal_arbiter_config(config); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/** - * Enable interrupt of adc digital controller by bitmask. - * - * @param adc_n ADC unit. - * @param intr Interrupt bitmask. - */ -static inline void adc_ll_digi_intr_enable(adc_unit_t adc_n, adc_digi_intr_t intr) -{ - if (adc_n == ADC_UNIT_1) { - if (intr & ADC_DIGI_INTR_MASK_MONITOR) { - APB_SARADC.int_ena.adc1_thres = 1; - } - if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) { - APB_SARADC.int_ena.adc1_done = 1; - } - } else { // adc_n == ADC_UNIT_2 - if (intr & ADC_DIGI_INTR_MASK_MONITOR) { - APB_SARADC.int_ena.adc2_thres = 1; - } - if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) { - APB_SARADC.int_ena.adc2_done = 1; - } - } -} - -esp_err_t adc_digi_intr_enable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) -{ - ADC_ENTER_CRITICAL(); - if (adc_unit == ADC_UNIT_1) { - adc_ll_digi_intr_enable(ADC_UNIT_1, intr_mask); - } else if (adc_unit == ADC_UNIT_2) { - adc_ll_digi_intr_enable(ADC_UNIT_2, intr_mask); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/** - * Disable interrupt of adc digital controller by bitmask. - * - * @param adc_n ADC unit. - * @param intr Interrupt bitmask. - */ -static inline void adc_ll_digi_intr_disable(adc_unit_t adc_n, adc_digi_intr_t intr) -{ - if (adc_n == ADC_UNIT_1) { - if (intr & ADC_DIGI_INTR_MASK_MONITOR) { - APB_SARADC.int_ena.adc1_thres = 0; - } - if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) { - APB_SARADC.int_ena.adc1_done = 0; - } - } else { // adc_n == ADC_UNIT_2 - if (intr & ADC_DIGI_INTR_MASK_MONITOR) { - APB_SARADC.int_ena.adc2_thres = 0; - } - if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) { - APB_SARADC.int_ena.adc2_done = 0; - } - } -} - -esp_err_t adc_digi_intr_disable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) -{ - ADC_ENTER_CRITICAL(); - if (adc_unit == ADC_UNIT_1) { - adc_ll_digi_intr_disable(ADC_UNIT_1, intr_mask); - } else if (adc_unit == ADC_UNIT_2) { - adc_ll_digi_intr_disable(ADC_UNIT_2, intr_mask); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/** - * Clear interrupt of adc digital controller by bitmask. - * - * @param adc_n ADC unit. - * @param intr Interrupt bitmask. - */ -static inline void adc_ll_digi_intr_clear(adc_unit_t adc_n, adc_digi_intr_t intr) -{ - if (adc_n == ADC_UNIT_1) { - if (intr & ADC_DIGI_INTR_MASK_MONITOR) { - APB_SARADC.int_clr.adc1_thres = 1; - } - if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) { - APB_SARADC.int_clr.adc1_done = 1; - } - } else { // adc_n == ADC_UNIT_2 - if (intr & ADC_DIGI_INTR_MASK_MONITOR) { - APB_SARADC.int_clr.adc2_thres = 1; - } - if (intr & ADC_DIGI_INTR_MASK_MEAS_DONE) { - APB_SARADC.int_clr.adc2_done = 1; - } - } -} - -esp_err_t adc_digi_intr_clear(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) -{ - ADC_ENTER_CRITICAL(); - if (adc_unit == ADC_UNIT_1) { - adc_ll_digi_intr_clear(ADC_UNIT_1, intr_mask); - } else if (adc_unit == ADC_UNIT_2) { - adc_ll_digi_intr_clear(ADC_UNIT_2, intr_mask); - } - ADC_EXIT_CRITICAL(); - - return ESP_OK; -} - -/** - * Get interrupt status mask of adc digital controller. - * - * @param adc_n ADC unit. - * @return - * - intr Interrupt bitmask. - */ -static inline uint32_t adc_ll_digi_get_intr_status(adc_unit_t adc_n) -{ - uint32_t int_st = APB_SARADC.int_st.val; - uint32_t ret_msk = 0; - - if (adc_n == ADC_UNIT_1) { - if (int_st & APB_SARADC_ADC1_DONE_INT_ST_M) { - ret_msk |= ADC_DIGI_INTR_MASK_MEAS_DONE; - } - if (int_st & APB_SARADC_ADC1_THRES_INT_ST) { - ret_msk |= ADC_DIGI_INTR_MASK_MONITOR; - } - } else { // adc_n == ADC_UNIT_2 - if (int_st & APB_SARADC_ADC2_DONE_INT_ST_M) { - ret_msk |= ADC_DIGI_INTR_MASK_MEAS_DONE; - } - if (int_st & APB_SARADC_ADC2_THRES_INT_ST_M) { - ret_msk |= ADC_DIGI_INTR_MASK_MONITOR; - } - } - - return ret_msk; -} - -uint32_t adc_digi_intr_get_status(adc_unit_t adc_unit) -{ - uint32_t ret = 0; - ADC_ENTER_CRITICAL(); - if (adc_unit == ADC_UNIT_1) { - ret = adc_ll_digi_get_intr_status(ADC_UNIT_1); - } else if (adc_unit == ADC_UNIT_2) { - ret = adc_ll_digi_get_intr_status(ADC_UNIT_2); - } - ADC_EXIT_CRITICAL(); - return ret; -} - -static uint8_t s_isr_registered = 0; -static intr_handle_t s_adc_isr_handle = NULL; - -esp_err_t adc_digi_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags) -{ - ADC_CHECK((fn != NULL), "Parameter error", ESP_ERR_INVALID_ARG); - ADC_CHECK(s_isr_registered == 0, "ADC ISR have installed, can not install again", ESP_FAIL); - - esp_err_t ret = esp_intr_alloc(ETS_APB_ADC_INTR_SOURCE, intr_alloc_flags, fn, arg, &s_adc_isr_handle); - if (ret == ESP_OK) { - s_isr_registered = 1; - } - return ret; -} - -esp_err_t adc_digi_isr_deregister(void) -{ - esp_err_t ret = ESP_FAIL; - if (s_isr_registered) { - ret = esp_intr_free(s_adc_isr_handle); - if (ret == ESP_OK) { - s_isr_registered = 0; - } - } - return ret; -} - -esp_err_t adc_digi_init(void) -{ - adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); - ADC_ENTER_CRITICAL(); - adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT, - ADC_HAL_FSM_STANDBY_WAIT_DEFAULT); - adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT); - adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); - adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1)); - adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2)); - adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT); - adc_hal_arbiter_config(&config); - ADC_EXIT_CRITICAL(); - - adc_hal_calibration_init(ADC_UNIT_1); - adc_hal_calibration_init(ADC_UNIT_2); - - return ESP_OK; -} - -esp_err_t adc_digi_deinit(void) -{ -#ifdef CONFIG_PM_ENABLE - if (adc_digi_arbiter_lock) { - esp_pm_lock_delete(adc_digi_arbiter_lock); - adc_digi_arbiter_lock = NULL; - } -#endif - adc_power_release(); - ADC_ENTER_CRITICAL(); - adc_hal_digi_deinit(NULL); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/** - * @brief Reset FSM of adc digital controller. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_reset(void) -{ - ADC_ENTER_CRITICAL(); - adc_ll_digi_reset(); - adc_ll_digi_clear_pattern_table(ADC_UNIT_1); - adc_ll_digi_clear_pattern_table(ADC_UNIT_2); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/** - * Set adc output data format for digital controller. - * - * @param format Output data format. - */ -static inline void adc_ll_digi_set_output_format(adc_digi_output_format_t format) -{ - APB_SARADC.ctrl.data_sar_sel = format; -} - -static inline void adc_ll_digi_prepare_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern) -{ - uint32_t tab; - uint8_t index = pattern_index / 4; - uint8_t offset = (pattern_index % 4) * 8; - if (adc_n == ADC_UNIT_1) { - tab = APB_SARADC.sar1_patt_tab[index]; // Read old register value - tab &= (~(0xFF000000 >> offset)); // clear old data - tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data - APB_SARADC.sar1_patt_tab[index] = tab; // Write back - } else { // adc_n == ADC_UNIT_2 - tab = APB_SARADC.sar2_patt_tab[index]; // Read old register value - tab &= (~(0xFF000000 >> offset)); // clear old data - tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data - APB_SARADC.sar2_patt_tab[index] = tab; // Write back - } -} - -static void adc_digi_controller_reg_set(const adc_digi_config_t *cfg) -{ - /* Single channel mode or multi channel mode. */ - switch (cfg->conv_mode) { - case ADC_CONV_SINGLE_UNIT_1: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1); - break; - case ADC_CONV_SINGLE_UNIT_2: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC2); - break; - case ADC_CONV_BOTH_UNIT: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT); - break; - case ADC_CONV_ALTER_UNIT: - adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ALTER_UNIT); - break; - default: - abort(); - } - - if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) { - if (cfg->adc1_pattern_len) { - adc_ll_digi_clear_pattern_table(ADC_UNIT_1); - adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, cfg->adc1_pattern_len); - for (uint32_t i = 0; i < cfg->adc1_pattern_len; i++) { - adc_ll_digi_prepare_pattern_table(ADC_UNIT_1, i, cfg->adc1_pattern[i]); - } - } - } - if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) { - if (cfg->adc2_pattern_len) { - adc_ll_digi_clear_pattern_table(ADC_UNIT_2); - adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, cfg->adc2_pattern_len); - for (uint32_t i = 0; i < cfg->adc2_pattern_len; i++) { - adc_ll_digi_prepare_pattern_table(ADC_UNIT_2, i, cfg->adc2_pattern[i]); - } - } - } - if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) { - adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG); - } - if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) { - adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_ARB); - } - adc_ll_digi_set_output_format(cfg->format); - if (cfg->conv_limit_en) { - adc_ll_digi_set_convert_limit_num(cfg->conv_limit_num); - adc_ll_digi_convert_limit_enable(); - } else { - adc_ll_digi_convert_limit_disable(); - } - - adc_ll_digi_set_trigger_interval(cfg->interval); - adc_ll_digi_controller_clk_div(cfg->dig_clk.div_num, cfg->dig_clk.div_b, cfg->dig_clk.div_a); - adc_ll_digi_clk_sel(cfg->dig_clk.use_apll); - adc_ll_digi_dma_set_eof_num(cfg->dma_eof_num); -} - -esp_err_t adc_digi_controller_config(const adc_digi_config_t *config) -{ -#ifdef CONFIG_PM_ENABLE - esp_err_t err; - if (adc_digi_arbiter_lock == NULL) { - if (config->dig_clk.use_apll) { - err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "adc_dma", &adc_digi_arbiter_lock); - } else { - err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &adc_digi_arbiter_lock); - } - if (err != ESP_OK) { - adc_digi_arbiter_lock = NULL; - ESP_LOGE(ADC_TAG, "ADC-DMA pm lock error"); - return err; - } - } -#endif //CONFIG_PM_ENABLE - - if (config->conv_mode & ADC_CONV_SINGLE_UNIT_1) { - for (int i = 0; i < config->adc1_pattern_len; i++) { - adc_cal_offset(ADC_UNIT_1, config->adc1_pattern[i].atten); - } - } - if (config->conv_mode & ADC_CONV_SINGLE_UNIT_2) { - for (int i = 0; i < config->adc2_pattern_len; i++) { - adc_cal_offset(ADC_UNIT_2, config->adc2_pattern[i].atten); - } - } - - /* If enable digtal controller, adc xpd should always on. */ - adc_power_acquire(); - ADC_ENTER_CRITICAL(); - adc_digi_controller_reg_set(config); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} -#endif // #if CONFIG_IDF_TARGET_ESP32S2 - - -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 -/*--------------------------------------------------------------- - ESP32S2 Depricated ADC functions and APIs ----------------------------------------------------------------*/ -esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) -{ - gpio_num_t gpio_num = 0; - //If called with `ADC_UNIT_BOTH (ADC_UNIT_1 | ADC_UNIT_2)`, both if blocks will be run - if (adc_unit == ADC_UNIT_1) { - ADC_CHANNEL_CHECK(ADC_UNIT_1, channel); - gpio_num = ADC_GET_IO_NUM(ADC_UNIT_1, channel); - ADC_CHECK_RET(rtc_gpio_init(gpio_num)); - ADC_CHECK_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - ADC_CHECK_RET(rtc_gpio_pulldown_dis(gpio_num)); - ADC_CHECK_RET(rtc_gpio_pullup_dis(gpio_num)); - } - if (adc_unit == ADC_UNIT_2) { - ADC_CHANNEL_CHECK(ADC_UNIT_2, channel); - gpio_num = ADC_GET_IO_NUM(ADC_UNIT_2, channel); - ADC_CHECK_RET(rtc_gpio_init(gpio_num)); - ADC_CHECK_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - ADC_CHECK_RET(rtc_gpio_pulldown_dis(gpio_num)); - ADC_CHECK_RET(rtc_gpio_pullup_dis(gpio_num)); - } - - return ESP_OK; -} -#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 diff --git a/components/driver/adc1_private.h b/components/driver/deprecated/adc1_private.h similarity index 100% rename from components/driver/adc1_private.h rename to components/driver/deprecated/adc1_private.h diff --git a/components/driver/adc.c b/components/driver/deprecated/adc_dma_legacy.c similarity index 54% rename from components/driver/adc.c rename to components/driver/deprecated/adc_dma_legacy.c index 1fd2ae0e78..625773a79e 100644 --- a/components/driver/adc.c +++ b/components/driver/deprecated/adc_dma_legacy.c @@ -19,11 +19,15 @@ #include "freertos/timers.h" #include "freertos/ringbuf.h" #include "esp_private/periph_ctrl.h" -#include "driver/gpio.h" -#include "driver/adc.h" +#include "esp_private/adc_private.h" +#include "esp_private/adc_lock.h" #include "hal/adc_types.h" #include "hal/adc_hal.h" #include "hal/dma_types.h" + +#include "driver/gpio.h" +#include "driver/adc_types_legacy.h" + //For calibration #if CONFIG_IDF_TARGET_ESP32S2 #include "esp_efuse_rtc_table.h" @@ -37,7 +41,6 @@ #include "hal/spi_types.h" #include "esp_private/spi_common_internal.h" #elif CONFIG_IDF_TARGET_ESP32 -#include "hal/i2s_types.h" #include "driver/i2s_types.h" #include "soc/i2s_periph.h" #include "esp_private/i2s_platform.h" @@ -51,21 +54,6 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi #define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock) #define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock) -/** - * 1. sar_adc1_lock: this mutex lock is to protect the SARADC1 module. - * 2. sar_adc2_lock: this mutex lock is to protect the SARADC2 module. - * 3. adc_reg_lock: this spin lock is to protect the shared registers used by ADC1 / ADC2 single read mode. - */ -static _lock_t sar_adc1_lock; -#define SAR_ADC1_LOCK_ACQUIRE() _lock_acquire(&sar_adc1_lock) -#define SAR_ADC1_LOCK_RELEASE() _lock_release(&sar_adc1_lock) -static _lock_t sar_adc2_lock; -#define SAR_ADC2_LOCK_ACQUIRE() _lock_acquire(&sar_adc2_lock) -#define SAR_ADC2_LOCK_RELEASE() _lock_release(&sar_adc2_lock) -portMUX_TYPE adc_reg_lock = portMUX_INITIALIZER_UNLOCKED; -#define ADC_REG_LOCK_ENTER() portENTER_CRITICAL(&adc_reg_lock) -#define ADC_REG_LOCK_EXIT() portEXIT_CRITICAL(&adc_reg_lock) - #define INTERNAL_BUF_NUM 5 /*--------------------------------------------------------------- @@ -101,10 +89,6 @@ static adc_digi_context_t *s_adc_digi_ctx = NULL; extern esp_pm_lock_handle_t adc_digi_arbiter_lock; #endif //CONFIG_PM_ENABLE -#if SOC_ADC_CALIBRATION_V1_SUPPORTED -uint32_t adc_get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten); -#endif - /*--------------------------------------------------------------- ADC Continuous Read Mode (via DMA) ---------------------------------------------------------------*/ @@ -152,9 +136,54 @@ static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask) return ret; } +esp_err_t adc_digi_deinitialize(void) +{ + if (!s_adc_digi_ctx) { + return ESP_ERR_INVALID_STATE; + } + + if (s_adc_digi_ctx->driver_start_flag != 0) { + ESP_LOGE(ADC_TAG, "The driver is not stopped"); + return ESP_ERR_INVALID_STATE; + } + + if (s_adc_digi_ctx->ringbuf_hdl) { + vRingbufferDelete(s_adc_digi_ctx->ringbuf_hdl); + s_adc_digi_ctx->ringbuf_hdl = NULL; + } + +#if CONFIG_PM_ENABLE + if (s_adc_digi_ctx->pm_lock) { + esp_pm_lock_delete(s_adc_digi_ctx->pm_lock); + } +#endif //CONFIG_PM_ENABLE + + free(s_adc_digi_ctx->rx_dma_buf); + free(s_adc_digi_ctx->hal.rx_desc); + free(s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern); +#if SOC_GDMA_SUPPORTED + gdma_disconnect(s_adc_digi_ctx->rx_dma_channel); + gdma_del_channel(s_adc_digi_ctx->rx_dma_channel); +#elif CONFIG_IDF_TARGET_ESP32S2 + esp_intr_free(s_adc_digi_ctx->intr_hdl); + spicommon_dma_chan_free(s_adc_digi_ctx->spi_host); + spicommon_periph_free(s_adc_digi_ctx->spi_host); +#elif CONFIG_IDF_TARGET_ESP32 + esp_intr_free(s_adc_digi_ctx->intr_hdl); + i2s_platform_release_occupation(s_adc_digi_ctx->i2s_host); +#endif + free(s_adc_digi_ctx); + s_adc_digi_ctx = NULL; + + periph_module_disable(PERIPH_SARADC_MODULE); + + return ESP_OK; +} + esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config) { esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE((init_config->conv_num_each_intr % SOC_ADC_DIGI_DATA_BYTES_PER_CONV == 0), ESP_ERR_INVALID_ARG, ADC_TAG, "conv_frame_size should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`"); s_adc_digi_ctx = calloc(1, sizeof(adc_digi_context_t)); if (s_adc_digi_ctx == NULL) { @@ -282,7 +311,7 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config) #endif .desc_max_num = INTERNAL_BUF_NUM, .dma_chan = dma_chan, - .eof_num = init_config->conv_num_each_intr / ADC_HAL_DATA_LEN_PER_CONV + .eof_num = init_config->conv_num_each_intr / SOC_ADC_DIGI_DATA_BYTES_PER_CONV }; adc_hal_dma_ctx_config(&s_adc_digi_ctx->hal, &config); @@ -362,116 +391,83 @@ static IRAM_ATTR bool s_adc_dma_intr(adc_digi_context_t *adc_digi_ctx) esp_err_t adc_digi_start(void) { - if (s_adc_digi_ctx) { - if (s_adc_digi_ctx->driver_start_flag != 0) { - ESP_LOGE(ADC_TAG, "The driver is already started"); - return ESP_ERR_INVALID_STATE; - } - adc_power_acquire(); - //reset flags - s_adc_digi_ctx->ringbuf_overflow_flag = 0; - s_adc_digi_ctx->driver_start_flag = 1; - if (s_adc_digi_ctx->use_adc1) { - SAR_ADC1_LOCK_ACQUIRE(); - } - if (s_adc_digi_ctx->use_adc2) { - SAR_ADC2_LOCK_ACQUIRE(); - } + + if (s_adc_digi_ctx->driver_start_flag != 0) { + ESP_LOGE(ADC_TAG, "The driver is already started"); + return ESP_ERR_INVALID_STATE; + } + adc_power_acquire(); + //reset flags + s_adc_digi_ctx->ringbuf_overflow_flag = 0; + s_adc_digi_ctx->driver_start_flag = 1; + if (s_adc_digi_ctx->use_adc1) { + adc_lock_acquire(ADC_UNIT_1); + } + if (s_adc_digi_ctx->use_adc2) { + adc_lock_acquire(ADC_UNIT_2); + } #if CONFIG_PM_ENABLE - // Lock APB frequency while ADC driver is in use - esp_pm_lock_acquire(s_adc_digi_ctx->pm_lock); + // Lock APB frequency while ADC driver is in use + esp_pm_lock_acquire(s_adc_digi_ctx->pm_lock); #endif #if SOC_ADC_CALIBRATION_V1_SUPPORTED - if (s_adc_digi_ctx->use_adc1) { - uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_1, s_adc_digi_ctx->adc1_atten); - adc_hal_set_calibration_param(ADC_UNIT_1, cal_val); - } - if (s_adc_digi_ctx->use_adc2) { - uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_2, s_adc_digi_ctx->adc2_atten); - adc_hal_set_calibration_param(ADC_UNIT_2, cal_val); - } + if (s_adc_digi_ctx->use_adc1) { + adc_set_hw_calibration_code(ADC_UNIT_1, s_adc_digi_ctx->adc1_atten); + } + if (s_adc_digi_ctx->use_adc2) { + adc_set_hw_calibration_code(ADC_UNIT_2, s_adc_digi_ctx->adc2_atten); + } #endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED #if SOC_ADC_ARBITER_SUPPORTED - adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); - adc_hal_arbiter_config(&config); + adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); + adc_hal_arbiter_config(&config); #endif //#if SOC_ADC_ARBITER_SUPPORTED - adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE); - adc_hal_set_controller(ADC_UNIT_2, ADC_HAL_CONTINUOUS_READ_MODE); + adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE); + adc_hal_set_controller(ADC_UNIT_2, ADC_HAL_CONTINUOUS_READ_MODE); - adc_hal_digi_init(&s_adc_digi_ctx->hal); - adc_hal_digi_controller_config(&s_adc_digi_ctx->hal, &s_adc_digi_ctx->hal_digi_ctrlr_cfg); + adc_hal_digi_init(&s_adc_digi_ctx->hal); + adc_hal_digi_controller_config(&s_adc_digi_ctx->hal, &s_adc_digi_ctx->hal_digi_ctrlr_cfg); - //start conversion - adc_hal_digi_start(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf); + //start conversion + adc_hal_digi_start(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf); - } -#if CONFIG_IDF_TARGET_ESP32S2 - //For being compatible with the deprecated behaviour - else { - ESP_LOGE(ADC_TAG, "API used without driver initialization before. The following behaviour is deprecated!!"); -#ifdef CONFIG_PM_ENABLE - ESP_RETURN_ON_FALSE((adc_digi_arbiter_lock), ESP_FAIL, ADC_TAG, "Should start after call `adc_digi_controller_config`"); - esp_pm_lock_acquire(adc_digi_arbiter_lock); -#endif - ADC_ENTER_CRITICAL(); - adc_ll_digi_dma_enable(); - adc_ll_digi_trigger_enable(); - ADC_EXIT_CRITICAL(); - } -#endif //#if CONFIG_IDF_TARGET_ESP32S2 return ESP_OK; } esp_err_t adc_digi_stop(void) { - if (s_adc_digi_ctx) { - if (s_adc_digi_ctx->driver_start_flag != 1) { - ESP_LOGE(ADC_TAG, "The driver is already stopped"); - return ESP_ERR_INVALID_STATE; - } - s_adc_digi_ctx->driver_start_flag = 0; + if (s_adc_digi_ctx->driver_start_flag != 1) { + ESP_LOGE(ADC_TAG, "The driver is already stopped"); + return ESP_ERR_INVALID_STATE; + } + s_adc_digi_ctx->driver_start_flag = 0; - //disable the in suc eof intrrupt - adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK); - //clear the in suc eof interrupt - adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK); - //stop ADC - adc_hal_digi_stop(&s_adc_digi_ctx->hal); + //disable the in suc eof intrrupt + adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK); + //clear the in suc eof interrupt + adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK); + //stop ADC + adc_hal_digi_stop(&s_adc_digi_ctx->hal); - adc_hal_digi_deinit(&s_adc_digi_ctx->hal); + adc_hal_digi_deinit(&s_adc_digi_ctx->hal); #if CONFIG_PM_ENABLE - if (s_adc_digi_ctx->pm_lock) { - esp_pm_lock_release(s_adc_digi_ctx->pm_lock); - } + if (s_adc_digi_ctx->pm_lock) { + esp_pm_lock_release(s_adc_digi_ctx->pm_lock); + } #endif //CONFIG_PM_ENABLE - if (s_adc_digi_ctx->use_adc1) { - SAR_ADC1_LOCK_RELEASE(); - } - if (s_adc_digi_ctx->use_adc2) { - SAR_ADC2_LOCK_RELEASE(); - } - adc_power_release(); + if (s_adc_digi_ctx->use_adc2) { + adc_lock_release(ADC_UNIT_2); } -#if CONFIG_IDF_TARGET_ESP32S2 - else { - //For being compatible with the deprecated behaviour - ESP_LOGE(ADC_TAG, "API used without driver initialization before. The following behaviour is deprecated!!"); -#ifdef CONFIG_PM_ENABLE - if (adc_digi_arbiter_lock) { - esp_pm_lock_release(adc_digi_arbiter_lock); - } -#endif - ADC_ENTER_CRITICAL(); - adc_ll_digi_trigger_disable(); - adc_ll_digi_dma_disable(); - ADC_EXIT_CRITICAL(); + if (s_adc_digi_ctx->use_adc1) { + adc_lock_release(ADC_UNIT_1); } -#endif //#if CONFIG_IDF_TARGET_ESP32S2 + adc_power_release(); + return ESP_OK; } @@ -507,50 +503,6 @@ esp_err_t adc_digi_read_bytes(uint8_t *buf, uint32_t length_max, uint32_t *out_l return ret; } -esp_err_t adc_digi_deinitialize(void) -{ - if (!s_adc_digi_ctx) { - return ESP_ERR_INVALID_STATE; - } - - if (s_adc_digi_ctx->driver_start_flag != 0) { - ESP_LOGE(ADC_TAG, "The driver is not stopped"); - return ESP_ERR_INVALID_STATE; - } - - if (s_adc_digi_ctx->ringbuf_hdl) { - vRingbufferDelete(s_adc_digi_ctx->ringbuf_hdl); - s_adc_digi_ctx->ringbuf_hdl = NULL; - } - -#if CONFIG_PM_ENABLE - if (s_adc_digi_ctx->pm_lock) { - esp_pm_lock_delete(s_adc_digi_ctx->pm_lock); - } -#endif //CONFIG_PM_ENABLE - - free(s_adc_digi_ctx->rx_dma_buf); - free(s_adc_digi_ctx->hal.rx_desc); - free(s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern); -#if SOC_GDMA_SUPPORTED - gdma_disconnect(s_adc_digi_ctx->rx_dma_channel); - gdma_del_channel(s_adc_digi_ctx->rx_dma_channel); -#elif CONFIG_IDF_TARGET_ESP32S2 - esp_intr_free(s_adc_digi_ctx->intr_hdl); - spicommon_dma_chan_free(s_adc_digi_ctx->spi_host); - spicommon_periph_free(s_adc_digi_ctx->spi_host); -#elif CONFIG_IDF_TARGET_ESP32 - esp_intr_free(s_adc_digi_ctx->intr_hdl); - i2s_platform_release_occupation(s_adc_digi_ctx->i2s_host); -#endif - free(s_adc_digi_ctx); - s_adc_digi_ctx = NULL; - - periph_module_disable(PERIPH_SARADC_MODULE); - - return ESP_OK; -} - /*--------------------------------------------------------------- Digital controller setting ---------------------------------------------------------------*/ @@ -573,9 +525,6 @@ esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config) } #endif ESP_RETURN_ON_FALSE(config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC sampling frequency out of range"); -#if CONFIG_IDF_TARGET_ESP32 - ESP_RETURN_ON_FALSE(config->conv_limit_en == 1, ESP_ERR_INVALID_ARG, ADC_TAG, "`conv_limit_en` should be set to 1"); -#endif #if CONFIG_IDF_TARGET_ESP32 ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1"); @@ -589,8 +538,6 @@ esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config) ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2"); #endif - s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_en = config->conv_limit_en; - s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_num = config->conv_limit_num; s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern_len = config->pattern_num; s_adc_digi_ctx->hal_digi_ctrlr_cfg.sample_freq_hz = config->sample_freq_hz; s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_mode = config->conv_mode; @@ -626,319 +573,18 @@ esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config) return ESP_OK; } - -#if CONFIG_IDF_TARGET_ESP32C3 -/*--------------------------------------------------------------- - ADC Single Read Mode ----------------------------------------------------------------*/ -static adc_atten_t s_atten1_single[ADC1_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC1, used by single read API -static adc_atten_t s_atten2_single[ADC2_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC2, used by single read API - -esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) +/** + * @brief This function will be called during start up, to check that adc_continuous driver is not running along with the legacy adc_continuous driver + */ +__attribute__((constructor)) +static void check_adc_continuous_driver_conflict(void) { - esp_err_t ret; - uint32_t channel = ADC2_CHANNEL_MAX; - if (adc_unit == ADC_UNIT_2) { - for (int i = 0; i < ADC2_CHANNEL_MAX; i++) { - if (gpio == ADC_GET_IO_NUM(ADC_UNIT_2, i)) { - channel = i; - break; - } - } - if (channel == ADC2_CHANNEL_MAX) { - return ESP_ERR_INVALID_ARG; - } + // This function was declared as weak here. adc_continuous driver has one implementation. + // So if adc_continuous driver is not linked in, then `adc_continuous_new_handle` should be NULL at runtime. + extern __attribute__((weak)) esp_err_t adc_continuous_new_handle(const void *init_config, void **ret_handle); + if ((void *)adc_continuous_new_handle != NULL) { + ESP_EARLY_LOGE(ADC_TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver"); + abort(); } - - adc_power_acquire(); - if (adc_unit == ADC_UNIT_1) { - ADC_ENTER_CRITICAL(); - adc_hal_vref_output(ADC_UNIT_1, channel, true); - ADC_EXIT_CRITICAL(); - } else { //ADC_UNIT_2 - ADC_ENTER_CRITICAL(); - adc_hal_vref_output(ADC_UNIT_2, channel, true); - ADC_EXIT_CRITICAL(); - } - - ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel)); - - return ret; + ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_continuous.h`"); } - -esp_err_t adc1_config_width(adc_bits_width_t width_bit) -{ - //On ESP32C3, the data width is always 12-bits. - if (width_bit != ADC_WIDTH_BIT_12) { - return ESP_ERR_INVALID_ARG; - } - - return ESP_OK; -} - -esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten) -{ - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC1 channel error"); - ESP_RETURN_ON_FALSE((atten < SOC_ADC_ATTEN_NUM), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC Atten Err"); - - esp_err_t ret = ESP_OK; - s_atten1_single[channel] = atten; - ret = adc_digi_gpio_init(ADC_UNIT_1, BIT(channel)); - - adc_hal_calibration_init(ADC_UNIT_1); - - return ret; -} - -int adc1_get_raw(adc1_channel_t channel) -{ - int raw_out = 0; - - periph_module_enable(PERIPH_SARADC_MODULE); - adc_power_acquire(); - - SAR_ADC1_LOCK_ACQUIRE(); - - adc_atten_t atten = s_atten1_single[channel]; - uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_1, atten); - adc_hal_set_calibration_param(ADC_UNIT_1, cal_val); - - ADC_REG_LOCK_ENTER(); - adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten); - adc_hal_convert(ADC_UNIT_1, channel, &raw_out); - ADC_REG_LOCK_EXIT(); - - SAR_ADC1_LOCK_RELEASE(); - - adc_power_release(); - periph_module_disable(PERIPH_SARADC_MODULE); - - return raw_out; -} - -esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) -{ - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_2), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 channel error"); - ESP_RETURN_ON_FALSE((atten <= ADC_ATTEN_11db), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 Atten Err"); - - esp_err_t ret = ESP_OK; - s_atten2_single[channel] = atten; - ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel)); - - adc_hal_calibration_init(ADC_UNIT_2); - - return ret; -} - -esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out) -{ - //On ESP32C3, the data width is always 12-bits. - if (width_bit != ADC_WIDTH_BIT_12) { - return ESP_ERR_INVALID_ARG; - } - - esp_err_t ret = ESP_OK; - - periph_module_enable(PERIPH_SARADC_MODULE); - adc_power_acquire(); - - SAR_ADC2_LOCK_ACQUIRE(); - - adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); - adc_hal_arbiter_config(&config); - - adc_atten_t atten = s_atten2_single[channel]; - uint32_t cal_val = adc_get_calibration_offset(ADC_UNIT_2, atten); - adc_hal_set_calibration_param(ADC_UNIT_2, cal_val); - - ADC_REG_LOCK_ENTER(); - adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten); - ret = adc_hal_convert(ADC_UNIT_2, channel, raw_out); - ADC_REG_LOCK_EXIT(); - - SAR_ADC2_LOCK_RELEASE(); - - adc_power_release(); - periph_module_disable(PERIPH_SARADC_MODULE); - - return ret; -} - -/*************************************/ -/* Digital controller filter setting */ -/*************************************/ - -esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx) -{ - ADC_ENTER_CRITICAL(); - adc_hal_digi_filter_reset(idx); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config) -{ - ADC_ENTER_CRITICAL(); - adc_hal_digi_filter_set_factor(idx, config); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config) -{ - ADC_ENTER_CRITICAL(); - adc_hal_digi_filter_get_factor(idx, config); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable) -{ - ADC_ENTER_CRITICAL(); - adc_hal_digi_filter_enable(idx, enable); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/**************************************/ -/* Digital controller monitor setting */ -/**************************************/ - -esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config) -{ - ADC_ENTER_CRITICAL(); - adc_hal_digi_monitor_config(idx, config); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable) -{ - - ADC_ENTER_CRITICAL(); - adc_hal_digi_monitor_enable(idx, enable); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} -#endif //#if CONFIG_IDF_TARGET_ESP32C3 - - -#if SOC_ADC_CALIBRATION_V1_SUPPORTED -/*--------------------------------------------------------------- - Hardware Calibration Setting ----------------------------------------------------------------*/ -#if CONFIG_IDF_TARGET_ESP32S2 -#define esp_efuse_rtc_calib_get_ver() esp_efuse_rtc_table_read_calib_version() - -static inline uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten) -{ - int tag = esp_efuse_rtc_table_get_tag(version, adc_unit + 1, atten, RTCCALIB_V2_PARAM_VINIT); - return esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); -} -#endif - -static uint16_t s_adc_cali_param[SOC_ADC_PERIPH_NUM][SOC_ADC_ATTEN_NUM] = {}; - -//NOTE: according to calibration version, different types of lock may be taken during the process: -// 1. Semaphore when reading efuse -// 2. Lock (Spinlock, or Mutex) if we actually do ADC calibration in the future -//This function shoudn't be called inside critical section or ISR -uint32_t adc_get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten) -{ - if (s_adc_cali_param[adc_n][atten]) { - ESP_LOGV(ADC_TAG, "Use calibrated val ADC%d atten=%d: %04X", adc_n, atten, s_adc_cali_param[adc_n][atten]); - return (uint32_t)s_adc_cali_param[adc_n][atten]; - } - - // check if we can fetch the values from eFuse. - int version = esp_efuse_rtc_calib_get_ver(); - - uint32_t init_code = 0; - - if (version == ESP_EFUSE_ADC_CALIB_VER) { - init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten); - - } else { - ESP_LOGD(ADC_TAG, "Calibration eFuse is not configured, use self-calibration for ICode"); - adc_power_acquire(); - ADC_ENTER_CRITICAL(); - const bool internal_gnd = true; - init_code = adc_hal_self_calibration(adc_n, atten, internal_gnd); - ADC_EXIT_CRITICAL(); - adc_power_release(); - } - - s_adc_cali_param[adc_n][atten] = init_code; - ESP_LOGV(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code); - - return init_code; -} - -// Internal function to calibrate PWDET for WiFi -esp_err_t adc_cal_offset(adc_unit_t adc_n, adc_atten_t atten) -{ - adc_hal_calibration_init(adc_n); - uint32_t cal_val = adc_get_calibration_offset(adc_n, atten); - ADC_ENTER_CRITICAL(); - adc_hal_set_calibration_param(adc_n, cal_val); - ADC_EXIT_CRITICAL(); - return ESP_OK; -} -#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED - -/*--------------------------------------------------------------- - Deprecated API ----------------------------------------------------------------*/ -#if CONFIG_IDF_TARGET_ESP32C3 -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#include "deprecated/driver/adc_deprecated.h" -#include "deprecated/driver/adc_types_deprecated.h" -esp_err_t adc_digi_controller_config(const adc_digi_config_t *config) -{ - if (!s_adc_digi_ctx) { - return ESP_ERR_INVALID_STATE; - } - ESP_RETURN_ON_FALSE((config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW), ESP_ERR_INVALID_ARG, ADC_TAG, "DC sampling frequency out of range"); - - s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_en = config->conv_limit_en; - s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_limit_num = config->conv_limit_num; - s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern_len = config->adc_pattern_len; - s_adc_digi_ctx->hal_digi_ctrlr_cfg.sample_freq_hz = config->sample_freq_hz; - - for (int i = 0; i < config->adc_pattern_len; i++) { - s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i].atten = config->adc_pattern[i].atten; - s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i].channel = config->adc_pattern[i].channel; - s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i].unit = config->adc_pattern[i].unit; - } - - - const int atten_uninitialized = 999; - s_adc_digi_ctx->adc1_atten = atten_uninitialized; - s_adc_digi_ctx->adc2_atten = atten_uninitialized; - s_adc_digi_ctx->use_adc1 = 0; - s_adc_digi_ctx->use_adc2 = 0; - for (int i = 0; i < config->adc_pattern_len; i++) { - const adc_digi_pattern_config_t *pat = &s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern[i]; - if (pat->unit == ADC_UNIT_1) { - s_adc_digi_ctx->use_adc1 = 1; - - if (s_adc_digi_ctx->adc1_atten == atten_uninitialized) { - s_adc_digi_ctx->adc1_atten = pat->atten; - } else if (s_adc_digi_ctx->adc1_atten != pat->atten) { - return ESP_ERR_INVALID_ARG; - } - } else if (pat->unit == ADC_UNIT_2) { - //See whether ADC2 will be used or not. If yes, the ``sar_adc2_mutex`` should be acquired in the continuous read driver - s_adc_digi_ctx->use_adc2 = 1; - - if (s_adc_digi_ctx->adc2_atten == atten_uninitialized) { - s_adc_digi_ctx->adc2_atten = pat->atten; - } else if (s_adc_digi_ctx->adc2_atten != pat->atten) { - return ESP_ERR_INVALID_ARG; - } - } - } - - return ESP_OK; -} -#endif //#if CONFIG_IDF_TARGET_ESP32C3 diff --git a/components/driver/deprecated/adc_i2s_deprecated.c b/components/driver/deprecated/adc_i2s_deprecated.c new file mode 100644 index 0000000000..245214f9f6 --- /dev/null +++ b/components/driver/deprecated/adc_i2s_deprecated.c @@ -0,0 +1,252 @@ +/* + * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/*---------------------------------------------------------------------------------- + This file contains ESP32 and ESP32S2 Depricated ADC APIs and functions +-----------------------------------------------------------------------------------*/ + +#include "sdkconfig.h" +#include "esp_types.h" +#include "esp_log.h" +#include "esp_intr_alloc.h" +#include "driver/rtc_io.h" +#include "hal/adc_hal.h" +#include "hal/adc_ll.h" +#include "hal/adc_types.h" +#include "hal/adc_hal_conf.h" +#ifdef CONFIG_PM_ENABLE +#include "esp_pm.h" +#endif +#include "esp_private/adc_private.h" +#include "freertos/FreeRTOS.h" + +#include "driver/adc_i2s_legacy.h" +#include "driver/adc_types_legacy.h" + +static __attribute__((unused)) const char *ADC_TAG = "ADC"; + +#define ADC_CHECK_RET(fun_ret) ({ \ + if (fun_ret != ESP_OK) { \ + ESP_LOGE(ADC_TAG,"%s:%d\n",__FUNCTION__,__LINE__); \ + return ESP_FAIL; \ + } \ +}) + +#define ADC_CHECK(a, str, ret_val) ({ \ + if (!(a)) { \ + ESP_LOGE(ADC_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } \ +}) + +#define ADC_CHANNEL_CHECK(periph, channel) ADC_CHECK(channel < SOC_ADC_CHANNEL_NUM(periph), "ADC"#periph" channel error", ESP_ERR_INVALID_ARG) +#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel]) + +extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished. +#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock) +#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock) + +#ifdef CONFIG_PM_ENABLE +esp_pm_lock_handle_t adc_digi_arbiter_lock = NULL; +#endif //CONFIG_PM_ENABLE + + +#if CONFIG_IDF_TARGET_ESP32 +/*--------------------------------------------------------------- + ESP32 Depricated ADC APIs and functions +---------------------------------------------------------------*/ +#define DIG_ADC_OUTPUT_FORMAT_DEFUALT (ADC_DIGI_FORMAT_12BIT) +#define DIG_ADC_ATTEN_DEFUALT (ADC_ATTEN_DB_11) +#define DIG_ADC_BIT_WIDTH_DEFUALT (3) //3 for ADC_WIDTH_BIT_12 + +/** + * @brief ADC digital controller (DMA mode) conversion rules setting. + */ +typedef struct { + union { + struct { + uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements. + 0: measurement range 0 - 800mV, + 1: measurement range 0 - 1100mV, + 2: measurement range 0 - 1350mV, + 3: measurement range 0 - 2600mV. */ + uint8_t bit_width: 2; /*!< ADC resolution. +- 0: 9 bit; +- 1: 10 bit; +- 2: 11 bit; +- 3: 12 bit. */ + int8_t channel: 4; /*!< ADC channel index. */ + }; + uint8_t val; /*!> offset)); // clear old data + tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data + SYSCON.saradc_sar1_patt_tab[index] = tab; // Write back + } else { // adc_n == ADC_UNIT_2 + tab = SYSCON.saradc_sar2_patt_tab[index]; // Read old register value + tab &= (~(0xFF000000 >> offset)); // clear old data + tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data + SYSCON.saradc_sar2_patt_tab[index] = tab; // Write back + } +} + +static void adc_digi_controller_reg_set(const adc_digi_config_t *cfg) +{ + /* On ESP32, only support ADC1 */ + switch (cfg->conv_mode) { + case ADC_CONV_SINGLE_UNIT_1: + adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1); + break; + case ADC_CONV_SINGLE_UNIT_2: + adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC2); + break; + case ADC_CONV_BOTH_UNIT: + adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT); + break; + case ADC_CONV_ALTER_UNIT: + adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ALTER_UNIT); + break; + default: + abort(); + } + + if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) { + adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG); + if (cfg->adc1_pattern_len) { + adc_ll_digi_clear_pattern_table(ADC_UNIT_1); + adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, cfg->adc1_pattern_len); + for (uint32_t i = 0; i < cfg->adc1_pattern_len; i++) { + adc_ll_digi_prepare_pattern_table(ADC_UNIT_1, i, cfg->adc1_pattern[i]); + } + } + } + if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) { + adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_DIG); + if (cfg->adc2_pattern_len) { + adc_ll_digi_clear_pattern_table(ADC_UNIT_2); + adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, cfg->adc2_pattern_len); + for (uint32_t i = 0; i < cfg->adc2_pattern_len; i++) { + adc_ll_digi_prepare_pattern_table(ADC_UNIT_2, i, cfg->adc2_pattern[i]); + } + } + } + adc_ll_digi_set_output_format(cfg->format); + adc_ll_digi_convert_limit_enable(ADC_LL_DEFAULT_CONV_LIMIT_EN); + adc_ll_digi_set_convert_limit_num(ADC_LL_DEFAULT_CONV_LIMIT_NUM); + adc_ll_digi_set_data_source(ADC_I2S_DATA_SRC_ADC); +} + +esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src) +{ + ADC_CHECK((src == ADC_I2S_DATA_SRC_IO_SIG || src == ADC_I2S_DATA_SRC_ADC), "ADC i2s data source error", ESP_ERR_INVALID_ARG); + ADC_ENTER_CRITICAL(); + adc_ll_digi_set_data_source(src); + ADC_EXIT_CRITICAL(); + return ESP_OK; +} + +extern esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel); +esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel) +{ + if (adc_unit == ADC_UNIT_1) { + ADC_CHANNEL_CHECK(ADC_UNIT_1, channel); + } else if (adc_unit == ADC_UNIT_2) { + //ADC2 does not support DMA mode + ADC_CHECK(false, "ADC2 not support DMA for now.", ESP_ERR_INVALID_ARG); + ADC_CHANNEL_CHECK(ADC_UNIT_2, channel); + } + + adc_digi_pattern_table_t adc1_pattern[1]; + adc_digi_pattern_table_t adc2_pattern[1]; + adc_digi_config_t dig_cfg = { + .format = DIG_ADC_OUTPUT_FORMAT_DEFUALT, + .conv_mode = ADC_CONV_SINGLE_UNIT_1, + }; + + if (adc_unit == ADC_UNIT_1) { + adc1_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT; + adc1_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT; + adc1_pattern[0].channel = channel; + dig_cfg.adc1_pattern_len = 1; + dig_cfg.adc1_pattern = adc1_pattern; + } else if (adc_unit == ADC_UNIT_2) { + adc2_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT; + adc2_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT; + adc2_pattern[0].channel = channel; + dig_cfg.adc2_pattern_len = 1; + dig_cfg.adc2_pattern = adc2_pattern; + } + adc_common_gpio_init(adc_unit, channel); + ADC_ENTER_CRITICAL(); + adc_ll_digi_set_fsm_time(ADC_HAL_FSM_RSTB_WAIT_DEFAULT, ADC_HAL_FSM_START_WAIT_DEFAULT, + ADC_HAL_FSM_STANDBY_WAIT_DEFAULT); + adc_ll_set_sample_cycle(ADC_HAL_SAMPLE_CYCLE_DEFAULT); + adc_hal_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); + adc_ll_digi_output_invert(ADC_UNIT_1, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1)); + adc_ll_digi_output_invert(ADC_UNIT_2, ADC_HAL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2)); + adc_ll_digi_set_clk_div(ADC_HAL_DIGI_SAR_CLK_DIV_DEFAULT); + adc_digi_controller_reg_set(&dig_cfg); + ADC_EXIT_CRITICAL(); + + return ESP_OK; +} + +#endif //#if CONFIG_IDF_TARGET_ESP32 diff --git a/components/driver/adc_single.c b/components/driver/deprecated/adc_legacy.c similarity index 60% rename from components/driver/adc_single.c rename to components/driver/deprecated/adc_legacy.c index 14a79fc490..8ba12c01a1 100644 --- a/components/driver/adc_single.c +++ b/components/driver/deprecated/adc_legacy.c @@ -8,6 +8,7 @@ #include #include #include "sdkconfig.h" + #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/timers.h" @@ -17,11 +18,14 @@ #include "driver/rtc_io.h" #include "sys/lock.h" #include "driver/gpio.h" -#include "driver/adc.h" +#include "esp_private/adc_private.h" #include "adc1_private.h" #include "hal/adc_types.h" #include "hal/adc_hal.h" #include "hal/adc_hal_conf.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/adc_lock.h" +#include "driver/adc_types_legacy.h" #if SOC_DAC_SUPPORTED #include "driver/dac.h" @@ -79,7 +83,6 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi #define FSM_ENTER() RTC_ENTER_CRITICAL() #define FSM_EXIT() RTC_EXIT_CRITICAL() -//TODO: IDF-3610 #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 //prevent ADC1 being used by I2S dma and other tasks at the same time. static _lock_t adc1_dma_lock; @@ -102,97 +105,20 @@ In ADC2, there're two locks used for different cases: Since conversions are short (about 31us), app returns the lock very soon, we use a spinlock to stand there waiting to do conversions one by one. -adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock. +adc2_spinlock should be acquired first, then call `adc_lock_release(ADC_UNIT_2)` or rtc_spinlock. */ -#ifdef CONFIG_IDF_TARGET_ESP32 -//prevent ADC2 being used by wifi and other tasks at the same time. -static _lock_t adc2_wifi_lock; -/** For ESP32S2 the ADC2 The right to use ADC2 is controlled by the arbiter, and there is no need to set a lock. */ -#define SARADC2_ACQUIRE() _lock_acquire( &adc2_wifi_lock ) -#define SARADC2_RELEASE() _lock_release( &adc2_wifi_lock ) -#define SARADC2_TRY_ACQUIRE() _lock_try_acquire( &adc2_wifi_lock ) -#define SARADC2_LOCK_CHECK() ((uint32_t *)adc2_wifi_lock != NULL) - -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 -#define SARADC2_ACQUIRE() -#define SARADC2_RELEASE() -#define SARADC2_TRY_ACQUIRE() (0) //WIFI controller and rtc controller have independent parameter configuration. -#define SARADC2_LOCK_CHECK() (true) - -#endif // CONFIG_IDF_TARGET_* - #if CONFIG_IDF_TARGET_ESP32S2 #ifdef CONFIG_PM_ENABLE static esp_pm_lock_handle_t s_adc2_arbiter_lock; #endif //CONFIG_PM_ENABLE #endif // !CONFIG_IDF_TARGET_ESP32 +static esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw); /*--------------------------------------------------------------- ADC Common ---------------------------------------------------------------*/ -// ADC Power - -// This gets incremented when adc_power_acquire() is called, and decremented when -// adc_power_release() is called. ADC is powered down when the value reaches zero. -// Should be modified within critical section (ADC_ENTER/EXIT_CRITICAL). -static int s_adc_power_on_cnt; - -static void adc_power_on_internal(void) -{ - /* Set the power always on to increase precision. */ - adc_hal_set_power_manage(ADC_POWER_SW_ON); -} - -void adc_power_acquire(void) -{ - ADC_POWER_ENTER(); - s_adc_power_on_cnt++; - if (s_adc_power_on_cnt == 1) { - adc_power_on_internal(); - } - ADC_POWER_EXIT(); -} - -void adc_power_on(void) -{ - ADC_POWER_ENTER(); - adc_power_on_internal(); - ADC_POWER_EXIT(); -} - -static void adc_power_off_internal(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - adc_hal_set_power_manage(ADC_POWER_SW_OFF); -#else - adc_hal_set_power_manage(ADC_POWER_BY_FSM); -#endif -} - -void adc_power_release(void) -{ - ADC_POWER_ENTER(); - s_adc_power_on_cnt--; - /* Sanity check */ - if (s_adc_power_on_cnt < 0) { - ADC_POWER_EXIT(); - ESP_LOGE(ADC_TAG, "%s called, but s_adc_power_on_cnt == 0", __func__); - abort(); - } else if (s_adc_power_on_cnt == 0) { - adc_power_off_internal(); - } - ADC_POWER_EXIT(); -} - -void adc_power_off(void) -{ - ADC_POWER_ENTER(); - adc_power_off_internal(); - ADC_POWER_EXIT(); -} - esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num) { ADC_CHANNEL_CHECK(ADC_UNIT_1, channel); @@ -207,6 +133,7 @@ esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num) return ESP_OK; } +#if (SOC_ADC_PERIPH_NUM >= 2) esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num) { ADC_CHANNEL_CHECK(ADC_UNIT_2, channel); @@ -220,20 +147,10 @@ esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num) return ESP_OK; } +#endif //------------------------------------------------------------RTC Single Read----------------------------------------------// #if SOC_ADC_RTC_CTRL_SUPPORTED - -#if SOC_ADC_CALIBRATION_V1_SUPPORTED -uint32_t get_calibration_offset(adc_unit_t adc_n, adc_channel_t chan) -{ - adc_atten_t atten = adc_ll_get_atten(adc_n, chan); - extern uint32_t adc_get_calibration_offset(adc_unit_t adc_n, adc_atten_t atten); - - return adc_get_calibration_offset(adc_n, atten); -} -#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED - esp_err_t adc_set_clk_div(uint8_t clk_div) { DIGI_CONTROLLER_ENTER(); @@ -264,11 +181,6 @@ static void adc_rtc_chan_init(adc_unit_t adc_unit) } } -/** - * This function is NOT an API. - * Now some to-be-deprecated APIs are using this function, so don't make it static for now. - * Will make this static on v5.0 - */ esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) { gpio_num_t gpio_num = 0; @@ -314,21 +226,25 @@ esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit) ADC_CHECK(width_bit < ADC_WIDTH_MAX, "unsupported bit width", ESP_ERR_INVALID_ARG); adc_bitwidth_t bitwidth = 0; #if CONFIG_IDF_TARGET_ESP32 - switch(width_bit) { - case ADC_WIDTH_BIT_9: - bitwidth = ADC_BITWIDTH_9; - break; - case ADC_WIDTH_BIT_10: - bitwidth = ADC_BITWIDTH_10; - break; - case ADC_WIDTH_BIT_11: - bitwidth = ADC_BITWIDTH_11; - break; - case ADC_WIDTH_BIT_12: - bitwidth = ADC_BITWIDTH_12; - break; - default: - abort(); + if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) { + bitwidth = SOC_ADC_RTC_MAX_BITWIDTH; + } else { + switch(width_bit) { + case ADC_WIDTH_BIT_9: + bitwidth = ADC_BITWIDTH_9; + break; + case ADC_WIDTH_BIT_10: + bitwidth = ADC_BITWIDTH_10; + break; + case ADC_WIDTH_BIT_11: + bitwidth = ADC_BITWIDTH_11; + break; + case ADC_WIDTH_BIT_12: + bitwidth = ADC_BITWIDTH_12; + break; + default: + return ESP_ERR_INVALID_ARG; + } } #elif CONFIG_IDF_TARGET_ESP32S2 bitwidth = ADC_BITWIDTH_13; @@ -392,21 +308,25 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit) ADC_CHECK(width_bit < ADC_WIDTH_MAX, "unsupported bit width", ESP_ERR_INVALID_ARG); adc_bitwidth_t bitwidth = 0; #if CONFIG_IDF_TARGET_ESP32 - switch(width_bit) { - case ADC_WIDTH_BIT_9: - bitwidth = ADC_BITWIDTH_9; - break; - case ADC_WIDTH_BIT_10: - bitwidth = ADC_BITWIDTH_10; - break; - case ADC_WIDTH_BIT_11: - bitwidth = ADC_BITWIDTH_11; - break; - case ADC_WIDTH_BIT_12: - bitwidth = ADC_BITWIDTH_12; - break; - default: - abort(); + if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) { + bitwidth = SOC_ADC_RTC_MAX_BITWIDTH; + } else { + switch(width_bit) { + case ADC_WIDTH_BIT_9: + bitwidth = ADC_BITWIDTH_9; + break; + case ADC_WIDTH_BIT_10: + bitwidth = ADC_BITWIDTH_10; + break; + case ADC_WIDTH_BIT_11: + bitwidth = ADC_BITWIDTH_11; + break; + case ADC_WIDTH_BIT_12: + bitwidth = ADC_BITWIDTH_12; + break; + default: + return ESP_ERR_INVALID_ARG; + } } #elif CONFIG_IDF_TARGET_ESP32S2 bitwidth = ADC_BITWIDTH_13; @@ -470,9 +390,8 @@ int adc1_get_raw(adc1_channel_t channel) adc1_rtc_mode_acquire(); #if SOC_ADC_CALIBRATION_V1_SUPPORTED - // Get calibration value before going into critical section - uint32_t cal_val = get_calibration_offset(ADC_UNIT_1, channel); - adc_hal_set_calibration_param(ADC_UNIT_1, cal_val); + adc_atten_t atten = adc_ll_get_atten(ADC_UNIT_1, channel); + adc_set_hw_calibration_code(ADC_UNIT_1, atten); #endif //SOC_ADC_CALIBRATION_V1_SUPPORTED SARADC1_ENTER(); @@ -515,27 +434,10 @@ void adc1_ulp_enable(void) } #endif +#if (SOC_ADC_PERIPH_NUM >= 2) /*--------------------------------------------------------------- ADC2 ---------------------------------------------------------------*/ -/** For ESP32S2 the ADC2 The right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/ -esp_err_t adc2_wifi_acquire(void) -{ - /* Wi-Fi module will use adc2. Use locks to avoid conflicts. */ - SARADC2_ACQUIRE(); - ESP_LOGD( ADC_TAG, "Wi-Fi takes adc2 lock." ); - return ESP_OK; -} - -esp_err_t adc2_wifi_release(void) -{ - ADC_CHECK(SARADC2_LOCK_CHECK(), "wifi release called before acquire", ESP_ERR_INVALID_STATE ); - SARADC2_RELEASE(); - ESP_LOGD( ADC_TAG, "Wi-Fi returns adc2 lock." ); - - return ESP_OK; -} - esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) { ADC_CHANNEL_CHECK(ADC_UNIT_2, channel); @@ -543,10 +445,13 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) adc_common_gpio_init(ADC_UNIT_2, channel); - if ( SARADC2_TRY_ACQUIRE() == -1 ) { +#if CONFIG_IDF_TARGET_ESP32 + /** For ESP32S2 and S3, the right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/ + if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) { //try the lock, return if failed (wifi using). return ESP_ERR_TIMEOUT; } +#endif //avoid collision with other tasks SARADC2_ENTER(); @@ -554,7 +459,9 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten); SARADC2_EXIT(); - SARADC2_RELEASE(); +#if CONFIG_IDF_TARGET_ESP32 + adc_lock_release(ADC_UNIT_2); +#endif #if SOC_ADC_CALIBRATION_V1_SUPPORTED adc_hal_calibration_init(ADC_UNIT_2); @@ -610,21 +517,25 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * ADC_CHECK(channel < ADC2_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG); ADC_CHECK(width_bit < ADC_WIDTH_MAX, "unsupported bit width", ESP_ERR_INVALID_ARG); #if CONFIG_IDF_TARGET_ESP32 - switch(width_bit) { - case ADC_WIDTH_BIT_9: - bitwidth = ADC_BITWIDTH_9; - break; - case ADC_WIDTH_BIT_10: - bitwidth = ADC_BITWIDTH_10; - break; - case ADC_WIDTH_BIT_11: - bitwidth = ADC_BITWIDTH_11; - break; - case ADC_WIDTH_BIT_12: - bitwidth = ADC_BITWIDTH_12; - break; - default: - abort(); + if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) { + bitwidth = SOC_ADC_RTC_MAX_BITWIDTH; + } else { + switch(width_bit) { + case ADC_WIDTH_BIT_9: + bitwidth = ADC_BITWIDTH_9; + break; + case ADC_WIDTH_BIT_10: + bitwidth = ADC_BITWIDTH_10; + break; + case ADC_WIDTH_BIT_11: + bitwidth = ADC_BITWIDTH_11; + break; + case ADC_WIDTH_BIT_12: + bitwidth = ADC_BITWIDTH_12; + break; + default: + return ESP_ERR_INVALID_ARG; + } } #elif CONFIG_IDF_TARGET_ESP32S2 bitwidth = ADC_BITWIDTH_13; @@ -633,15 +544,17 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * #endif #if SOC_ADC_CALIBRATION_V1_SUPPORTED - // Get calibration value before going into critical section - uint32_t cal_val = get_calibration_offset(ADC_UNIT_2, channel); - adc_hal_set_calibration_param(ADC_UNIT_2, cal_val); + adc_atten_t atten = adc_ll_get_atten(ADC_UNIT_2, channel); + adc_set_hw_calibration_code(ADC_UNIT_2, atten); #endif //SOC_ADC_CALIBRATION_V1_SUPPORTED - if ( SARADC2_TRY_ACQUIRE() == -1 ) { +#if CONFIG_IDF_TARGET_ESP32 + /** For ESP32S2 and S3, the right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/ + if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) { //try the lock, return if failed (wifi using). return ESP_ERR_TIMEOUT; } +#endif adc_power_acquire(); //in critical section with whole rtc module //avoid collision with other tasks @@ -689,17 +602,14 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * SARADC2_EXIT(); adc_power_release(); - SARADC2_RELEASE(); +#if CONFIG_IDF_TARGET_ESP32 + adc_lock_release(ADC_UNIT_2); +#endif *raw_out = adc_value; return ret; } -esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) -{ - return adc_vref_to_gpio(ADC_UNIT_2, gpio); -} - esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) { #ifdef CONFIG_IDF_TARGET_ESP32 @@ -736,3 +646,278 @@ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) } #endif //SOC_ADC_RTC_CTRL_SUPPORTED +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) + + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED +/*--------------------------------------------------------------- + Legacy ADC Single Read Mode + when RTC controller isn't supported +---------------------------------------------------------------*/ +#include "esp_check.h" + +portMUX_TYPE adc_reg_lock = portMUX_INITIALIZER_UNLOCKED; +#define ADC_REG_LOCK_ENTER() portENTER_CRITICAL(&adc_reg_lock) +#define ADC_REG_LOCK_EXIT() portEXIT_CRITICAL(&adc_reg_lock) + +static adc_atten_t s_atten1_single[ADC1_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC1, used by single read API +#if (SOC_ADC_PERIPH_NUM >= 2) +static adc_atten_t s_atten2_single[ADC2_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC2, used by single read API +#endif + + +static int8_t adc_digi_get_io_num(adc_unit_t adc_unit, uint8_t adc_channel) +{ + assert(adc_unit <= SOC_ADC_PERIPH_NUM); + uint8_t adc_n = (adc_unit == ADC_UNIT_1) ? 0 : 1; + return adc_channel_io_map[adc_n][adc_channel]; +} + +static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask) +{ + esp_err_t ret = ESP_OK; + uint64_t gpio_mask = 0; + uint32_t n = 0; + int8_t io = 0; + + while (channel_mask) { + if (channel_mask & 0x1) { + io = adc_digi_get_io_num(adc_unit, n); + if (io < 0) { + return ESP_ERR_INVALID_ARG; + } + gpio_mask |= BIT64(io); + } + channel_mask = channel_mask >> 1; + n++; + } + + gpio_config_t cfg = { + .pin_bit_mask = gpio_mask, + .mode = GPIO_MODE_DISABLE, + }; + ret = gpio_config(&cfg); + + return ret; +} + +#if CONFIG_IDF_TARGET_ESP32C3 +esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) +{ + esp_err_t ret; + uint32_t channel = ADC2_CHANNEL_MAX; + if (adc_unit == ADC_UNIT_2) { + for (int i = 0; i < ADC2_CHANNEL_MAX; i++) { + if (gpio == ADC_GET_IO_NUM(ADC_UNIT_2, i)) { + channel = i; + break; + } + } + if (channel == ADC2_CHANNEL_MAX) { + return ESP_ERR_INVALID_ARG; + } + } + + adc_power_acquire(); + if (adc_unit == ADC_UNIT_1) { + RTC_ENTER_CRITICAL(); + adc_hal_vref_output(ADC_UNIT_1, channel, true); + RTC_EXIT_CRITICAL(); + } else { //ADC_UNIT_2 + RTC_ENTER_CRITICAL(); + adc_hal_vref_output(ADC_UNIT_2, channel, true); + RTC_EXIT_CRITICAL(); + } + + ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel)); + + return ret; +} +#endif + +esp_err_t adc1_config_width(adc_bits_width_t width_bit) +{ + //On ESP32C3, the data width is always 12-bits. + if (width_bit != ADC_WIDTH_BIT_12) { + return ESP_ERR_INVALID_ARG; + } + + return ESP_OK; +} + +esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten) +{ + ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC1 channel error"); + ESP_RETURN_ON_FALSE((atten < SOC_ADC_ATTEN_NUM), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC Atten Err"); + + esp_err_t ret = ESP_OK; + s_atten1_single[channel] = atten; + ret = adc_digi_gpio_init(ADC_UNIT_1, BIT(channel)); + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + adc_hal_calibration_init(ADC_UNIT_1); +#endif + + return ret; +} + +int adc1_get_raw(adc1_channel_t channel) +{ + int raw_out = 0; + + if (adc_lock_try_acquire(ADC_UNIT_1) != ESP_OK) { + return ESP_ERR_TIMEOUT; + } + + periph_module_enable(PERIPH_SARADC_MODULE); + adc_power_acquire(); + adc_ll_digi_clk_sel(0); + + adc_atten_t atten = s_atten1_single[channel]; +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + adc_set_hw_calibration_code(ADC_UNIT_1, atten); +#endif + + ADC_REG_LOCK_ENTER(); + adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten); + adc_hal_convert(ADC_UNIT_1, channel, &raw_out); + ADC_REG_LOCK_EXIT(); + + adc_power_release(); + periph_module_disable(PERIPH_SARADC_MODULE); + adc_lock_release(ADC_UNIT_1); + + return raw_out; +} + +#if (SOC_ADC_PERIPH_NUM >= 2) +esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) +{ + ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_2), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 channel error"); + ESP_RETURN_ON_FALSE((atten <= ADC_ATTEN_DB_11), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 Atten Err"); + + esp_err_t ret = ESP_OK; + s_atten2_single[channel] = atten; + ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel)); + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + adc_hal_calibration_init(ADC_UNIT_2); +#endif + + return ret; +} + +esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out) +{ + //On ESP32C3, the data width is always 12-bits. + if (width_bit != ADC_WIDTH_BIT_12) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t ret = ESP_OK; + + if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) { + return ESP_ERR_TIMEOUT; + } + + periph_module_enable(PERIPH_SARADC_MODULE); + adc_power_acquire(); + + adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); + adc_hal_arbiter_config(&config); + + adc_atten_t atten = s_atten2_single[channel]; +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + adc_set_hw_calibration_code(ADC_UNIT_2, atten); +#endif + + ADC_REG_LOCK_ENTER(); + adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten); + ret = adc_hal_convert(ADC_UNIT_2, channel, raw_out); + ADC_REG_LOCK_EXIT(); + + adc_power_release(); + periph_module_disable(PERIPH_SARADC_MODULE); + adc_lock_release(ADC_UNIT_2); + + return ret; +} +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) +#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + + +static void adc_hal_onetime_start(adc_unit_t adc_n) +{ +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + (void)adc_n; + /** + * There is a hardware limitation. If the APB clock frequency is high, the step of this reg signal: ``onetime_start`` may not be captured by the + * ADC digital controller (when its clock frequency is too slow). A rough estimate for this step should be at least 3 ADC digital controller + * clock cycle. + * + * This limitation will be removed in hardware future versions. + * + */ + uint32_t digi_clk = APB_CLK_FREQ / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1); + //Convert frequency to time (us). Since decimals are removed by this division operation. Add 1 here in case of the fact that delay is not enough. + uint32_t delay = (1000 * 1000) / digi_clk + 1; + //3 ADC digital controller clock cycle + delay = delay * 3; + //This coefficient (8) is got from test. When digi_clk is not smaller than ``APB_CLK_FREQ/8``, no delay is needed. + if (digi_clk >= APB_CLK_FREQ/8) { + delay = 0; + } + + adc_oneshot_ll_start(false); + esp_rom_delay_us(delay); + adc_oneshot_ll_start(true); + + //No need to delay here. Becuase if the start signal is not seen, there won't be a done intr. +#else + adc_oneshot_ll_start(adc_n); +#endif +} + +static esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw) +{ + uint32_t event = (adc_n == ADC_UNIT_1) ? ADC_LL_EVENT_ADC1_ONESHOT_DONE : ADC_LL_EVENT_ADC2_ONESHOT_DONE; + adc_oneshot_ll_clear_event(event); + adc_oneshot_ll_disable_all_unit(); + adc_oneshot_ll_enable(adc_n); + adc_oneshot_ll_set_channel(adc_n, channel); + + adc_hal_onetime_start(adc_n); + + while (adc_oneshot_ll_get_event(event) != true) { + ; + } + + *out_raw = adc_oneshot_ll_get_raw_result(adc_n); + if (adc_oneshot_ll_raw_check_valid(adc_n, *out_raw) == false) { + return ESP_ERR_INVALID_STATE; + } + + //HW workaround: when enabling periph clock, this should be false + adc_oneshot_ll_disable_all_unit(); + + return ESP_OK; +} + +#if !CONFIG_IDF_TARGET_ESP32 +//wrapper should be removed after I2S deprecation +/** + * @brief This function will be called during start up, to check that adc_oneshot driver is not running along with the legacy adc oneshot driver + */ +__attribute__((constructor)) +static void check_adc_oneshot_driver_conflict(void) +{ + // This function was declared as weak here. adc_oneshot driver has one implementation. + // So if adc_oneshot driver is not linked in, then `adc_oneshot_new_unit` should be NULL at runtime. + extern __attribute__((weak)) esp_err_t adc_oneshot_new_unit(const void *init_config, void **ret_unit); + if ((void *)adc_oneshot_new_unit != NULL) { + ESP_EARLY_LOGE(ADC_TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver"); + abort(); + } + ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_oneshot.h`"); +} +#endif diff --git a/components/driver/include/driver/adc.h b/components/driver/deprecated/driver/adc.h similarity index 52% rename from components/driver/include/driver/adc.h rename to components/driver/deprecated/driver/adc.h index dfbf82e3d8..269d5c390d 100644 --- a/components/driver/include/driver/adc.h +++ b/components/driver/deprecated/driver/adc.h @@ -1,152 +1,31 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#pragma once +/*---------------------------------------------------------------------------------- + This file contains Deprecated ADC APIs +-----------------------------------------------------------------------------------*/ -#include -#include -#include "esp_err.h" +#pragma once #include "sdkconfig.h" +#include "esp_err.h" #include "driver/gpio.h" +#include "driver/adc_types_legacy.h" #include "hal/adc_types.h" +#if !CONFIG_ADC_SUPPRESS_DEPRECATE_WARN +#warning "legacy adc driver is deprecated, please migrate to use esp_adc/adc_oneshot.h and esp_adc/adc_continuous.h for oneshot mode and continuous mode drivers respectively" +#endif + #ifdef __cplusplus extern "C" { #endif -#if CONFIG_IDF_TARGET_ESP32 -/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/ -typedef enum { - ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 */ - ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 */ - ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO38 */ - ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO39 */ - ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO32 */ - ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO33 */ - ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO34 */ - ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO35 */ - ADC1_CHANNEL_MAX, -} adc1_channel_t; -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // TODO ESP32-S3 channels are wrong IDF-1776 -/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/ -typedef enum { - ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO1 */ - ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO2 */ - ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO3 */ - ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO4 */ - ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO5 */ - ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO6 */ - ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO7 */ - ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO8 */ - ADC1_CHANNEL_8, /*!< ADC1 channel 8 is GPIO9 */ - ADC1_CHANNEL_9, /*!< ADC1 channel 9 is GPIO10 */ - ADC1_CHANNEL_MAX, -} adc1_channel_t; -#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 -/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/ -typedef enum { - ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO0 */ - ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO1 */ - ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO2 */ - ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO3 */ - ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO4 */ - ADC1_CHANNEL_MAX, -} adc1_channel_t; -#endif // CONFIG_IDF_TARGET_* - -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // TODO ESP32-S3 channels are wrong IDF-1776 -/**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/ -typedef enum { - ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 (ESP32), GPIO11 (ESP32-S2) */ - ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 (ESP32), GPIO12 (ESP32-S2) */ - ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 (ESP32), GPIO13 (ESP32-S2) */ - ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 (ESP32), GPIO14 (ESP32-S2) */ - ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 (ESP32), GPIO15 (ESP32-S2) */ - ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 (ESP32), GPIO16 (ESP32-S2) */ - ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 (ESP32), GPIO17 (ESP32-S2) */ - ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 (ESP32), GPIO18 (ESP32-S2) */ - ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 (ESP32), GPIO19 (ESP32-S2) */ - ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */ - ADC2_CHANNEL_MAX, -} adc2_channel_t; -#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 -/**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/ -typedef enum { - ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO5 */ - ADC2_CHANNEL_MAX, -} adc2_channel_t; -#endif - - -/** - * @brief ADC rtc controller attenuation option. - * - * @note This definitions are only for being back-compatible - */ -#define ADC_ATTEN_0db ADC_ATTEN_DB_0 -#define ADC_ATTEN_2_5db ADC_ATTEN_DB_2_5 -#define ADC_ATTEN_6db ADC_ATTEN_DB_6 -#define ADC_ATTEN_11db ADC_ATTEN_DB_11 - -/** - * The default (max) bit width of the ADC of current version. You can also get the maximum bitwidth - * by `SOC_ADC_RTC_MAX_BITWIDTH` defined in soc_caps.h. - */ -#define ADC_WIDTH_BIT_DEFAULT (ADC_WIDTH_MAX-1) - -//this definitions are only for being back-compatible -#define ADC_WIDTH_9Bit ADC_WIDTH_BIT_9 -#define ADC_WIDTH_10Bit ADC_WIDTH_BIT_10 -#define ADC_WIDTH_11Bit ADC_WIDTH_BIT_11 -#define ADC_WIDTH_12Bit ADC_WIDTH_BIT_12 - -/** - * @brief ADC digital controller encode option. - * - * @deprecated The ESP32-S2 doesn't use I2S DMA. Call ``adc_digi_output_format_t`` instead. - */ -typedef enum { - ADC_ENCODE_12BIT, /*!< ADC to DMA data format, , [15:12]-channel [11:0]-12 bits ADC data */ - ADC_ENCODE_11BIT, /*!< ADC to DMA data format, [15]-unit, [14:11]-channel [10:0]-11 bits ADC data */ - ADC_ENCODE_MAX, -} adc_i2s_encode_t; - /*--------------------------------------------------------------- - Common setting + Deprecated API ---------------------------------------------------------------*/ - -/** - * @brief Enable ADC power - * @deprecated Use adc_power_acquire and adc_power_release instead. - */ -void adc_power_on(void) __attribute__((deprecated)); - -/** - * @brief Power off SAR ADC - * @deprecated Use adc_power_acquire and adc_power_release instead. - * This function will force power down for ADC. - * This function is deprecated because forcing power ADC power off may - * disrupt operation of other components which may be using the ADC. - */ -void adc_power_off(void) __attribute__((deprecated)); - -/** - * @brief Increment the usage counter for ADC module. - * ADC will stay powered on while the counter is greater than 0. - * Call adc_power_release when done using the ADC. - */ -void adc_power_acquire(void); - -/** - * @brief Decrement the usage counter for ADC module. - * ADC will stay powered on while the counter is greater than 0. - * Call this function when done using the ADC. - */ -void adc_power_release(void); - /*--------------------------------------------------------------- ADC Single Read Setting ---------------------------------------------------------------*/ @@ -288,6 +167,7 @@ esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit); void adc1_ulp_enable(void); #endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if (SOC_ADC_PERIPH_NUM >= 2) /** * @brief Get the GPIO number of a specific ADC2 channel. * @@ -396,59 +276,13 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * * - ESP_ERR_INVALID_ARG: Unsupported GPIO */ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) -/** - * @brief Output ADC2 reference voltage to ``adc2_channe_t``'s IO. - * - * This function routes the internal reference voltage of ADCn to one of - * ADC2's channels. This reference voltage can then be manually measured - * for calibration purposes. - * - * @deprecated Use ``adc_vref_to_gpio`` instead. - * - * @param[in] gpio GPIO number (ADC2's channels are supported) - * - * @return - * - ESP_OK: v_ref successfully routed to selected GPIO - * - ESP_ERR_INVALID_ARG: Unsupported GPIO - */ -esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) __attribute__((deprecated)); /*--------------------------------------------------------------- - DMA setting + ADC DMA Read Setting ---------------------------------------------------------------*/ -/** - * @brief Digital ADC DMA read max timeout value, it may make the ``adc_digi_read_bytes`` block forever if the OS supports - */ -#define ADC_MAX_DELAY UINT32_MAX - -/** - * @brief ADC DMA driver configuration - */ -typedef struct adc_digi_init_config_s { - uint32_t max_store_buf_size; ///< Max length of the converted data that driver can store before they are processed. - uint32_t conv_num_each_intr; ///< Bytes of data that can be converted in 1 interrupt. - uint32_t adc1_chan_mask; ///< Channel list of ADC1 to be initialized. - uint32_t adc2_chan_mask; ///< Channel list of ADC2 to be initialized. -} adc_digi_init_config_t; - -/** - * @brief ADC digital controller settings - */ -typedef struct { - bool conv_limit_en; ///< To limit ADC conversion times. Conversion stops after finishing `conv_limit_num` times conversion - uint32_t conv_limit_num; ///< Set the upper limit of the number of ADC conversion triggers. Range: 1 ~ 255. - uint32_t pattern_num; ///< Number of ADC channels that will be used - adc_digi_pattern_config_t *adc_pattern; ///< List of configs for each ADC channel that will be used - uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Range: 611Hz ~ 83333Hz - Fs = Fd / interval / 2 - Fs: sampling frequency; - Fd: digital controller frequency, no larger than 5M for better performance - interval: interval between 2 measurement trigger signal, the smallest interval should not be smaller than the ADC measurement period, the largest interval should not be larger than 4095 */ - adc_digi_convert_mode_t conv_mode; ///< ADC DMA conversion mode, see `adc_digi_convert_mode_t`. - adc_digi_output_format_t format; ///< ADC DMA conversion output format, see `adc_digi_output_format_t`. -} adc_digi_configuration_t; - +#if SOC_ADC_DMA_SUPPORTED /** * @brief Initialize the Digital ADC. * @@ -515,130 +349,6 @@ esp_err_t adc_digi_deinitialize(void); * - ESP_OK On success */ esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config); - - -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 -//TODO IDF-3610 -/** - * @brief Reset adc digital controller filter. - * - * @param idx Filter index. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx); - -/** - * @brief Set adc digital controller filter configuration. - * - * @note For ESP32S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time. - * - * @param idx Filter index. - * @param config See ``adc_digi_filter_t``. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config); - -/** - * @brief Get adc digital controller filter configuration. - * - * @note For ESP32S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time. - * - * @param idx Filter index. - * @param config See ``adc_digi_filter_t``. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config); - -/** - * @brief Enable/disable adc digital controller filter. - * Filtering the ADC data to obtain smooth data at higher sampling rates. - * - * @note For ESP32S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time. - * - * @param idx Filter index. - * @param enable Enable/Disable filter. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable); - -/** - * @brief Config monitor of adc digital controller. - * - * @note For ESP32S2, The monitor will monitor all the enabled channel data of the each ADC unit at the same time. - * - * @param idx Monitor index. - * @param config See ``adc_digi_monitor_t``. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config); - -/** - * @brief Enable/disable monitor of adc digital controller. - * - * @note For ESP32S2, The monitor will monitor all the enabled channel data of the each ADC unit at the same time. - * - * @param idx Monitor index. - * @param enable True or false enable monitor. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable); -#endif //#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 - -#if CONFIG_IDF_TARGET_ESP32 -//TODO IDF-3610 -/** - * @brief Read Hall Sensor - * - * @note When the power switch of SARADC1, SARADC2, HALL sensor and AMP sensor is turned on, - * the input of GPIO36 and GPIO39 will be pulled down for about 80ns. - * When enabling power for any of these peripherals, ignore input from GPIO36 and GPIO39. - * Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue. - * - * @note The Hall Sensor uses channels 0 and 3 of ADC1. Do not configure - * these channels for use as ADC channels. - * - * @note The ADC1 module must be enabled by calling - * adc1_config_width() before calling hall_sensor_read(). ADC1 - * should be configured for 12 bit readings, as the hall sensor - * readings are low values and do not cover the full range of the - * ADC. - * - * @return The hall sensor reading. - */ -int hall_sensor_read(void); - -/*--------------------------------------------------------------- - To Be Deprecated TODO: IDF-3610 ----------------------------------------------------------------*/ -/** - * @brief Set I2S data source - * @param src I2S DMA data source, I2S DMA can get data from digital signals or from ADC. - * @return - * - ESP_OK success - */ -esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src); - -/** - * @brief Initialize I2S ADC mode - * @param adc_unit ADC unit index - * @param channel ADC channel index - * @return - * - ESP_OK success - * - ESP_ERR_INVALID_ARG Parameter error - */ -esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel); #endif #ifdef __cplusplus diff --git a/components/driver/deprecated/driver/adc_deprecated.h b/components/driver/deprecated/driver/adc_deprecated.h deleted file mode 100644 index bdd0547c06..0000000000 --- a/components/driver/deprecated/driver/adc_deprecated.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/*---------------------------------------------------------------------------------- - This file contains Deprecated ADC APIs ------------------------------------------------------------------------------------*/ - -#pragma once -#include "esp_err.h" -#include "hal/adc_types.h" -#include "driver/adc_types_deprecated.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -#if CONFIG_IDF_TARGET_ESP32S2 -/*--------------------------------------------------------------- - ESP32S2 Deprecated ADC APIs ----------------------------------------------------------------*/ -/** - * @brief Config ADC module arbiter. - * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, - * the low priority controller will read the invalid ADC2 data, and the validity of the data can be judged by the flag bit in the data. - * - * @note Only ADC2 support arbiter. - * @note Default priority: Wi-Fi > RTC > Digital; - * @note In normal use, there is no need to call this interface to config arbiter. - * - * @param adc_unit ADC unit. - * @param config Refer to `adc_arbiter_t`. - * - * @return - * - ESP_OK Success - * - ESP_ERR_NOT_SUPPORTED ADC unit not support arbiter. - */ -esp_err_t adc_arbiter_config(adc_unit_t adc_unit, adc_arbiter_t *config) __attribute__((deprecated)); - -/** - * @brief Enable interrupt of adc digital controller by bitmask. - * - * @param adc_unit ADC unit. - * @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_intr_enable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) __attribute__((deprecated)); - -/** - * @brief Disable interrupt of adc digital controller by bitmask. - * - * @param adc_unit ADC unit. - * @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_intr_disable(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) __attribute__((deprecated)); - -/** - * @brief Clear interrupt of adc digital controller by bitmask. - * - * @param adc_unit ADC unit. - * @param intr_mask Interrupt bitmask. See ``adc_digi_intr_t``. - * - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_intr_clear(adc_unit_t adc_unit, adc_digi_intr_t intr_mask) __attribute__((deprecated)); - -/** - * @brief Get interrupt status mask of adc digital controller. - * - * @param adc_unit ADC unit. - * @return - * - intr Interrupt bitmask, See ``adc_digi_intr_t``. - */ -uint32_t adc_digi_intr_get_status(adc_unit_t adc_unit) __attribute__((deprecated)); - -/** - * @brief Register ADC interrupt handler, the handler is an ISR. - * The handler will be attached to the same CPU core that this function is running on. - * - * @param fn Interrupt handler function. - * @param arg Parameter for handler function - * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) - * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. - * - * @return - * - ESP_OK Success - * - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags. - * - ESP_ERR_INVALID_ARG Function pointer error. - */ -esp_err_t adc_digi_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags) __attribute__((deprecated)); - -/** - * @brief Deregister ADC interrupt handler, the handler is an ISR. - * - * @return - * - ESP_OK Success - * - ESP_ERR_INVALID_ARG hander error. - * - ESP_FAIL ISR not be registered. - */ -esp_err_t adc_digi_isr_deregister(void) __attribute__((deprecated)); -#endif // #if CONFIG_IDF_TARGET_ESP32S2 - - -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 -/*--------------------------------------------------------------- - ESP32, ESP32S2 Deprecated ADC APIs ----------------------------------------------------------------*/ -/** - * @brief ADC digital controller initialization. - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_init(void) __attribute__((deprecated)); - -/** - * @brief ADC digital controller deinitialization. - * @return - * - ESP_OK Success - */ -esp_err_t adc_digi_deinit(void) __attribute__((deprecated)); -#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 - - -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 -/*--------------------------------------------------------------- - ESP32, ESP32S2, ESP32C3 Deprecated ADC APIs ----------------------------------------------------------------*/ -/** - * @brief Setting the digital controller. - * - * @param config Pointer to digital controller paramter. Refer to ``adc_digi_config_t``. - * - * @return - * - ESP_ERR_INVALID_STATE Driver state is invalid. - * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. - * - ESP_OK On success - */ -esp_err_t adc_digi_controller_config(const adc_digi_config_t *config) __attribute__((deprecated)); - -/** - * @brief Initialize ADC pad - * @param adc_unit ADC unit index - * @param channel ADC channel index - * @return - * - ESP_OK success - * - ESP_ERR_INVALID_ARG Parameter error - */ -esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) __attribute__((deprecated));; -#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 - - -#ifdef __cplusplus -} -#endif diff --git a/components/driver/deprecated/driver/adc_i2s_legacy.h b/components/driver/deprecated/driver/adc_i2s_legacy.h new file mode 100644 index 0000000000..44af449212 --- /dev/null +++ b/components/driver/deprecated/driver/adc_i2s_legacy.h @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include "sdkconfig.h" +#include "esp_err.h" +#include "hal/adc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_IDF_TARGET_ESP32 +/** + * @brief ESP32 ADC DMA source selection. + */ +typedef enum { + ADC_I2S_DATA_SRC_IO_SIG = 0, /*!< I2S data from GPIO matrix signal */ + ADC_I2S_DATA_SRC_ADC = 1, /*!< I2S data from ADC */ +} adc_i2s_source_t; +#endif + +#if CONFIG_IDF_TARGET_ESP32 +/*--------------------------------------------------------------- + ESP32 Deprecated API +---------------------------------------------------------------*/ +/** + * @brief Set I2S data source + * @param src I2S DMA data source, I2S DMA can get data from digital signals or from ADC. + * @return + * - ESP_OK success + */ +esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src); + +/** + * @brief Initialize I2S ADC mode + * @param adc_unit ADC unit index + * @param channel ADC channel index + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/deprecated/driver/adc_types_deprecated.h b/components/driver/deprecated/driver/adc_types_deprecated.h deleted file mode 100644 index 5d0e0dc232..0000000000 --- a/components/driver/deprecated/driver/adc_types_deprecated.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once -#include "esp_err.h" -#include "hal/adc_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if CONFIG_IDF_TARGET_ESP32 -/*--------------------------------------------------------------- - ESP32 Deprecated Types ----------------------------------------------------------------*/ -/** - * @brief ADC digital controller (DMA mode) conversion rules setting. - */ -typedef struct { - union { - struct { - uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements. - 0: measurement range 0 - 800mV, - 1: measurement range 0 - 1100mV, - 2: measurement range 0 - 1350mV, - 3: measurement range 0 - 2600mV. */ - uint8_t bit_width: 2; /*!< ADC resolution. -- 0: 9 bit; -- 1: 10 bit; -- 2: 11 bit; -- 3: 12 bit. */ - int8_t channel: 4; /*!< ADC channel index. */ - }; - uint8_t val; /*! -#include -#include "sdkconfig.h" -#include "esp_types.h" -#include "esp_log.h" -#include "sys/lock.h" -#include "soc/rtc.h" -#include "soc/periph_defs.h" -#include "freertos/FreeRTOS.h" -#include "freertos/xtensa_api.h" -#include "freertos/semphr.h" -#include "freertos/timers.h" -#include "esp_intr_alloc.h" -#include "driver/rtc_io.h" -#include "esp_private/rtc_ctrl.h" -#include "driver/gpio.h" -#include "driver/adc.h" - -#ifndef NDEBUG -// Enable built-in checks in queue.h in debug builds -#define INVARIANTS -#endif -#include "sys/queue.h" -#include "hal/adc_types.h" -#include "hal/adc_hal.h" - - -#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel]) - - -extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished. -#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock) -#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock) - - -/*--------------------------------------------------------------- - HALL SENSOR ----------------------------------------------------------------*/ - -static int hall_sensor_get_value(void) //hall sensor without LNA -{ - int hall_value; - - adc_power_acquire(); - - ADC_ENTER_CRITICAL(); - /* disable other peripherals. */ - adc_ll_amp_disable(); - adc_ll_hall_enable(); - // set controller - adc_ll_set_controller( ADC_UNIT_1, ADC_LL_CTRL_RTC ); - hall_value = adc_hal_hall_convert(); - adc_ll_hall_disable(); - ADC_EXIT_CRITICAL(); - - adc_power_release(); - return hall_value; -} - -/** - * To Be Deprecated - */ -extern esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel); -int hall_sensor_read(void) -{ - adc_common_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_0); - adc_common_gpio_init(ADC_UNIT_1, ADC1_CHANNEL_3); - adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0); - adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_0); - return hall_sensor_get_value(); -} diff --git a/components/driver/esp32s2/adc.c b/components/driver/esp32s2/adc.c deleted file mode 100644 index 2cc086a203..0000000000 --- a/components/driver/esp32s2/adc.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "sdkconfig.h" -#include "esp_types.h" -#include "esp_log.h" -#include "sys/lock.h" -#include "freertos/FreeRTOS.h" -#include "hal/adc_types.h" -#include "hal/adc_ll.h" - -extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished. -#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock) -#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock) - -/** - * Config monitor of adc digital controller. - * - * @note The monitor will monitor all the enabled channel data of the each ADC unit at the same time. - * @param adc_n ADC unit. - * @param config Refer to ``adc_digi_monitor_t``. - */ -static void adc_digi_monitor_config(adc_unit_t adc_n, adc_digi_monitor_t *config) -{ - adc_ll_digi_monitor_set_mode(adc_n, config->mode); - adc_ll_digi_monitor_set_thres(adc_n, config->threshold); -} - -/*************************************/ -/* Digital controller filter setting */ -/*************************************/ - -esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx) -{ - ADC_ENTER_CRITICAL(); - if (idx == ADC_DIGI_FILTER_IDX0) { - adc_ll_digi_filter_reset(ADC_UNIT_1); - } else if (idx == ADC_DIGI_FILTER_IDX1) { - adc_ll_digi_filter_reset(ADC_UNIT_2); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config) -{ - ADC_ENTER_CRITICAL(); - if (idx == ADC_DIGI_FILTER_IDX0) { - adc_ll_digi_filter_set_factor(ADC_UNIT_1, config->mode); - } else if (idx == ADC_DIGI_FILTER_IDX1) { - adc_ll_digi_filter_set_factor(ADC_UNIT_2, config->mode); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config) -{ - ADC_ENTER_CRITICAL(); - if (idx == ADC_DIGI_FILTER_IDX0) { - config->adc_unit = ADC_UNIT_1; - config->channel = SOC_ADC_CHANNEL_NUM(0); - adc_ll_digi_filter_get_factor(ADC_UNIT_1, &config->mode); - } else if (idx == ADC_DIGI_FILTER_IDX1) { - config->adc_unit = ADC_UNIT_2; - config->channel = SOC_ADC_CHANNEL_NUM(1); - adc_ll_digi_filter_get_factor(ADC_UNIT_2, &config->mode); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable) -{ - ADC_ENTER_CRITICAL(); - if (idx == ADC_DIGI_FILTER_IDX0) { - adc_ll_digi_filter_enable(ADC_UNIT_1, enable); - } else if (idx == ADC_DIGI_FILTER_IDX1) { - adc_ll_digi_filter_enable(ADC_UNIT_2, enable); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -/** - * @brief Get the filtered data of adc digital controller filter. For debug. - * 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 For ESP32S2, The filter will filter all the enabled channel data of the each ADC unit at the same time. - * @param idx Filter index. - * @return Filtered data. if <0, the read data invalid. - */ -int adc_digi_filter_read_data(adc_digi_filter_idx_t idx) -{ - if (idx == ADC_DIGI_FILTER_IDX0) { - return adc_ll_digi_filter_read_data(ADC_UNIT_1); - } else if (idx == ADC_DIGI_FILTER_IDX1) { - return adc_ll_digi_filter_read_data(ADC_UNIT_2); - } else { - return -1; - } -} - -/**************************************/ -/* Digital controller monitor setting */ -/**************************************/ - -esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config) -{ - ADC_ENTER_CRITICAL(); - if (idx == ADC_DIGI_MONITOR_IDX0) { - adc_digi_monitor_config(ADC_UNIT_1, config); - } else if (idx == ADC_DIGI_MONITOR_IDX1) { - adc_digi_monitor_config(ADC_UNIT_2, config); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} - -esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable) -{ - ADC_ENTER_CRITICAL(); - if (idx == ADC_DIGI_MONITOR_IDX0) { - adc_ll_digi_monitor_enable(ADC_UNIT_1, enable); - } else if (idx == ADC_DIGI_MONITOR_IDX1) { - adc_ll_digi_monitor_enable(ADC_UNIT_2, enable); - } - ADC_EXIT_CRITICAL(); - return ESP_OK; -} diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index 4fcfb3a201..fb5c29bb18 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -27,6 +27,7 @@ #if SOC_I2S_SUPPORTS_ADC_DAC #include "hal/adc_ll.h" +#include "driver/adc_i2s_legacy.h" #endif #if SOC_I2S_SUPPORTS_APLL #include "clk_ctrl_os.h" diff --git a/components/driver/include/driver/adc_common.h b/components/driver/include/driver/adc_common.h deleted file mode 100644 index e081f28d15..0000000000 --- a/components/driver/include/driver/adc_common.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * This file is only a wrapper for `driver/adc.h` for back-compatability. - */ - -#include "adc.h" diff --git a/components/driver/include/esp_private/adc_cali.h b/components/driver/include/esp_private/adc_cali.h deleted file mode 100644 index 428e0f5cb4..0000000000 --- a/components/driver/include/esp_private/adc_cali.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// Internal header for calibration, don't use in app - -#include "sdkconfig.h" -#include "esp_err.h" -#include "hal/adc_hal.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if !CONFIG_IDF_TARGET_ESP32 - -/** - * @brief Calibrate the offset of ADC. (Based on the pre-stored efuse or actual calibration) - * - * @param adc_n ADC unit to calibrate - * @param atten Attenuation to use - * @return Always ESP_OK - */ -extern esp_err_t adc_cal_offset(adc_unit_t adc_n, adc_atten_t atten); - -#endif - -#ifdef __cplusplus -} -#endif diff --git a/components/driver/test/CMakeLists.txt b/components/driver/test/CMakeLists.txt index 664a5227ad..be884ab0b2 100644 --- a/components/driver/test/CMakeLists.txt +++ b/components/driver/test/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRC_DIRS . param_test touch_sensor_test adc_dma_test dac_dma_test +idf_component_register(SRC_DIRS . param_test touch_sensor_test dac_dma_test PRIV_INCLUDE_DIRS include param_test/include touch_sensor_test/include PRIV_REQUIRES cmock test_utils driver nvs_flash esp_serial_slave_link - esp_adc_cal esp_timer) + esp_timer esp_adc) diff --git a/components/driver/test/adc_dma_test/test_esp32s2.c b/components/driver/test/adc_dma_test/test_esp32s2.c deleted file mode 100644 index 75c56d198f..0000000000 --- a/components/driver/test/adc_dma_test/test_esp32s2.c +++ /dev/null @@ -1,654 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - Tests for the adc device driver on ESP32-S2 only -*/ -#include "sdkconfig.h" -#include "unity.h" -#include "test_utils.h" - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2) //TODO: IDF-3160 -#if CONFIG_IDF_TARGET_ESP32S2 - - -#include "esp_system.h" -#include "esp_intr_alloc.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "driver/adc.h" -#include "driver/rtc_io.h" -#include "driver/gpio.h" -#include "unity.h" -#include "esp_system.h" -#include "esp_event.h" -#include "esp_wifi.h" -#include "esp_log.h" -#include "nvs_flash.h" -#include "test_utils.h" -#include "soc/adc_periph.h" -#include "test/test_common_adc.h" -#include "esp_rom_sys.h" -#include "driver/dac.h" - -#include "soc/system_reg.h" -#include "soc/spi_reg.h" -#include "soc/soc.h" -#include "soc/lldesc.h" -#include "test/test_adc_dac_dma.h" - -#include "driver/adc_deprecated.h" -#include "hal/adc_ll.h" -#include "esp_pm.h" - -static const char *TAG = "test_adc"; - -#define PLATFORM_SELECT (1) //0: pxp; 1: chip -#if (PLATFORM_SELECT == 0) //PXP platform -#include "soc/syscon_reg.h" -#define SET_BREAK_POINT(flag) REG_WRITE(SYSCON_DATE_REG, flag) -//PXP clk is slower. -#define SYS_DELAY_TIME_MOM (1/40) -#define RTC_SLOW_CLK_FLAG 1 // Slow clock is 32KHz. -static void test_pxp_deinit_io(void) -{ - for (int i = 0; i < 22; i++) { - rtc_gpio_init(i); - } -} -#else -//PXP clk is slower. -#define SET_BREAK_POINT(flag) -#define SYS_DELAY_TIME_MOM (1) -#define RTC_SLOW_CLK_FLAG 0 // Slow clock is 32KHz. -#endif - -#define ADC_REG_BASE_TEST() ({ \ - TEST_ASSERT_EQUAL_UINT32(REG_GET_FIELD(APB_SARADC_APB_CTRL_DATE_REG, APB_SARADC_APB_CTRL_DATE), APB_SARADC.apb_ctrl_date); \ - TEST_ASSERT_EQUAL_UINT32(REG_GET_FIELD(SENS_SARDATE_REG, SENS_SAR_DATE), SENS.sardate.sar_date); \ - TEST_ASSERT_EQUAL_UINT32(REG_GET_FIELD(RTC_IO_DATE_REG, RTC_IO_IO_DATE), RTCIO.date.date); \ -}) -/** Sample rate = APB_CLK(80 MHz) / (CLK_DIV + 1) / TRIGGER_INTERVAL / 2. */ -#define TEST_ADC_TRIGGER_INTERVAL_DEFAULT (40) -#define TEST_ADC_DIGI_CLK_DIV_DEFAULT (9) -static uint8_t adc_test_num = 9; -static adc_channel_t adc_list[SOC_ADC_PATT_LEN_MAX] = { - ADC_CHANNEL_0, - ADC_CHANNEL_1, - ADC_CHANNEL_2, - ADC_CHANNEL_3, - ADC_CHANNEL_4, - ADC_CHANNEL_5, - ADC_CHANNEL_6, - // ADC_CHANNEL_7, // Workaround: IO18 is pullup outside in ESP32S2-Saola Runner. - ADC_CHANNEL_8, - ADC_CHANNEL_9, -}; -/* For ESP32S2, it should use same atten, or, it will have error. */ -#define TEST_ADC_ATTEN_DEFAULT (ADC_ATTEN_11db) - - -/* Work mode. - * single: eof_num; - * double: SAR_EOF_NUMBER/2; - * alter: eof_num; - * */ -#define SAR_SIMPLE_NUM 512 // Set sample number of enabled unit. -/* Use two DMA linker to save ADC data. ADC sample 1 times -> 2 byte data -> 2 DMA link buf. */ -#define SAR_DMA_DATA_SIZE(unit, sample_num) (SAR_EOF_NUMBER(unit, sample_num)) -#define SAR_EOF_NUMBER(unit, sample_num) ((sample_num) * (unit)) -#define SAR_MEAS_LIMIT_NUM(unit, sample_num) (SAR_SIMPLE_NUM) -#define SAR_SIMPLE_TIMEOUT_MS 1000 - -typedef struct dma_msg { - uint32_t int_msk; - uint8_t *data; - uint32_t data_len; -} adc_dma_event_t; - -static uint8_t link_buf[2][SAR_DMA_DATA_SIZE(2, SAR_SIMPLE_NUM)] = {0}; -static lldesc_t dma1 = {0}; -static lldesc_t dma2 = {0}; -static QueueHandle_t que_adc = NULL; -static adc_dma_event_t adc_evt; - -/** - * @brief Reset FSM of adc digital controller. - * - * @return - * - ESP_OK Success - */ -static esp_err_t adc_digi_reset(void) -{ - adc_ll_digi_reset(); - adc_ll_digi_clear_pattern_table(ADC_NUM_1); - adc_ll_digi_clear_pattern_table(ADC_NUM_2); - return ESP_OK; -} - -/** ADC-DMA ISR handler. */ -static IRAM_ATTR void adc_dma_isr(void *arg) -{ - uint32_t int_st = REG_READ(SPI_DMA_INT_ST_REG(3)); - int task_awoken = pdFALSE; - REG_WRITE(SPI_DMA_INT_CLR_REG(3), int_st); - if (int_st & SPI_IN_SUC_EOF_INT_ST_M) { - adc_evt.int_msk = int_st; - xQueueSendFromISR(que_adc, &adc_evt, &task_awoken); - } - if (int_st & SPI_IN_DONE_INT_ST) { - adc_evt.int_msk = int_st; - xQueueSendFromISR(que_adc, &adc_evt, &task_awoken); - } - ESP_EARLY_LOGV(TAG, "int msk%x\n", int_st); - if (task_awoken == pdTRUE) { - portYIELD_FROM_ISR(); - } -} - -/** - * DMA liner initialization and start. - * @param is_loop - * - true: The two dma linked lists are connected end to end, with no end mark (eof). - * - false: The two dma linked lists are connected end to end, with end mark (eof). - */ -static uint32_t adc_dma_linker_init(adc_unit_t adc, bool is_loop) -{ - dma1 = (lldesc_t) { - .size = SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM), - .owner = 1, - .buf = &link_buf[0][0], - .qe.stqe_next = &dma2, - }; - dma2 = (lldesc_t) { - .size = SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM), - .owner = 1, - .buf = &link_buf[1][0], - }; - if (is_loop) { - dma2.qe.stqe_next = &dma1; - } else { - dma2.qe.stqe_next = NULL; - } - return (uint32_t)&dma1; -} - -#define DEBUG_CHECK_ENABLE 1 -#define DEBUG_PRINT_ENABLE 1 -#define DEBUG_CHECK_ERROR 10 - -/** - * Check the ADC-DMA data in linker buffer by input level. - * ideal_level - * - -1: Don't check data. - * - 0: ADC channel voltage is 0v. - * - 1: ADC channel voltage is 3.3v. - * - 2: ADC channel voltage is 1.4v. - */ -static esp_err_t adc_dma_data_check(adc_unit_t adc, int ideal_level) -{ - int unit_old = 1; - int ch_cnt = 0; - for (int cnt = 0; cnt < 2; cnt++) { - esp_rom_printf("\n[%s] link_buf[%d]: \n", __func__, cnt % 2); - for (int i = 0; i < SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM); i += 2) { - uint8_t h = link_buf[cnt % 2][i + 1], l = link_buf[cnt % 2][i]; - uint16_t temp = (h << 8 | l); - adc_digi_output_data_t *data = (adc_digi_output_data_t *)&temp; - - if (adc > ADC_UNIT_2) { //ADC_ENCODE_11BIT -#if DEBUG_PRINT_ENABLE - if (i % 16 == 0) { - esp_rom_printf("\n"); - } - esp_rom_printf("[%d_%d_%04x] ", data->type2.unit, data->type2.channel, data->type2.data); -#endif -#if DEBUG_CHECK_ENABLE - if (ideal_level >= 0) { - TEST_ASSERT_NOT_EQUAL(unit_old, data->type2.unit); - unit_old = data->type2.unit; - if (data->type2.channel > ADC_CHANNEL_MAX) { - printf("Data invalid [%d]\n", data->type2.channel); - continue; - } - int cur_ch = ((ch_cnt++ / 2) % adc_test_num); - TEST_ASSERT_EQUAL( data->type2.channel, adc_list[cur_ch] ); - } - if (ideal_level == 1) { // high level 3.3v - TEST_ASSERT_EQUAL( 0x7FF, data->type2.data ); - } else if (ideal_level == 0) { // low level 0v - TEST_ASSERT_LESS_THAN( 10, data->type2.data ); - } else if (ideal_level == 2) { // middle level 1.4v - TEST_ASSERT_INT_WITHIN( 128, 1100, data->type2.data ); - } else if (ideal_level == 3) { // normal level - } else { // no check - } -#endif - } else { //ADC_ENCODE_12BIT -#if DEBUG_PRINT_ENABLE - if (i % 16 == 0) { - esp_rom_printf("\n"); - } - esp_rom_printf("[%d_%04x] ", data->type1.channel, data->type1.data); -#endif -#if DEBUG_CHECK_ENABLE - if (ideal_level >= 0) { - int cur_ch = ((ch_cnt++) % adc_test_num); - TEST_ASSERT_EQUAL( adc_list[cur_ch], data->type1.channel ); - } - if (ideal_level == 1) { // high level 3.3v - TEST_ASSERT_EQUAL( 0XFFF, data->type1.data ); - } else if (ideal_level == 0) { // low level 0v - TEST_ASSERT_LESS_THAN( 10, data->type1.data ); - } else if (ideal_level == 2) { // middle level 1.4v - TEST_ASSERT_INT_WITHIN( 256, 2200, data->type1.data ); - } else if (ideal_level == 3) { // normal level - } else { // no check - } -#endif - } - link_buf[cnt % 2][i] = 0; - link_buf[cnt % 2][i + 1] = 0; - } - esp_rom_printf("\n"); - } - return ESP_OK; -} - -static esp_err_t adc_dma_data_multi_st_check(adc_unit_t adc, void *dma_addr, uint32_t int_mask) -{ - adc_dma_event_t evt; - - ESP_LOGI(TAG, "adc IO normal, test ..."); - for (int i = 0; i < adc_test_num; i++) { - adc_io_normal(adc, adc_list[i]); - } - TEST_ESP_OK( adc_digi_start() ); - while (1) { - TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE ); - if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) { - break; - } - } - TEST_ESP_OK( adc_digi_stop() ); - adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask); - adc_digi_reset(); - TEST_ESP_OK( adc_dma_data_check(adc, -1) ); // Don't check data. - - ESP_LOGI(TAG, "adc IO fake tie high, test ..."); - for (int i = 0; i < adc_test_num; i++) { - adc_fake_tie_high(adc, adc_list[i]); - } - TEST_ESP_OK( adc_digi_start() ); - while (1) { - TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE ); - if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) { - break; - } - } - TEST_ESP_OK( adc_digi_stop() ); - adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask); - adc_digi_reset(); - TEST_ESP_OK( adc_dma_data_check(adc, 1) ); - - ESP_LOGI(TAG, "adc IO fake tie low, test ..."); - for (int i = 0; i < adc_test_num; i++) { - adc_fake_tie_low(adc, adc_list[i]); - } - TEST_ESP_OK( adc_digi_start() ); - while (1) { - TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE ); - if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) { - break; - } - } - TEST_ESP_OK( adc_digi_stop() ); - adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask); - adc_digi_reset(); - TEST_ESP_OK( adc_dma_data_check(adc, 0) ); - - ESP_LOGI(TAG, "adc IO fake tie middle, test ..."); - for (int i = 0; i < adc_test_num; i++) { - adc_fake_tie_middle(adc, adc_list[i]); - } - TEST_ESP_OK( adc_digi_start() ); - while (1) { - TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, SAR_SIMPLE_TIMEOUT_MS / portTICK_PERIOD_MS), pdTRUE ); - if (evt.int_msk & SPI_IN_SUC_EOF_INT_ENA) { - break; - } - } - TEST_ESP_OK( adc_digi_stop() ); - adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask); - adc_digi_reset(); - TEST_ESP_OK( adc_dma_data_check(adc, 2) ); - - return ESP_OK; -} - -#include "soc/apb_saradc_struct.h" -/** - * Test the partten table setting. It's easy wrong. - * - * @param adc_n ADC unit. - * @param in_partten_len The length of partten be set. - * @param in_last_ch The channel number of the last message. - */ -static esp_err_t adc_check_patt_table(adc_unit_t adc, uint32_t in_partten_len, adc_channel_t in_last_ch) -{ - esp_err_t ret = ESP_FAIL; - uint8_t index = (in_partten_len - 1) / 4; - uint8_t offset = 24 - ((in_partten_len - 1) % 4) * 8; - uint32_t temp = 0, len; - - if (adc & ADC_UNIT_1) { - len = APB_SARADC.ctrl.sar1_patt_len + 1; - temp = APB_SARADC.sar1_patt_tab[index]; - printf("patt1 len %d\n", len); - printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[0]); - printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[1]); - printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[2]); - printf("patt1 0x%08x\n", APB_SARADC.sar1_patt_tab[3]); - if (in_partten_len == len) { - if (in_last_ch == (((temp >> (offset + 4))) & 0xf)) { - ret = ESP_OK; - } - } - } - if (adc & ADC_UNIT_2) { - len = APB_SARADC.ctrl.sar2_patt_len + 1; - temp = APB_SARADC.sar2_patt_tab[index]; - printf("patt2 len %d\n", len); - printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[0]); - printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[1]); - printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[2]); - printf("patt2 0x%08x\n", APB_SARADC.sar2_patt_tab[3]); - if (in_partten_len == len) { - if (in_last_ch == (((temp >> (offset + 4))) & 0xf)) { - ret = ESP_OK; - } - } - } - return ret; -} - -/** - * Testcase: Check the base function of ADC-DMA. Include: - * - Various conversion modes. - * - Whether the channel and data are lost. - * - Whether the data is the same as the channel voltage. - */ -int test_adc_dig_dma_single_unit(adc_unit_t adc) -{ - ESP_LOGI(TAG, " >> %s << ", __func__); - ESP_LOGI(TAG, " >> adc unit: %x << ", adc); - - TEST_ESP_OK( adc_digi_init() ); - /* arbiter config */ - adc_arbiter_t arb_cfg = { - .mode = ADC_ARB_MODE_FIX, - .dig_pri = 0, - .pwdet_pri = 2, - .rtc_pri = 1, - }; - TEST_ESP_OK( adc_arbiter_config(ADC_UNIT_2, &arb_cfg) ); // If you want use force - - adc_digi_config_t config = { - .conv_limit_en = false, - .conv_limit_num = 0, - .interval = TEST_ADC_TRIGGER_INTERVAL_DEFAULT, - .dig_clk.use_apll = 0, // APB clk - .dig_clk.div_num = TEST_ADC_DIGI_CLK_DIV_DEFAULT, - .dig_clk.div_b = 0, - .dig_clk.div_a = 0, - .dma_eof_num = SAR_EOF_NUMBER((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM), - }; - /* Config pattern table */ - adc_digi_pattern_table_t adc1_patt[SOC_ADC_PATT_LEN_MAX] = {0}; - adc_digi_pattern_table_t adc2_patt[SOC_ADC_PATT_LEN_MAX] = {0}; - if (adc & ADC_UNIT_1) { - config.adc1_pattern_len = adc_test_num; - config.adc1_pattern = adc1_patt; - for (int i = 0; i < adc_test_num; i++) { - adc1_patt[i].atten = TEST_ADC_ATTEN_DEFAULT; - adc1_patt[i].channel = adc_list[i]; - adc_gpio_init(ADC_UNIT_1, adc_list[i]); - } - } - if (adc & ADC_UNIT_2) { - config.adc2_pattern_len = adc_test_num; - config.adc2_pattern = adc2_patt; - for (int i = 0; i < adc_test_num; i++) { - adc2_patt[i].atten = TEST_ADC_ATTEN_DEFAULT; - adc2_patt[i].channel = adc_list[i]; - adc_gpio_init(ADC_UNIT_2, adc_list[i]); - } - } - if (adc == ADC_UNIT_1) { - config.conv_mode = ADC_CONV_SINGLE_UNIT_1; - config.format = ADC_DIGI_FORMAT_12BIT; - } else if (adc == ADC_UNIT_2) { - config.conv_mode = ADC_CONV_SINGLE_UNIT_2; - config.format = ADC_DIGI_FORMAT_12BIT; - } else if (adc == ADC_UNIT_BOTH) { - config.conv_mode = ADC_CONV_BOTH_UNIT; - config.format = ADC_DIGI_FORMAT_11BIT; - } else if (adc == ADC_UNIT_ALTER) { - config.conv_mode = ADC_CONV_ALTER_UNIT; - config.format = ADC_DIGI_FORMAT_11BIT; - } - TEST_ESP_OK( adc_digi_controller_config(&config) ); - - /* ADC-DMA linker init */ - if (que_adc == NULL) { - que_adc = xQueueCreate(5, sizeof(adc_dma_event_t)); - } else { - xQueueReset(que_adc); - } - uint32_t int_mask = SPI_IN_SUC_EOF_INT_ENA; - uint32_t dma_addr = adc_dma_linker_init(adc, false); - adc_dac_dma_isr_register(adc_dma_isr, NULL, int_mask); - adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask); - - TEST_ESP_OK( adc_check_patt_table(adc, adc_test_num, adc_list[adc_test_num - 1]) ); - adc_dma_data_multi_st_check(adc, (void *)dma_addr, int_mask); - - adc_dac_dma_linker_deinit(); - adc_dac_dma_isr_deregister(adc_dma_isr, NULL); - TEST_ESP_OK( adc_digi_deinit() ); - vTaskDelay(10 / portTICK_PERIOD_MS); - - return 0; -} - -TEST_CASE("ADC DMA single read", "[ADC]") -{ - test_adc_dig_dma_single_unit(ADC_UNIT_BOTH); - - test_adc_dig_dma_single_unit(ADC_UNIT_ALTER); - - test_adc_dig_dma_single_unit(ADC_UNIT_1); - - test_adc_dig_dma_single_unit(ADC_UNIT_2); -} - -#include "touch_scope.h" -/** - * 0: ADC1 channels raw data debug. - * 1: ADC2 channels raw data debug. - * 2: ADC1 one channel raw data debug. - */ -#define SCOPE_DEBUG_TYPE 0 -#define SCOPE_DEBUG_CHANNEL_MAX (10) -#define SCOPE_DEBUG_ENABLE (0) -#define SCOPE_UART_BUADRATE (256000) -#define SCOPE_DEBUG_FREQ_MS (50) -#define SCOPE_OUTPUT_UART (0) -static float scope_temp[SCOPE_DEBUG_CHANNEL_MAX] = {0}; // max scope channel is 10. - -int test_adc_dig_scope_debug_unit(adc_unit_t adc) -{ - ESP_LOGI(TAG, " >> %s << ", __func__); - ESP_LOGI(TAG, " >> adc unit: %x << ", adc); - - TEST_ESP_OK( adc_digi_init() ); - if (adc & ADC_UNIT_2) { - /* arbiter config */ - adc_arbiter_t arb_cfg = { - .mode = ADC_ARB_MODE_FIX, - .dig_pri = 0, - .pwdet_pri = 2, - .rtc_pri = 1, - }; - TEST_ESP_OK( adc_arbiter_config(ADC_UNIT_2, &arb_cfg) ); // If you want use force - } - adc_digi_config_t config = { - .conv_limit_en = false, - .conv_limit_num = 0, - .interval = TEST_ADC_TRIGGER_INTERVAL_DEFAULT, - .dig_clk.use_apll = 0, // APB clk - .dig_clk.div_num = TEST_ADC_DIGI_CLK_DIV_DEFAULT, - .dig_clk.div_a = 0, - .dig_clk.div_b = 0, - .dma_eof_num = SAR_EOF_NUMBER((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM), - }; - /* Config pattern table */ - adc_digi_pattern_table_t adc1_patt[SOC_ADC_PATT_LEN_MAX] = {0}; - adc_digi_pattern_table_t adc2_patt[SOC_ADC_PATT_LEN_MAX] = {0}; - if (adc & ADC_UNIT_1) { - config.adc1_pattern_len = adc_test_num; - config.adc1_pattern = adc1_patt; - for (int i = 0; i < adc_test_num; i++) { - adc1_patt[i].atten = TEST_ADC_ATTEN_DEFAULT; - adc1_patt[i].channel = adc_list[i]; - adc_gpio_init(ADC_UNIT_1, adc_list[i]); - } - } - if (adc & ADC_UNIT_2) { - config.adc2_pattern_len = adc_test_num; - config.adc2_pattern = adc2_patt; - for (int i = 0; i < adc_test_num; i++) { - adc2_patt[i].atten = TEST_ADC_ATTEN_DEFAULT; - adc2_patt[i].channel = adc_list[i]; - adc_gpio_init(ADC_UNIT_2, adc_list[i]); - } - } - if (adc == ADC_UNIT_1) { - config.conv_mode = ADC_CONV_SINGLE_UNIT_1; - config.format = ADC_DIGI_FORMAT_12BIT; - } else if (adc == ADC_UNIT_2) { - config.conv_mode = ADC_CONV_SINGLE_UNIT_2; - config.format = ADC_DIGI_FORMAT_12BIT; - } else if (adc == ADC_UNIT_BOTH) { - config.conv_mode = ADC_CONV_BOTH_UNIT; - config.format = ADC_DIGI_FORMAT_11BIT; - } else if (adc == ADC_UNIT_ALTER) { - config.conv_mode = ADC_CONV_ALTER_UNIT; - config.format = ADC_DIGI_FORMAT_11BIT; - } - TEST_ESP_OK( adc_digi_controller_config(&config) ); - - /* ADC-DMA linker init */ - if (que_adc == NULL) { - que_adc = xQueueCreate(5, sizeof(adc_dma_event_t)); - } else { - xQueueReset(que_adc); - } - uint32_t int_mask = SPI_IN_SUC_EOF_INT_ENA; - uint32_t dma_addr = adc_dma_linker_init(adc, false); - adc_dac_dma_isr_register(adc_dma_isr, NULL, int_mask); - adc_dac_dma_linker_start(DMA_ONLY_ADC_INLINK, (void *)dma_addr, int_mask); - - ESP_LOGI(TAG, "adc IO fake tie middle, test ..."); - for (int i = 0; i < adc_test_num; i++) { - adc_fake_tie_middle(adc, adc_list[i]); - } - - return 0; -} - -static void scope_output(int adc_num, int channel, int data) -{ - /** can replace by uart log.*/ -#if SCOPE_OUTPUT_UART - static int icnt = 0; - if (icnt++ % 8 == 0) { - esp_rom_printf("\n"); - } - esp_rom_printf("[%d_%d_%04x] ", adc_num, channel, data); - return; -#endif -#if SCOPE_DEBUG_TYPE == 0 - if (adc_num != 0) { - return; - } -#elif SCOPE_DEBUG_TYPE == 1 - if (adc_num != 1) { - return; - } -#endif - int i; - /* adc Read */ - for (i = 0; i < adc_test_num; i++) { - if (adc_list[i] == channel && scope_temp[i] == 0) { - scope_temp[i] = data; - break; - } - } - if (i == adc_test_num) { - test_tp_print_to_scope(scope_temp, adc_test_num); - vTaskDelay(SCOPE_DEBUG_FREQ_MS / portTICK_PERIOD_MS); - for (int i = 0; i < adc_test_num; i++) { - scope_temp[i] = 0; - } - } -} - -/** - * Manual test: Capture ADC-DMA data and display it on the serial oscilloscope. Used to observe the stability of the data. - * Use step: - * 1. Run this test from the unit test app. - * 2. Use `ESP-Tuning Tool`(download from `www.espressif.com`) to capture. - * 3. The readings of multiple channels will be displayed on the tool. - */ -TEST_CASE("test_adc_digi_slope_debug", "[adc_dma][ignore]") -{ - adc_dma_event_t evt; - test_tp_scope_debug_init(0, -1, -1, SCOPE_UART_BUADRATE); - adc_unit_t adc = ADC_CONV_BOTH_UNIT; - test_adc_dig_scope_debug_unit(adc); - while (1) { - TEST_ESP_OK( adc_digi_start() ); - TEST_ASSERT_EQUAL( xQueueReceive(que_adc, &evt, portMAX_DELAY), pdTRUE ); - if (evt.int_msk & SPI_IN_SUC_EOF_INT_ST) { - TEST_ESP_OK( adc_digi_stop() ); - adc_digi_reset(); - for (int cnt = 0; cnt < 2; cnt++) { - esp_rom_printf("cnt%d\n", cnt); - for (int i = 0; i < SAR_DMA_DATA_SIZE((adc > 2) ? 2 : 1, SAR_SIMPLE_NUM); i += 2) { - uint8_t h = link_buf[cnt % 2][i + 1], l = link_buf[cnt % 2][i]; - uint16_t temp = (h << 8 | l); - adc_digi_output_data_t *data = (adc_digi_output_data_t *)&temp; - if (adc > ADC_UNIT_2) { //ADC_ENCODE_11BIT - scope_output(data->type2.unit, data->type2.channel, data->type2.data); - } else { //ADC_ENCODE_12BIT - if (adc == ADC_UNIT_1) { - scope_output(0, data->type1.channel, data->type1.data); - } else if (adc == ADC_UNIT_2) { - scope_output(1, data->type1.channel, data->type1.data); - } - } - link_buf[cnt % 2][i] = 0; - link_buf[cnt % 2][i + 1] = 0; - } - } - } - } -} - -#endif // CONFIG_IDF_TARGET_ESP32S2 -#endif //#if !DISABLED_FOR_TARGETS(ESP32S2) diff --git a/components/driver/test/dac_dma_test/test_esp32s2.c b/components/driver/test/dac_dma_test/test_esp32s2.c index 4e1b04111a..c54101d183 100644 --- a/components/driver/test/dac_dma_test/test_esp32s2.c +++ b/components/driver/test/dac_dma_test/test_esp32s2.c @@ -15,7 +15,6 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" -#include "driver/adc.h" #include "driver/rtc_io.h" #include "driver/gpio.h" #include "unity.h" diff --git a/components/driver/test/include/test/test_common_adc.h b/components/driver/test/include/test/test_common_adc.h index 951a2d55ae..a858fd1d52 100644 --- a/components/driver/test/include/test/test_common_adc.h +++ b/components/driver/test/include/test/test_common_adc.h @@ -6,7 +6,7 @@ #pragma once -#include "driver/adc.h" +#include "hal/adc_types.h" /**@{*/ /** diff --git a/components/driver/test/test_adc.c b/components/driver/test/test_adc.c deleted file mode 100644 index f9d54531eb..0000000000 --- a/components/driver/test/test_adc.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "sdkconfig.h" -#include -#include -#include "esp_log.h" -#include "test_utils.h" -#include "esp_adc_cal.h" -#include "driver/adc_common.h" -#include "esp_cpu.h" - -__attribute__((unused)) static const char *TAG = "ADC"; - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2) -//TODO: IDF-3160 - -#define TEST_COUNT 4096 -#define MAX_ARRAY_SIZE 4096 -#define TEST_ATTEN ADC_ATTEN_MAX //Set to ADC_ATTEN_*db to test a single attenuation only - -static int s_adc_count[MAX_ARRAY_SIZE]={}; -static int s_adc_offset = -1; - -static int insert_point(uint32_t value) -{ - const bool fixed_size = true; - - if (s_adc_offset < 0) { - if (fixed_size) { - TEST_ASSERT_GREATER_OR_EQUAL(4096, MAX_ARRAY_SIZE); - s_adc_offset = 0; //Fixed to 0 because the array can hold all the data in 12 bits - } else { - s_adc_offset = MAX((int)value - MAX_ARRAY_SIZE/2, 0); - } - } - - if (!fixed_size && (value < s_adc_offset || value >= s_adc_offset + MAX_ARRAY_SIZE)) { - TEST_ASSERT_GREATER_OR_EQUAL(s_adc_offset, value); - TEST_ASSERT_LESS_THAN(s_adc_offset + MAX_ARRAY_SIZE, value); - } - - s_adc_count[value - s_adc_offset] ++; - return value - s_adc_offset; -} - -static void reset_array(void) -{ - memset(s_adc_count, 0, sizeof(s_adc_count)); - s_adc_offset = -1; -} - -static uint32_t 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]; - } - return sum/count; -} - -static void print_summary(bool figure) -{ - const int MAX_WIDTH=20; - int max_count = 0; - int start = -1; - 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]; - } - if (s_adc_count[i] > 0 && start < 0) { - start = i; - } - if (s_adc_count[i] > 0) { - end = i; - } - count += s_adc_count[i]; - sum += s_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; - for (int j = 0; j < count; j++) { - putchar('|'); - } - printf(" %d\n", s_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) { - continue; - } - float delta = i + s_adc_offset - average; - variation_square += (delta * delta) * s_adc_count[i]; - } - - printf("%d points.\n", count); - printf("average: %.1f\n", (float)sum/count); - printf("std: %.2f\n", sqrt(variation_square/count)); -} - -static void continuous_adc_init(uint16_t adc1_chan_mask, uint16_t adc2_chan_mask, adc_channel_t *channel, uint8_t channel_num, adc_atten_t atten) -{ - adc_digi_init_config_t adc_dma_config = { - .max_store_buf_size = TEST_COUNT*2, - .conv_num_each_intr = 128, - .adc1_chan_mask = adc1_chan_mask, - .adc2_chan_mask = adc2_chan_mask, - }; - TEST_ESP_OK(adc_digi_initialize(&adc_dma_config)); - - adc_digi_pattern_table_t adc_pattern[10] = {0}; - adc_digi_config_t dig_cfg = { - .conv_limit_en = 0, - .conv_limit_num = 250, - .sample_freq_hz = 83333, - }; - - dig_cfg.adc_pattern_len = channel_num; - for (int i = 0; i < channel_num; i++) { - uint8_t unit = ((channel[i] >> 3) & 0x1); - uint8_t ch = channel[i] & 0x7; - adc_pattern[i].atten = atten; - adc_pattern[i].channel = ch; - adc_pattern[i].unit = unit; - } - dig_cfg.adc_pattern = adc_pattern; - TEST_ESP_OK(adc_digi_controller_config(&dig_cfg)); -} - -TEST_CASE("test_adc_dma", "[adc][ignore][manual]") -{ - uint16_t adc1_chan_mask = BIT(2); - uint16_t adc2_chan_mask = 0; - adc_channel_t channel[1] = {ADC1_CHANNEL_2}; - adc_atten_t target_atten = TEST_ATTEN; - - const int output_data_size = sizeof(adc_digi_output_data_t); - - int buffer_size = TEST_COUNT*output_data_size; - uint8_t* read_buf = malloc(buffer_size); - TEST_ASSERT_NOT_NULL(read_buf); - - adc_atten_t atten; - bool print_figure; - if (target_atten == ADC_ATTEN_MAX) { - atten = ADC_ATTEN_DB_0; - target_atten = ADC_ATTEN_DB_11; - print_figure = false; - } else { - atten = target_atten; - print_figure = true; - } - - while (1) { - ESP_LOGI("TEST_ADC", "Test with atten: %d", atten); - memset(read_buf, 0xce, buffer_size); - - bool do_calibration = false; - - esp_adc_cal_characteristics_t chan1_char = {}; - esp_adc_cal_value_t cal_ret = esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_12Bit, 0, &chan1_char); - if (cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP) { - do_calibration = true; - } - - continuous_adc_init(adc1_chan_mask, adc2_chan_mask, channel, sizeof(channel) / sizeof(adc_channel_t), atten); - adc_digi_start(); - - int remain_count = TEST_COUNT; - while (remain_count) { - int already_got = TEST_COUNT - remain_count; - uint32_t ret_num; - TEST_ESP_OK(adc_digi_read_bytes(read_buf + already_got*output_data_size, - remain_count*output_data_size, &ret_num, ADC_MAX_DELAY)); - - TEST_ASSERT((ret_num % output_data_size) == 0); - remain_count -= ret_num / output_data_size; - } - - adc_digi_output_data_t *p = (void*)read_buf; - reset_array(); - for (int i = 0; i < TEST_COUNT; i++) { - insert_point(p[i].type2.data); - } - - print_summary(print_figure); - - if (do_calibration) { - uint32_t raw = get_average(); - uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char); - printf("Voltage = %d mV\n", voltage_mv); - } - - adc_digi_stop(); - TEST_ESP_OK(adc_digi_deinitialize()); - - if (atten == target_atten) { - break; - } - - atten++; - } - - free(read_buf); -} - -TEST_CASE("test_adc_single", "[adc][ignore][manual]") -{ - adc_atten_t target_atten = TEST_ATTEN; - adc_atten_t atten; - bool print_figure; - if (target_atten == ADC_ATTEN_MAX) { - atten = ADC_ATTEN_DB_0; - target_atten = ADC_ATTEN_DB_11; - print_figure = false; - } else { - atten = target_atten; - print_figure = true; - } - - adc1_config_width(ADC_WIDTH_BIT_12); - - - while (1) { - ESP_LOGI("TEST_ADC", "Test with atten: %d", atten); - - adc1_config_channel_atten(ADC1_CHANNEL_2, atten); - - bool do_calibration = false; - - esp_adc_cal_characteristics_t chan1_char = {}; - esp_adc_cal_value_t cal_ret = esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_12Bit, 0, &chan1_char); - if (cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP) { - do_calibration = true; - } - - - const int test_count = TEST_COUNT; - adc1_channel_t channel = ADC1_CHANNEL_2; - while (1) { - - reset_array(); - - for (int i = 0; i < test_count; i++) { - uint32_t raw = adc1_get_raw(channel); - insert_point(raw); - } - print_summary(print_figure); - break; - } - - if (do_calibration) { - uint32_t raw = get_average(); - uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char); - printf("Voltage = %d mV\n", voltage_mv); - } - - - if (atten == target_atten) { - break; - } - atten++; - } -} - -#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2) - - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2) //TODO IDF-3908 - -/******************************************************************************** - * ADC Speed Related Tests - ********************************************************************************/ - -#define RECORD_TIME_PREPARE() uint32_t __t1, __t2 -#define RECORD_TIME_START() do {__t1 = esp_cpu_get_ccount();}while(0) -#define RECORD_TIME_END(p_time) do{__t2 = esp_cpu_get_ccount(); *p_time = (__t2-__t1);}while(0) -#define GET_US_BY_CCOUNT(t) ((double)t/CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) - - -//ADC Channels -#if CONFIG_IDF_TARGET_ESP32 -#define ADC1_CALI_TEST_CHAN0 ADC1_CHANNEL_6 -#define ADC2_CALI_TEST_CHAN0 ADC2_CHANNEL_0 -#else -#define ADC1_CALI_TEST_CHAN0 ADC1_CHANNEL_2 -#define ADC2_CALI_TEST_CHAN0 ADC2_CHANNEL_0 -#endif - -//ADC Calibration -#if CONFIG_IDF_TARGET_ESP32 -#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF -#elif CONFIG_IDF_TARGET_ESP32S2 -#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP -#elif CONFIG_IDF_TARGET_ESP32C3 -#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP -#elif CONFIG_IDF_TARGET_ESP32S3 -#define ADC_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT -#endif - -#define TIMES_PER_ATTEN 10 - -static esp_adc_cal_characteristics_t adc1_chars; -static esp_adc_cal_characteristics_t adc2_chars; - -static void adc_single_cali_init(adc_unit_t adc_n, adc_channel_t chan, uint32_t atten) -{ - esp_err_t ret; - esp_adc_cal_value_t ret_val = ESP_ADC_CAL_VAL_NOT_SUPPORTED; - - ret = esp_adc_cal_check_efuse(ADC_TEST_CALI_SCHEME); - if (ret == ESP_ERR_NOT_SUPPORTED) { - ESP_LOGE(TAG, "Cali scheme not supported!"); - TEST_ASSERT(ret != ESP_ERR_NOT_SUPPORTED); - } else if (ret != ESP_OK) { - ESP_LOGW(TAG, "No cali eFuse, but will run the test"); - } - - if (adc_n == ADC_UNIT_1) { - ret_val = esp_adc_cal_characterize(adc_n, atten, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars); - TEST_ESP_OK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT)); - TEST_ESP_OK(adc1_config_channel_atten((adc1_channel_t)chan, atten)); - } else if (adc_n == ADC_UNIT_2) { - TEST_ESP_OK(adc2_config_channel_atten((adc2_channel_t)chan, atten)); - ret_val = esp_adc_cal_characterize(adc_n, atten, ADC_WIDTH_BIT_DEFAULT, 0, &adc2_chars); - } - if (ret_val == ESP_ADC_CAL_VAL_NOT_SUPPORTED) { - ESP_LOGW(TAG, "No cali eFuse, or invalid arg, but will run the test"); - } - ESP_LOGI(TAG, "ADC%d, channel%d, atten%d", adc_n, chan, atten); -} - -static IRAM_ATTR NOINLINE_ATTR uint32_t get_cali_time_in_ccount(uint32_t adc_raw, esp_adc_cal_characteristics_t *chars) -{ - uint32_t time; - - RECORD_TIME_PREPARE(); - RECORD_TIME_START(); - esp_adc_cal_raw_to_voltage(adc_raw, chars); - RECORD_TIME_END(&time); - - return time; -} - -TEST_CASE("test_adc_single_cali_time", "[adc][ignore][manual]") -{ - ESP_LOGI(TAG, "CPU FREQ is %dMHz", CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ); - uint32_t adc1_time_record[4][TIMES_PER_ATTEN] = {}; - uint32_t adc2_time_record[4][TIMES_PER_ATTEN] = {}; - int adc1_raw = 0; - int adc2_raw = 0; - - //atten0 ~ atten3 - for (int i = 0; i < 4; i++) { - ESP_LOGI(TAG, "----------------atten%d----------------", i); - adc_single_cali_init(ADC_UNIT_1, ADC1_CALI_TEST_CHAN0, i); - adc_single_cali_init(ADC_UNIT_2, ADC2_CALI_TEST_CHAN0, i); - - for (int j = 0; j < TIMES_PER_ATTEN; j++) { - - adc1_raw = adc1_get_raw(ADC1_CALI_TEST_CHAN0); - TEST_ESP_OK(adc2_get_raw(ADC2_CALI_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc2_raw)); - - adc1_time_record[i][j] = get_cali_time_in_ccount(adc1_raw, &adc1_chars); - adc2_time_record[i][j] = get_cali_time_in_ccount(adc2_raw, &adc2_chars); - - IDF_LOG_PERFORMANCE("ADC1 Cali time", "%d us", (int)GET_US_BY_CCOUNT(adc1_time_record[i][j])); - IDF_LOG_PERFORMANCE("ADC2 Cali time", "%d us", (int)GET_US_BY_CCOUNT(adc2_time_record[i][j])); - } - } -} - - -/******************************************************************************** - * ADC Single with Light Sleep - ********************************************************************************/ -#include -#include "esp_sleep.h" -#include "esp_private/regi2c_ctrl.h" -#if REGI2C_ANA_CALI_PD_WORKAROUND -#include "soc/regi2c_saradc.h" -#endif - -//ADC Channels -#if CONFIG_IDF_TARGET_ESP32 -#define ADC1_SLEEP_TEST_CHAN ADC1_CHANNEL_6 -#define ADC2_SLEEP_TEST_CHAN ADC2_CHANNEL_0 -static const char *TAG_CH[2][10] = {{"ADC1_CH6"}, {"ADC2_CH0"}}; -#else -#define ADC1_SLEEP_TEST_CHAN ADC1_CHANNEL_2 -#define ADC2_SLEEP_TEST_CHAN ADC2_CHANNEL_0 -static const char *TAG_CH[2][10] = {{"ADC1_CH2"}, {"ADC2_CH0"}}; -#endif - -//ADC Attenuation -#define ADC_SLEEP_TEST_ATTEN ADC_ATTEN_DB_6 - -//ADC Calibration -#if CONFIG_IDF_TARGET_ESP32 -#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF -#elif CONFIG_IDF_TARGET_ESP32S2 -#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP -#elif CONFIG_IDF_TARGET_ESP32C3 -#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP -#elif CONFIG_IDF_TARGET_ESP32S3 -#define ADC_SLEEP_TEST_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT -#endif - -static esp_adc_cal_characteristics_t adc1_chars; -static esp_adc_cal_characteristics_t adc2_chars; - - -static bool adc_calibration_init(void) -{ - esp_err_t ret; - bool cali_enable = false; - - ret = esp_adc_cal_check_efuse(ADC_SLEEP_TEST_CALI_SCHEME); - if (ret == ESP_ERR_NOT_SUPPORTED) { - ESP_LOGW(TAG, "Calibration scheme not supported, skip software calibration"); - } else if (ret == ESP_ERR_INVALID_VERSION) { - ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); - } else if (ret == ESP_OK) { - cali_enable = true; - esp_adc_cal_characterize(ADC_UNIT_1, ADC_SLEEP_TEST_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars); - esp_adc_cal_characterize(ADC_UNIT_2, ADC_SLEEP_TEST_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc2_chars); - } else { - ESP_LOGE(TAG, "Invalid arg"); - } - - return cali_enable; -} - -#define TEST_REGI2C_ANA_CALI_BYTE_NUM 8 - -TEST_CASE("test ADC1 Single Read with Light Sleep", "[adc][manul][ignore]") -{ - //ADC1 config - TEST_ESP_OK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT)); - TEST_ESP_OK(adc1_config_channel_atten(ADC1_SLEEP_TEST_CHAN, ADC_SLEEP_TEST_ATTEN)); - - //ADC config calibration - bool cali_en = adc_calibration_init(); - - int raw_expected = 0; - uint32_t cali_expected = 0; - uint8_t regi2c_cali_val_before[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {}; - - int raw_after_sleep = 0; - uint32_t cali_after_sleep = 0; - uint8_t regi2c_cali_val_after[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {}; - - //---------------------------------Before Sleep-----------------------------------// - ESP_LOGI("Before", "Light Sleep"); - - //Read - raw_expected = adc1_get_raw(ADC1_SLEEP_TEST_CHAN); - if (cali_en) { - cali_expected = esp_adc_cal_raw_to_voltage(raw_expected, &adc1_chars); - } - -#if REGI2C_ANA_CALI_PD_WORKAROUND - //Print regi2c - for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { - regi2c_cali_val_before[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i); - printf("regi2c cali val is 0x%x", regi2c_cali_val_before[i]); - } - printf("\n"); -#endif - - //Print result - ESP_LOGI(TAG_CH[0][0], "ADC1 raw data: %d", raw_expected); - if (cali_en) { - ESP_LOGI(TAG_CH[0][0], "ADC1 cali data: %d", cali_expected); - } - - //---------------------------------After Sleep-----------------------------------// - ESP_LOGI("After", "Light Sleep"); - esp_sleep_enable_timer_wakeup(30 * 1000); - esp_light_sleep_start(); - ESP_LOGI(TAG, "Wakeup from light sleep."); - -#if REGI2C_ANA_CALI_PD_WORKAROUND - //Print regi2c - for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { - regi2c_cali_val_after[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i); - printf("regi2c cali val is 0x%x", regi2c_cali_val_after[i]); - } - printf("\n"); -#endif - - //Read - raw_after_sleep = adc1_get_raw(ADC1_SLEEP_TEST_CHAN); - if (cali_en) { - cali_after_sleep = esp_adc_cal_raw_to_voltage(raw_after_sleep, &adc1_chars); - } - - //Print result - ESP_LOGI(TAG_CH[0][0], "after light sleep, ADC1 cali data: %d", raw_after_sleep); - if (cali_en) { - ESP_LOGI(TAG_CH[0][0], "after light sleep, ADC1 cali data: %d", cali_after_sleep); - } - - //Compare - int32_t raw_diff = raw_expected - raw_after_sleep; - IDF_LOG_PERFORMANCE("ADC1 raw diff after sleep", "%d", raw_diff); - if (cali_en) { - int32_t cali_diff = cali_expected - cali_after_sleep; - IDF_LOG_PERFORMANCE("ADC1 cali diff after sleep", "%d mV", cali_diff); - } - - for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { - TEST_ASSERT_EQUAL(regi2c_cali_val_before[i], regi2c_cali_val_after[i]); - } -} - -TEST_CASE("test ADC2 Single Read with Light Sleep", "[adc][manul][ignore]") -{ - //ADC2 config - ESP_ERROR_CHECK(adc2_config_channel_atten(ADC2_SLEEP_TEST_CHAN, ADC_SLEEP_TEST_ATTEN)); - //ADC config calibration - bool cali_en = adc_calibration_init(); - - int raw_expected = 0; - uint32_t cali_expected = 0; - uint8_t regi2c_cali_val_before[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {}; - - int raw_after_sleep = 0; - uint32_t cali_after_sleep = 0; - uint8_t regi2c_cali_val_after[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {}; - - //---------------------------------Before Sleep-----------------------------------// - ESP_LOGI("Before", "Light Sleep"); - - //Read - TEST_ESP_OK(adc2_get_raw(ADC2_SLEEP_TEST_CHAN, ADC_WIDTH_BIT_DEFAULT, &raw_expected)); - if (cali_en) { - cali_expected = esp_adc_cal_raw_to_voltage(raw_expected, &adc2_chars); - } - -#if REGI2C_ANA_CALI_PD_WORKAROUND - //Print regi2c - for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { - regi2c_cali_val_before[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i); - printf("regi2c cali val is 0x%x", regi2c_cali_val_before[i]); - } - printf("\n"); -#endif - - //Print result - ESP_LOGI(TAG_CH[1][0], "ADC2 raw data: %d", raw_expected); - if (cali_en) { - ESP_LOGI(TAG_CH[1][0], "ADC2 cali data: %d", cali_expected); - } - - //---------------------------------After Sleep-----------------------------------// - ESP_LOGI("After", "Light Sleep"); - esp_sleep_enable_timer_wakeup(30 * 1000); - esp_light_sleep_start(); - ESP_LOGI(TAG, "Wakeup from light sleep."); - -#if REGI2C_ANA_CALI_PD_WORKAROUND - //Print regi2c - for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { - regi2c_cali_val_after[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i); - printf("regi2c cali val is 0x%x", regi2c_cali_val_after[i]); - } - printf("\n"); -#endif - - //Read - TEST_ESP_OK(adc2_get_raw(ADC2_SLEEP_TEST_CHAN, ADC_WIDTH_BIT_DEFAULT, &raw_after_sleep)); - if (cali_en) { - cali_after_sleep += esp_adc_cal_raw_to_voltage(raw_after_sleep, &adc2_chars); - } - - //Print result - ESP_LOGI(TAG_CH[1][0], "after light sleep, ADC2 cali data: %d", raw_after_sleep); - if (cali_en) { - ESP_LOGI(TAG_CH[1][0], "after light sleep, ADC2 cali data: %d", cali_after_sleep); - } - - //Compare - int32_t raw_diff = raw_expected - raw_after_sleep; - IDF_LOG_PERFORMANCE("ADC2 raw diff after sleep", "%d", raw_diff); - if (cali_en) { - int32_t cali_diff = cali_expected - cali_after_sleep; - IDF_LOG_PERFORMANCE("ADC2 cali diff after sleep", "%d mV", cali_diff); - } - for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { - TEST_ASSERT_EQUAL(regi2c_cali_val_before[i], regi2c_cali_val_after[i]); - } -} -#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C2) //TODO IDF-3908 diff --git a/components/driver/test/test_adc2_with_wifi.c b/components/driver/test/test_adc2_with_wifi.c index d03fc63126..a889592bb9 100644 --- a/components/driver/test/test_adc2_with_wifi.c +++ b/components/driver/test/test_adc2_with_wifi.c @@ -15,12 +15,13 @@ #include "nvs_flash.h" #include "test_utils.h" #include "driver/gpio.h" -#include "driver/adc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" +#define CONFIG_ADC_SUPPRESS_DEPRECATE_WARN 1 +#include "driver/adc.h" -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3, ESP32S3, ESP32C2) +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3, ESP32C2) static const char* TAG = "test_adc2"; @@ -149,7 +150,7 @@ TEST_CASE("adc2 work with wifi","[adc]") bool test_list[TEST_NUM] ={1, 1, 0, 0, 1, 0, 1, 0}; adc2_pad_get_io_num(ADC2_CHAN1, &test_adc_io); - TEST_ESP_OK(adc2_config_channel_atten(ADC2_CHAN1, ADC_ATTEN_0db)); + TEST_ESP_OK(adc2_config_channel_atten(ADC2_CHAN1, ADC_ATTEN_DB_0)); printf("test_adc_io is %d\n", test_adc_io); //---------------------------------GPIO init-----------------------------------// diff --git a/components/driver/test/test_adc_common.c b/components/driver/test/test_adc_common.c deleted file mode 100644 index c05e50651d..0000000000 --- a/components/driver/test/test_adc_common.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -/* - Tests for the adc device driver -*/ -#include "esp_system.h" -#include "driver/adc.h" -#include "driver/rtc_io.h" -#include "driver/gpio.h" -#include "unity.h" -#include "esp_system.h" -#include "esp_event.h" -#include "esp_wifi.h" -#include "esp_log.h" -#include "nvs_flash.h" -#include "test_utils.h" -#include "soc/adc_periph.h" - -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3,ESP32C3, ESP32C2) -#include "driver/dac.h" - -static const char *TAG = "test_adc"; - -#ifdef CONFIG_IDF_TARGET_ESP32 -#define ADC1_TEST_WIDTH ADC_WIDTH_BIT_12 -#define ADC2_TEST_WIDTH ADC_WIDTH_BIT_12 -#elif defined CONFIG_IDF_TARGET_ESP32S2 -#define ADC1_TEST_WIDTH ADC_WIDTH_BIT_13 //ESP32S2 only support 13 bit width -#define ADC2_TEST_WIDTH ADC_WIDTH_BIT_13 //ESP32S2 only support 13 bit width -#endif - -#define ADC1_TEST_ATTEN ADC_ATTEN_DB_11 -#define ADC2_TEST_ATTEN ADC_ATTEN_DB_11 - -#if CONFIG_IDF_TARGET_ESP32 -#define ADC1_TEST_CHANNEL_NUM 8 -#elif CONFIG_IDF_TARGET_ESP32S2 -#define ADC1_TEST_CHANNEL_NUM 10 -#endif -#define ADC2_TEST_CHANNEL_NUM 6 - -static const int adc1_ch[ADC1_TEST_CHANNEL_NUM] = { - ADC1_CHANNEL_0, - ADC1_CHANNEL_1, - ADC1_CHANNEL_2, - ADC1_CHANNEL_3, - ADC1_CHANNEL_4, - ADC1_CHANNEL_5, - ADC1_CHANNEL_6, - ADC1_CHANNEL_7, -#if CONFIG_IDF_TARGET_ESP32S2 - ADC1_CHANNEL_8, - ADC1_CHANNEL_9, -#endif -}; - -static const int adc2_ch[ADC2_TEST_CHANNEL_NUM] = { - ADC2_CHANNEL_0, - ADC2_CHANNEL_1, - ADC2_CHANNEL_2, - ADC2_CHANNEL_3, - ADC2_CHANNEL_4, - ADC2_CHANNEL_5, -}; - -#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel]) - -void adc_fake_tie_middle(adc_unit_t adc_unit, adc_channel_t channel) -{ - gpio_num_t gpio_num = 0; - if (adc_unit == ADC_UNIT_1) { - gpio_num = ADC_GET_IO_NUM(0, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_PULLDOWN)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - } - if (adc_unit == ADC_UNIT_2) { - gpio_num = ADC_GET_IO_NUM(1, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_PULLDOWN)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - } - vTaskDelay(10 / portTICK_PERIOD_MS); -} - -void adc_fake_tie_high(adc_unit_t adc_unit, adc_channel_t channel) -{ - gpio_num_t gpio_num = 0; - if (adc_unit == ADC_UNIT_1) { - gpio_num = ADC_GET_IO_NUM(0, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_ONLY)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY)); - TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 1)); - } - if (adc_unit == ADC_UNIT_2) { - gpio_num = ADC_GET_IO_NUM(1, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_en(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLUP_ONLY)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY)); - TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 1)); - } - vTaskDelay(10 / portTICK_PERIOD_MS); -} - -void adc_fake_tie_low(adc_unit_t adc_unit, adc_channel_t channel) -{ - gpio_num_t gpio_num = 0; - if (adc_unit == ADC_UNIT_1) { - gpio_num = ADC_GET_IO_NUM(0, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLDOWN_ONLY)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY)); - TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 0)); - } - if (adc_unit == ADC_UNIT_2) { - gpio_num = ADC_GET_IO_NUM(1, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_en(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_PULLDOWN_ONLY)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_OUTPUT_ONLY)); - TEST_ESP_OK(rtc_gpio_set_level(gpio_num, 0)); - } - vTaskDelay(10 / portTICK_PERIOD_MS); -} - -void adc_io_normal(adc_unit_t adc_unit, adc_channel_t channel) -{ - gpio_num_t gpio_num = 0; - if (adc_unit == ADC_UNIT_1) { - gpio_num = ADC_GET_IO_NUM(0, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - } - if (adc_unit == ADC_UNIT_2) { - gpio_num = ADC_GET_IO_NUM(1, channel); - TEST_ESP_OK(rtc_gpio_init(gpio_num)); - TEST_ESP_OK(rtc_gpio_pullup_dis(gpio_num)); - TEST_ESP_OK(rtc_gpio_pulldown_dis(gpio_num)); - TEST_ESP_OK(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); - TEST_ESP_OK(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - } - vTaskDelay(10 / portTICK_PERIOD_MS); -} - -TEST_CASE("ADC1 rtc read", "[adc1]") -{ - int adc1_val[ADC1_TEST_CHANNEL_NUM] = {0}; - - /* adc1 Configure */ - adc1_config_width(ADC1_TEST_WIDTH); - ESP_LOGI(TAG, "ADC1 [CH - GPIO]:"); - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc1_config_channel_atten(adc1_ch[i], ADC1_TEST_ATTEN) ); - ESP_LOGI(TAG, "[CH%d - IO%d]:", adc1_ch[i], ADC_GET_IO_NUM(0, adc1_ch[i])); - } - printf("ADC tie normal read: "); - vTaskDelay(10 / portTICK_PERIOD_MS); - - /* adc Read */ - printf("ADC1: "); - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]); - printf("CH%d-%d ", adc1_ch[i], adc1_val[i]); - } - printf("\n"); - - /* tie high */ - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_high(ADC_UNIT_1, adc1_ch[i]); - } - printf("ADC tie high read: "); - vTaskDelay(50 / portTICK_PERIOD_MS); - /* adc Read */ - printf("ADC1: "); - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]); - printf("CH%d-%d ", adc1_ch[i], adc1_val[i]); -#ifdef CONFIG_IDF_TARGET_ESP32S2 - TEST_ASSERT_EQUAL( adc1_val[i], 0x1fff ); -#endif - } - printf("\n"); - - /* tie low */ - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_low(ADC_UNIT_1, adc1_ch[i]); - } - printf("ADC tie low read: "); - vTaskDelay(50 / portTICK_PERIOD_MS); - /* adc Read */ - printf("ADC1: "); - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]); - printf("CH%d-%d ", adc1_ch[i], adc1_val[i]); -#ifdef CONFIG_IDF_TARGET_ESP32S2 - TEST_ASSERT_INT_WITHIN( 100, 0, adc1_val[i] ); -#endif - } - printf("\n"); - - /* tie midedle */ - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_middle(ADC_UNIT_1, adc1_ch[i]); - } - printf("ADC tie mid read: "); - vTaskDelay(50 / portTICK_PERIOD_MS); - /* adc Read */ - printf("ADC1: "); - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc1_val[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]); - printf("CH%d-%d ", adc1_ch[i], adc1_val[i]); -#ifdef CONFIG_IDF_TARGET_ESP32S2 - TEST_ASSERT_NOT_EQUAL( adc1_val[i], 0x1fff ); - TEST_ASSERT_NOT_EQUAL( adc1_val[i], 0 ); -#endif - } - printf("\n"); - - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc_io_normal(ADC_UNIT_1, adc1_ch[i]); - } -} - -TEST_CASE("ADC2 rtc read", "[adc2]") -{ - int adc2_val[ADC2_TEST_CHANNEL_NUM] = {0}; - - /* adc2 Configure */ - ESP_LOGI(TAG, "ADC2 [CH - GPIO]:"); - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc2_config_channel_atten(adc2_ch[i], ADC2_TEST_ATTEN) ); - ESP_LOGI(TAG, "[CH%d - IO%d]:", adc2_ch[i], ADC_GET_IO_NUM(1, adc2_ch[i])); - } - printf("ADC float read: "); - vTaskDelay(10 / portTICK_PERIOD_MS); - - /* adc Read */ - printf("ADC2: "); - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) ); - printf("CH%d-%d ", adc2_ch[i], adc2_val[i]); - } - printf("\n"); - - /* tie high */ - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_high(ADC_UNIT_2, adc2_ch[i]); - } - printf("ADC tie high read: "); - vTaskDelay(10 / portTICK_PERIOD_MS); - /* adc Read */ - printf("ADC2: "); - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) ); - printf("CH%d-%d ", adc2_ch[i], adc2_val[i]); -#ifdef CONFIG_IDF_TARGET_ESP32S2 - TEST_ASSERT_EQUAL( adc2_val[i], 0x1fff ); -#endif - } - printf("\n"); - - /* tie low */ - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_low(ADC_UNIT_2, adc2_ch[i]); - } - printf("ADC tie low read: "); - vTaskDelay(10 / portTICK_PERIOD_MS); - /* adc Read */ - printf("ADC2: "); - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) ); - printf("CH%d-%d ", adc2_ch[i], adc2_val[i]); -#ifdef CONFIG_IDF_TARGET_ESP32S2 - TEST_ASSERT_INT_WITHIN( 100, 0, adc2_val[i] ); -#endif - } - printf("\n"); - - /* tie midedle */ - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_middle(ADC_UNIT_2, adc2_ch[i]); - } - printf("ADC tie middle read: "); - vTaskDelay(10 / portTICK_PERIOD_MS); - /* adc Read */ - printf("ADC2: "); - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]) ); - printf("CH%d-%d ", adc2_ch[i], adc2_val[i]); -#ifdef CONFIG_IDF_TARGET_ESP32S2 - TEST_ASSERT_NOT_EQUAL( 0, adc2_val[i] ); - TEST_ASSERT_NOT_EQUAL( 0x1fff, adc2_val[i] ); -#endif - } - printf("\n"); - - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc_io_normal(ADC_UNIT_1, adc1_ch[i]); - } -} - -#include "touch_scope.h" -/** - * 0: ADC1 channels raw data debug. - * 1: ADC2 channels raw data debug. - */ -#define SCOPE_DEBUG_TYPE 1 -#define SCOPE_DEBUG_CHANNEL_MAX (10) -#define SCOPE_DEBUG_ENABLE (0) -#define SCOPE_UART_BUADRATE (256000) -#define SCOPE_DEBUG_FREQ_MS (50) - -/** - * Manual test: Capture ADC-DMA data and display it on the serial oscilloscope. Used to observe the stability of the data. - * Use step: - * 1. Call this function in `esp-idf/tools/unit-test-app/main/app_main.c`. - * 2. Use `ESP-Tuning Tool`(download from `www.espressif.com`) to capture. - * 3. The readings of multiple channels will be displayed on the tool. - */ -void test_adc_slope_debug(void) -{ - float scope_temp[SCOPE_DEBUG_CHANNEL_MAX] = {0}; // max scope channel is 10. - test_tp_scope_debug_init(0, -1, -1, SCOPE_UART_BUADRATE); - -#if SCOPE_DEBUG_TYPE == 0 - /* adc1 Configure */ - adc1_config_width(ADC1_TEST_WIDTH); - ESP_LOGI(TAG, "ADC1 [CH - GPIO] atten %d:", ADC1_TEST_ATTEN); - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc1_config_channel_atten(adc1_ch[i], ADC1_TEST_ATTEN) ); - ESP_LOGI(TAG, "[CH%d - IO%d]", adc1_ch[i], ADC_GET_IO_NUM(0, adc1_ch[i])); - } - /* tie midedle */ - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_middle(ADC_UNIT_1, adc1_ch[i]); - } - vTaskDelay(10 / portTICK_PERIOD_MS); - - while (1) { - /* adc Read */ - for (int i = 0; i < ADC1_TEST_CHANNEL_NUM; i++) { - scope_temp[i] = adc1_get_raw((adc1_channel_t)adc1_ch[i]); - } - test_tp_print_to_scope(scope_temp, ADC1_TEST_CHANNEL_NUM); - vTaskDelay(SCOPE_DEBUG_FREQ_MS / portTICK_PERIOD_MS); - } -#elif SCOPE_DEBUG_TYPE == 1 - int adc2_val[ADC2_TEST_CHANNEL_NUM] = {0}; - - /* adc2 Configure */ - ESP_LOGI(TAG, "ADC2 [CH - GPIO] atten %d:", ADC2_TEST_ATTEN); - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - TEST_ESP_OK( adc2_config_channel_atten(adc2_ch[i], ADC2_TEST_ATTEN) ); - ESP_LOGI(TAG, "[CH%d - IO%d]:", adc2_ch[i], ADC_GET_IO_NUM(1, adc2_ch[i])); - } - /* tie midedle */ - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - adc_fake_tie_middle(ADC_UNIT_2, adc2_ch[i]); - } - vTaskDelay(10 / portTICK_PERIOD_MS); - - while (1) { - /* adc Read */ - printf("ADC2: "); - for (int i = 0; i < ADC2_TEST_CHANNEL_NUM; i++) { - adc2_get_raw((adc2_channel_t)adc2_ch[i], ADC2_TEST_WIDTH, &adc2_val[i]); - scope_temp[i] = adc2_val[i]; - } - - test_tp_print_to_scope(scope_temp, ADC2_TEST_CHANNEL_NUM); - vTaskDelay(SCOPE_DEBUG_FREQ_MS / portTICK_PERIOD_MS); - } -#endif -} - -#endif diff --git a/components/driver/test/test_dac.c b/components/driver/test/test_dac.c index 0537f23148..9377039a74 100644 --- a/components/driver/test/test_dac.c +++ b/components/driver/test/test_dac.c @@ -8,7 +8,6 @@ */ #include "esp_system.h" -#include "driver/adc.h" #include "unity.h" #include "esp_system.h" #include "esp_event.h" @@ -17,6 +16,8 @@ #include "nvs_flash.h" #include "test_utils.h" #include "soc/soc_caps.h" +#define CONFIG_ADC_SUPPRESS_DEPRECATE_WARN 1 +#include "driver/adc.h" #if SOC_DAC_SUPPORTED #include "driver/dac.h" diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/main/test_i2s_dac.c b/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/main/test_i2s_dac.c index 7af9a520f0..90a370153d 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/main/test_i2s_dac.c +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/main/test_i2s_dac.c @@ -13,7 +13,6 @@ #if CONFIG_IDF_TARGET_ESP32 #include "esp_system.h" -#include "driver/adc.h" #include "unity.h" #include "esp_system.h" #include "esp_event.h" diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/sdkconfig.defaults b/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/sdkconfig.defaults index 7fb17baea9..4295a349c9 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/sdkconfig.defaults +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac/sdkconfig.defaults @@ -1,3 +1,4 @@ CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y +CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y CONFIG_I2S_ENABLE_DEBUG_LOG=y CONFIG_ESP_TASK_WDT=n diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/sdkconfig.defaults b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/sdkconfig.defaults index 7fb17baea9..4295a349c9 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/sdkconfig.defaults +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/sdkconfig.defaults @@ -1,3 +1,4 @@ CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y +CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y CONFIG_I2S_ENABLE_DEBUG_LOG=y CONFIG_ESP_TASK_WDT=n diff --git a/components/driver/test_apps/legacy_adc_driver/CMakeLists.txt b/components/driver/test_apps/legacy_adc_driver/CMakeLists.txt new file mode 100644 index 0000000000..b1cf7d2df9 --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/CMakeLists.txt @@ -0,0 +1,5 @@ +# 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(legacy_adc_driver_test) diff --git a/components/driver/test_apps/legacy_adc_driver/README.md b/components/driver/test_apps/legacy_adc_driver/README.md new file mode 100644 index 0000000000..b5be4985c5 --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/legacy_adc_driver/main/CMakeLists.txt b/components/driver/test_apps/legacy_adc_driver/main/CMakeLists.txt new file mode 100644 index 0000000000..ed39466490 --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(srcs "test_app_main.c" + "test_legacy_adc.c") + +idf_component_register(SRCS ${srcs} + WHOLE_ARCHIVE) diff --git a/components/driver/test_apps/legacy_adc_driver/main/test_app_main.c b/components/driver/test_apps/legacy_adc_driver/main/test_app_main.c new file mode 100644 index 0000000000..027d2b69c0 --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/main/test_app_main.c @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +#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) +{ + unity_run_menu(); +} diff --git a/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c b/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c new file mode 100644 index 0000000000..041d800660 --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c @@ -0,0 +1,129 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include "unity.h" +#include "esp_log.h" +#include "driver/adc.h" +#include "driver/gpio.h" +#include "driver/rtc_io.h" +#include "soc/adc_periph.h" + +#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel]) + +/** + * We use weak pulldown, `ADC_TEST_LOW_THRESH` may vary. + * If connect to GND, `ADC_TEST_LOW_THRESH` will usually within 10 + */ +#if CONFIG_IDF_TARGET_ESP32 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 10 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_THRESH 10 + +#elif CONFIG_IDF_TARGET_ESP32S2 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 25 + +#define ADC_TEST_HIGH_VAL 8191 +#define ADC_TEST_HIGH_THRESH 10 + +#elif CONFIG_IDF_TARGET_ESP32C3 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 30 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_THRESH 10 + +#elif CONFIG_IDF_TARGET_ESP32S3 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 15 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_THRESH 0 + +#elif CONFIG_IDF_TARGET_ESP32C2 +#define ADC_TEST_LOW_VAL 2147 +#define ADC_TEST_LOW_THRESH 50 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_THRESH 0 + +#elif CONFIG_IDF_TARGET_ESP32H2 +#define ADC_TEST_LOW_VAL 2147 +#define ADC_TEST_LOW_THRESH 50 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_THRESH 0 +#endif + +//ADC Channels +#if CONFIG_IDF_TARGET_ESP32 +#define ADC1_TEST_CHAN0 ADC1_CHANNEL_4 +#define ADC2_TEST_CHAN0 ADC2_CHANNEL_0 +#elif (SOC_ADC_PERIPH_NUM >= 2) +#define ADC1_TEST_CHAN0 ADC1_CHANNEL_2 +#define ADC2_TEST_CHAN0 ADC2_CHANNEL_0 +#else +#define ADC1_TEST_CHAN0 ADC1_CHANNEL_2 +#endif + +const __attribute__((unused)) static char *TAG = "TEST_ADC_LEGACY"; + + +void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level) +{ + TEST_ASSERT(channel < SOC_ADC_CHANNEL_NUM(unit) && "invalid channel"); + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + uint32_t io_num = ADC_GET_IO_NUM(unit, channel); + TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY: GPIO_PULLDOWN_ONLY))); +#else + gpio_num_t io_num = ADC_GET_IO_NUM(unit, channel); + if (level) { + TEST_ESP_OK(rtc_gpio_pullup_en(io_num)); + TEST_ESP_OK(rtc_gpio_pulldown_dis(io_num)); + } else { + TEST_ESP_OK(rtc_gpio_pullup_dis(io_num)); + TEST_ESP_OK(rtc_gpio_pulldown_en(io_num)); + } +#endif +} + +TEST_CASE("Legacy ADC oneshot high/low test", "[legacy_adc_oneshot]") +{ + int adc_raw = 0; + //ADC1 config + TEST_ESP_OK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT)); + TEST_ESP_OK(adc1_config_channel_atten(ADC1_TEST_CHAN0, ADC_ATTEN_DB_11)); +#if (SOC_ADC_PERIPH_NUM >= 2) + //ADC2 config + TEST_ESP_OK(adc2_config_channel_atten(ADC2_TEST_CHAN0, ADC_ATTEN_DB_11)); +#endif + + test_adc_set_io_level(ADC_UNIT_1, (adc1_channel_t)ADC1_TEST_CHAN0, 0); + adc_raw = adc1_get_raw(ADC1_TEST_CHAN0); + ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_1, ADC1_TEST_CHAN0, adc_raw); + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw); + + test_adc_set_io_level(ADC_UNIT_1, (adc1_channel_t)ADC1_TEST_CHAN0, 1); + adc_raw = adc1_get_raw(ADC1_TEST_CHAN0); + ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_1, ADC1_TEST_CHAN0, adc_raw); + TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw); + +#if (SOC_ADC_PERIPH_NUM >= 2) + test_adc_set_io_level(ADC_UNIT_2, (adc2_channel_t)ADC2_TEST_CHAN0, 0); + TEST_ESP_OK(adc2_get_raw(ADC2_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw)); + ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_2, ADC2_TEST_CHAN0, adc_raw); + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw); + + test_adc_set_io_level(ADC_UNIT_2, (adc2_channel_t)ADC2_TEST_CHAN0, 1); + TEST_ESP_OK(adc2_get_raw(ADC2_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw)); + ESP_LOGI(TAG, "ADC%d Channel %d raw: %d\n", ADC_UNIT_2, ADC2_TEST_CHAN0, adc_raw); + TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw); +#endif +} diff --git a/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py new file mode 100644 index 0000000000..9718e7ecee --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.esp32c3 +@pytest.mark.esp32c2 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'release', + ], + indirect=True, +) +def test_legacy_adc(dut: Dut) -> None: + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('*') + dut.expect_unity_test_output(timeout=240) diff --git a/components/driver/test_apps/legacy_adc_driver/sdkconfig.ci.release b/components/driver/test_apps/legacy_adc_driver/sdkconfig.ci.release new file mode 100644 index 0000000000..91d93f163e --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/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/legacy_adc_driver/sdkconfig.defaults b/components/driver/test_apps/legacy_adc_driver/sdkconfig.defaults new file mode 100644 index 0000000000..2b6418fbd4 --- /dev/null +++ b/components/driver/test_apps/legacy_adc_driver/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n +CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y diff --git a/components/efuse/esp32c3/esp_efuse_rtc_calib.c b/components/efuse/esp32c3/esp_efuse_rtc_calib.c index 5c3afae263..ccf4c7d422 100644 --- a/components/efuse/esp32c3/esp_efuse_rtc_calib.c +++ b/components/efuse/esp32c3/esp_efuse_rtc_calib.c @@ -39,8 +39,9 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a return init_code + 1000; // version 1 logic } -esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv) +esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, uint32_t adc_unit, int atten, uint32_t* out_digi, uint32_t* out_vol_mv) { + (void)adc_unit; //On esp32c3, V1 we don't have calibration data for ADC2, using the efuse data of ADC1 const esp_efuse_desc_t** cal_vol_efuse; uint32_t calib_vol_expected_mv; if (version != 1) { diff --git a/components/efuse/esp32c3/include/esp_efuse_rtc_calib.h b/components/efuse/esp32c3/include/esp_efuse_rtc_calib.h index 40e7ad0330..1f6e4748bd 100644 --- a/components/efuse/esp32c3/include/esp_efuse_rtc_calib.h +++ b/components/efuse/esp32c3/include/esp_efuse_rtc_calib.h @@ -35,6 +35,7 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a * @brief Get the calibration digits stored in the efuse, and the corresponding voltage. * * @param version Version of the stored efuse + * @param adc_unit ADC unit (not used on ESP32C3, for compatibility) * @param atten Attenuation to use * @param out_digi Output buffer of the digits * @param out_vol_mv Output of the voltage, in mV @@ -42,7 +43,7 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a * - ESP_ERR_INVALID_ARG: If efuse version or attenuation is invalid * - ESP_OK: if success */ -esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv); +esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, uint32_t adc_unit, int atten, uint32_t* out_digi, uint32_t* out_vol_mv); /** * @brief Get the temperature sensor calibration number delta_T stored in the efuse. diff --git a/components/esp_adc/CMakeLists.txt b/components/esp_adc/CMakeLists.txt new file mode 100644 index 0000000000..44e8d40724 --- /dev/null +++ b/components/esp_adc/CMakeLists.txt @@ -0,0 +1,39 @@ +idf_build_get_property(target IDF_TARGET) + +set(includes "include" "interface" "${target}/include" "deprecated/include") + +set(srcs "adc_cali.c" + "adc_cali_curve_fitting.c" + "adc_oneshot.c" + "adc_common.c" + "adc_lock.c" + "deprecated/esp_adc_cal_common_legacy.c") + +if(CONFIG_SOC_ADC_DMA_SUPPORTED) + list(APPEND srcs "adc_continuous.c") +endif() + +# init constructor for wifi +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/adc2_init_cal.c") + list(APPEND srcs "${target}/adc2_init_cal.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") +endif() + +# curve fitting scheme coefficients +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/curve_fitting_coefficients.c") + list(APPEND srcs "${target}/curve_fitting_coefficients.c") +endif() + +# legacy calibration driver +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deprecated/${target}/esp_adc_cal_legacy.c") + list(APPEND srcs "deprecated/${target}/esp_adc_cal_legacy.c") +endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ${includes} + PRIV_REQUIRES driver efuse + LDFRAGMENTS linker.lf) diff --git a/components/esp_adc/Kconfig b/components/esp_adc/Kconfig new file mode 100644 index 0000000000..87a8fbe567 --- /dev/null +++ b/components/esp_adc/Kconfig @@ -0,0 +1,47 @@ +menu "ADC and ADC Calibration" + + config ADC_ONESHOT_CTRL_FUNC_IN_IRAM + bool "Place ISR version ADC oneshot mode read function into IRAM" + default n + help + Place ISR version ADC oneshot mode read function into IRAM. + + config ADC_CONTINUOUS_ISR_IRAM_SAFE + depends on SOC_ADC_DMA_SUPPORTED + bool "ADC continuous mode driver ISR IRAM-Safe" + default n + select GDMA_ISR_IRAM_SAFE if SOC_ADC_DMA_SUPPORTED && SOC_GDMA_SUPPORTED + help + Ensure the ADC continuous mode ISR is IRAM-Safe. When enabled, the ISR handler + will be available when the cache is disabled. + + menu "ADC Calibration Configurations" + depends on IDF_TARGET_ESP32 + + config ADC_CALI_EFUSE_TP_ENABLE + bool "Use Two Point Values" + default "y" + help + Some ESP32s have Two Point calibration values burned into eFuse BLOCK3. + This option will allow the ADC calibration component to characterize the + ADC-Voltage curve using Two Point values if they are available. + + config ADC_CALI_EFUSE_VREF_ENABLE + bool "Use eFuse Vref" + default "y" + help + Some ESP32s have Vref burned into eFuse BLOCK0. This option will allow + the ADC calibration component to characterize the ADC-Voltage curve using + eFuse Vref if it is available. + + config ADC_CALI_LUT_ENABLE + bool "Use Lookup Tables" + default "y" + help + This option will allow the ADC calibration component to use Lookup Tables + to correct for non-linear behavior in 11db attenuation. Other attenuations + do not exhibit non-linear behavior hence will not be affected by this option. + + endmenu + +endmenu diff --git a/components/esp_adc/adc_cali.c b/components/esp_adc/adc_cali.c new file mode 100644 index 0000000000..4b5b4e26aa --- /dev/null +++ b/components/esp_adc/adc_cali.c @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "esp_types.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "hal/adc_types.h" +#include "esp_adc/adc_cali.h" +#include "adc_cali_interface.h" + +const __attribute__((unused)) static char *TAG = "adc_cali"; + + +esp_err_t adc_cali_check_scheme(adc_cali_scheme_ver_t *scheme_mask) +{ + ESP_RETURN_ON_FALSE(scheme_mask, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + *scheme_mask = 0; +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + *scheme_mask |= ADC_CALI_SCHEME_VER_LINE_FITTING; +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + *scheme_mask |= ADC_CALI_SCHEME_VER_CURVE_FITTING; +#endif + + //Add your custom ADC calibration scheme here + + ESP_RETURN_ON_FALSE((*scheme_mask) != 0, ESP_ERR_NOT_SUPPORTED, TAG, "no supported calibration scheme yet"); + + return ESP_OK; +} + +esp_err_t adc_cali_raw_to_voltage(adc_cali_handle_t handle, int raw, int *voltage) +{ + ESP_RETURN_ON_FALSE(handle && voltage, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(handle->ctx, ESP_ERR_INVALID_STATE, TAG, "no calibration scheme, create a scheme first"); + + return handle->raw_to_voltage(handle->ctx, raw, voltage); +} diff --git a/components/esp_adc/adc_cali_curve_fitting.c b/components/esp_adc/adc_cali_curve_fitting.c new file mode 100644 index 0000000000..9b80e47b2c --- /dev/null +++ b/components/esp_adc/adc_cali_curve_fitting.c @@ -0,0 +1,247 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "esp_types.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "soc/soc_caps.h" +#include "esp_adc/adc_cali_scheme.h" +#include "adc_cali_interface.h" +#include "curve_fitting_coefficients.h" + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED +#include "esp_efuse_rtc_calib.h" + +const __attribute__((unused)) static char *TAG = "adc_cali"; + + +// coeff_a is actually a float number +// it is scaled to put them into uint32_t so that the headers do not have to be changed +static const int coeff_a_scaling = 65536; + + +/* -------------------- Characterization Helper Data Types ------------------ */ +typedef struct { + uint32_t voltage; + uint32_t digi; +} adc_calib_data_ver1_t; + +typedef struct { + char version_num; + adc_unit_t unit_id; + adc_atten_t atten; + union { + adc_calib_data_ver1_t ver1; + } ref_data; +} adc_calib_info_t; + + +/* ------------------------ Context Structure--------------------------- */ +typedef struct { + uint32_t coeff_a; ///< Gradient of ADC-Voltage curve + uint32_t coeff_b; ///< Offset of ADC-Voltage curve +} cali_chars_first_step_t; + +typedef struct { + uint8_t term_num; ///< Term number of the algorithm formula + const uint64_t (*coeff)[COEFF_GROUP_NUM][TERM_MAX][2]; ///< Coeff of each term. See `adc_error_coef_atten` for details (and the magic number 2) + const int32_t (*sign)[COEFF_GROUP_NUM][TERM_MAX]; ///< Sign of each term +} cali_chars_second_step_t; + +typedef struct { + adc_unit_t unit_id; ///< ADC unit + adc_atten_t atten; ///< ADC attenuation + cali_chars_first_step_t chars_first_step; ///< Calibration first step characteristics + cali_chars_second_step_t chars_second_step; ///< Calibration second step characteristics +} cali_chars_curve_fitting_t; + + +/* ----------------------- Characterization Functions ----------------------- */ +static void get_first_step_reference_point(int version_num, adc_unit_t unit_id, adc_atten_t atten, adc_calib_info_t *calib_info); +static void calc_first_step_coefficients(const adc_calib_info_t *parsed_data, cali_chars_curve_fitting_t *chars); +static void calc_second_step_coefficients(const adc_cali_curve_fitting_config_t *config, cali_chars_curve_fitting_t *ctx); +static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param, adc_atten_t atten); +static esp_err_t check_valid(const adc_cali_curve_fitting_config_t *config); + + +/* ------------------------ Interface Functions --------------------------- */ +static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage); + +/* ------------------------- Public API ------------------------------------- */ +esp_err_t adc_cali_create_scheme_curve_fitting(const adc_cali_curve_fitting_config_t *config, adc_cali_handle_t *ret_handle) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer"); + ret = check_valid(config); + if (ret != ESP_OK) { + return ret; + } + // current version only accepts encoding ver 1. + uint8_t adc_encoding_version = esp_efuse_rtc_calib_get_ver(); + ESP_RETURN_ON_FALSE(adc_encoding_version == 1, ESP_ERR_NOT_SUPPORTED, TAG, "Calibration required eFuse bits not burnt"); + + adc_cali_scheme_t *scheme = (adc_cali_scheme_t *)heap_caps_calloc(1, sizeof(adc_cali_scheme_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for adc calibration scheme"); + + cali_chars_curve_fitting_t *chars = (cali_chars_curve_fitting_t *)heap_caps_calloc(1, sizeof(cali_chars_curve_fitting_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(chars, ESP_ERR_NO_MEM, err, TAG, "no memory for the calibration characteristics"); + + scheme->raw_to_voltage = cali_raw_to_voltage; + scheme->ctx = chars; + + //Prepare calibration characteristics + adc_calib_info_t calib_info = {0}; + //Set first step calibration context + get_first_step_reference_point(adc_encoding_version, config->unit_id, config->atten, &calib_info); + calc_first_step_coefficients(&calib_info, chars); + //Set second step calibration context + calc_second_step_coefficients(config, chars); + chars->unit_id = config->unit_id; + chars->atten = config->atten; + + *ret_handle = scheme; + + return ESP_OK; + +err: + if (scheme) { + free(scheme); + } + return ret; +} + +esp_err_t adc_cali_delete_scheme_curve_fitting(adc_cali_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + free(handle->ctx); + handle->ctx = NULL; + + free(handle); + handle = NULL; + + return ESP_OK; +} + + +/* ------------------------ Interface Functions --------------------------- */ +static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage) +{ + //pointers are checked in the upper layer + + cali_chars_curve_fitting_t *ctx = arg; + uint64_t v_cali_1 = raw * ctx->chars_first_step.coeff_a / coeff_a_scaling + ctx->chars_first_step.coeff_b; + int32_t error = get_reading_error(v_cali_1, &(ctx->chars_second_step), ctx->atten); + + *voltage = (int32_t)v_cali_1 - error; + + return ESP_OK; +} + + +/* ----------------------- Characterization Functions ----------------------- */ +//To get the reference point (Dout, Vin) +static void get_first_step_reference_point(int version_num, adc_unit_t unit_id, adc_atten_t atten, adc_calib_info_t *calib_info) +{ + assert(version_num == 1); + esp_err_t ret; + + calib_info->version_num = version_num; + calib_info->unit_id = unit_id; + calib_info->atten = atten; + + uint32_t voltage = 0; + uint32_t digi = 0; + ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, unit_id, atten, &digi, &voltage); + assert(ret == ESP_OK); + calib_info->ref_data.ver1.voltage = voltage; + calib_info->ref_data.ver1.digi = digi; +} + +/* + * Estimate the (assumed) linear relationship btwn the measured raw value and the voltage + * with the previously done measurement when the chip was manufactured. + */ +static void calc_first_step_coefficients(const adc_calib_info_t *parsed_data, cali_chars_curve_fitting_t *ctx) +{ + ctx->chars_first_step.coeff_a = coeff_a_scaling * parsed_data->ref_data.ver1.voltage / parsed_data->ref_data.ver1.digi; + ctx->chars_first_step.coeff_b = 0; + ESP_LOGV(TAG, "Calib V1, Cal Voltage = %d, Digi out = %d, Coef_a = %d\n", parsed_data->ref_data.ver1.voltage, parsed_data->ref_data.ver1.digi, ctx->chars_first_step.coeff_a); +} + +static void calc_second_step_coefficients(const adc_cali_curve_fitting_config_t *config, cali_chars_curve_fitting_t *ctx) +{ + ctx->chars_second_step.term_num = (config->atten == 3) ? 5 : 3; +#if CONFIG_IDF_TARGET_ESP32C3 + //On esp32c3, ADC1 and ADC2 share the second step coefficients + ctx->chars_second_step.coeff = &adc1_error_coef_atten; + ctx->chars_second_step.sign = &adc1_error_sign; +#else + ctx->chars_second_step.coeff = (config->unit_id == ADC_UNIT_1) ? &adc1_error_coef_atten : &adc2_error_coef_atten; + ctx->chars_second_step.sign = (config->unit_id == ADC_UNIT_1) ? &adc1_error_sign : &adc2_error_sign; +#endif +} + +static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param, adc_atten_t atten) +{ + if (v_cali_1 == 0) { + return 0; + } + + uint8_t term_num = param->term_num; + int32_t error = 0; + uint64_t coeff = 0; + uint64_t variable[term_num]; + uint64_t term[term_num]; + memset(variable, 0, term_num * sizeof(uint64_t)); + memset(term, 0, term_num * sizeof(uint64_t)); + + /** + * For atten0 ~ 2: + * error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); + * + * For atten3: + * error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4); + */ + variable[0] = 1; + coeff = (*param->coeff)[atten][0][0]; + term[0] = variable[0] * coeff / (*param->coeff)[atten][0][1]; + error = (int32_t)term[0] * (*param->sign)[atten][0]; + + for (int i = 1; i < term_num; i++) { + variable[i] = variable[i-1] * v_cali_1; + coeff = (*param->coeff)[atten][i][0]; + term[i] = variable[i] * coeff; + ESP_LOGV(TAG, "big coef is %llu, big term%d is %llu, coef_id is %d", coeff, i, term[i], i); + + term[i] = term[i] / (*param->coeff)[atten][i][1]; + error += (int32_t)term[i] * (*param->sign)[atten][i]; + ESP_LOGV(TAG, "term%d is %llu, error is %d", i, term[i], error); + } + + return error; +} + +static esp_err_t check_valid(const adc_cali_curve_fitting_config_t *config) +{ + ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit"); + ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation"); + + bool available_oneshot_bitwidth = (config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH); + bool available_dma_bitwidth = (config->bitwidth >= SOC_ADC_DIGI_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_DIGI_MAX_BITWIDTH); + bool default_bitwidth_mark = (config->bitwidth == ADC_BITWIDTH_DEFAULT); + bool available_bitwidth = (available_oneshot_bitwidth || available_dma_bitwidth || default_bitwidth_mark); + ESP_RETURN_ON_FALSE(available_bitwidth, ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth"); + + return ESP_OK; +} + +#endif //#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED diff --git a/components/esp_adc/adc_common.c b/components/esp_adc/adc_common.c new file mode 100644 index 0000000000..1e449f6653 --- /dev/null +++ b/components/esp_adc/adc_common.c @@ -0,0 +1,208 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "freertos/FreeRTOS.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/adc_private.h" +#include "driver/gpio.h" +#include "hal/adc_hal.h" +#include "hal/adc_hal_common.h" +#include "hal/adc_hal_conf.h" +#include "soc/adc_periph.h" + +//For calibration +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp_efuse_rtc_table.h" +#elif SOC_ADC_CALIBRATION_V1_SUPPORTED +#include "esp_efuse_rtc_calib.h" +#endif + +static const char *TAG = "adc_common"; +static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; +extern portMUX_TYPE rtc_spinlock; + +/*------------------------------------------------------------------------------ +* For those who use APB_SARADC periph +*----------------------------------------------------------------------------*/ +static int s_adc_digi_ctrlr_cnt; + +void adc_apb_periph_claim(void) +{ + portENTER_CRITICAL(&s_spinlock); + s_adc_digi_ctrlr_cnt++; + if (s_adc_digi_ctrlr_cnt == 1) { + //enable ADC digital part + periph_module_enable(PERIPH_SARADC_MODULE); + //reset ADC digital part + periph_module_reset(PERIPH_SARADC_MODULE); + } + + portEXIT_CRITICAL(&s_spinlock); +} + +void adc_apb_periph_free(void) +{ + portENTER_CRITICAL(&s_spinlock); + s_adc_digi_ctrlr_cnt--; + if (s_adc_digi_ctrlr_cnt == 0) { + periph_module_disable(PERIPH_SARADC_MODULE); + } else if (s_adc_digi_ctrlr_cnt < 0) { + portEXIT_CRITICAL(&s_spinlock); + ESP_LOGE(TAG, "%s called, but `s_adc_digi_ctrlr_cnt == 0`", __func__); + abort(); + } + + portEXIT_CRITICAL(&s_spinlock); +} + +/*------------------------------------------------------------------------------ +* ADC Power +*----------------------------------------------------------------------------*/ +// This gets incremented when adc_power_acquire() is called, and decremented when +// adc_power_release() is called. ADC is powered down when the value reaches zero. +// Should be modified within critical section (ADC_ENTER/EXIT_CRITICAL). +static int s_adc_power_on_cnt; + +static void adc_power_on_internal(void) +{ + /* Set the power always on to increase precision. */ + adc_hal_set_power_manage(ADC_POWER_SW_ON); +} + +void adc_power_acquire(void) +{ + portENTER_CRITICAL(&rtc_spinlock); + s_adc_power_on_cnt++; + if (s_adc_power_on_cnt == 1) { + adc_power_on_internal(); + } + portEXIT_CRITICAL(&rtc_spinlock); +} + +static void adc_power_off_internal(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + adc_hal_set_power_manage(ADC_POWER_SW_OFF); +#else + adc_hal_set_power_manage(ADC_POWER_BY_FSM); +#endif +} + +void adc_power_release(void) +{ + portENTER_CRITICAL(&rtc_spinlock); + s_adc_power_on_cnt--; + /* Sanity check */ + if (s_adc_power_on_cnt < 0) { + portEXIT_CRITICAL(&rtc_spinlock); + ESP_LOGE(TAG, "%s called, but s_adc_power_on_cnt == 0", __func__); + abort(); + } else if (s_adc_power_on_cnt == 0) { + adc_power_off_internal(); + } + portEXIT_CRITICAL(&rtc_spinlock); +} + +/*--------------------------------------------------------------- + ADC IOs +---------------------------------------------------------------*/ +esp_err_t adc_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel) +{ + ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(io_num), ESP_ERR_INVALID_ARG, TAG, "invalid gpio number"); + ESP_RETURN_ON_FALSE(unit_id && channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + bool found = false; + for (int i = 0; i < SOC_ADC_PERIPH_NUM; i++) { + for (int j = 0; j < SOC_ADC_MAX_CHANNEL_NUM; j++) { + if (adc_channel_io_map[i][j] == io_num) { + *channel = j; + *unit_id = i; + found = true; + } + } + } + return (found) ? ESP_OK : ESP_ERR_NOT_FOUND; +} + +esp_err_t adc_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num) +{ + ESP_RETURN_ON_FALSE(unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid unit"); + ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel"); + ESP_RETURN_ON_FALSE(io_num, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + *io_num = adc_channel_io_map[unit_id][channel]; + return ESP_OK; +} + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Hardware Calibration +---------------------------------------------------------------*/ +#if CONFIG_IDF_TARGET_ESP32S2 +#define esp_efuse_rtc_calib_get_ver() esp_efuse_rtc_table_read_calib_version() + +static inline uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten) +{ + int tag = esp_efuse_rtc_table_get_tag(version, adc_unit + 1, atten, RTCCALIB_V2_PARAM_VINIT); + return esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); +} +#endif + +static uint32_t s_adc_cali_param[SOC_ADC_PERIPH_NUM][SOC_ADC_ATTEN_NUM] = {}; + +void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) +{ + if (s_adc_cali_param[adc_n][atten]) { + ESP_EARLY_LOGV(TAG, "Use calibrated val ADC%d atten=%d: %04X", adc_n + 1, atten, s_adc_cali_param[adc_n][atten]); + return ; + } + + // check if we can fetch the values from eFuse. + int version = esp_efuse_rtc_calib_get_ver(); + + uint32_t init_code = 0; + + if (version == ESP_EFUSE_ADC_CALIB_VER) { + init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten); + } else { + ESP_EARLY_LOGD(TAG, "Calibration eFuse is not configured, use self-calibration for ICode"); + adc_power_acquire(); + portENTER_CRITICAL(&rtc_spinlock); + adc_ll_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); + const bool internal_gnd = true; + init_code = adc_hal_self_calibration(adc_n, atten, internal_gnd); + portEXIT_CRITICAL(&rtc_spinlock); + adc_power_release(); + } + + s_adc_cali_param[adc_n][atten] = init_code; + ESP_EARLY_LOGV(TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n + 1, atten, init_code); +} + +void IRAM_ATTR adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) +{ + adc_hal_set_calibration_param(adc_n, s_adc_cali_param[adc_n][atten]); +} + +static __attribute__((constructor)) void adc_hw_calibration(void) +{ + //Calculate all ICode + for (int i = 0; i < SOC_ADC_PERIPH_NUM; i++) { + adc_hal_calibration_init(i); + for (int j = 0; j < SOC_ADC_ATTEN_NUM; j++) { + /** + * This may get wrong when attenuations are NOT consecutive on some chips, + * update this when bringing up the calibration on that chip + */ + adc_calc_hw_calibration_code(i, j); + } + } +} +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED diff --git a/components/esp_adc/adc_continuous.c b/components/esp_adc/adc_continuous.c new file mode 100644 index 0000000000..df103a99d1 --- /dev/null +++ b/components/esp_adc/adc_continuous.c @@ -0,0 +1,630 @@ +/* + * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_intr_alloc.h" +#include "esp_log.h" +#include "esp_pm.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" +#include "freertos/ringbuf.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/adc_private.h" +#include "esp_private/adc_lock.h" +#include "driver/gpio.h" +#include "esp_adc/adc_continuous.h" +#include "hal/adc_types.h" +#include "hal/adc_hal.h" +#include "hal/dma_types.h" +//For DMA +#if SOC_GDMA_SUPPORTED +#include "esp_private/gdma.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "hal/spi_types.h" +#include "esp_private/spi_common_internal.h" +#elif CONFIG_IDF_TARGET_ESP32 +#include "hal/i2s_types.h" +#include "driver/i2s_types.h" +#include "soc/i2s_periph.h" +#include "esp_private/i2s_platform.h" +#endif + +static const char *ADC_TAG = "adc_continuous"; + +#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel]) + +extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished. +#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock) +#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock) + +#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; +#endif //CONFIG_PM_ENABLE + +/*--------------------------------------------------------------- + ADC Continuous Read Mode (via DMA) +---------------------------------------------------------------*/ +//Function to address transaction +static bool s_adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx); + +#if SOC_GDMA_SUPPORTED +static bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); +#else +static void adc_dma_intr_handler(void *arg); +#endif + +static int8_t adc_digi_get_io_num(adc_unit_t adc_unit, uint8_t adc_channel) +{ + assert(adc_unit <= SOC_ADC_PERIPH_NUM); + uint8_t adc_n = (adc_unit == ADC_UNIT_1) ? 0 : 1; + return adc_channel_io_map[adc_n][adc_channel]; +} + +static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask) +{ + esp_err_t ret = ESP_OK; + uint64_t gpio_mask = 0; + uint32_t n = 0; + int8_t io = 0; + + while (channel_mask) { + if (channel_mask & 0x1) { + io = adc_digi_get_io_num(adc_unit, n); + if (io < 0) { + return ESP_ERR_INVALID_ARG; + } + gpio_mask |= BIT64(io); + } + channel_mask = channel_mask >> 1; + n++; + } + + gpio_config_t cfg = { + .pin_bit_mask = gpio_mask, + .mode = GPIO_MODE_DISABLE, + }; + ret = gpio_config(&cfg); + + return ret; +} + +esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_config, adc_continuous_handle_t *ret_handle) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE((hdl_config->conv_frame_size % SOC_ADC_DIGI_DATA_BYTES_PER_CONV == 0), ESP_ERR_INVALID_ARG, ADC_TAG, "conv_frame_size should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`"); + + adc_continuous_ctx_t *adc_ctx = heap_caps_calloc(1, sizeof(adc_continuous_ctx_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (adc_ctx == NULL) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + + //ringbuffer storage/struct buffer + adc_ctx->ringbuf_storage = heap_caps_calloc(1, hdl_config->max_store_buf_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + adc_ctx->ringbuf_struct = heap_caps_calloc(1, sizeof(StaticRingbuffer_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (!adc_ctx->ringbuf_storage || !adc_ctx->ringbuf_struct) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + + //ringbuffer + adc_ctx->ringbuf_hdl = xRingbufferCreateStatic(hdl_config->max_store_buf_size, RINGBUF_TYPE_BYTEBUF, adc_ctx->ringbuf_storage, adc_ctx->ringbuf_struct); + if (!adc_ctx->ringbuf_hdl) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + + //malloc internal buffer used by DMA + adc_ctx->rx_dma_buf = heap_caps_calloc(1, hdl_config->conv_frame_size * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + if (!adc_ctx->rx_dma_buf) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + + //malloc dma descriptor + adc_ctx->hal.rx_desc = heap_caps_calloc(1, (sizeof(dma_descriptor_t)) * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + if (!adc_ctx->hal.rx_desc) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + + //malloc pattern table + adc_ctx->hal_digi_ctrlr_cfg.adc_pattern = calloc(1, SOC_ADC_PATT_LEN_MAX * sizeof(adc_digi_pattern_config_t)); + if (!adc_ctx->hal_digi_ctrlr_cfg.adc_pattern) { + ret = ESP_ERR_NO_MEM; + goto cleanup; + } + +#if CONFIG_PM_ENABLE + ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &adc_ctx->pm_lock); + if (ret != ESP_OK) { + goto cleanup; + } +#endif //CONFIG_PM_ENABLE + +#if SOC_GDMA_SUPPORTED + //alloc rx gdma channel + gdma_channel_alloc_config_t rx_alloc_config = { + .direction = GDMA_CHANNEL_DIRECTION_RX, + }; + ret = gdma_new_channel(&rx_alloc_config, &adc_ctx->rx_dma_channel); + if (ret != ESP_OK) { + goto cleanup; + } + gdma_connect(adc_ctx->rx_dma_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_ADC, 0)); + + gdma_strategy_config_t strategy_config = { + .auto_update_desc = true, + .owner_check = true + }; + gdma_apply_strategy(adc_ctx->rx_dma_channel, &strategy_config); + + gdma_rx_event_callbacks_t cbs = { + .on_recv_eof = adc_dma_in_suc_eof_callback + }; + gdma_register_rx_event_callbacks(adc_ctx->rx_dma_channel, &cbs, adc_ctx); + + int dma_chan; + gdma_get_channel_id(adc_ctx->rx_dma_channel, &dma_chan); + +#elif CONFIG_IDF_TARGET_ESP32S2 + //ADC utilises SPI3 DMA on ESP32S2 + bool spi_success = false; + uint32_t dma_chan = 0; + + spi_success = spicommon_periph_claim(SPI3_HOST, "adc"); + ret = spicommon_dma_chan_alloc(SPI3_HOST, SPI_DMA_CH_AUTO, &dma_chan, &dma_chan); + if (ret == ESP_OK) { + adc_ctx->spi_host = SPI3_HOST; + } + if (!spi_success || (adc_ctx->spi_host != SPI3_HOST)) { + goto cleanup; + } + + ret = esp_intr_alloc(spicommon_irqdma_source_for_host(adc_ctx->spi_host), ESP_INTR_FLAG_IRAM, adc_dma_intr_handler, + (void *)adc_ctx, &adc_ctx->dma_intr_hdl); + if (ret != ESP_OK) { + goto cleanup; + } + +#elif CONFIG_IDF_TARGET_ESP32 + //ADC utilises I2S0 DMA on ESP32 + uint32_t dma_chan = 0; + ret = i2s_platform_acquire_occupation(I2S_NUM_0, "adc"); + if (ret != ESP_OK) { + ret = ESP_ERR_NOT_FOUND; + goto cleanup; + } + + adc_ctx->i2s_host = I2S_NUM_0; + ret = esp_intr_alloc(i2s_periph_signal[adc_ctx->i2s_host].irq, ESP_INTR_FLAG_IRAM, adc_dma_intr_handler, + (void *)adc_ctx, &adc_ctx->dma_intr_hdl); + if (ret != ESP_OK) { + goto cleanup; + } +#endif + + adc_hal_dma_config_t config = { +#if SOC_GDMA_SUPPORTED + .dev = (void *)GDMA_LL_GET_HW(0), +#elif CONFIG_IDF_TARGET_ESP32S2 + .dev = (void *)SPI_LL_GET_HW(adc_ctx->spi_host), +#elif CONFIG_IDF_TARGET_ESP32 + .dev = (void *)I2S_LL_GET_HW(adc_ctx->i2s_host), +#endif + .desc_max_num = INTERNAL_BUF_NUM, + .dma_chan = dma_chan, + .eof_num = hdl_config->conv_frame_size / SOC_ADC_DIGI_DATA_BYTES_PER_CONV + }; + adc_hal_dma_ctx_config(&adc_ctx->hal, &config); + + adc_ctx->fsm = ADC_FSM_INIT; + *ret_handle = adc_ctx; + + //enable ADC digital part + periph_module_enable(PERIPH_SARADC_MODULE); + //reset ADC digital part + periph_module_reset(PERIPH_SARADC_MODULE); + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + adc_hal_calibration_init(ADC_UNIT_1); + adc_hal_calibration_init(ADC_UNIT_2); +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED + + return ret; + +cleanup: + adc_continuous_deinit(adc_ctx); + return ret; +} + +#if SOC_GDMA_SUPPORTED +static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +{ + assert(event_data); + adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)user_data; + ctx->rx_eof_desc_addr = event_data->rx_eof_desc_addr; + return s_adc_dma_intr(user_data); +} +#else +static IRAM_ATTR void adc_dma_intr_handler(void *arg) +{ + adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)arg; + bool need_yield = false; + + bool conversion_finish = adc_hal_check_event(&ctx->hal, ADC_HAL_DMA_INTR_MASK); + if (conversion_finish) { + adc_hal_digi_clr_intr(&ctx->hal, ADC_HAL_DMA_INTR_MASK); + + intptr_t desc_addr = adc_hal_get_desc_addr(&ctx->hal); + + ctx->rx_eof_desc_addr = desc_addr; + need_yield = s_adc_dma_intr(ctx); + } + + if (need_yield) { + portYIELD_FROM_ISR(); + } +} +#endif + +static IRAM_ATTR bool s_adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx) +{ + portBASE_TYPE taskAwoken = 0; + bool need_yield = false; + BaseType_t ret; + adc_hal_dma_desc_status_t status = false; + dma_descriptor_t *current_desc = NULL; + + while (1) { + status = adc_hal_get_reading_result(&adc_digi_ctx->hal, adc_digi_ctx->rx_eof_desc_addr, ¤t_desc); + if (status != ADC_HAL_DMA_DESC_VALID) { + break; + } + + ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, current_desc->buffer, current_desc->dw0.length, &taskAwoken); + need_yield |= (taskAwoken == pdTRUE); + + if (adc_digi_ctx->cbs.on_conv_done) { + adc_continuous_evt_data_t edata = { + .conv_frame_buffer = current_desc->buffer, + .size = current_desc->dw0.length, + }; + if (adc_digi_ctx->cbs.on_conv_done(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) { + need_yield |= true; + } + } + + if (ret == pdFALSE) { + //ringbuffer overflow + if (adc_digi_ctx->cbs.on_pool_ovf) { + adc_continuous_evt_data_t edata = {}; + if (adc_digi_ctx->cbs.on_conv_done(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) { + need_yield |= true; + } + } + } + } + + if (status == ADC_HAL_DMA_DESC_NULL) { + //start next turns of dma operation + adc_hal_digi_start(&adc_digi_ctx->hal, adc_digi_ctx->rx_dma_buf); + } + + return need_yield; +} + +esp_err_t adc_continuous_start(adc_continuous_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised"); + ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "ADC continuous mode isn't in the init state, it's started already"); + + if (handle->pm_lock) { + ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(handle->pm_lock), ADC_TAG, "acquire pm_lock failed"); + } + + handle->fsm = ADC_FSM_STARTED; + adc_power_acquire(); + //reset flags + if (handle->use_adc1) { + adc_lock_acquire(ADC_UNIT_1); + } + if (handle->use_adc2) { + adc_lock_acquire(ADC_UNIT_2); + } + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + if (handle->use_adc1) { + adc_set_hw_calibration_code(ADC_UNIT_1, handle->adc1_atten); + } + if (handle->use_adc2) { + adc_set_hw_calibration_code(ADC_UNIT_2, handle->adc2_atten); + } +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED + +#if SOC_ADC_ARBITER_SUPPORTED + if (handle->use_adc2) { + adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); + adc_hal_arbiter_config(&config); + } +#endif //#if SOC_ADC_ARBITER_SUPPORTED + + if (handle->use_adc1) { + adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE); + } + if (handle->use_adc2) { + adc_hal_set_controller(ADC_UNIT_2, ADC_HAL_CONTINUOUS_READ_MODE); + } + + adc_hal_digi_init(&handle->hal); + adc_hal_digi_controller_config(&handle->hal, &handle->hal_digi_ctrlr_cfg); + + //start conversion + adc_hal_digi_start(&handle->hal, handle->rx_dma_buf); + + return ESP_OK; +} + +esp_err_t adc_continuous_stop(adc_continuous_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised"); + ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_STARTED, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver is already stopped"); + + handle->fsm = ADC_FSM_INIT; + //disable the in suc eof intrrupt + adc_hal_digi_dis_intr(&handle->hal, ADC_HAL_DMA_INTR_MASK); + //clear the in suc eof interrupt + adc_hal_digi_clr_intr(&handle->hal, ADC_HAL_DMA_INTR_MASK); + //stop ADC + adc_hal_digi_stop(&handle->hal); + + adc_hal_digi_deinit(&handle->hal); +#if CONFIG_PM_ENABLE + if (handle->pm_lock) { + esp_pm_lock_release(handle->pm_lock); + } +#endif //CONFIG_PM_ENABLE + + if (handle->use_adc2) { + adc_lock_release(ADC_UNIT_2); + } + if (handle->use_adc1) { + adc_lock_release(ADC_UNIT_1); + } + adc_power_release(); + + //release power manager lock + if (handle->pm_lock) { + ESP_RETURN_ON_ERROR(esp_pm_lock_release(handle->pm_lock), ADC_TAG, "release pm_lock failed"); + } + + return ESP_OK; +} + +esp_err_t adc_continuous_read(adc_continuous_handle_t handle, uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised"); + ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_STARTED, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver is already stopped"); + + TickType_t ticks_to_wait; + esp_err_t ret = ESP_OK; + uint8_t *data = NULL; + size_t size = 0; + + ticks_to_wait = timeout_ms / portTICK_PERIOD_MS; + if (timeout_ms == ADC_MAX_DELAY) { + ticks_to_wait = portMAX_DELAY; + } + + data = xRingbufferReceiveUpTo(handle->ringbuf_hdl, &size, ticks_to_wait, length_max); + if (!data) { + ESP_LOGV(ADC_TAG, "No data, increase timeout"); + ret = ESP_ERR_TIMEOUT; + *out_length = 0; + return ret; + } + + memcpy(buf, data, size); + vRingbufferReturnItem(handle->ringbuf_hdl, data); + assert((size % 4) == 0); + *out_length = size; + + return ret; +} + +esp_err_t adc_continuous_deinit(adc_continuous_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised"); + ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver is still running"); + + if (handle->ringbuf_hdl) { + vRingbufferDelete(handle->ringbuf_hdl); + handle->ringbuf_hdl = NULL; + free(handle->ringbuf_storage); + free(handle->ringbuf_struct); + } + +#if CONFIG_PM_ENABLE + if (handle->pm_lock) { + esp_pm_lock_delete(handle->pm_lock); + } +#endif //CONFIG_PM_ENABLE + + free(handle->rx_dma_buf); + free(handle->hal.rx_desc); + free(handle->hal_digi_ctrlr_cfg.adc_pattern); +#if SOC_GDMA_SUPPORTED + gdma_disconnect(handle->rx_dma_channel); + gdma_del_channel(handle->rx_dma_channel); +#elif CONFIG_IDF_TARGET_ESP32S2 + esp_intr_free(handle->dma_intr_hdl); + spicommon_dma_chan_free(handle->spi_host); + spicommon_periph_free(handle->spi_host); +#elif CONFIG_IDF_TARGET_ESP32 + esp_intr_free(handle->dma_intr_hdl); + i2s_platform_release_occupation(handle->i2s_host); +#endif + free(handle); + handle = NULL; + + periph_module_disable(PERIPH_SARADC_MODULE); + + return ESP_OK; +} + +/*--------------------------------------------------------------- + Digital controller setting +---------------------------------------------------------------*/ +esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_continuous_config_t *config) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised"); + ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "ADC continuous mode isn't in the init state, it's started already"); + + //Pattern related check + ESP_RETURN_ON_FALSE(config->pattern_num <= SOC_ADC_PATT_LEN_MAX, ESP_ERR_INVALID_ARG, ADC_TAG, "Max pattern num is %d", SOC_ADC_PATT_LEN_MAX); +#if CONFIG_IDF_TARGET_ESP32 + for (int i = 0; i < config->pattern_num; i++) { + ESP_RETURN_ON_FALSE((config->adc_pattern[i].bit_width >= SOC_ADC_DIGI_MIN_BITWIDTH && config->adc_pattern->bit_width <= SOC_ADC_DIGI_MAX_BITWIDTH), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC bitwidth not supported"); + ESP_RETURN_ON_FALSE(config->adc_pattern[i].unit == 0, ESP_ERR_INVALID_ARG, ADC_TAG, "Only support using ADC1 DMA mode"); + } +#else + for (int i = 0; i < config->pattern_num; i++) { + ESP_RETURN_ON_FALSE((config->adc_pattern[i].bit_width == SOC_ADC_DIGI_MAX_BITWIDTH), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC bitwidth not supported"); + } +#endif + ESP_RETURN_ON_FALSE(config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC sampling frequency out of range"); + +#if CONFIG_IDF_TARGET_ESP32 + ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1"); +#elif CONFIG_IDF_TARGET_ESP32S2 + if (config->conv_mode == ADC_CONV_BOTH_UNIT || config->conv_mode == ADC_CONV_ALTER_UNIT) { + ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2"); + } else if (config->conv_mode == ADC_CONV_SINGLE_UNIT_1 || config->conv_mode == ADC_CONV_SINGLE_UNIT_2) { + ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1"); + } +#else + ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2"); +#endif + + handle->hal_digi_ctrlr_cfg.adc_pattern_len = config->pattern_num; + handle->hal_digi_ctrlr_cfg.sample_freq_hz = config->sample_freq_hz; + handle->hal_digi_ctrlr_cfg.conv_mode = config->conv_mode; + memcpy(handle->hal_digi_ctrlr_cfg.adc_pattern, config->adc_pattern, config->pattern_num * sizeof(adc_digi_pattern_config_t)); + + const int atten_uninitialized = 999; + handle->adc1_atten = atten_uninitialized; + handle->adc2_atten = atten_uninitialized; + handle->use_adc1 = 0; + handle->use_adc2 = 0; + uint32_t adc1_chan_mask = 0; + uint32_t adc2_chan_mask = 0; + for (int i = 0; i < config->pattern_num; i++) { + const adc_digi_pattern_config_t *pat = &config->adc_pattern[i]; + if (pat->unit == ADC_UNIT_1) { + handle->use_adc1 = 1; + adc1_chan_mask |= BIT(pat->channel); + + if (handle->adc1_atten == atten_uninitialized) { + handle->adc1_atten = pat->atten; + } else if (handle->adc1_atten != pat->atten) { + return ESP_ERR_INVALID_ARG; + } + } else if (pat->unit == ADC_UNIT_2) { + handle->use_adc2 = 1; + adc2_chan_mask |= BIT(pat->channel); + + if (handle->adc2_atten == atten_uninitialized) { + handle->adc2_atten = pat->atten; + } else if (handle->adc2_atten != pat->atten) { + return ESP_ERR_INVALID_ARG; + } + } + } + + if (handle->use_adc1) { + adc_digi_gpio_init(ADC_UNIT_1, adc1_chan_mask); + } + if (handle->use_adc2) { + adc_digi_gpio_init(ADC_UNIT_2, adc2_chan_mask); + } + + return ESP_OK; +} + +esp_err_t adc_continuous_register_event_callbacks(adc_continuous_handle_t handle, const adc_continuous_evt_cbs_t *cbs, void *user_data) +{ + ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, ADC_TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "ADC continuous mode isn't in the init state, it's started already"); + +#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE + if (cbs->on_conv_done) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_conv_done), ESP_ERR_INVALID_ARG, ADC_TAG, "on_conv_done callback not in IRAM"); + } + if (cbs->on_pool_ovf) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_pool_ovf), ESP_ERR_INVALID_ARG, ADC_TAG, "on_pool_ovf callback not in IRAM"); + } +#endif + + handle->cbs.on_conv_done = cbs->on_conv_done; + handle->cbs.on_pool_ovf = cbs->on_pool_ovf; + handle->user_data = user_data; + + return ESP_OK; +} + +esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel) +{ + return adc_io_to_channel(io_num, unit_id, channel); +} + +esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num) +{ + return adc_channel_to_io(unit_id, channel, io_num); +} diff --git a/components/esp_adc/adc_lock.c b/components/esp_adc/adc_lock.c new file mode 100644 index 0000000000..a25954a08a --- /dev/null +++ b/components/esp_adc/adc_lock.c @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "sys/lock.h" +#include "esp_log.h" +#include "esp_err.h" +#include "esp_check.h" +#include "hal/adc_types.h" + +#include "esp_private/adc_lock.h" +#include "esp_private/adc2_wifi.h" + + +static const char *TAG = "adc_lock"; + +static _lock_t adc1_lock; +static _lock_t adc2_lock; + +esp_err_t adc_lock_acquire(adc_unit_t unit_mask) +{ + if (unit_mask & ADC_UNIT_1) { + _lock_acquire(&adc1_lock); + } + + if (unit_mask & ADC_UNIT_2) { + _lock_acquire(&adc2_lock); + } + + return ESP_OK; +} + +esp_err_t adc_lock_release(adc_unit_t unit_mask) +{ + if (unit_mask & ADC_UNIT_2) { + ESP_RETURN_ON_FALSE(((uint32_t *)adc2_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc2 lock release without acquiring"); + _lock_release(&adc2_lock); + } + + if (unit_mask & ADC_UNIT_1) { + ESP_RETURN_ON_FALSE(((uint32_t *)adc1_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc1 lock release without acquiring"); + _lock_release(&adc1_lock); + } + + return ESP_OK; +} + +esp_err_t adc_lock_try_acquire(adc_unit_t unit_mask) +{ + if (unit_mask & ADC_UNIT_1) { + if (_lock_try_acquire(&adc1_lock) == -1) { + return ESP_ERR_TIMEOUT; + } + } + + if (unit_mask & ADC_UNIT_2) { + if (_lock_try_acquire(&adc2_lock) == -1) { + return ESP_ERR_TIMEOUT; + } + } + + return ESP_OK; +} + +esp_err_t adc2_wifi_acquire(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + /* Wi-Fi module will use adc2. Use locks to avoid conflicts. */ + adc_lock_acquire(ADC_UNIT_2); + ESP_LOGD(TAG, "Wi-Fi takes adc2 lock."); +#endif + + return ESP_OK; +} + +esp_err_t adc2_wifi_release(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + return adc_lock_release(ADC_UNIT_2); +#endif + + return ESP_OK; +} diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c new file mode 100644 index 0000000000..da90cf486e --- /dev/null +++ b/components/esp_adc/adc_oneshot.c @@ -0,0 +1,260 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "stdatomic.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "driver/gpio.h" +#include "driver/rtc_io.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_private/adc_private.h" +#include "esp_private/adc_lock.h" +#include "hal/adc_types.h" +#include "hal/adc_oneshot_hal.h" +#include "hal/adc_ll.h" +#include "hal/adc_hal_conf.h" +#include "soc/adc_periph.h" + + +#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM +#define ADC_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define ADC_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#endif + + +extern portMUX_TYPE rtc_spinlock; +static const char *TAG = "adc_oneshot"; + + +typedef struct adc_oneshot_unit_ctx_t { + adc_oneshot_hal_ctx_t hal; + uint32_t unit_id; + adc_ulp_mode_t ulp_mode; +} adc_oneshot_unit_ctx_t; + +typedef struct adc_oneshot_ctx_t { + _lock_t mutex; + adc_oneshot_unit_ctx_t *units[SOC_ADC_PERIPH_NUM]; + int apb_periph_ref_cnts; //For the chips that ADC oneshot mode using APB_SARADC periph +} adc_oneshot_ctx_t; + + +static adc_oneshot_ctx_t s_ctx; //ADC oneshot mode context +static atomic_bool s_adc_unit_claimed[SOC_ADC_PERIPH_NUM] = {ATOMIC_VAR_INIT(false), +#if (SOC_ADC_PERIPH_NUM >= 2) +ATOMIC_VAR_INIT(false) +#endif +}; + + +static bool s_adc_unit_claim(adc_unit_t unit); +static bool s_adc_unit_free(adc_unit_t unit); +static esp_err_t s_adc_io_init(adc_unit_t unit, adc_channel_t channel); + + +esp_err_t adc_oneshot_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel) +{ + return adc_io_to_channel(io_num, unit_id, channel); +} + +esp_err_t adc_oneshot_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num) +{ + return adc_channel_to_io(unit_id, channel, io_num); +} + +esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, adc_oneshot_unit_handle_t *ret_unit) +{ + esp_err_t ret = ESP_OK; + adc_oneshot_unit_ctx_t *unit = NULL; + ESP_GOTO_ON_FALSE(init_config && ret_unit, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument: null pointer"); + ESP_GOTO_ON_FALSE(init_config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, err, TAG, "invalid unit"); + + unit = heap_caps_calloc(1, sizeof(adc_oneshot_unit_ctx_t), ADC_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, TAG, "no mem for unit"); + + bool success_claim = s_adc_unit_claim(init_config->unit_id); + ESP_GOTO_ON_FALSE(success_claim, ESP_ERR_NOT_FOUND, err, TAG, "adc%d is already in use", init_config->unit_id + 1); + _lock_acquire(&s_ctx.mutex); + s_ctx.units[init_config->unit_id] = unit; + _lock_release(&s_ctx.mutex); + unit->unit_id = init_config->unit_id; + unit->ulp_mode = init_config->ulp_mode; + + adc_oneshot_hal_cfg_t config = { + .unit = init_config->unit_id, + .work_mode = (init_config->ulp_mode == ADC_ULP_MODE_FSM) ? ADC_HAL_ULP_FSM_MODE : ADC_HAL_SINGLE_READ_MODE, + }; + adc_oneshot_hal_init(&(unit->hal), &config); + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + //To enable the APB_SARADC periph if needed + _lock_acquire(&s_ctx.mutex); + s_ctx.apb_periph_ref_cnts++; + if (s_ctx.apb_periph_ref_cnts == 1) { + adc_apb_periph_claim(); + } + _lock_release(&s_ctx.mutex); +#endif + + adc_power_acquire(); + + ESP_LOGD(TAG, "new adc unit%d is created", unit->unit_id); + *ret_unit = unit; + return ESP_OK; + +err: + if (unit) { + free(unit); + } + return ret; +} + +esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_channel_t channel, const adc_oneshot_chan_cfg_t *config) +{ + ESP_RETURN_ON_FALSE(handle && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid attenuation"); + ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth"); + ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel"); + + s_adc_io_init(handle->unit_id, channel); + + adc_oneshot_hal_ctx_t *hal = &(handle->hal); + adc_oneshot_hal_chan_cfg_t cfg = { + .atten = config->atten, + .bitwidth = (config->bitwidth == ADC_BITWIDTH_DEFAULT) ? SOC_ADC_RTC_MAX_BITWIDTH : config->bitwidth, + }; + portENTER_CRITICAL(&rtc_spinlock); + adc_oneshot_hal_channel_config(hal, &cfg, channel); + if (handle->ulp_mode) { + adc_oneshot_hal_setup(hal, channel); + } + portEXIT_CRITICAL(&rtc_spinlock); + + return ESP_OK; +} + +esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw) +{ + ESP_RETURN_ON_FALSE(handle && out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(chan < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel"); + + if (adc_lock_try_acquire(handle->unit_id) != ESP_OK) { + return ESP_ERR_TIMEOUT; + } + portENTER_CRITICAL(&rtc_spinlock); + + adc_oneshot_hal_setup(&(handle->hal), chan); +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan); + adc_hal_calibration_init(handle->unit_id); + adc_set_hw_calibration_code(handle->unit_id, atten); +#endif + bool valid = false; + valid = adc_oneshot_hal_convert(&(handle->hal), out_raw); + + portEXIT_CRITICAL(&rtc_spinlock); + adc_lock_release(handle->unit_id); + + return valid ? ESP_OK : ESP_ERR_TIMEOUT; +} + +esp_err_t adc_oneshot_read_isr(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw) +{ + ESP_RETURN_ON_FALSE_ISR(handle && out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(chan < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel"); + + portENTER_CRITICAL_SAFE(&rtc_spinlock); + + adc_oneshot_hal_setup(&(handle->hal), chan); +#if SOC_ADC_CALIBRATION_V1_SUPPORTED + adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan); + adc_hal_calibration_init(handle->unit_id); + adc_set_hw_calibration_code(handle->unit_id, atten); +#endif + + adc_oneshot_hal_convert(&(handle->hal), out_raw); + + portEXIT_CRITICAL_SAFE(&rtc_spinlock); + + return ESP_OK; +} + +esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + bool success_free = s_adc_unit_free(handle->unit_id); + ESP_RETURN_ON_FALSE(success_free, ESP_ERR_NOT_FOUND, TAG, "adc%d isn't in use", handle->unit_id + 1); + + _lock_acquire(&s_ctx.mutex); + s_ctx.units[handle->unit_id] = NULL; + _lock_release(&s_ctx.mutex); + + ESP_LOGD(TAG, "adc unit%d is deleted", handle->unit_id); + free(handle); + + adc_power_release(); + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + //To free the APB_SARADC periph if needed + _lock_acquire(&s_ctx.mutex); + s_ctx.apb_periph_ref_cnts--; + assert(s_ctx.apb_periph_ref_cnts >= 0); + if (s_ctx.apb_periph_ref_cnts == 0) { + adc_apb_periph_free(); + } + _lock_release(&s_ctx.mutex); +#endif + + return ESP_OK; +} + + +#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel]) + +static esp_err_t s_adc_io_init(adc_unit_t unit, adc_channel_t channel) +{ + ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(unit), ESP_ERR_INVALID_ARG, TAG, "invalid channel"); + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + + uint32_t io_num = ADC_GET_IO_NUM(unit, channel); + gpio_config_t cfg = { + .pin_bit_mask = BIT64(io_num), + .mode = GPIO_MODE_DISABLE, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + ESP_RETURN_ON_ERROR(gpio_config(&cfg), TAG, "IO config fail"); +#else + gpio_num_t io_num = ADC_GET_IO_NUM(unit, channel); + ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), TAG, "IO config fail"); + ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_DISABLED), TAG, "IO config fail"); + ESP_RETURN_ON_ERROR(rtc_gpio_pulldown_dis(io_num), TAG, "IO config fail"); + ESP_RETURN_ON_ERROR(rtc_gpio_pullup_dis(io_num), TAG, "IO config fail"); +#endif + + return ESP_OK; +} + +static bool s_adc_unit_claim(adc_unit_t unit) +{ + bool false_var = false; + return atomic_compare_exchange_strong(&s_adc_unit_claimed[unit], &false_var, true); +} + +static bool s_adc_unit_free(adc_unit_t unit) +{ + bool true_var = true; + return atomic_compare_exchange_strong(&s_adc_unit_claimed[unit], &true_var, false); +} diff --git a/components/esp_adc/curve_fitting_coefficients.h b/components/esp_adc/curve_fitting_coefficients.h new file mode 100644 index 0000000000..1a77ac6b76 --- /dev/null +++ b/components/esp_adc/curve_fitting_coefficients.h @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include + +#define COEFF_GROUP_NUM 4 +#define TERM_MAX 5 + +/** + * @note Error Calculation + * Coefficients for calculating the reading voltage error. + * Four sets of coefficients for atten0 ~ atten3 respectively. + * + * For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient. + * + * @note {0,0} stands for unused item + * @note In case of the overflow, these coeffcients are recorded as Absolute Value + * @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4); + * @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered. + * @note ADC1 and ADC2 use same coeffients + */ +extern const uint64_t adc1_error_coef_atten[COEFF_GROUP_NUM][TERM_MAX][2]; +extern const uint64_t adc2_error_coef_atten[COEFF_GROUP_NUM][TERM_MAX][2]; + +/** + * Term sign + */ +extern const int32_t adc1_error_sign[COEFF_GROUP_NUM][TERM_MAX]; +extern const int32_t adc2_error_sign[COEFF_GROUP_NUM][TERM_MAX]; diff --git a/components/esp_adc_cal/esp32/esp_adc_cal.c b/components/esp_adc/deprecated/esp32/esp_adc_cal_legacy.c similarity index 99% rename from components/esp_adc_cal/esp32/esp_adc_cal.c rename to components/esp_adc/deprecated/esp32/esp_adc_cal_legacy.c index 2a845a9ef3..58cd8476cb 100644 --- a/components/esp_adc_cal/esp32/esp_adc_cal.c +++ b/components/esp_adc/deprecated/esp32/esp_adc_cal_legacy.c @@ -6,12 +6,13 @@ #include #include "esp_types.h" -#include "driver/adc.h" -#include "hal/efuse_ll.h" #include "esp_err.h" #include "esp_check.h" #include "assert.h" -#include "esp_adc_cal.h" +#include "hal/efuse_ll.h" +#include "hal/adc_types.h" +#include "driver/adc_types_legacy.h" +#include "esp_adc_cal_types_legacy.h" /* ----------------------------- Configuration ------------------------------ */ #ifdef CONFIG_ADC_CAL_EFUSE_TP_ENABLE diff --git a/components/esp_adc_cal/esp32c3/esp_adc_cal.c b/components/esp_adc/deprecated/esp32c3/esp_adc_cal_legacy.c similarity index 92% rename from components/esp_adc_cal/esp32c3/esp_adc_cal.c rename to components/esp_adc/deprecated/esp32c3/esp_adc_cal_legacy.c index bf73affbec..b6374113a6 100644 --- a/components/esp_adc_cal/esp32c3/esp_adc_cal.c +++ b/components/esp_adc/deprecated/esp32c3/esp_adc_cal_legacy.c @@ -11,11 +11,12 @@ #include "esp_err.h" #include "esp_log.h" #include "esp_check.h" -#include "driver/adc.h" -#include "hal/adc_ll.h" #include "esp_efuse_rtc_calib.h" -#include "esp_adc_cal.h" -#include "../esp_adc_cal_internal.h" +#include "hal/adc_ll.h" +#include "hal/adc_types.h" +#include "driver/adc_types_legacy.h" +#include "esp_adc_cal_types_legacy.h" +#include "../esp_adc_cal_internal_legacy.h" const static char LOG_TAG[] = "ADC_CALI"; @@ -79,9 +80,12 @@ static esp_err_t prepare_calib_data_for(int version_num, adc_unit_t adc_num, adc parsed_data_storage->version_num = version_num; parsed_data_storage->adc_num = adc_num; parsed_data_storage->atten_level = atten; - // V1 we don't have calibration data for ADC2, using the efuse data of ADC1 uint32_t voltage, digi; - ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, atten, &digi, &voltage); + /** + * V1 we don't have calibration data for ADC2, using the efuse data of ADC1. + * Here passing the `adc_num` is just for compatibility + */ + ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, adc_num, atten, &digi, &voltage); if (ret != ESP_OK) { return ret; } @@ -129,7 +133,7 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num, ESP_RETURN_ON_FALSE(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid unit num"); ESP_RETURN_ON_FALSE(chars != NULL, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Ivalid characteristic"); ESP_RETURN_ON_FALSE(bit_width == ADC_WIDTH_BIT_12, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid bit_width"); - ESP_RETURN_ON_FALSE(atten < 4, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid attenuation"); + ESP_RETURN_ON_FALSE(atten < SOC_ADC_ATTEN_NUM, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid attenuation"); int version_num = esp_efuse_rtc_calib_get_ver(); ESP_RETURN_ON_FALSE(version_num == 1, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "No calibration efuse burnt"); diff --git a/components/esp_adc_cal/esp32s2/esp_adc_cal.c b/components/esp_adc/deprecated/esp32s2/esp_adc_cal_legacy.c similarity index 98% rename from components/esp_adc_cal/esp32s2/esp_adc_cal.c rename to components/esp_adc/deprecated/esp32s2/esp_adc_cal_legacy.c index 4de5b11eba..eeeb61c7f6 100644 --- a/components/esp_adc_cal/esp32s2/esp_adc_cal.c +++ b/components/esp_adc/deprecated/esp32s2/esp_adc_cal_legacy.c @@ -6,16 +6,17 @@ #include #include "esp_types.h" -#include "driver/adc.h" #include "soc/efuse_periph.h" #include "esp_err.h" #include "esp_check.h" #include "assert.h" -#include "esp_adc_cal.h" #include "esp_efuse.h" #include "esp_efuse_table.h" #include "esp_efuse_rtc_table.h" #include "hal/adc_hal.h" +#include "hal/adc_types.h" +#include "driver/adc_types_legacy.h" +#include "esp_adc_cal_types_legacy.h" const static char LOG_TAG[] = "adc_calib"; diff --git a/components/esp_adc_cal/esp32s3/esp_adc_cal.c b/components/esp_adc/deprecated/esp32s3/esp_adc_cal_legacy.c similarity index 98% rename from components/esp_adc_cal/esp32s3/esp_adc_cal.c rename to components/esp_adc/deprecated/esp32s3/esp_adc_cal_legacy.c index ccd39d683b..b9e11e6c23 100644 --- a/components/esp_adc_cal/esp32s3/esp_adc_cal.c +++ b/components/esp_adc/deprecated/esp32s3/esp_adc_cal_legacy.c @@ -11,11 +11,12 @@ #include "esp_err.h" #include "esp_log.h" #include "esp_check.h" -#include "driver/adc.h" #include "hal/adc_types.h" #include "esp_efuse_rtc_calib.h" -#include "esp_adc_cal.h" -#include "../esp_adc_cal_internal.h" +#include "hal/adc_types.h" +#include "driver/adc_types_legacy.h" +#include "esp_adc_cal_types_legacy.h" +#include "../esp_adc_cal_internal_legacy.h" const static char LOG_TAG[] = "ADC_CALI"; diff --git a/components/esp_adc_cal/esp_adc_cal_common.c b/components/esp_adc/deprecated/esp_adc_cal_common_legacy.c similarity index 89% rename from components/esp_adc_cal/esp_adc_cal_common.c rename to components/esp_adc/deprecated/esp_adc_cal_common_legacy.c index 516797032d..83b889275e 100644 --- a/components/esp_adc_cal/esp_adc_cal_common.c +++ b/components/esp_adc/deprecated/esp_adc_cal_common_legacy.c @@ -6,14 +6,18 @@ #include #include +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 #include "esp_types.h" #include "esp_err.h" #include "esp_log.h" #include "esp_check.h" -#include "driver/adc.h" #include "hal/adc_types.h" +#define CONFIG_ADC_SUPPRESS_DEPRECATE_WARN 1 #include "esp_adc_cal.h" -#include "esp_adc_cal_internal.h" +#include "esp_adc_cal_internal_legacy.h" +#include "driver/adc.h" const __attribute__((unused)) static char *TAG = "ADC_CALI"; @@ -41,6 +45,7 @@ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, return ret; } + #if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED /*------------------------------------------------------------------------------ * Private API @@ -86,3 +91,5 @@ int32_t esp_adc_cal_get_reading_error(const esp_adc_error_calc_param_t *param, u return error; } #endif //#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED + +#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 diff --git a/components/esp_adc_cal/esp_adc_cal_internal.h b/components/esp_adc/deprecated/esp_adc_cal_internal_legacy.h similarity index 100% rename from components/esp_adc_cal/esp_adc_cal_internal.h rename to components/esp_adc/deprecated/esp_adc_cal_internal_legacy.h diff --git a/components/esp_adc_cal/include/esp_adc_cal.h b/components/esp_adc/deprecated/include/esp_adc_cal.h similarity index 71% rename from components/esp_adc_cal/include/esp_adc_cal.h rename to components/esp_adc/deprecated/include/esp_adc_cal.h index b0f7b63541..6ce111496b 100644 --- a/components/esp_adc_cal/include/esp_adc_cal.h +++ b/components/esp_adc/deprecated/include/esp_adc_cal.h @@ -4,46 +4,24 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __ESP_ADC_CAL_H__ -#define __ESP_ADC_CAL_H__ +#pragma once #include +#include "sdkconfig.h" #include "esp_err.h" -#include "driver/adc.h" +#include "hal/adc_types.h" +#include "driver/adc_types_legacy.h" +#include "esp_adc_cal_types_legacy.h" + +#if !CONFIG_ADC_SUPPRESS_DEPRECATE_WARN +#warning "legacy adc calibration driver is deprecated, please migrate to use esp_adc/adc_cali.h and esp_adc/adc_cali_scheme.h" +#endif #ifdef __cplusplus extern "C" { #endif -/** - * @brief Type of calibration value used in characterization - */ -typedef enum { - ESP_ADC_CAL_VAL_EFUSE_VREF = 0, /**< Characterization based on reference voltage stored in eFuse*/ - ESP_ADC_CAL_VAL_EFUSE_TP = 1, /**< Characterization based on Two Point values stored in eFuse*/ - ESP_ADC_CAL_VAL_DEFAULT_VREF = 2, /**< Characterization based on default reference voltage*/ - ESP_ADC_CAL_VAL_EFUSE_TP_FIT = 3, /**< Characterization based on Two Point values and fitting curve coefficients stored in eFuse */ - ESP_ADC_CAL_VAL_MAX, - ESP_ADC_CAL_VAL_NOT_SUPPORTED = ESP_ADC_CAL_VAL_MAX, -} esp_adc_cal_value_t; - -/** - * @brief Structure storing characteristics of an ADC - * - * @note Call esp_adc_cal_characterize() to initialize the structure - */ -typedef struct { - adc_unit_t adc_num; /**< ADC unit*/ - adc_atten_t atten; /**< ADC attenuation*/ - adc_bits_width_t bit_width; /**< ADC bit width */ - uint32_t coeff_a; /**< Gradient of ADC-Voltage curve*/ - uint32_t coeff_b; /**< Offset of ADC-Voltage curve*/ - uint32_t vref; /**< Vref used by lookup table*/ - const uint32_t *low_curve; /**< Pointer to low Vref curve of lookup table (NULL if unused)*/ - const uint32_t *high_curve; /**< Pointer to high Vref curve of lookup table (NULL if unused)*/ - uint8_t version; /**< ADC Calibration */ -} esp_adc_cal_characteristics_t; - +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 /** * @brief Checks if ADC calibration values are burned into eFuse * @@ -128,8 +106,8 @@ uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_char */ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, const esp_adc_cal_characteristics_t *chars, uint32_t *voltage); +#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + #ifdef __cplusplus } #endif - -#endif /* __ESP_ADC_CAL_H__ */ diff --git a/components/esp_adc/deprecated/include/esp_adc_cal_types_legacy.h b/components/esp_adc/deprecated/include/esp_adc_cal_types_legacy.h new file mode 100644 index 0000000000..7c366afabe --- /dev/null +++ b/components/esp_adc/deprecated/include/esp_adc_cal_types_legacy.h @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" +#include "driver/adc_types_legacy.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 +/** + * @brief Type of calibration value used in characterization + */ +typedef enum { + ESP_ADC_CAL_VAL_EFUSE_VREF = 0, /**< Characterization based on reference voltage stored in eFuse*/ + ESP_ADC_CAL_VAL_EFUSE_TP = 1, /**< Characterization based on Two Point values stored in eFuse*/ + ESP_ADC_CAL_VAL_DEFAULT_VREF = 2, /**< Characterization based on default reference voltage*/ + ESP_ADC_CAL_VAL_EFUSE_TP_FIT = 3, /**< Characterization based on Two Point values and fitting curve coefficients stored in eFuse */ + ESP_ADC_CAL_VAL_MAX, + ESP_ADC_CAL_VAL_NOT_SUPPORTED = ESP_ADC_CAL_VAL_MAX, +} esp_adc_cal_value_t; + +/** + * @brief Structure storing characteristics of an ADC + * + * @note Call esp_adc_cal_characterize() to initialize the structure + */ +typedef struct { + adc_unit_t adc_num; /**< ADC unit*/ + adc_atten_t atten; /**< ADC attenuation*/ + adc_bits_width_t bit_width; /**< ADC bit width */ + uint32_t coeff_a; /**< Gradient of ADC-Voltage curve*/ + uint32_t coeff_b; /**< Offset of ADC-Voltage curve*/ + uint32_t vref; /**< Vref used by lookup table*/ + const uint32_t *low_curve; /**< Pointer to low Vref curve of lookup table (NULL if unused)*/ + const uint32_t *high_curve; /**< Pointer to high Vref curve of lookup table (NULL if unused)*/ + uint8_t version; /**< ADC Calibration */ +} esp_adc_cal_characteristics_t; +#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/esp32/adc_cali_line_fitting.c b/components/esp_adc/esp32/adc_cali_line_fitting.c new file mode 100644 index 0000000000..0421b27fd4 --- /dev/null +++ b/components/esp_adc/esp32/adc_cali_line_fitting.c @@ -0,0 +1,435 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "assert.h" +#include "esp_types.h" +#include "esp_err.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "hal/adc_types.h" +#include "hal/efuse_ll.h" +#include "soc/soc_caps.h" +#include "esp_adc/adc_cali_scheme.h" +#include "adc_cali_interface.h" + +/* ----------------------------- Configuration ------------------------------ */ +#ifdef CONFIG_ADC_CALI_EFUSE_TP_ENABLE +#define EFUSE_TP_ENABLED 1 +#else +#define EFUSE_TP_ENABLED 0 +#endif + +#ifdef CONFIG_ADC_CALI_EFUSE_VREF_ENABLE +#define EFUSE_VREF_ENABLED 1 +#else +#define EFUSE_VREF_ENABLED 0 +#endif + +#ifdef CONFIG_ADC_CALI_LUT_ENABLE +#define LUT_ENABLED 1 +#else +#define LUT_ENABLED 0 +#endif + +/* ESP32s with both Two Point Values and Vref burned into eFuse are required to + * also burn the EFUSE_BLK3_PART_RESERVE flag. A limited set of ESP32s + * (not available through regular sales channel) DO NOT have the + * EFUSE_BLK3_PART_RESERVE burned. Moreover, this set of ESP32s represents Vref + * in Two's Complement format. If this is the case, modify the preprocessor + * definitions below as follows... + * #define CHECK_BLK3_FLAG 0 //Do not check BLK3 flag as it is not burned + * #define VREF_FORMAT 1 //eFuse Vref is in Two's Complement format + */ +#define CHECK_BLK3_FLAG 1 +#define VREF_FORMAT 0 + +/* ------------------------------ eFuse Access ----------------------------- */ +#define VREF_MASK 0x1F +#define VREF_STEP_SIZE 7 +#define VREF_OFFSET 1100 + +#define TP_LOW1_OFFSET 278 +#define TP_LOW2_OFFSET 421 +#define TP_LOW_MASK 0x7F +#define TP_LOW_VOLTAGE 150 +#define TP_HIGH1_OFFSET 3265 +#define TP_HIGH2_OFFSET 3406 +#define TP_HIGH_MASK 0x1FF +#define TP_HIGH_VOLTAGE 850 +#define TP_STEP_SIZE 4 + +/* ----------------------- Raw to Voltage Constants ------------------------- */ +#define LIN_COEFF_A_SCALE 65536 +#define LIN_COEFF_A_ROUND (LIN_COEFF_A_SCALE/2) + +#define LUT_VREF_LOW 1000 +#define LUT_VREF_HIGH 1200 +#define LUT_ADC_STEP_SIZE 64 +#define LUT_POINTS 20 +#define LUT_LOW_THRESH 2880 +#define LUT_HIGH_THRESH (LUT_LOW_THRESH + LUT_ADC_STEP_SIZE) +#define ADC_12_BIT_RES 4096 + +/* ------------------------ Characterization Constants ---------------------- */ +static const uint32_t adc1_tp_atten_scale[4] = {65504, 86975, 120389, 224310}; +static const uint32_t adc2_tp_atten_scale[4] = {65467, 86861, 120416, 224708}; +static const uint32_t adc1_tp_atten_offset[4] = {0, 1, 27, 54}; +static const uint32_t adc2_tp_atten_offset[4] = {0, 9, 26, 66}; + +static const uint32_t adc1_vref_atten_scale[4] = {57431, 76236, 105481, 196602}; +static const uint32_t adc2_vref_atten_scale[4] = {57236, 76175, 105678, 197170}; +static const uint32_t adc1_vref_atten_offset[4] = {75, 78, 107, 142}; +static const uint32_t adc2_vref_atten_offset[4] = {63, 66, 89, 128}; + +//20 Point lookup tables, covering ADC readings from 2880 to 4096, step size of 64 +static const uint32_t lut_adc1_low[LUT_POINTS] = {2240, 2297, 2352, 2405, 2457, 2512, 2564, 2616, 2664, 2709, + 2754, 2795, 2832, 2868, 2903, 2937, 2969, 3000, 3030, 3060}; +static const uint32_t lut_adc1_high[LUT_POINTS] = {2667, 2706, 2745, 2780, 2813, 2844, 2873, 2901, 2928, 2956, + 2982, 3006, 3032, 3059, 3084, 3110, 3135, 3160, 3184, 3209}; +static const uint32_t lut_adc2_low[LUT_POINTS] = {2238, 2293, 2347, 2399, 2451, 2507, 2561, 2613, 2662, 2710, + 2754, 2792, 2831, 2869, 2904, 2937, 2968, 2999, 3029, 3059}; +static const uint32_t lut_adc2_high[LUT_POINTS] = {2657, 2698, 2738, 2774, 2807, 2838, 2867, 2894, 2921, 2946, + 2971, 2996, 3020, 3043, 3067, 3092, 3116, 3139, 3162, 3185}; + +const __attribute__((unused)) static char *TAG = "adc_cali"; + + +/* ----------------------- EFuse Access Functions --------------------------- */ +static bool check_efuse_vref(void); +static bool check_efuse_tp(void); +static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl); +static uint32_t read_efuse_vref(void); +static uint32_t read_efuse_tp_low(adc_unit_t unit_id); +static uint32_t read_efuse_tp_high(adc_unit_t unit_id); + + +/* ----------------------- Characterization Functions ----------------------- */ +static void characterize_using_two_point(adc_unit_t unit_id, + adc_atten_t atten, + uint32_t high, + uint32_t low, + uint32_t *coeff_a, + uint32_t *coeff_b); +static void characterize_using_vref(adc_unit_t unit_id, + adc_atten_t atten, + uint32_t vref, + uint32_t *coeff_a, + uint32_t *coeff_b); + + +/* ------------------------ Conversion Functions --------------------------- */ +static uint32_t calculate_voltage_linear(uint32_t adc_reading, uint32_t coeff_a, uint32_t coeff_b); +//Only call when ADC reading is above threshold +static uint32_t calculate_voltage_lut(uint32_t adc, uint32_t vref, const uint32_t *low_vref_curve, const uint32_t *high_vref_curve); + +static inline uint32_t interpolate_two_points(uint32_t y1, uint32_t y2, uint32_t x_step, uint32_t x) +{ + //Interpolate between two points (x1,y1) (x2,y2) between 'lower' and 'upper' separated by 'step' + return ((y1 * x_step) + (y2 * x) - (y1 * x) + (x_step / 2)) / x_step; +} + + +/* ------------------------ Interface Functions --------------------------- */ +static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage); + + +/* ------------------------ Context Structure--------------------------- */ +typedef struct { + adc_unit_t unit_id; ///< ADC unit + adc_atten_t atten; ///< ADC attenuation + adc_bitwidth_t bitwidth; ///< ADC bit width + uint32_t coeff_a; ///< Gradient of ADC-Voltage curve + uint32_t coeff_b; ///< Offset of ADC-Voltage curve + uint32_t vref; ///< Vref used by lookup table + const uint32_t *low_curve; ///< Pointer to low Vref curve of lookup table (NULL if unused) + const uint32_t *high_curve; ///< Pointer to high Vref curve of lookup table (NULL if unused) + adc_cali_line_fitting_efuse_val_t efuse_val; ///< Type of calibration value used in characterization +} cali_chars_line_fitting_t; + + +/* ------------------------- Public API ------------------------------------- */ +esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(config && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit"); + ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation"); + ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth"); + + adc_cali_scheme_t *scheme = (adc_cali_scheme_t *)heap_caps_calloc(1, sizeof(adc_cali_scheme_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for adc calibration scheme"); + + cali_chars_line_fitting_t *chars = (cali_chars_line_fitting_t *)heap_caps_calloc(1, sizeof(cali_chars_line_fitting_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(chars, ESP_ERR_NO_MEM, err, TAG, "no memory for the calibration characteristics"); + + //Check eFuse if enabled to do so + if (check_efuse_tp() && EFUSE_TP_ENABLED) { + //Characterize based on Two Point values + chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP; + //Characterize based on Two Point values + uint32_t high = read_efuse_tp_high(config->unit_id); + uint32_t low = read_efuse_tp_low(config->unit_id); + characterize_using_two_point(config->unit_id, config->atten, high, low, &chars->coeff_a, &chars->coeff_b); + } else if (check_efuse_vref() && EFUSE_VREF_ENABLED) { + //Characterize based on eFuse Vref + chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF; + chars->vref = read_efuse_vref(); + characterize_using_vref(config->unit_id, config->atten, chars->vref, &chars->coeff_a, &chars->coeff_b); + } else { + //Characterized based on default Vref + chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF; + ESP_GOTO_ON_FALSE(config->default_vref, ESP_ERR_INVALID_ARG, err, TAG, "default vref didn't set"); + chars->vref = config->default_vref; + characterize_using_vref(config->unit_id, config->atten, chars->vref, &chars->coeff_a, &chars->coeff_b); + } + + chars->unit_id = config->unit_id; + chars->atten = config->atten; + chars->bitwidth = (config->bitwidth == ADC_BITWIDTH_DEFAULT) ? ADC_BITWIDTH_12 : config->bitwidth; + //Initialize fields for lookup table if necessary + if (LUT_ENABLED && config->atten == ADC_ATTEN_DB_11) { + chars->low_curve = (config->unit_id == ADC_UNIT_1) ? lut_adc1_low : lut_adc2_low; + chars->high_curve = (config->unit_id == ADC_UNIT_1) ? lut_adc1_high : lut_adc2_high; + } else { + chars->low_curve = NULL; + chars->high_curve = NULL; + } + scheme->raw_to_voltage = cali_raw_to_voltage; + scheme->ctx = chars; + *ret_handle = scheme; + + return ESP_OK; + +err: + if (scheme) { + free(scheme); + } + return ret; +} + +esp_err_t adc_cali_scheme_line_fitting_check_efuse(adc_cali_line_fitting_efuse_val_t *cali_val) +{ + ESP_RETURN_ON_FALSE(cali_val, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + if (check_efuse_tp()) { + *cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP; + } else if (check_efuse_vref()) { + *cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF; + } else { + *cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF; + } + + return ESP_OK; +} + +esp_err_t adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + free(handle->ctx); + handle->ctx = NULL; + + free(handle); + handle = NULL; + + return ESP_OK; +} + +/* ------------------------ Interface Functions --------------------------- */ +static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage) +{ + //pointers are checked in the upper layer + + cali_chars_line_fitting_t *ctx = arg; + + //Scale adc_rading if not 12 bits wide + raw = (raw << (ADC_BITWIDTH_12 - ctx->bitwidth)); + if (raw > ADC_12_BIT_RES - 1) { + raw = ADC_12_BIT_RES - 1; //Set to 12bit res max + } + + if (LUT_ENABLED && (ctx->atten == ADC_ATTEN_DB_11) && (raw >= LUT_LOW_THRESH)) { //Check if in non-linear region + //Use lookup table to get voltage in non linear portion of ADC_ATTEN_DB_11 + uint32_t lut_voltage = calculate_voltage_lut(raw, ctx->vref, ctx->low_curve, ctx->high_curve); + if (raw <= LUT_HIGH_THRESH) { //If ADC is transitioning from linear region to non-linear region + //Linearly interpolate between linear voltage and lut voltage + uint32_t linear_voltage = calculate_voltage_linear(raw, ctx->coeff_a, ctx->coeff_b); + *voltage = interpolate_two_points(linear_voltage, lut_voltage, LUT_ADC_STEP_SIZE, (raw - LUT_LOW_THRESH)); + } else { + *voltage = lut_voltage; + } + } else { + *voltage = calculate_voltage_linear(raw, ctx->coeff_a, ctx->coeff_b); + } + + return ESP_OK; +} + +/* ----------------------- EFuse Access Functions --------------------------- */ +static bool check_efuse_vref(void) +{ + //Check if Vref is burned in eFuse + return (efuse_ll_get_adc_vref() != 0) ? true : false; +} + +static bool check_efuse_tp(void) +{ + //Check if Two Point values are burned in eFuse + if (CHECK_BLK3_FLAG && (efuse_ll_get_blk3_part_reserve() == 0)) { + return false; + } + //All TP cal values must be non zero + return efuse_ll_get_adc1_tp_low() && + efuse_ll_get_adc2_tp_low() && + efuse_ll_get_adc1_tp_high() && + efuse_ll_get_adc2_tp_high(); +} + +static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl) +{ + int ret; + if (bits & (~(mask >> 1) & mask)) { //Check sign bit (MSB of mask) + //Negative + if (is_twos_compl) { + ret = -(((~bits) + 1) & (mask >> 1)); //2's complement + } else { + ret = -(bits & (mask >> 1)); //Sign-magnitude + } + } else { + //Positive + ret = bits & (mask >> 1); + } + return ret; +} + +static uint32_t read_efuse_vref(void) +{ + //eFuse stores deviation from ideal reference voltage + uint32_t ret = VREF_OFFSET; //Ideal vref + uint32_t bits = efuse_ll_get_adc_vref(); + ret += decode_bits(bits, VREF_MASK, VREF_FORMAT) * VREF_STEP_SIZE; + return ret; //ADC Vref in mV +} + +static uint32_t read_efuse_tp_low(adc_unit_t unit_id) +{ + //ADC reading at 150mV stored in two's complement format + uint32_t ret; + uint32_t bits; + + if (unit_id == ADC_UNIT_1) { + ret = TP_LOW1_OFFSET; + bits = efuse_ll_get_adc1_tp_low(); + } else { + ret = TP_LOW2_OFFSET; + bits = efuse_ll_get_adc2_tp_low(); + } + ret += decode_bits(bits, TP_LOW_MASK, true) * TP_STEP_SIZE; + return ret; //Reading of ADC at 150mV +} + +static uint32_t read_efuse_tp_high(adc_unit_t unit_id) +{ + //ADC reading at 850mV stored in two's complement format + uint32_t ret; + uint32_t bits; + + if (unit_id == ADC_UNIT_1) { + ret = TP_HIGH1_OFFSET; + bits = efuse_ll_get_adc1_tp_high(); + } else { + ret = TP_HIGH2_OFFSET; + bits = efuse_ll_get_adc2_tp_high(); + } + ret += decode_bits(bits, TP_HIGH_MASK, true) * TP_STEP_SIZE; + return ret; //Reading of ADC at 850mV +} + + +/* ----------------------- Characterization Functions ----------------------- */ +static void characterize_using_two_point(adc_unit_t unit_id, + adc_atten_t atten, + uint32_t high, + uint32_t low, + uint32_t *coeff_a, + uint32_t *coeff_b) +{ + const uint32_t *atten_scales; + const uint32_t *atten_offsets; + + if (unit_id == ADC_UNIT_1) { //Using ADC 1 + atten_scales = adc1_tp_atten_scale; + atten_offsets = adc1_tp_atten_offset; + } else { //Using ADC 2 + atten_scales = adc2_tp_atten_scale; + atten_offsets = adc2_tp_atten_offset; + } + //Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b + uint32_t delta_x = high - low; + uint32_t delta_v = TP_HIGH_VOLTAGE - TP_LOW_VOLTAGE; + //Where coeff_a = (delta_v/delta_x) * atten_scale + *coeff_a = (delta_v * atten_scales[atten] + (delta_x / 2)) / delta_x; //+(delta_x/2) for rounding + //Where coeff_b = high_v - ((delta_v/delta_x) * high_x) + atten_offset + *coeff_b = TP_HIGH_VOLTAGE - ((delta_v * high + (delta_x / 2)) / delta_x) + atten_offsets[atten]; +} + +static void characterize_using_vref(adc_unit_t unit_id, + adc_atten_t atten, + uint32_t vref, + uint32_t *coeff_a, + uint32_t *coeff_b) +{ + const uint32_t *atten_scales; + const uint32_t *atten_offsets; + + if (unit_id == ADC_UNIT_1) { //Using ADC 1 + atten_scales = adc1_vref_atten_scale; + atten_offsets = adc1_vref_atten_offset; + } else { //Using ADC 2 + atten_scales = adc2_vref_atten_scale; + atten_offsets = adc2_vref_atten_offset; + } + //Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b + //Where coeff_a = (vref/4096) * atten_scale + *coeff_a = (vref * atten_scales[atten]) / (ADC_12_BIT_RES); + *coeff_b = atten_offsets[atten]; +} + + +/* ------------------------ Conversion Functions --------------------------- */ +static uint32_t calculate_voltage_linear(uint32_t adc_reading, uint32_t coeff_a, uint32_t coeff_b) +{ + //Where voltage = coeff_a * adc_reading + coeff_b + return (((coeff_a * adc_reading) + LIN_COEFF_A_ROUND) / LIN_COEFF_A_SCALE) + coeff_b; +} + +//Only call when ADC reading is above threshold +static uint32_t calculate_voltage_lut(uint32_t adc, uint32_t vref, const uint32_t *low_vref_curve, const uint32_t *high_vref_curve) +{ + //Get index of lower bound points of LUT + uint32_t i = (adc - LUT_LOW_THRESH) / LUT_ADC_STEP_SIZE; + + //Let the X Axis be Vref, Y axis be ADC reading, and Z be voltage + int x2dist = LUT_VREF_HIGH - vref; //(x2 - x) + int x1dist = vref - LUT_VREF_LOW; //(x - x1) + int y2dist = ((i + 1) * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH - adc; //(y2 - y) + int y1dist = adc - ((i * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH); //(y - y1) + + //For points for bilinear interpolation + int q11 = low_vref_curve[i]; //Lower bound point of low_vref_curve + int q12 = low_vref_curve[i + 1]; //Upper bound point of low_vref_curve + int q21 = high_vref_curve[i]; //Lower bound point of high_vref_curve + int q22 = high_vref_curve[i + 1]; //Upper bound point of high_vref_curve + + //Bilinear interpolation + //Where z = 1/((x2-x1)*(y2-y1)) * ( (q11*x2dist*y2dist) + (q21*x1dist*y2dist) + (q12*x2dist*y1dist) + (q22*x1dist*y1dist) ) + int voltage = (q11 * x2dist * y2dist) + (q21 * x1dist * y2dist) + (q12 * x2dist * y1dist) + (q22 * x1dist * y1dist); + voltage += ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE) / 2; //Integer division rounding + voltage /= ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE); //Divide by ((x2-x1)*(y2-y1)) + return (uint32_t)voltage; +} diff --git a/components/esp_adc/esp32/include/adc_cali_schemes.h b/components/esp_adc/esp32/include/adc_cali_schemes.h new file mode 100644 index 0000000000..dc6fa544ef --- /dev/null +++ b/components/esp_adc/esp32/include/adc_cali_schemes.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file adc_cali_schemes.h + * + * @brief Supported calibration schemes + */ + +#define ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED 1 diff --git a/components/esp_adc/esp32c2/include/adc_cali_schemes.h b/components/esp_adc/esp32c2/include/adc_cali_schemes.h new file mode 100644 index 0000000000..a691b4d4d1 --- /dev/null +++ b/components/esp_adc/esp32c2/include/adc_cali_schemes.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file adc_cali_schemes.h + * + * @brief Supported calibration schemes + */ + +//No scheme supported diff --git a/components/driver/esp32c3/adc2_init_cal.c b/components/esp_adc/esp32c3/adc2_init_cal.c similarity index 69% rename from components/driver/esp32c3/adc2_init_cal.c rename to components/esp_adc/esp32c3/adc2_init_cal.c index f774d7b8bc..8bf714b328 100644 --- a/components/driver/esp32c3/adc2_init_cal.c +++ b/components/esp_adc/esp32c3/adc2_init_cal.c @@ -8,9 +8,13 @@ The linker will link constructor (adc2_init_code_calibration) only when any sections inside the same file (adc2_cal_include) is used. Don't put any other code into this file. */ -#include "hal/adc_hal.h" +#include "freertos/FreeRTOS.h" +#include "hal/adc_types.h" +#include "hal/adc_hal_common.h" #include "esp_private/adc2_wifi.h" -#include "esp_private/adc_cali.h" +#include "esp_private/adc_private.h" + +extern portMUX_TYPE rtc_spinlock; /** * @brief Set initial code to ADC2 after calibration. ADC2 RTC and ADC2 PWDET controller share the initial code. @@ -18,9 +22,11 @@ Don't put any other code into this file. */ */ static __attribute__((constructor)) void adc2_init_code_calibration(void) { - const adc_unit_t adc_n = ADC_UNIT_2; - const adc_atten_t atten = ADC_ATTEN_DB_11; - adc_cal_offset(adc_n, atten); + adc_hal_calibration_init(ADC_UNIT_2); + adc_calc_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11); + portENTER_CRITICAL(&rtc_spinlock); + adc_set_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11); + portEXIT_CRITICAL(&rtc_spinlock); } /** Don't call `adc2_cal_include` in user code. */ diff --git a/components/esp_adc/esp32c3/curve_fitting_coefficients.c b/components/esp_adc/esp32c3/curve_fitting_coefficients.c new file mode 100644 index 0000000000..c8f8d5776e --- /dev/null +++ b/components/esp_adc/esp32c3/curve_fitting_coefficients.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/** + * @note Error Calculation + * Coefficients for calculating the reading voltage error. + * Four sets of coefficients for atten0 ~ atten3 respectively. + * + * For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient. + * + * @note {0,0} stands for unused item + * @note In case of the overflow, these coeffcients are recorded as Absolute Value + * @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4); + * @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered. + * @note ADC1 and ADC2 use same coeffients + */ +const uint64_t adc1_error_coef_atten[4][5][2] = { + {{225966470500043, 1e15}, {7265418501948, 1e16}, {109410402681, 1e16}, {0, 0}, {0, 0}}, //atten0 + {{4229623392600516, 1e16}, {731527490903, 1e16}, {88166562521, 1e16}, {0, 0}, {0, 0}}, //atten1 + {{1017859239236435, 1e15}, {97159265299153, 1e16}, {149794028038, 1e16}, {0, 0}, {0, 0}}, //atten2 + {{14912262772850453, 1e16}, {228549975564099, 1e16}, {356391935717, 1e16}, {179964582, 1e16}, {42046, 1e16}} //atten3 + }; +/** + * Term sign + */ +const int32_t adc1_error_sign[4][5] = { + {-1, -1, 1, 0, 0}, //atten0 + { 1, -1, 1, 0, 0}, //atten1 + {-1, -1, 1, 0, 0}, //atten2 + {-1, -1, 1, -1, 1} //atten3 + }; diff --git a/components/esp_adc/esp32c3/include/adc_cali_schemes.h b/components/esp_adc/esp32c3/include/adc_cali_schemes.h new file mode 100644 index 0000000000..2eb6842031 --- /dev/null +++ b/components/esp_adc/esp32c3/include/adc_cali_schemes.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file adc_cali_schemes.h + * + * @brief Supported calibration schemes + */ + +#define ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED 1 diff --git a/components/esp_adc/esp32h2/include/adc_cali_schemes.h b/components/esp_adc/esp32h2/include/adc_cali_schemes.h new file mode 100644 index 0000000000..2505fb46f6 --- /dev/null +++ b/components/esp_adc/esp32h2/include/adc_cali_schemes.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file adc_cali_schemes.h + * + * @brief Supported calibration schemes + */ + +//Now no scheme supported diff --git a/components/driver/esp32s2/adc2_init_cal.c b/components/esp_adc/esp32s2/adc2_init_cal.c similarity index 69% rename from components/driver/esp32s2/adc2_init_cal.c rename to components/esp_adc/esp32s2/adc2_init_cal.c index f774d7b8bc..8bf714b328 100644 --- a/components/driver/esp32s2/adc2_init_cal.c +++ b/components/esp_adc/esp32s2/adc2_init_cal.c @@ -8,9 +8,13 @@ The linker will link constructor (adc2_init_code_calibration) only when any sections inside the same file (adc2_cal_include) is used. Don't put any other code into this file. */ -#include "hal/adc_hal.h" +#include "freertos/FreeRTOS.h" +#include "hal/adc_types.h" +#include "hal/adc_hal_common.h" #include "esp_private/adc2_wifi.h" -#include "esp_private/adc_cali.h" +#include "esp_private/adc_private.h" + +extern portMUX_TYPE rtc_spinlock; /** * @brief Set initial code to ADC2 after calibration. ADC2 RTC and ADC2 PWDET controller share the initial code. @@ -18,9 +22,11 @@ Don't put any other code into this file. */ */ static __attribute__((constructor)) void adc2_init_code_calibration(void) { - const adc_unit_t adc_n = ADC_UNIT_2; - const adc_atten_t atten = ADC_ATTEN_DB_11; - adc_cal_offset(adc_n, atten); + adc_hal_calibration_init(ADC_UNIT_2); + adc_calc_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11); + portENTER_CRITICAL(&rtc_spinlock); + adc_set_hw_calibration_code(ADC_UNIT_2, ADC_ATTEN_DB_11); + portEXIT_CRITICAL(&rtc_spinlock); } /** Don't call `adc2_cal_include` in user code. */ diff --git a/components/esp_adc/esp32s2/adc_cali_line_fitting.c b/components/esp_adc/esp32s2/adc_cali_line_fitting.c new file mode 100644 index 0000000000..93f509020a --- /dev/null +++ b/components/esp_adc/esp32s2/adc_cali_line_fitting.c @@ -0,0 +1,255 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "assert.h" +#include "esp_types.h" +#include "esp_err.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "esp_efuse_rtc_table.h" +#include "hal/adc_types.h" +#include "soc/efuse_periph.h" +#include "soc/soc_caps.h" +#include "esp_adc/adc_cali_scheme.h" +#include "adc_cali_interface.h" + +const __attribute__((unused)) static char *TAG = "adc_cali"; + +/* ------------------------ Characterization Constants ---------------------- */ +// coeff_a and coeff_b are actually floats +// they are scaled to put them into uint32_t so that the headers do not have to be changed +static const int coeff_a_scaling = 65536; +static const int coeff_b_scaling = 1024; + + +/* -------------------- Characterization Helper Data Types ------------------ */ +typedef struct { + int adc_calib_high; + int adc_calib_low; +} adc_calib_data_ver1_t; + +typedef struct { + int adc_calib_high; // the reading of adc ... + int adc_calib_high_voltage; // ... at this voltage (mV) +} adc_calib_data_ver2_t; + +typedef struct { + char version_num; + adc_unit_t unit_id; + adc_atten_t atten_level; + union { + adc_calib_data_ver1_t ver1; + adc_calib_data_ver2_t ver2; + } efuse_data; +} adc_calib_parsed_info_t; + + +/* ------------------------ Context Structure--------------------------- */ +typedef struct { + adc_unit_t unit_id; ///< ADC unit + adc_atten_t atten; ///< ADC attenuation + uint32_t coeff_a; ///< Gradient of ADC-Voltage curve + uint32_t coeff_b; ///< Offset of ADC-Voltage curve +} cali_chars_line_fitting_t; + + +/* ----------------------- Characterization Functions ----------------------- */ +static bool prepare_calib_data_for(adc_unit_t unit_id, adc_atten_t atten, adc_calib_parsed_info_t *parsed_data_storage); +/** + * (Used in V1 of calibration scheme) + * The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation + * between input voltage and ADC response. (Response = A * Vinput + B) + * A and B are scaled ints. + * @param high The ADC response at the higher voltage of the corresponding attenuation (600mV, 800mV, 1000mV, 2000mV). + * @param low The ADC response at the lower voltage of the corresponding attenuation (all 250mV). + * + */ +static void characterize_using_two_point(adc_unit_t unit_id, + adc_atten_t atten, + uint32_t high, + uint32_t low, + uint32_t *coeff_a, + uint32_t *coeff_b); +/* + * Estimate the (assumed) linear relationship btwn the measured raw value and the voltage + * with the previously done measurement when the chip was manufactured. + * */ +static bool calculate_characterization_coefficients(const adc_calib_parsed_info_t *parsed_data, cali_chars_line_fitting_t *ctx); + + +/* ------------------------ Interface Functions --------------------------- */ +static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage); + + +/* ------------------------- Public API ------------------------------------- */ +esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer"); + ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit"); + ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation"); + //S2 Oneshot read only supports 13 bits, DMA read only supports 12 bits + ESP_RETURN_ON_FALSE(((config->bitwidth == SOC_ADC_RTC_MAX_BITWIDTH || config->bitwidth == SOC_ADC_DIGI_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth"); + // current version only accepts encoding ver 1 and ver 2. + uint8_t adc_encoding_version = esp_efuse_rtc_table_read_calib_version(); + ESP_RETURN_ON_FALSE(((adc_encoding_version == 1) || (adc_encoding_version == 2)), ESP_ERR_NOT_SUPPORTED, TAG, "Calibration required eFuse bits not burnt"); + + adc_cali_scheme_t *scheme = (adc_cali_scheme_t *)heap_caps_calloc(1, sizeof(adc_cali_scheme_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for adc calibration scheme"); + + cali_chars_line_fitting_t *chars = (cali_chars_line_fitting_t *)heap_caps_calloc(1, sizeof(cali_chars_line_fitting_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(chars, ESP_ERR_NO_MEM, err, TAG, "no memory for the calibration characteristics"); + + scheme->raw_to_voltage = cali_raw_to_voltage; + scheme->ctx = chars; + + adc_calib_parsed_info_t efuse_parsed_data = {0}; + bool success = prepare_calib_data_for(config->unit_id, config->atten, &efuse_parsed_data); + assert(success); + success = calculate_characterization_coefficients(&efuse_parsed_data, chars); + assert(success); + ESP_LOGD(TAG, "adc%d (atten leven %d) calibration done: A:%d B:%d\n", config->unit_id, config->atten, chars->coeff_a, chars->coeff_b); + chars->unit_id = config->unit_id; + chars->atten = config->atten; + + *ret_handle = scheme; + + return ESP_OK; + +err: + if (scheme) { + free(scheme); + } + return ret; +} + +esp_err_t adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + free(handle->ctx); + handle->ctx = NULL; + + free(handle); + handle = NULL; + + return ESP_OK; +} + + +/* ------------------------ Interface Functions --------------------------- */ +static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage) +{ + //pointers are checked in the upper layer + + cali_chars_line_fitting_t *ctx = arg; + *voltage = raw * ctx->coeff_a / coeff_a_scaling + ctx->coeff_b / coeff_b_scaling; + + return ESP_OK; +} + + +/* ----------------------- Characterization Functions ----------------------- */ +static bool prepare_calib_data_for(adc_unit_t unit_id, adc_atten_t atten, adc_calib_parsed_info_t *parsed_data_storage) +{ + int version_num = esp_efuse_rtc_table_read_calib_version(); + int tag; + parsed_data_storage->version_num = version_num; + parsed_data_storage->unit_id = unit_id; + parsed_data_storage->atten_level = atten; + switch (version_num) { + case 1: + // note: use the unit_id as in hal, which start from 0. + tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VLOW); + parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); + tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VHIGH); + parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); + break; + case 2: + tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V2_PARAM_VHIGH); + parsed_data_storage->efuse_data.ver2.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); + switch (parsed_data_storage->atten_level) { + case ADC_ATTEN_DB_0: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 600; + break; + case ADC_ATTEN_DB_2_5: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 800; + break; + case ADC_ATTEN_DB_6: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 1000; + break; + case ADC_ATTEN_DB_11: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 2000; + break; + default: + break; + } + break; + default: + // fall back to case 1 with zeros as params. + parsed_data_storage->version_num = 1; + tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VLOW); + parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true); + tag = esp_efuse_rtc_table_get_tag(version_num, unit_id, atten, RTCCALIB_V1_PARAM_VHIGH); + parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true); + break; + } + return true; +} + +/** + * (Used in V1 of calibration scheme) + * The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation + * between input voltage and ADC response. (Response = A * Vinput + B) + * A and B are scaled ints. + * @param high The ADC response at the higher voltage of the corresponding attenuation (600mV, 800mV, 1000mV, 2000mV). + * @param low The ADC response at the lower voltage of the corresponding attenuation (all 250mV). + * + */ +static void characterize_using_two_point(adc_unit_t unit_id, + adc_atten_t atten, + uint32_t high, + uint32_t low, + uint32_t *coeff_a, + uint32_t *coeff_b) +{ + // once we have recovered the reference high(Dhigh) and low(Dlow) readings, we can calculate a and b from + // the measured high and low readings + static const uint32_t v_high[] = {600, 800, 1000, 2000}; + static const uint32_t v_low = 250; + *coeff_a = coeff_a_scaling * (v_high[atten] - v_low) / (high - low); + *coeff_b = coeff_b_scaling * (v_low * high - v_high[atten] * low) / (high - low); +} + +/* + * Estimate the (assumed) linear relationship btwn the measured raw value and the voltage + * with the previously done measurement when the chip was manufactured. + * */ +static bool calculate_characterization_coefficients(const adc_calib_parsed_info_t *parsed_data, cali_chars_line_fitting_t *ctx) +{ + switch (parsed_data->version_num) { + case 1: + ESP_LOGD(TAG, "Calib V1, low%dmV, high%dmV\n", parsed_data->efuse_data.ver1.adc_calib_low, parsed_data->efuse_data.ver1.adc_calib_high); + + characterize_using_two_point(parsed_data->unit_id, parsed_data->atten_level, + parsed_data->efuse_data.ver1.adc_calib_high, parsed_data->efuse_data.ver1.adc_calib_low, + &(ctx->coeff_a), &(ctx->coeff_b)); + break; + case 2: + ESP_LOGD(TAG, "Calib V2, volt%dmV\n", parsed_data->efuse_data.ver2.adc_calib_high); + ctx->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver2.adc_calib_high_voltage / + parsed_data->efuse_data.ver2.adc_calib_high; + ctx->coeff_b = 0; + break; + default: + return false; + break; + } + return true; +} diff --git a/components/esp_adc/esp32s2/include/adc_cali_schemes.h b/components/esp_adc/esp32s2/include/adc_cali_schemes.h new file mode 100644 index 0000000000..dc6fa544ef --- /dev/null +++ b/components/esp_adc/esp32s2/include/adc_cali_schemes.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file adc_cali_schemes.h + * + * @brief Supported calibration schemes + */ + +#define ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED 1 diff --git a/components/esp_adc/esp32s3/curve_fitting_coefficients.c b/components/esp_adc/esp32s3/curve_fitting_coefficients.c new file mode 100644 index 0000000000..b81ad58c63 --- /dev/null +++ b/components/esp_adc/esp32s3/curve_fitting_coefficients.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +/** + * @note Error Calculation + * Coefficients for calculating the reading voltage error. + * Four sets of coefficients for atten0 ~ atten3 respectively. + * + * For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient. + * + * @note {0,0} stands for unused item + * @note In case of the overflow, these coeffcients are recorded as Absolute Value + * @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4); + * @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered. + */ +const uint64_t adc1_error_coef_atten[4][5][2] = { + {{27856531419538344, 1e16}, {50871540569528, 1e16}, {9798249589, 1e15}, {0, 0}, {0, 0}}, //ADC1 atten0 + {{29831022915028695, 1e16}, {49393185868806, 1e16}, {101379430548, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten1 + {{23285545746296417, 1e16}, {147640181047414, 1e16}, {208385525314, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten2 + {{644403418269478, 1e15}, {644334888647536, 1e16}, {1297891447611, 1e16}, {70769718, 1e15}, {13515, 1e15}} //ADC1 atten3 + }; +const uint64_t adc2_error_coef_atten[4][5][2] = { + {{25668651654328927, 1e16}, {1353548869615, 1e16}, {36615265189, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten0 + {{23690184690298404, 1e16}, {66319894226185, 1e16}, {118964995959, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten1 + {{9452499397020617, 1e16}, {200996773954387, 1e16}, {259011467956, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten2 + {{12247719764336924,1e16}, {755717904943462, 1e16}, {1478791187119, 1e16}, {79672528, 1e15}, {15038, 1e15}} //ADC2 atten3 + }; +/** + * Term sign + */ +const int32_t adc1_error_sign[4][5] = { + {-1, -1, 1, 0, 0}, //ADC1 atten0 + {-1, -1, 1, 0, 0}, //ADC1 atten1 + {-1, -1, 1, 0, 0}, //ADC1 atten2 + {-1, -1, 1, -1, 1} //ADC1 atten3 + }; +const int32_t adc2_error_sign[4][5] = { + {-1, 1, 1, 0, 0}, //ADC2 atten0 + {-1, -1, 1, 0, 0}, //ADC2 atten1 + {-1, -1, 1, 0, 0}, //ADC2 atten2 + { 1, -1, 1, -1, 1} //ADC2 atten3 + }; diff --git a/components/esp_adc/esp32s3/include/adc_cali_schemes.h b/components/esp_adc/esp32s3/include/adc_cali_schemes.h new file mode 100644 index 0000000000..2eb6842031 --- /dev/null +++ b/components/esp_adc/esp32s3/include/adc_cali_schemes.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +/** + * @file adc_cali_schemes.h + * + * @brief Supported calibration schemes + */ + +#define ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED 1 diff --git a/components/esp_adc/include/esp_adc/adc_cali.h b/components/esp_adc/include/esp_adc/adc_cali.h new file mode 100644 index 0000000000..b9b949b19f --- /dev/null +++ b/components/esp_adc/include/esp_adc/adc_cali.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_err.h" +#include "esp_bit_defs.h" +#include "hal/adc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ADC calibration handle + */ +typedef struct adc_cali_scheme_t *adc_cali_handle_t; + +/** + * @brief ADC calibration scheme + */ +typedef enum { + ADC_CALI_SCHEME_VER_LINE_FITTING = BIT(0), ///< Line fitting scheme + ADC_CALI_SCHEME_VER_CURVE_FITTING = BIT(1), ///< Curve fitting scheme +} adc_cali_scheme_ver_t; + +/** + * @brief Check the supported ADC calibration scheme + * + * @param[out] scheme_mask Supported ADC calibration scheme(s) + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NOT_SUPPORTED: No supported calibration scheme + */ +esp_err_t adc_cali_check_scheme(adc_cali_scheme_ver_t *scheme_mask); + +/** + * @brief Convert ADC raw data to calibrated voltage + * + * @param[in] handle ADC calibration handle + * @param[in] raw ADC raw data + * @param[out] voltage Calibrated ADC voltage (in mV) + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid state, scheme didn't registered + */ +esp_err_t adc_cali_raw_to_voltage(adc_cali_handle_t handle, int raw, int *voltage); + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/include/esp_adc/adc_cali_scheme.h b/components/esp_adc/include/esp_adc/adc_cali_scheme.h new file mode 100644 index 0000000000..8f148c4c88 --- /dev/null +++ b/components/esp_adc/include/esp_adc/adc_cali_scheme.h @@ -0,0 +1,135 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "sdkconfig.h" +#include "esp_adc/adc_cali.h" +#include "adc_cali_schemes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED +/*--------------------------------------------------------------- + Curve Fitting Calibration Scheme +---------------------------------------------------------------*/ +typedef struct { + adc_unit_t unit_id; ///< ADC unit + adc_atten_t atten; ///< ADC attenuation + adc_bitwidth_t bitwidth; ///< ADC raw output bitwidth +} adc_cali_curve_fitting_config_t; + +/** + * @brief Create a Curve Fitting calibration scheme + * + * After creating, you'll get a handle to this scheme. Then you can use the driver APIS in `esp_adc/adc_cali.h` to do the + * ADC calibration via the handle you get. + * + * @param[in] config Initial configurations + * @param[out] handle ADC calibration handle + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: No enough memory + * - ESP_ERR_NOT_SUPPORTED: Scheme required eFuse bits not burnt + */ +esp_err_t adc_cali_create_scheme_curve_fitting(const adc_cali_curve_fitting_config_t *config, adc_cali_handle_t *ret_handle); + +/** + * @brief Delete the Curve Fitting calibration scheme handle + * + * @param[in] handle ADC calibration handle + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + */ +esp_err_t adc_cali_delete_scheme_curve_fitting(adc_cali_handle_t handle); +#endif // #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + + +#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED +/*--------------------------------------------------------------- + Line Fitting Calibration Scheme +---------------------------------------------------------------*/ +/** + * @brief Type of calibration value used in line fitting scheme characterization + */ +typedef enum { + ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF = 0, ///< Characterization based on reference voltage stored in eFuse + ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP = 1, ///< Characterization based on Two Point values stored in eFuse + ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF = 2, ///< Characterization based on default reference voltage +} adc_cali_line_fitting_efuse_val_t; + +typedef struct { + adc_unit_t unit_id; ///< ADC unit + adc_atten_t atten; ///< ADC attenuation + adc_bitwidth_t bitwidth; ///< ADC raw output bitwidth +#if CONFIG_IDF_TARGET_ESP32 + /** + * @brief Default ADC reference voltage in mV. + * + * Use this when the ADC calibration value is `ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF`. + * If others, driver will use the calibration code burnt in the eFuse for calibration. + */ + uint32_t default_vref; +#endif +} adc_cali_line_fitting_config_t; + +/** + * @brief Create a Line Fitting calibration scheme + * + * After creating, you'll get a handle to this scheme. Then you can use the driver APIS in `esp_adc/adc_cali.h` to do the + * ADC calibration via the handle you get. + * + * @param[in] config Initial configurations + * @param[out] handle ADC calibration handle + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: No enough memory + * - ESP_ERR_NOT_SUPPORTED: Scheme required eFuse bits not burnt + */ +esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle); + +/** + * @brief Delete the Line Fitting calibration scheme handle + * + * @param[in] handle ADC calibration handle + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + */ +esp_err_t adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle); + +#if CONFIG_IDF_TARGET_ESP32 +/** + * @brief Helper function to quickly check the ADC calibration code burnt on your eFuse + * + * @note If `cali_val` equals to `ESP_ADC_CALI_VAL_DEFAULT_VREF`, please set the `default_vref` + * when creating this scheme (See `ESP_ADC_CALI_SCHEME_VER_LINE_FITTING_init_t`) + * + * @param[out] cali_val See `esp_adc_cali_value_t` + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NOT_SUPPORTED: Scheme required eFuse bits not burnt + */ +esp_err_t adc_cali_scheme_line_fitting_check_efuse(adc_cali_line_fitting_efuse_val_t *cali_val); +#endif // CONFIG_IDF_TARGET_ESP32 +#endif // #if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/include/esp_adc/adc_continuous.h b/components/esp_adc/include/esp_adc/adc_continuous.h new file mode 100644 index 0000000000..8db0f53135 --- /dev/null +++ b/components/esp_adc/include/esp_adc/adc_continuous.h @@ -0,0 +1,232 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "sdkconfig.h" +#include "hal/adc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_ADC_DMA_SUPPORTED + +/** + * @brief Driver Backgrounds + * + * -------------------------------------------------------------------------------------------------------- + * | Conversion Frame | + * -------------------------------------------------------------------------------------------------------- + * | Conversion Result | Conversion Result | Conversion Result | Conversion Result | ... | + * -------------------------------------------------------------------------------------------------------- + * + * ADC continuous mode conversion is made up with multiple Conversion Frames. + * - Conversion Frame: One Conversion Frame contains multiple Conversion Results. + * Conversion Frame size is configured in `adc_continuous_handle_cfg_t:conv_frame_size`, in bytes. + * Each time driver see an interrupt event, this means one Conversion Frame is generated by the hardware. + * - Conversion Result: One Conversion Result contains multiple bytes (see `SOC_ADC_DIGI_RESULT_BYTES`). Its + * structure is `adc_digi_output_data_t`, including ADC Unit, ADC Channel and Raw Data. + * + * For example: + * conv_frame_size = 100, + * then one Conversion Frame contains (100 / `SOC_ADC_DIGI_RESULT_BYTES`) pieces of Conversion Results + */ + +/** + * @brief ADC read max timeout value, it may make the ``adc_continuous_read`` block forever if the OS supports + */ +#define ADC_MAX_DELAY UINT32_MAX + +/** + * @brief Type of adc continuous mode driver handle + */ +typedef struct adc_continuous_ctx_t *adc_continuous_handle_t; + +/** + * @brief ADC continuous mode driver initial configurations + */ +typedef struct { + uint32_t max_store_buf_size; ///< Max length of the conversion Results that driver can store, in bytes. + uint32_t conv_frame_size; ///< Conversion frame size, in bytes. This should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`. +} adc_continuous_handle_cfg_t; + +/** + * @brief ADC continuous mode driver configurations + */ +typedef struct { + uint32_t pattern_num; ///< Number of ADC channels that will be used + adc_digi_pattern_config_t *adc_pattern; ///< List of configs for each ADC channel that will be used + uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Please refer to `soc/soc_caps.h` to know available sampling frequency range*/ + adc_digi_convert_mode_t conv_mode; ///< ADC DMA conversion mode, see `adc_digi_convert_mode_t`. + adc_digi_output_format_t format; ///< ADC DMA conversion output format, see `adc_digi_output_format_t`. +} adc_continuous_config_t; + +/** + * @brief Event data structure + * @note The `conv_frame_buffer` is maintained by the driver itself, so never free this piece of memory. + */ +typedef struct { + uint8_t *conv_frame_buffer; ///< Pointer to conversion result buffer for one conversion frame + uint32_t size; ///< Conversion frame size +} adc_continuous_evt_data_t; + +/** + * @brief Prototype of ADC continuous mode event callback + * + * @param[in] handle ADC continuous mode driver handle + * @param[in] edata Pointer to ADC contunuous mode event data + * @param[in] user_data User registered context, registered when in `adc_continuous_register_event_callbacks()` + * + * @return Whether a high priority task is woken up by this function + */ +typedef bool (*adc_continuous_callback_t)(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data); + +/** + * @brief Group of ADC continuous mode callbacks + * + * @note These callbacks are all running in an ISR environment. + * @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 should be in internal RAM as well. + */ +typedef struct { + adc_continuous_callback_t on_conv_done; ///< Event callback, invoked when one conversion frame is done. See `@brief Driver Backgrounds` to konw `conversion frame` concept. + adc_continuous_callback_t on_pool_ovf; ///< Event callback, invoked when the internal pool is full. +} adc_continuous_evt_cbs_t; + +/** + * @brief Initialize ADC continuous driver and get a handle to it + * + * @param[in] hdl_config Pointer to ADC initilization config. Refer to ``adc_continuous_handle_cfg_t``. + * @param[out] ret_handle ADC continuous mode driver handle + * + * @return + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags + * - ESP_ERR_NO_MEM If out of memory + * - ESP_OK On success + */ +esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_config, adc_continuous_handle_t *ret_handle); + +/** + * @brief Set ADC continuous mode required configurations + * + * @param[in] handle ADC continuous mode driver handle + * @param[in] config Refer to ``adc_digi_config_t``. + * + * @return + * - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment + * - ESP_ERR_INVALID_ARG: If the combination of arguments is invalid. + * - ESP_OK: On success + */ +esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_continuous_config_t *config); + +/** + * @brief Register callbacks + * + * @note User can deregister a previously registered callback by calling this function and setting the to-be-deregistered callback member int + * 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. + * @note You should only call this API when the ADC continuous mode driver isn't started. Check return value to know this. + * + * @param[in] handle ADC continuous mode driver handle + * @param[in] cbs Group of callback functions + * @param[in] user_data User data, which will be delivered to the callback functions directly + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments + * - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment + */ +esp_err_t adc_continuous_register_event_callbacks(adc_continuous_handle_t handle, const adc_continuous_evt_cbs_t *cbs, void *user_data); + +/** + * @brief Start the ADC under continuous mode. After this, the hardware starts working. + * + * @param[in] handle ADC continuous mode driver handle + * + * @return + * - ESP_ERR_INVALID_STATE Driver state is invalid. + * - ESP_OK On success + */ +esp_err_t adc_continuous_start(adc_continuous_handle_t handle); + +/** + * @brief Read bytes from ADC under continuous mode. + * + * @param[in] handle ADC continuous mode driver handle + * @param[out] buf Conversion result buffer to read from ADC. Suggest convert to `adc_digi_output_data_t` for `ADC Conversion Results`. + * See `@brief Driver Backgrounds` to know this concept. + * @param[in] length_max Expected length of the Conversion Results read from the ADC, in bytes. + * @param[out] out_length Real length of the Conversion Results read from the ADC via this API, in bytes. + * @param[in] timeout_ms Time to wait for data via this API, in millisecond. + * + * @return + * - ESP_ERR_INVALID_STATE Driver state is invalid. Usually it means the ADC sampling rate is faster than the task processing rate. + * - ESP_ERR_TIMEOUT Operation timed out + * - ESP_OK On success + */ +esp_err_t adc_continuous_read(adc_continuous_handle_t handle, uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms); + +/** + * @brief Stop the ADC. After this, the hardware stops working. + * + * @param[in] handle ADC continuous mode driver handle + * + * @return + * - ESP_ERR_INVALID_STATE Driver state is invalid. + * - ESP_OK On success + */ +esp_err_t adc_continuous_stop(adc_continuous_handle_t handle); + +/** + * @brief Deinitialize the ADC continuous driver. + * + * @param[in] handle ADC continuous mode driver handle + * + * @return + * - ESP_ERR_INVALID_STATE Driver state is invalid. + * - ESP_OK On success + */ +esp_err_t adc_continuous_deinit(adc_continuous_handle_t handle); + +/** + * @brief Get ADC channel from the given GPIO number + * + * @param[in] io_num GPIO number + * @param[out] unit_id ADC unit + * @param[out] channel ADC channel + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NOT_FOUND: The IO is not a valid ADC pad + */ +esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel); + +/** + * @brief Get GPIO number from the given ADC channel + * + * @param[in] unit_id ADC unit + * @param[in] channel ADC channel + * @param[out] io_num GPIO number + * + * @param + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + */ +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 +} +#endif diff --git a/components/esp_adc/include/esp_adc/adc_oneshot.h b/components/esp_adc/include/esp_adc/adc_oneshot.h new file mode 100644 index 0000000000..b3b21778a0 --- /dev/null +++ b/components/esp_adc/include/esp_adc/adc_oneshot.h @@ -0,0 +1,130 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "hal/adc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of ADC unit handle for oneshot mode + */ +typedef struct adc_oneshot_unit_ctx_t *adc_oneshot_unit_handle_t; + +/** + * @brief ADC oneshot driver initial configurations + */ +typedef struct { + adc_unit_t unit_id; ///< ADC unit + adc_ulp_mode_t ulp_mode; ///< ADC controlled by ULP, see `adc_ulp_mode_t` +} adc_oneshot_unit_init_cfg_t; + +/** + * @brief ADC channel configurations + */ +typedef struct { + adc_atten_t atten; ///< ADC attenuation + adc_bitwidth_t bitwidth; ///< ADC conversion result bits +} adc_oneshot_chan_cfg_t; + +/** + * @brief Create a handle to a specific ADC unit + * + * @note This API is thread-safe. For more details, see ADC programming guide + * + * @param[in] init_config Driver initial configurations + * @param[out] ret_unit ADC unit handle + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments + * - ESP_ERR_NO_MEM: No memory + * - ESP_ERR_NOT_FOUND: The ADC peripheral to be claimed is already in use + */ +esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, adc_oneshot_unit_handle_t *ret_unit); + +/** + * @brief Set ADC oneshot mode required configurations + * + * @note This API is thread-safe. For more details, see ADC programming guide + * + * @param[in] handle ADC handle + * @param[in] channel ADC channel to be configured + * @param[in] config ADC configurations + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments + */ +esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_channel_t channel, const adc_oneshot_chan_cfg_t *config); + +/** + * @brief Get one ADC conversion raw result + * + * @note This API is thread-safe. For more details, see ADC programming guide + * @note This API should NOT be called in an ISR context + * + * @param[in] handle ADC handle + * @param[in] chan ADC channel + * @param[out] out_raw ADC conversion raw result + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments + * - ESP_ERR_TIMEOUT: Timeout, the ADC result is invalid + */ +esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw); + +/** + * @brief Delete the ADC unit handle + * + * @note This API is thread-safe. For more details, see ADC programming guide + * + * @param[in] handle ADC handle + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments + * - ESP_ERR_NOT_FOUND: The ADC peripheral to be disclaimed isn't in use + */ +esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle); + +/** + * @brief Get ADC channel from the given GPIO number + * + * @param[in] io_num GPIO number + * @param[out] unit_id ADC unit + * @param[out] channel ADC channel + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NOT_FOUND: The IO is not a valid ADC pad + */ +esp_err_t adc_oneshot_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel); + +/** + * @brief Get GPIO number from the given ADC channel + * + * @param[in] unit_id ADC unit + * @param[in] channel ADC channel + * @param[out] io_num GPIO number + * + * @param + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + */ +esp_err_t adc_oneshot_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num); + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/include/esp_private/adc2_wifi.h b/components/esp_adc/include/esp_private/adc2_wifi.h similarity index 84% rename from components/driver/include/esp_private/adc2_wifi.h rename to components/esp_adc/include/esp_private/adc2_wifi.h index 669213fb3d..2d0e1baad5 100644 --- a/components/driver/include/esp_private/adc2_wifi.h +++ b/components/esp_adc/include/esp_private/adc2_wifi.h @@ -21,19 +21,20 @@ extern "C" { * The WIFI module may have to wait for a short time for the current conversion (if exist) to finish. * * @return - * - ESP_OK success - * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. + * - ESP_OK success + * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. */ esp_err_t adc2_wifi_acquire(void); - /** * @brief For WIFI module to let other tasks use the ADC2 when WIFI is not work. * * Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``. * Call this function to release the occupation of ADC2 by WIFI. * - * @return always return ESP_OK. + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet */ esp_err_t adc2_wifi_release(void); diff --git a/components/esp_adc/include/esp_private/adc_lock.h b/components/esp_adc/include/esp_private/adc_lock.h new file mode 100644 index 0000000000..cac15a728b --- /dev/null +++ b/components/esp_adc/include/esp_private/adc_lock.h @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_err.h" +#include "hal/adc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Acquire ADC lock by unit + * + * The lock acquiring sequence will be: ADC1, ADC2, ... + * + * @note If any of the locks are taken, this API will wait until the lock is successfully acquired. + * + * @param[in] unit_mask ADC unit mask + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_lock_acquire(adc_unit_t unit_mask); + +/** + * @brief Release ADC lock by unit + * + * The lock releasing sequence will be: ..., ADC2, ADC1 + * + * @param[in] unit_mask ADC unit mask + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet + */ +esp_err_t adc_lock_release(adc_unit_t unit_mask); + +/** + * @brief Try to acquire ADC lock by unit + * + * The lock acquiring sequence will be: ADC1, ADC2, ... + * + * @note If any of the locks are taken, this API will return immediately with an error `ESP_ERR_TIMEOUT` + * + * @param[in] unit_mask ADC unit mask + * + * @return + * - ESP_OK: On success + * - ESP_ERR_TIMEOUT: Lock(s) is taken already + */ +esp_err_t adc_lock_try_acquire(adc_unit_t unit_mask); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/include/esp_private/adc_private.h b/components/esp_adc/include/esp_private/adc_private.h new file mode 100644 index 0000000000..a491911936 --- /dev/null +++ b/components/esp_adc/include/esp_private/adc_private.h @@ -0,0 +1,130 @@ +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// DO NOT USE THESE APIS IN ANY APPLICATIONS + +#pragma once +#include "esp_err.h" +#include "hal/adc_types.h" +#include "soc/soc_caps.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ +* For those who use APB_SARADC periph +*----------------------------------------------------------------------------*/ +/** + * @brief Claim the usage of the APB_SARADC periph + * + * Reference count inside + */ +void adc_apb_periph_claim(void); + +/** + * @brief Free the usage of the APB_SARADC periph + * + * Reference count inside + */ +void adc_apb_periph_free(void); + + +/*------------------------------------------------------------------------------ +* ADC Power +*----------------------------------------------------------------------------*/ +/** + * @brief Acquire the ADC Power + */ +void adc_power_acquire(void); + +/** + * @brief Release the ADC Power + */ +void adc_power_release(void); + + +/*--------------------------------------------------------------- + ADC IOs +---------------------------------------------------------------*/ +/** + * @brief Get ADC channel from the given GPIO number + * + * @param[in] io_num GPIO number + * @param[out] unit_id ADC unit + * @param[out] channel ADC channel + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NOT_FOUND: The IO is not a valid ADC pad + */ +esp_err_t adc_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel); + +/** + * @brief Get GPIO number from the given ADC channel + * + * @param[in] unit_id ADC unit + * @param[in] channel ADC channel + * @param[out] io_num GPIO number + * + * @param + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + */ +esp_err_t adc_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num); + + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Hardware Calibration +---------------------------------------------------------------*/ +/** + * @brief Calculate the ADC HW calibration code. (Based on the pre-stored efuse or actual calibration) + * + * @param adc_n ADC unit to calibrate + * @param atten Attenuation to use + */ +void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten); + +/** + * @brief Set the ADC HW calibration code. + * + * @param adc_n ADC unit to calibrate + * @param atten Attenuation to use + */ +void adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten); +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED + +/*--------------------------------------------------------------- + ADC Oneshot Read API ISR Version +---------------------------------------------------------------*/ +typedef struct adc_oneshot_unit_ctx_t *adc_oneshot_unit_handle_t; +/** + * @brief ISR version to get one ADC conversion raw result + * + * @note This API only provide atomic register settings, without hardware resources protection. When other drivers are using + * SAR-ADCs, calling this API may get wrong ADC result. + * @note This API can be called in an ISR context. + * @note Strongly suggest using this function when there's no concurrent hardware usage to the ADC. You can refer to ADC Oneshot + * Programming Guide to know ADC Hardware Limitations + * + * @param[in] handle ADC handle + * @param[in] chan ADC channel + * @param[out] out_raw ADC conversion raw result + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments + * - ESP_ERR_INVALID_STATE: Invalid state, the ADC result is invalid + */ +esp_err_t adc_oneshot_read_isr(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw); + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/interface/adc_cali_interface.h b/components/esp_adc/interface/adc_cali_interface.h new file mode 100644 index 0000000000..751fef5276 --- /dev/null +++ b/components/esp_adc/interface/adc_cali_interface.h @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "esp_types.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct adc_cali_scheme_t adc_cali_scheme_t; + +/** + * @brief ADC Calibration Scheme Interface and Context + */ +struct adc_cali_scheme_t { + + /** + * @brief Convert ADC raw data to calibrated voltage + * + * @param[in] arg ///< ADC calibration scheme specific context + * @param[in] raw ///< ADC raw data + * @param[out] voltage ///< Calibrated ADC voltage (in mV) + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid state, scheme didn't registered + */ + esp_err_t (*raw_to_voltage)(void *arg, int raw, int *voltage); + + /** + * @brief ADC calibration specific contexts + * Can be customized to difference calibration schemes + */ + void *ctx; + +}; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/linker.lf b/components/esp_adc/linker.lf new file mode 100644 index 0000000000..b2e1851e28 --- /dev/null +++ b/components/esp_adc/linker.lf @@ -0,0 +1,5 @@ +[mapping:esp_adc] +archive: libesp_adc.a +entries: + if ADC_ONESHOT_CTRL_FUNC_IN_IRAM = y: + adc_oneshot: adc_oneshot_read_isr (noflash) diff --git a/components/esp_adc/test_apps/adc/CMakeLists.txt b/components/esp_adc/test_apps/adc/CMakeLists.txt new file mode 100644 index 0000000000..36ae549fed --- /dev/null +++ b/components/esp_adc/test_apps/adc/CMakeLists.txt @@ -0,0 +1,20 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(adc_test) + +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/esp_adc/ + --elf-file ${CMAKE_BINARY_DIR}/adc_test.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text,.flash.rodata + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/esp_adc/test_apps/adc/README.md b/components/esp_adc/test_apps/adc/README.md new file mode 100644 index 0000000000..b5be4985c5 --- /dev/null +++ b/components/esp_adc/test_apps/adc/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | diff --git a/components/esp_adc/test_apps/adc/main/CMakeLists.txt b/components/esp_adc/test_apps/adc/main/CMakeLists.txt new file mode 100644 index 0000000000..85bbc4bb8e --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/CMakeLists.txt @@ -0,0 +1,11 @@ +set(srcs "test_app_main.c" + "test_adc.c" + "test_adc_performance.c" + "test_adc_driver.c" + "test_adc_driver_iram.c" + "test_common_adc.c") + +# In order for the cases defined by `TEST_CASE` to be linked into the final elf, +# the component can be registered as WHOLE_ARCHIVE +idf_component_register(SRCS ${srcs} + WHOLE_ARCHIVE) diff --git a/components/esp_adc/test_apps/adc/main/test_adc.c b/components/esp_adc/test_apps/adc/main/test_adc.c new file mode 100644 index 0000000000..b8896853e1 --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/test_adc.c @@ -0,0 +1,260 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "unity.h" +#include "esp_log.h" +#include "soc/adc_periph.h" +#include "esp_adc/adc_oneshot.h" +#include "driver/gpio.h" +#include "driver/rtc_io.h" +#include "test_common_adc.h" + +const __attribute__((unused)) static char *TAG = "TEST_ADC"; + +/*--------------------------------------------------------------- + ADC General Macros +---------------------------------------------------------------*/ +//ADC Channels +#if CONFIG_IDF_TARGET_ESP32 +#define ADC1_TEST_CHAN0 ADC_CHANNEL_4 +#define ADC1_TEST_CHAN1 ADC_CHANNEL_5 +#define ADC2_TEST_CHAN0 ADC_CHANNEL_0 +static const char *TAG_CH[2][10] = {{"ADC1_CH4", "ADC1_CH5"}, {"ADC2_CH0"}}; +#else +#define ADC1_TEST_CHAN0 ADC_CHANNEL_2 +#define ADC1_TEST_CHAN1 ADC_CHANNEL_3 +#define ADC2_TEST_CHAN0 ADC_CHANNEL_0 +static const char *TAG_CH[2][10] = {{"ADC1_CH2", "ADC1_CH3"}, {"ADC2_CH0"}}; +#endif + + +/*--------------------------------------------------------------- + ADC Oneshot High / Low test +---------------------------------------------------------------*/ +TEST_CASE("ADC oneshot high/low test", "[adc_oneshot]") +{ + static int adc_raw[2][10]; + + //-------------ADC1 Init---------------// + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = false, + }; + TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + +#if (SOC_ADC_PERIPH_NUM >= 2) + //-------------ADC2 Init---------------// + adc_oneshot_unit_handle_t adc2_handle; + adc_oneshot_unit_init_cfg_t init_config2 = { + .unit_id = ADC_UNIT_2, + .ulp_mode = false, + }; + TEST_ESP_OK(adc_oneshot_new_unit(&init_config2, &adc2_handle)); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) + + //-------------ADC1 TEST Channel 0 Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, + }; + TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, ADC1_TEST_CHAN0, &config)); + + //-------------ADC1 TEST Channel 1 Config---------------// + TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, ADC1_TEST_CHAN1, &config)); + +#if (SOC_ADC_PERIPH_NUM >= 2) + //-------------ADC2 TEST Channel 0 Config---------------// + TEST_ESP_OK(adc_oneshot_config_channel(adc2_handle, ADC2_TEST_CHAN0, &config)); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) + + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0); + TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN0, &adc_raw[0][0])); + ESP_LOGI(TAG_CH[0][0], "raw data: %d", adc_raw[0][0]); + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[0][0]); + + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN1, 1); + TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN1, &adc_raw[0][1])); + ESP_LOGI(TAG_CH[0][1], "raw data: %d", adc_raw[0][1]); + TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[0][1]); + +#if (SOC_ADC_PERIPH_NUM >= 2) + test_adc_set_io_level(ADC_UNIT_2, ADC2_TEST_CHAN0, 0); + TEST_ESP_OK(adc_oneshot_read(adc2_handle, ADC2_TEST_CHAN0, &adc_raw[1][0])); + ESP_LOGI(TAG_CH[1][0], "raw data: %d", adc_raw[1][0]); + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[1][0]); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) + + + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1); + TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN0, &adc_raw[0][0])); + ESP_LOGI(TAG_CH[0][0], "raw data: %d", adc_raw[0][0]); + TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[0][0]); + + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN1, 0); + TEST_ESP_OK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHAN1, &adc_raw[0][1])); + ESP_LOGI(TAG_CH[0][1], "raw data: %d", adc_raw[0][1]); + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw[0][1]); + +#if (SOC_ADC_PERIPH_NUM >= 2) + test_adc_set_io_level(ADC_UNIT_2, ADC2_TEST_CHAN0, 1); + TEST_ESP_OK(adc_oneshot_read(adc2_handle, ADC2_TEST_CHAN0, &adc_raw[1][0])); + ESP_LOGI(TAG_CH[1][0], "raw data: %d", adc_raw[1][0]); + TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw[1][0]); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) + + + TEST_ESP_OK(adc_oneshot_del_unit(adc1_handle)); +#if (SOC_ADC_PERIPH_NUM >= 2) + TEST_ESP_OK(adc_oneshot_del_unit(adc2_handle)); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) +} + + + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Oneshot with Light Sleep +---------------------------------------------------------------*/ +#include +#include "esp_sleep.h" +#include "esp_private/regi2c_ctrl.h" +#include "soc/regi2c_saradc.h" + +#define TEST_REGI2C_ANA_CALI_BYTE_NUM 8 + +static void s_adc_oneshot_with_sleep(adc_unit_t unit_id, adc_channel_t channel) +{ + adc_atten_t atten[SOC_ADC_ATTEN_NUM] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_2_5, ADC_ATTEN_DB_6, ADC_ATTEN_DB_11}; + //-------------ADC Init---------------// + adc_oneshot_unit_handle_t adc_handle; + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = unit_id, + .ulp_mode = false, + }; + TEST_ESP_OK(adc_oneshot_new_unit(&init_config, &adc_handle)); + + //-------------ADC Channel Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = SOC_ADC_RTC_MAX_BITWIDTH, + }; + + //-------------ADC Calibration Init---------------// + bool do_calibration = false; + adc_cali_handle_t cali_handle[SOC_ADC_ATTEN_NUM] = {}; + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + do_calibration = test_adc_calibration_init(unit_id, i, SOC_ADC_RTC_MAX_BITWIDTH, &cali_handle[i]); + } + if (!do_calibration) { + ESP_LOGW(TAG, "No efuse bits burnt, only test the regi2c analog register values"); + } + + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + + //-------------ADC Channel Config---------------// + config.atten = atten[i]; + TEST_ESP_OK(adc_oneshot_config_channel(adc_handle, channel, &config)); + printf("Test with atten: %d\n", atten[i]); + + //---------------------------------Before Sleep-----------------------------------// + printf("Before Light Sleep\n"); + int raw_expected = 0; + int cali_expected = 0; + uint8_t regi2c_cali_val_before[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {}; + + //Read + TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &raw_expected)); + if (do_calibration) { + TEST_ESP_OK(adc_cali_raw_to_voltage(cali_handle[i], raw_expected, &cali_expected)); + } + + //Print regi2c + printf("regi2c cali val is: "); + for (int j = 0; j < TEST_REGI2C_ANA_CALI_BYTE_NUM; j++) { + regi2c_cali_val_before[j] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, j); + printf("0x%x ", regi2c_cali_val_before[j]); + } + printf("\n"); + + //Print result + ESP_LOGI(TAG, "ADC%d Chan%d: raw data: %d", unit_id + 1, channel, raw_expected); + ESP_LOGI(TAG, "ADC%d Chan%d: cali data: %d", unit_id + 1, channel, cali_expected); + + //---------------------------------Sleep-----------------------------------// + esp_sleep_enable_timer_wakeup(30 * 1000); + esp_light_sleep_start(); + + //---------------------------------After Sleep-----------------------------------// + printf("After Light Sleep\n"); + int raw_after_sleep = 0; + int cali_after_sleep = 0; + uint8_t regi2c_cali_val_after[TEST_REGI2C_ANA_CALI_BYTE_NUM] = {}; + + //Print regi2c + printf("regi2c cali val is: "); + for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { + regi2c_cali_val_after[i] = regi2c_ctrl_read_reg(I2C_SAR_ADC, I2C_SAR_ADC_HOSTID, i); + printf("0x%x ", regi2c_cali_val_after[i]); + } + printf("\n"); + + //Read + TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &raw_after_sleep)); + if (do_calibration) { + TEST_ESP_OK(adc_cali_raw_to_voltage(cali_handle[i], raw_after_sleep, &cali_after_sleep)); + } + + //Print result + ESP_LOGI(TAG, "ADC%d Chan%d: raw data: %d", unit_id + 1, channel, raw_after_sleep); + if (do_calibration) { + ESP_LOGI(TAG, "ADC%d Chan%d: cali data: %d", unit_id + 1, channel, cali_after_sleep); + } + + //Compare + int32_t raw_diff = raw_expected - raw_after_sleep; + ESP_LOGI(TAG, "ADC%d Chan%d: raw difference: %d", unit_id + 1, channel, raw_diff); + + if (do_calibration) { + int32_t cali_diff = cali_expected - cali_after_sleep; + ESP_LOGI(TAG, "ADC%d Chan%d: cali difference: %d", unit_id + 1, channel, cali_diff); + } + + //Test Calibration registers + for (int i = 0; i < TEST_REGI2C_ANA_CALI_BYTE_NUM; i++) { + TEST_ASSERT_EQUAL(regi2c_cali_val_before[i], regi2c_cali_val_after[i]); + } + ESP_LOGI(TAG, "Cali register settings unchanged\n"); + + } + TEST_ESP_OK(adc_oneshot_del_unit(adc_handle)); + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + if (cali_handle[i]) { + test_adc_calibration_deinit(cali_handle[i]); + } + } +} + +//ADC Channels +#if CONFIG_IDF_TARGET_ESP32 +#define ADC1_SLEEP_TEST_CHAN ADC_CHANNEL_6 +#define ADC2_SLEEP_TEST_CHAN ADC_CHANNEL_0 +#else +#define ADC1_SLEEP_TEST_CHAN ADC_CHANNEL_2 +#define ADC2_SLEEP_TEST_CHAN ADC_CHANNEL_0 +#endif + +TEST_CASE("test ADC1 Single Read with Light Sleep", "[adc][manul][ignore]") +{ + s_adc_oneshot_with_sleep(ADC_UNIT_1, ADC1_SLEEP_TEST_CHAN); +} + +TEST_CASE("test ADC2 Single Read with Light Sleep", "[adc][manul][ignore]") +{ + s_adc_oneshot_with_sleep(ADC_UNIT_2, ADC2_SLEEP_TEST_CHAN); +} +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED diff --git a/components/esp_adc/test_apps/adc/main/test_adc_driver.c b/components/esp_adc/test_apps/adc/main/test_adc_driver.c new file mode 100644 index 0000000000..c5e2c4dfb4 --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/test_adc_driver.c @@ -0,0 +1,128 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "unity.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gptimer.h" +#include "esp_rom_sys.h" +#include "esp_adc/adc_oneshot.h" +#include "test_common_adc.h" + +const __attribute__((unused)) static char *TAG = "TEST_ADC"; + +/*--------------------------------------------------------------- + ADC General Macros +---------------------------------------------------------------*/ +//ADC Channels +#if CONFIG_IDF_TARGET_ESP32 +#define ADC1_TEST_CHAN0 ADC_CHANNEL_4 +#else +#define ADC1_TEST_CHAN0 ADC_CHANNEL_2 +#endif + +/*--------------------------------------------------------------- + ADC work with ISR +---------------------------------------------------------------*/ +typedef struct { + TaskHandle_t task_handle; //Task handle + adc_oneshot_unit_handle_t adc_handle; //ADC handle + bool level; //ADC level +} test_adc_isr_ctx_t; + +static bool IRAM_ATTR s_alarm_callback(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) +{ + test_adc_isr_ctx_t *test_ctx = (test_adc_isr_ctx_t *)user_data; + BaseType_t high_task_wakeup; + int adc_raw = 0; + + /** + * This test won't disable the cache, so having some code on Flash is OK. + * If you copy this test callback with cache disabled, do remeber to put all code in internal RAM. + */ + + esp_rom_printf("alarm isr count=%llu\r\n", edata->count_value); + TEST_ESP_OK(adc_oneshot_read_isr(test_ctx->adc_handle, ADC1_TEST_CHAN0, &adc_raw)); + esp_rom_printf("adc raw: %d\r\n", adc_raw); + if (test_ctx->level) { + TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw); + } else { + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw); + } + + + // check the count value at alarm event + vTaskNotifyGiveFromISR(test_ctx->task_handle, &high_task_wakeup); + return high_task_wakeup == pdTRUE; +} + + +TEST_CASE("ADC oneshot fast work with ISR", "[adc_oneshot]") +{ + static test_adc_isr_ctx_t isr_test_ctx = {}; + isr_test_ctx.adc_handle = NULL; + isr_test_ctx.task_handle = xTaskGetCurrentTaskHandle(); + + //-------------ADC1 Init---------------// + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = false, + }; + TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &isr_test_ctx.adc_handle)); + + //-------------ADC1 TEST Channel 0 Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, + }; + TEST_ESP_OK(adc_oneshot_config_channel(isr_test_ctx.adc_handle, ADC1_TEST_CHAN0, &config)); + + //-------------GPTimer Init & Config---------------// + gptimer_handle_t timer = NULL; + gptimer_config_t timer_config = { + .resolution_hz = 1 * 1000 * 1000, + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + }; + TEST_ESP_OK(gptimer_new_timer(&timer_config, &timer)); + + gptimer_event_callbacks_t cbs = { + .on_alarm = s_alarm_callback, + }; + gptimer_alarm_config_t alarm_config = { + .reload_count = 0, + .alarm_count = 100000, // 100ms + }; + TEST_ESP_OK(gptimer_set_alarm_action(timer, &alarm_config)); + TEST_ESP_OK(gptimer_register_event_callbacks(timer, &cbs, &isr_test_ctx)); + + //ADC IO tile low + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0); + isr_test_ctx.level = 0; + printf("start timer\r\n"); + TEST_ESP_OK(gptimer_enable(timer)); + TEST_ESP_OK(gptimer_start(timer)); + TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); + TEST_ESP_OK(gptimer_stop(timer)); + + + //ADC IO tile high + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1); + isr_test_ctx.level = 1; + //Reset counter value to zero + TEST_ESP_OK(gptimer_set_raw_count(timer, 0)); + printf("start timer\r\n"); + TEST_ESP_OK(gptimer_start(timer)); + TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); + + //Tear Down + TEST_ESP_OK(gptimer_disable(timer)); + TEST_ESP_OK(gptimer_del_timer(timer)); + TEST_ESP_OK(adc_oneshot_del_unit(isr_test_ctx.adc_handle)); +} 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 new file mode 100644 index 0000000000..dd493aec08 --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c @@ -0,0 +1,266 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "unity.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gptimer.h" +#include "esp_rom_sys.h" +#include "test_common_adc.h" +#include "esp_adc/adc_oneshot.h" + +const __attribute__((unused)) static char *TAG = "TEST_ADC"; + +/*--------------------------------------------------------------- + ADC General Macros +---------------------------------------------------------------*/ +//ADC Channels +#if CONFIG_IDF_TARGET_ESP32 +#define ADC1_TEST_CHAN0 ADC_CHANNEL_4 +#else +#define ADC1_TEST_CHAN0 ADC_CHANNEL_2 +#endif + +typedef struct { + void *adc_handle; //ADC handle, could be oneshot / continuous handle + bool level; //ADC level + int adc_raw_high; //ADC reading raw when IO tie high + int cb_exe_times_high; //Callback running times when IO tie high and $ disabled + int adc_raw_low; //ADC reading raw when IO tie low + int cb_exe_times_low; //Callback running times when IO tie low and $ disabled + bool cache_disable_flag; //Indicating cache is disabled +} test_adc_iram_ctx_t; + +extern void spi_flash_disable_interrupts_caches_and_other_cpu(void); +extern void spi_flash_enable_interrupts_caches_and_other_cpu(void); +__attribute__((unused)) +static void s_test_cache_disable_period_us(test_adc_iram_ctx_t *ctx, uint32_t period_us); + + +#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE +/*--------------------------------------------------------------- + ADC oneshot work with cache safe ISR +---------------------------------------------------------------*/ +static bool IRAM_ATTR NOINLINE_ATTR s_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) +{ + test_adc_iram_ctx_t *test_ctx = (test_adc_iram_ctx_t *)user_data; + adc_oneshot_unit_handle_t oneshot_handle = *(adc_oneshot_unit_handle_t *)(test_ctx->adc_handle); + + if (test_ctx->cache_disable_flag) { + + if (test_ctx->level) { + adc_oneshot_read_isr(oneshot_handle, ADC1_TEST_CHAN0, &test_ctx->adc_raw_high); + esp_rom_printf(DRAM_STR("adc raw: %d\n"), test_ctx->adc_raw_high); + test_ctx->cb_exe_times_high++; + } else { + adc_oneshot_read_isr(oneshot_handle, ADC1_TEST_CHAN0, &test_ctx->adc_raw_low); + esp_rom_printf(DRAM_STR("adc raw: %d\n"), test_ctx->adc_raw_low); + test_ctx->cb_exe_times_low++; + } + } + + return false; +} + +TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]") +{ + adc_oneshot_unit_handle_t oneshot_handle; + static DRAM_ATTR test_adc_iram_ctx_t isr_test_ctx = {}; + isr_test_ctx.adc_handle = &oneshot_handle; + + //-------------ADC1 Init---------------// + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = false, + }; + TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &oneshot_handle)); + + //-------------ADC1 TEST Channel 0 Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, + }; + TEST_ESP_OK(adc_oneshot_config_channel(oneshot_handle, ADC1_TEST_CHAN0, &config)); + + //-------------GPTimer Init & Config---------------// + gptimer_handle_t timer = NULL; + gptimer_config_t timer_config = { + .resolution_hz = 1 * 1000 * 1000, + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + }; + TEST_ESP_OK(gptimer_new_timer(&timer_config, &timer)); + + gptimer_event_callbacks_t cbs = { + .on_alarm = s_alarm_cb, + }; + gptimer_alarm_config_t alarm_config = { + .reload_count = 0, + .alarm_count = 100000, // 100ms + .flags.auto_reload_on_alarm = true, + }; + TEST_ESP_OK(gptimer_set_alarm_action(timer, &alarm_config)); + TEST_ESP_OK(gptimer_register_event_callbacks(timer, &cbs, &isr_test_ctx)); + + //ADC IO tile low + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0); + isr_test_ctx.level = 0; + printf("start timer\r\n"); + TEST_ESP_OK(gptimer_enable(timer)); + TEST_ESP_OK(gptimer_start(timer)); + s_test_cache_disable_period_us(&isr_test_ctx, 100 * 1000); + TEST_ESP_OK(gptimer_stop(timer)); + //Checks + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, isr_test_ctx.adc_raw_low); + esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_low); + TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_low); + + //ADC IO tile high + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1); + isr_test_ctx.level = 1; + //Reset counter value to zero + TEST_ESP_OK(gptimer_set_raw_count(timer, 0)); + printf("start timer\r\n"); + TEST_ESP_OK(gptimer_start(timer)); + s_test_cache_disable_period_us(&isr_test_ctx, 100 * 1000); + TEST_ESP_OK(gptimer_stop(timer)); + //Checks + TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, isr_test_ctx.adc_raw_high); + esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_high); + TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_high); + + //Tear Down + TEST_ESP_OK(gptimer_disable(timer)); + TEST_ESP_OK(gptimer_del_timer(timer)); + TEST_ESP_OK(adc_oneshot_del_unit(oneshot_handle)); +} +#endif //#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE + + +#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE +#include "esp_adc/adc_continuous.h" +/*--------------------------------------------------------------- + ADC continuous work with cache safe ISR +---------------------------------------------------------------*/ +#if (SOC_ADC_DIGI_RESULT_BYTES == 2) +#define ADC_TEST_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1 +#else +#define ADC_TEST_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 +#endif + +#define ADC_TEST_FREQ_HZ (50 * 1000) +#define ADC_TEST_PKG_SIZE 100 +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; + + if (test_ctx->cache_disable_flag) { + int raw = 0; + + for (int i = 0; i < edata->size; i += SOC_ADC_DIGI_RESULT_BYTES) { + adc_digi_output_data_t *p = (void*)&(edata->conv_frame_buffer[i]); +#if (SOC_ADC_DIGI_RESULT_BYTES == 2) + raw += p->type1.data; +#else + raw += p->type2.data; +#endif + } + if (test_ctx->level) { + test_ctx->adc_raw_high = raw / (edata->size / SOC_ADC_DIGI_RESULT_BYTES); + test_ctx->cb_exe_times_high++; + } else { + test_ctx->adc_raw_low = raw / (edata->size / SOC_ADC_DIGI_RESULT_BYTES); + test_ctx->cb_exe_times_low++; + } + } + + + return false; +} + +TEST_CASE("ADC continuous work with ISR and Flash", "[adc_oneshot]") +{ + adc_continuous_handle_t handle = NULL; + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = 1024, + .conv_frame_size = ADC_TEST_PKG_SIZE, + }; + TEST_ESP_OK(adc_continuous_new_handle(&adc_config, &handle)); + + 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 = ADC_ATTEN_DB_0; + adc_pattern[0].channel = ADC1_TEST_CHAN0; + 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)); + + static DRAM_ATTR test_adc_iram_ctx_t isr_test_ctx = {}; + isr_test_ctx.adc_handle = &handle; + adc_continuous_evt_cbs_t cbs = { + .on_conv_done = s_conv_done_cb, + }; + TEST_ESP_OK(adc_continuous_register_event_callbacks(handle, &cbs, &isr_test_ctx)); + +#if CONFIG_IDF_TARGET_ESP32 + //This may need to be bigger, when the sampling freq is low + uint32_t overhead_us = 150; +#else + uint32_t overhead_us = 0; +#endif + uint32_t wait_time_us = (1000 * 1000 / ADC_TEST_FREQ_HZ * ADC_TEST_PKG_SIZE / SOC_ADC_DIGI_RESULT_BYTES) + overhead_us; + printf("period is %d us\n", wait_time_us); + + //ADC IO tile low + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 0); + isr_test_ctx.level = 0; + TEST_ESP_OK(adc_continuous_start(handle)); + s_test_cache_disable_period_us(&isr_test_ctx, wait_time_us); + TEST_ESP_OK(adc_continuous_stop(handle)); + //Checks + TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, isr_test_ctx.adc_raw_low); + esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_low); + TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_low); + + vTaskDelay(10); + + printf("to set high\n"); + //ADC IO tile high + test_adc_set_io_level(ADC_UNIT_1, ADC1_TEST_CHAN0, 1); + isr_test_ctx.level = 1; + TEST_ESP_OK(adc_continuous_start(handle)); + s_test_cache_disable_period_us(&isr_test_ctx, wait_time_us); + TEST_ESP_OK(adc_continuous_stop(handle)); + //Checks + // TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL_DMA, isr_test_ctx.adc_raw_high); + esp_rom_printf("callback runs %d times when $ disabled\n", isr_test_ctx.cb_exe_times_high); + TEST_ASSERT_GREATER_OR_EQUAL(1, isr_test_ctx.cb_exe_times_high); + + TEST_ESP_OK(adc_continuous_deinit(handle)); + +} +#endif //#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE + +static void IRAM_ATTR NOINLINE_ATTR s_test_cache_disable_period_us(test_adc_iram_ctx_t *ctx, uint32_t period_us) +{ + spi_flash_disable_interrupts_caches_and_other_cpu(); + ctx->cache_disable_flag = 1; + + esp_rom_delay_us(period_us); + + ctx->cache_disable_flag = 0; + spi_flash_enable_interrupts_caches_and_other_cpu(); +} 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 new file mode 100644 index 0000000000..87814321f8 --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/test_adc_performance.c @@ -0,0 +1,298 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "unity.h" +#include "test_utils.h" +#include "esp_log.h" +#include "esp_err.h" +#include "soc/adc_periph.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_adc/adc_oneshot.h" +#include "test_common_adc.h" + +#if CONFIG_IDF_TARGET_ESP32 || SOC_ADC_CALIBRATION_V1_SUPPORTED + +__attribute__((unused)) static const char *TAG = "TEST_ADC"; + +/*--------------------------------------------------------------- + ADC Oneshot Average / STD_Deviation Test +---------------------------------------------------------------*/ +#define TEST_COUNT (1<= s_adc_offset + MAX_ARRAY_SIZE)) { + TEST_ASSERT_GREATER_OR_EQUAL(s_adc_offset, value); + TEST_ASSERT_LESS_THAN(s_adc_offset + MAX_ARRAY_SIZE, value); + } + + s_adc_count[value - s_adc_offset] ++; + return value - s_adc_offset; +} + +static void s_reset_array(void) +{ + memset(s_adc_count, 0, sizeof(s_adc_count)); + s_adc_offset = -1; +} + +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]; + } + return sum/count; +} + +static void s_print_summary(bool figure) +{ + const int MAX_WIDTH=20; + int max_count = 0; + int start = -1; + 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]; + } + if (s_adc_count[i] > 0 && start < 0) { + start = i; + } + if (s_adc_count[i] > 0) { + end = i; + } + count += s_adc_count[i]; + sum += s_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; + for (int j = 0; j < count; j++) { + putchar('|'); + } + printf(" %d\n", s_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) { + continue; + } + float delta = i + s_adc_offset - average; + variation_square += (delta * delta) * s_adc_count[i]; + } + + printf("%d points.\n", count); + printf("average: %.1f\n", (float)sum/count); + printf("std: %.2f\n", sqrt(variation_square/count)); +} + +#if CONFIG_IDF_TARGET_ESP32 +#define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_6 +#else +#define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_2 +#endif + +TEST_CASE("ADC1 oneshot raw average / std_deviation", "[adc_oneshot][ignore][manual]") +{ + adc_atten_t atten[SOC_ADC_ATTEN_NUM] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_2_5, ADC_ATTEN_DB_6, ADC_ATTEN_DB_11}; + adc_channel_t channel = TEST_STD_ADC1_CHANNEL0; + int raw = 0; + bool print_figure = false; + + //-------------ADC1 Init---------------// + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = false, + }; + TEST_ESP_OK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + //-------------ADC Channel Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = SOC_ADC_RTC_MAX_BITWIDTH, + }; + + //-------------ADC Calibration Init---------------// + bool do_calibration = false; + adc_cali_handle_t cali_handle[SOC_ADC_ATTEN_NUM] = {}; + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + do_calibration = test_adc_calibration_init(ADC_UNIT_1, i, ADC_BITWIDTH_DEFAULT, &cali_handle[i]); + } + if (!do_calibration) { + ESP_LOGW(TAG, "calibration fail, jump calibration\n"); + } + + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + + //-------------ADC1 Channel Config---------------// + config.atten = atten[i]; + TEST_ESP_OK(adc_oneshot_config_channel(adc1_handle, channel, &config)); + ESP_LOGI("TEST_ADC", "Test with atten: %d", atten[i]); + + 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); + } + } + + TEST_ESP_OK(adc_oneshot_del_unit(adc1_handle)); + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + if (cali_handle[i]) { + test_adc_calibration_deinit(cali_handle[i]); + } + } +} + + +/*--------------------------------------------------------------- + ADC Calibration Speed +---------------------------------------------------------------*/ +#ifdef CONFIG_IDF_TARGET_ESP32 +#define CPU_FREQ_MHZ CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ +#elif CONFIG_IDF_TARGET_ESP32S2 +#define CPU_FREQ_MHZ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ +#elif CONFIG_IDF_TARGET_ESP32S3 +#define CPU_FREQ_MHZ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ +#elif CONFIG_IDF_TARGET_ESP32C3 +#define CPU_FREQ_MHZ CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ +#endif + +#define RECORD_TIME_PREPARE() uint32_t __t1, __t2 +#define RECORD_TIME_START() do {__t1 = esp_cpu_get_ccount();}while(0) +#define RECORD_TIME_END(p_time) do{__t2 = esp_cpu_get_ccount(); *p_time = (__t2-__t1);}while(0) +#define GET_US_BY_CCOUNT(t) ((double)t/CPU_FREQ_MHZ) + + +//ADC Channels +#if CONFIG_IDF_TARGET_ESP32 +#define ADC1_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_6 +#define ADC2_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_0 +#else +#define ADC1_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_2 +#define ADC2_CALI_SPEED_TEST_CHAN0 ADC_CHANNEL_0 +#endif + +#define TIMES_PER_ATTEN 10 + + +static IRAM_ATTR NOINLINE_ATTR uint32_t get_cali_time_in_ccount(adc_cali_handle_t cali_handle, int adc_raw) +{ + uint32_t time; + int voltage = 0; + RECORD_TIME_PREPARE(); + RECORD_TIME_START(); + adc_cali_raw_to_voltage(cali_handle, adc_raw, &voltage); + RECORD_TIME_END(&time); + + return time; +} + +static void s_adc_cali_speed(adc_unit_t unit_id, adc_channel_t channel) +{ + //-------------ADC Calibration Init---------------// + bool do_calibration = false; + adc_cali_handle_t cali_handle[SOC_ADC_ATTEN_NUM] = {}; + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + do_calibration = test_adc_calibration_init(unit_id, i, SOC_ADC_RTC_MAX_BITWIDTH, &cali_handle[i]); + } + + if (!do_calibration) { + ESP_LOGW(TAG, "no efuse burnt, jump test"); + } else { + + ESP_LOGI(TAG, "CPU FREQ is %dMHz", CPU_FREQ_MHZ); + adc_atten_t atten[SOC_ADC_ATTEN_NUM] = {ADC_ATTEN_DB_0, ADC_ATTEN_DB_2_5, ADC_ATTEN_DB_6, ADC_ATTEN_DB_11}; + uint32_t adc_time_record[4][TIMES_PER_ATTEN] = {}; + int adc_raw = 0; + + //-------------ADC Init---------------// + adc_oneshot_unit_handle_t adc_handle; + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = unit_id, + .ulp_mode = false, + }; + TEST_ESP_OK(adc_oneshot_new_unit(&init_config, &adc_handle)); + + //-------------ADC Channel Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = SOC_ADC_RTC_MAX_BITWIDTH, + }; + + //atten0 ~ atten3 + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + + //-------------ADC Channel Config---------------// + config.atten = atten[i]; + TEST_ESP_OK(adc_oneshot_config_channel(adc_handle, channel, &config)); + ESP_LOGI("TEST_ADC", "Test with atten: %d", atten[i]); + + for (int j = 0; j < TIMES_PER_ATTEN; j++) { + TEST_ESP_OK(adc_oneshot_read(adc_handle, channel, &adc_raw)); + adc_time_record[i][j] = get_cali_time_in_ccount(cali_handle[i], adc_raw); + IDF_LOG_PERFORMANCE("ADC1 Cali time", "%d us", (int)GET_US_BY_CCOUNT(adc_time_record[i][j])); + } + } + + TEST_ESP_OK(adc_oneshot_del_unit(adc_handle)); + for (int i = 0; i < SOC_ADC_ATTEN_NUM; i++) { + if (cali_handle[i]) { + test_adc_calibration_deinit(cali_handle[i]); + } + } + } +} + +TEST_CASE("ADC1 Calibration Speed", "[adc][ignore][manual]") +{ + s_adc_cali_speed(ADC_UNIT_1, ADC1_CALI_SPEED_TEST_CHAN0); +} + +TEST_CASE("ADC2 Calibration Speed", "[adc][ignore][manual]") +{ + s_adc_cali_speed(ADC_UNIT_2, ADC2_CALI_SPEED_TEST_CHAN0); +} +#endif //#if CONFIG_IDF_TARGET_ESP32 || SOC_ADC_CALIBRATION_V1_SUPPORTED diff --git a/components/esp_adc/test_apps/adc/main/test_app_main.c b/components/esp_adc/test_apps/adc/main/test_app_main.c new file mode 100644 index 0000000000..e19a4c2c37 --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/test_app_main.c @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +#define TEST_MEMORY_LEAK_THRESHOLD (-600) + +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) +{ + unity_run_menu(); +} 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 new file mode 100644 index 0000000000..984ac9516a --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/test_common_adc.c @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include "unity.h" +#include "esp_log.h" +#include "driver/gpio.h" +#include "driver/rtc_io.h" +#include "soc/adc_periph.h" +#include "test_common_adc.h" + +__attribute__((unused)) static const char *TAG = "TEST_ADC"; + +/*--------------------------------------------------------------- + ADC Calibration +---------------------------------------------------------------*/ +bool test_adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_bitwidth_t bitwidth, adc_cali_handle_t *out_handle) +{ + esp_err_t ret = ESP_FAIL; + adc_cali_handle_t handle = NULL; + bool calibrated = false; + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting"); + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = bitwidth, + }; + ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle); + +#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting"); + adc_cali_line_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = bitwidth, + }; + ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle); +#endif + + if (ret == ESP_OK) { + calibrated = true; + } else if (ret == ESP_ERR_NOT_SUPPORTED) { + ESP_LOGW(TAG, "calibration fail due to lack of eFuse bits"); + } else { + TEST_ASSERT(false); + } + + *out_handle = handle; + + return calibrated; +} + +void test_adc_calibration_deinit(adc_cali_handle_t handle) +{ +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + ESP_LOGI(TAG, "deregister %s calibration scheme", "Curve Fitting"); + TEST_ESP_OK(adc_cali_delete_scheme_curve_fitting(handle)); + +#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + ESP_LOGI(TAG, "deregister %s calibration scheme", "Line Fitting"); + TEST_ESP_OK(adc_cali_delete_scheme_line_fitting(handle)); +#endif +} + + +/*--------------------------------------------------------------- + ADC GPIO +---------------------------------------------------------------*/ +#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel]) + +void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level) +{ + TEST_ASSERT(channel < SOC_ADC_CHANNEL_NUM(unit) && "invalid channel"); + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + uint32_t io_num = ADC_GET_IO_NUM(unit, channel); + TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY: GPIO_PULLDOWN_ONLY))); +#else + gpio_num_t io_num = ADC_GET_IO_NUM(unit, channel); + if (level) { + TEST_ESP_OK(rtc_gpio_pullup_en(io_num)); + TEST_ESP_OK(rtc_gpio_pulldown_dis(io_num)); + } else { + TEST_ESP_OK(rtc_gpio_pullup_dis(io_num)); + TEST_ESP_OK(rtc_gpio_pulldown_en(io_num)); + } + TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY: GPIO_PULLDOWN_ONLY))); +#endif +} 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 new file mode 100644 index 0000000000..05a270bf1d --- /dev/null +++ b/components/esp_adc/test_apps/adc/main/test_common_adc.h @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "soc/soc_caps.h" +#include "esp_private/adc_private.h" +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_cali_scheme.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +/*--------------------------------------------------------------- + ADC Calibration +---------------------------------------------------------------*/ +/** + * @brief Initialise ADC Calibration + * + * @param[out] out_handle ADC calibration handle + * + * @return + * - True Calibration success + * - False Calibration fail + */ +bool test_adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_bitwidth_t bitwidth, adc_cali_handle_t *out_handle); + +/** + * @brief De-initialise ADC Calibration + * + * @param[in] handle ADC calibration handle + */ +void test_adc_calibration_deinit(adc_cali_handle_t handle); + + +/*--------------------------------------------------------------- + ADC GPIO +---------------------------------------------------------------*/ +/** + * We use weak pulldown, `ADC_TEST_LOW_THRESH` may vary. + * If connect to GND, `ADC_TEST_LOW_THRESH` can be smaller + */ +#if CONFIG_IDF_TARGET_ESP32 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 10 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_VAL_DMA 4095 +#define ADC_TEST_HIGH_THRESH 10 + +#elif CONFIG_IDF_TARGET_ESP32S2 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 35 + +#define ADC_TEST_HIGH_VAL 8191 +#define ADC_TEST_HIGH_VAL_DMA 4095 +#define ADC_TEST_HIGH_THRESH 10 + +#elif CONFIG_IDF_TARGET_ESP32C3 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 60 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_VAL_DMA 4095 +#define ADC_TEST_HIGH_THRESH 10 + +#elif CONFIG_IDF_TARGET_ESP32S3 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 15 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_VAL_DMA 4095 +#define ADC_TEST_HIGH_THRESH 0 + +#elif CONFIG_IDF_TARGET_ESP32C2 +#define ADC_TEST_LOW_VAL 2147 +#define ADC_TEST_LOW_THRESH 50 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_THRESH 0 +#endif + +/** + * @brief Set ADC IO level + * + * @param[in] unit ADC unit + * @param[in] channel ADC channel + * @param[in] level IO level. True: high; False: low + */ +void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/test_apps/adc/pytest_adc.py b/components/esp_adc/test_apps/adc/pytest_adc.py new file mode 100644 index 0000000000..6bbeb4d5fa --- /dev/null +++ b/components/esp_adc/test_apps/adc/pytest_adc.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.esp32c3 +@pytest.mark.esp32s3 +@pytest.mark.esp32c2 +@pytest.mark.generic +@pytest.mark.parametrize('config', [ + 'iram_safe', + 'release', +], indirect=True) +def test_adc(dut: Dut) -> None: + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('*') + dut.expect_unity_test_output(timeout=120) diff --git a/components/esp_adc/test_apps/adc/sdkconfig.ci.iram_safe b/components/esp_adc/test_apps/adc/sdkconfig.ci.iram_safe new file mode 100644 index 0000000000..f8f19f5dff --- /dev/null +++ b/components/esp_adc/test_apps/adc/sdkconfig.ci.iram_safe @@ -0,0 +1,6 @@ +CONFIG_COMPILER_DUMP_RTL_FILES=y +CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM=y +CONFIG_GPTIMER_ISR_IRAM_SAFE=y +CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y +# silent the error check, as the error string are stored in rodata, causing RTL check failure +CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y diff --git a/components/esp_adc/test_apps/adc/sdkconfig.ci.release b/components/esp_adc/test_apps/adc/sdkconfig.ci.release new file mode 100644 index 0000000000..3cff15d49e --- /dev/null +++ b/components/esp_adc/test_apps/adc/sdkconfig.ci.release @@ -0,0 +1,3 @@ +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_adc/test_apps/adc/sdkconfig.defaults b/components/esp_adc/test_apps/adc/sdkconfig.defaults new file mode 100644 index 0000000000..b308cb2ddd --- /dev/null +++ b/components/esp_adc/test_apps/adc/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n diff --git a/components/esp_adc_cal/CMakeLists.txt b/components/esp_adc_cal/CMakeLists.txt deleted file mode 100644 index 2d1f824147..0000000000 --- a/components/esp_adc_cal/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -idf_build_get_property(target IDF_TARGET) - -set(srcs "esp_adc_cal_common.c") -set(src_target "${target}/esp_adc_cal.c") -if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${src_target}") - list(APPEND srcs ${src_target}) -endif() - -idf_component_register(SRCS ${srcs} - INCLUDE_DIRS include - REQUIRES driver - PRIV_REQUIRES efuse) diff --git a/components/esp_adc_cal/Kconfig b/components/esp_adc_cal/Kconfig deleted file mode 100644 index 800cb6698b..0000000000 --- a/components/esp_adc_cal/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -menu "ADC-Calibration" - - config ADC_CAL_EFUSE_TP_ENABLE - depends on IDF_TARGET_ESP32 - bool "Use Two Point Values" - default "y" - help - Some ESP32s have Two Point calibration values burned into eFuse BLOCK3. - This option will allow the ADC calibration component to characterize the - ADC-Voltage curve using Two Point values if they are available. - - config ADC_CAL_EFUSE_VREF_ENABLE - depends on IDF_TARGET_ESP32 - bool "Use eFuse Vref" - default "y" - help - Some ESP32s have Vref burned into eFuse BLOCK0. This option will allow - the ADC calibration component to characterize the ADC-Voltage curve using - eFuse Vref if it is available. - - config ADC_CAL_LUT_ENABLE - depends on IDF_TARGET_ESP32 - bool "Use Lookup Tables" - default "y" - help - This option will allow the ADC calibration component to use Lookup Tables - to correct for non-linear behavior in 11db attenuation. Other attenuations - do not exhibit non-linear behavior hence will not be affected by this option. - - -endmenu # ADC-Calibration diff --git a/components/esp_phy/CMakeLists.txt b/components/esp_phy/CMakeLists.txt index c5219d8ffc..7c51b79542 100644 --- a/components/esp_phy/CMakeLists.txt +++ b/components/esp_phy/CMakeLists.txt @@ -31,7 +31,7 @@ endif() # [refactor-todo]: requires "driver" component for periph_ctrl header file idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" "${idf_target}/include" - PRIV_REQUIRES nvs_flash driver efuse esp_timer + PRIV_REQUIRES nvs_flash driver efuse esp_timer esp_adc LDFRAGMENTS "${ldfragments}" EMBED_FILES ${embed_files} ) diff --git a/components/esp_phy/src/phy_override.c b/components/esp_phy/src/phy_override.c index dee4f9289d..9ba3700413 100644 --- a/components/esp_phy/src/phy_override.c +++ b/components/esp_phy/src/phy_override.c @@ -5,8 +5,9 @@ */ #include +#include "esp_attr.h" #include "esp_private/regi2c_ctrl.h" -#include "driver/adc.h" +#include "esp_private/adc_private.h" /* * This file is used to override the hooks provided by the PHY lib for some system features. diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index ef8eab80c0..8ee8be6b8b 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -30,7 +30,7 @@ endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" REQUIRES esp_event esp_phy - PRIV_REQUIRES driver esptool_py esp_netif esp_pm esp_timer nvs_flash + PRIV_REQUIRES driver esptool_py esp_netif esp_pm esp_timer nvs_flash esp_adc wpa_supplicant hal lwip ${extra_priv_requires} LDFRAGMENTS "${ldfragments}") diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index c263721352..0f5a9a5a7e 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -15,6 +15,7 @@ #include "esp_private/esp_clk.h" #include "esp_wpa.h" #include "esp_netif.h" +#include "esp_private/adc_private.h" #include "esp_coexist_internal.h" #include "esp_phy_init.h" #include "phy.h" diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 7920e247bf..53f04a40a3 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -44,7 +44,7 @@ if(NOT BOOTLOADER_BUILD) "spi_flash_encrypt_hal_iram.c" "sha_hal.c" "adc_hal_common.c" - "adc_hal.c") + "adc_oneshot_hal.c") if(CONFIG_SOC_SYSTIMER_SUPPORTED AND NOT CONFIG_HAL_SYSTIMER_USE_ROM_IMPL) list(APPEND srcs "systimer_hal.c") @@ -82,6 +82,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "emac_hal.c") endif() + if(CONFIG_SOC_ADC_DMA_SUPPORTED) + list(APPEND srcs "adc_hal.c") + endif() + if(CONFIG_SOC_LCDCAM_SUPPORTED) list(APPEND srcs "lcd_hal.c") endif() @@ -96,7 +100,6 @@ if(NOT BOOTLOADER_BUILD) "sdio_slave_hal.c" "touch_sensor_hal.c" "aes_hal.c" - "esp32/adc_hal.c" "esp32/brownout_hal.c" "esp32/touch_sensor_hal.c" "esp32/gpio_hal_workaround.c") @@ -143,7 +146,6 @@ if(NOT BOOTLOADER_BUILD) "spi_slave_hd_hal.c" "xt_wdt_hal.c" "aes_hal.c" - "esp32c3/adc_hal.c" "esp32c3/brownout_hal.c" "esp32c3/hmac_hal.c" "esp32c3/rtc_cntl_hal.c") diff --git a/components/hal/adc_hal.c b/components/hal/adc_hal.c index 89d02f0a6d..bc974e706c 100644 --- a/components/hal/adc_hal.c +++ b/components/hal/adc_hal.c @@ -25,16 +25,6 @@ #include "soc/spi_struct.h" #endif -#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED -/*--------------------------------------------------------------- - Single Read ----------------------------------------------------------------*/ -/** - * For chips without RTC controller, Digital controller is used to trigger an ADC single read. - */ -#include "esp_rom_sys.h" -#endif //SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED - /*--------------------------------------------------------------- Define all ADC DMA required operations here ---------------------------------------------------------------*/ @@ -190,9 +180,12 @@ static void adc_hal_digi_sample_freq_config(adc_hal_dma_ctx_t *hal, uint32_t fre adc_ll_digi_clk_sel(0); //use APB #else i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_SRC_DEFAULT); /*!< Clock from PLL_D2_CLK(160M)*/ - uint32_t bck = I2S_BASE_CLK / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_B_DEFAULT / ADC_LL_CLKM_DIV_A_DEFAULT) / 2 / freq; - i2s_ll_set_raw_mclk_div(hal->dev, ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT); - i2s_ll_rx_set_bck_div_num(hal->dev, bck); + uint32_t bclk_div = 16; + uint32_t bclk = freq * 2; + uint32_t mclk = bclk * bclk_div; + uint32_t mclk_div = I2S_BASE_CLK / mclk; + i2s_ll_rx_set_mclk(hal->dev, I2S_BASE_CLK, mclk, mclk_div); + i2s_ll_rx_set_bck_div_num(hal->dev, bclk_div); #endif } @@ -231,13 +224,8 @@ void adc_hal_digi_controller_config(adc_hal_dma_ctx_t *hal, const adc_hal_digi_c #endif - if (cfg->conv_limit_en) { - adc_ll_digi_set_convert_limit_num(cfg->conv_limit_num); - adc_ll_digi_convert_limit_enable(); - } else { - adc_ll_digi_convert_limit_disable(); - } - + adc_ll_digi_convert_limit_enable(ADC_LL_DEFAULT_CONV_LIMIT_EN); + adc_ll_digi_set_convert_limit_num(ADC_LL_DEFAULT_CONV_LIMIT_NUM); adc_ll_digi_set_convert_mode(get_convert_mode(cfg->conv_mode)); //clock and sample frequency @@ -277,7 +265,7 @@ void adc_hal_digi_start(adc_hal_dma_ctx_t *hal, uint8_t *data_buf) //reset the current descriptor address hal->cur_desc_ptr = &hal->desc_dummy_head; - adc_hal_digi_dma_link_descriptors(hal->rx_desc, data_buf, hal->eof_num * ADC_HAL_DATA_LEN_PER_CONV, hal->desc_max_num); + adc_hal_digi_dma_link_descriptors(hal->rx_desc, data_buf, hal->eof_num * SOC_ADC_DIGI_DATA_BYTES_PER_CONV, hal->desc_max_num); //start DMA adc_dma_ll_rx_start(hal->dev, hal->dma_chan, (lldesc_t *)hal->rx_desc); @@ -334,67 +322,3 @@ void adc_hal_digi_stop(adc_hal_dma_ctx_t *hal) //disconnect DMA and peripheral adc_ll_digi_dma_disable(); } - - -/*--------------------------------------------------------------- - Single Read ----------------------------------------------------------------*/ -/** - * For chips without RTC controller, Digital controller is used to trigger an ADC single read. - */ - -//--------------------Single Read-------------------------------// -static void adc_hal_onetime_start(adc_unit_t adc_n) -{ -#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED - (void)adc_n; - /** - * There is a hardware limitation. If the APB clock frequency is high, the step of this reg signal: ``onetime_start`` may not be captured by the - * ADC digital controller (when its clock frequency is too slow). A rough estimate for this step should be at least 3 ADC digital controller - * clock cycle. - * - * This limitation will be removed in hardware future versions. - * - */ - uint32_t digi_clk = APB_CLK_FREQ / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1); - //Convert frequency to time (us). Since decimals are removed by this division operation. Add 1 here in case of the fact that delay is not enough. - uint32_t delay = (1000 * 1000) / digi_clk + 1; - //3 ADC digital controller clock cycle - delay = delay * 3; - //This coefficient (8) is got from test. When digi_clk is not smaller than ``APB_CLK_FREQ/8``, no delay is needed. - if (digi_clk >= APB_CLK_FREQ/8) { - delay = 0; - } - - adc_oneshot_ll_start(false); - esp_rom_delay_us(delay); - adc_oneshot_ll_start(true); - - //No need to delay here. Becuase if the start signal is not seen, there won't be a done intr. -#else - adc_oneshot_ll_start(adc_n); -#endif -} - -esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw) -{ - uint32_t event = (adc_n == ADC_UNIT_1) ? ADC_LL_EVENT_ADC1_ONESHOT_DONE : ADC_LL_EVENT_ADC2_ONESHOT_DONE; - adc_oneshot_ll_clear_event(event); - adc_oneshot_ll_disable_all_unit(); - adc_oneshot_ll_enable(adc_n); - adc_oneshot_ll_set_channel(adc_n, channel); - - adc_hal_onetime_start(adc_n); - while (adc_oneshot_ll_get_event(event) != true) { - ; - } - *out_raw = adc_oneshot_ll_get_raw_result(adc_n); - if (adc_oneshot_ll_raw_check_valid(adc_n, *out_raw) == false) { - return ESP_ERR_INVALID_STATE; - } - - //HW workaround: when enabling periph clock, this should be false - adc_oneshot_ll_disable_all_unit(); - - return ESP_OK; -} diff --git a/components/hal/adc_hal_common.c b/components/hal/adc_hal_common.c index f4d4053273..e5e0d29aca 100644 --- a/components/hal/adc_hal_common.c +++ b/components/hal/adc_hal_common.c @@ -19,7 +19,7 @@ static adc_ll_controller_t get_controller(adc_unit_t unit, adc_hal_work_mode_t w if (unit == ADC_UNIT_1) { switch (work_mode) { #if SOC_ULP_SUPPORTED - case ADC_HAL_ULP_MODE: + case ADC_HAL_ULP_FSM_MODE: return ADC_LL_CTRL_ULP; #endif case ADC_HAL_SINGLE_READ_MODE: @@ -36,10 +36,14 @@ static adc_ll_controller_t get_controller(adc_unit_t unit, adc_hal_work_mode_t w } else { switch (work_mode) { #if SOC_ULP_SUPPORTED - case ADC_HAL_ULP_MODE: + case ADC_HAL_ULP_FSM_MODE: return ADC_LL_CTRL_ULP; #endif #if !SOC_ADC_ARBITER_SUPPORTED //No ADC2 arbiter on ESP32 +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + default: + return ADC_LL_CTRL_DIG; +#else case ADC_HAL_SINGLE_READ_MODE: return ADC_LL_CTRL_RTC; case ADC_HAL_CONTINUOUS_READ_MODE: @@ -48,6 +52,7 @@ static adc_ll_controller_t get_controller(adc_unit_t unit, adc_hal_work_mode_t w return ADC_LL_CTRL_PWDET; default: abort(); +#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED #else default: return ADC_LL_CTRL_ARB; diff --git a/components/hal/adc_oneshot_hal.c b/components/hal/adc_oneshot_hal.c new file mode 100644 index 0000000000..e8597f62f3 --- /dev/null +++ b/components/hal/adc_oneshot_hal.c @@ -0,0 +1,180 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "soc/soc_caps.h" +#include "hal/adc_oneshot_hal.h" +#include "hal/adc_hal_common.h" +#include "hal/adc_hal_conf.h" +#include "hal/adc_ll.h" +#include "hal/assert.h" + +#if SOC_DAC_SUPPORTED +#include "hal/dac_ll.h" +#endif + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED +/** + * For chips without RTC controller, Digital controller is used to trigger an ADC single read. + */ +#include "esp_rom_sys.h" +#endif + + +#if SOC_DAC_SUPPORTED +// To disable DAC, workarounds, see this function body to know more +static void s_disable_dac(adc_oneshot_hal_ctx_t *hal, adc_channel_t channel); +#endif + + +void adc_oneshot_hal_init(adc_oneshot_hal_ctx_t *hal, const adc_oneshot_hal_cfg_t *config) +{ + hal->unit = config->unit; + hal->work_mode = config->work_mode; +} + +void adc_oneshot_hal_channel_config(adc_oneshot_hal_ctx_t *hal, const adc_oneshot_hal_chan_cfg_t *config, adc_channel_t chan) +{ + hal->chan_configs[chan].atten = config->atten; + hal->chan_configs[chan].bitwidth = config->bitwidth; +} + +void adc_oneshot_hal_setup(adc_oneshot_hal_ctx_t *hal, adc_channel_t chan) +{ + adc_unit_t unit = hal->unit; + +#ifdef CONFIG_IDF_TARGET_ESP32 + adc_ll_hall_disable(); //Disable other peripherals. + adc_ll_amp_disable(); //Currently the LNA is not open, close it by default. +#endif + +#if SOC_DAC_SUPPORTED + s_disable_dac(hal, chan); +#endif + +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + adc_ll_digi_clk_sel(0); +#else + adc_ll_set_sar_clk_div(unit, ADC_HAL_SAR_CLK_DIV_DEFAULT(unit)); + if (unit == ADC_UNIT_2) { + adc_ll_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); + } +#endif + + adc_oneshot_ll_output_invert(unit, ADC_HAL_DATA_INVERT_DEFAULT(unit)); + adc_oneshot_ll_set_atten(unit, chan, hal->chan_configs[chan].atten); + adc_oneshot_ll_set_output_bits(unit, hal->chan_configs[chan].bitwidth); + adc_oneshot_ll_set_channel(unit, chan); + adc_hal_set_controller(unit, hal->work_mode); + +#if SOC_ADC_ARBITER_SUPPORTED + adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); + adc_hal_arbiter_config(&config); +#endif //#if SOC_ADC_ARBITER_SUPPORTED +} + +static void adc_hal_onetime_start(adc_unit_t unit) +{ +#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED + (void)unit; + /** + * There is a hardware limitation. If the APB clock frequency is high, the step of this reg signal: ``onetime_start`` may not be captured by the + * ADC digital controller (when its clock frequency is too slow). A rough estimate for this step should be at least 3 ADC digital controller + * clock cycle. + * + * This limitation will be removed in hardware future versions. + * + */ + uint32_t digi_clk = APB_CLK_FREQ / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1); + //Convert frequency to time (us). Since decimals are removed by this division operation. Add 1 here in case of the fact that delay is not enough. + uint32_t delay = (1000 * 1000) / digi_clk + 1; + //3 ADC digital controller clock cycle + delay = delay * 3; + //This coefficient (8) is got from test. When digi_clk is not smaller than ``APB_CLK_FREQ/8``, no delay is needed. + if (digi_clk >= APB_CLK_FREQ/8) { + delay = 0; + } + + adc_oneshot_ll_start(false); + esp_rom_delay_us(delay); + adc_oneshot_ll_start(true); + + //No need to delay here. Becuase if the start signal is not seen, there won't be a done intr. +#else + adc_oneshot_ll_start(unit); +#endif +} + +bool adc_oneshot_hal_convert(adc_oneshot_hal_ctx_t *hal, int *out_raw) +{ + bool valid = true; + uint32_t event = 0; + if (hal->unit == ADC_UNIT_1) { + event = ADC_LL_EVENT_ADC1_ONESHOT_DONE; + } else { + event = ADC_LL_EVENT_ADC2_ONESHOT_DONE; + } + + adc_oneshot_ll_clear_event(event); + adc_oneshot_ll_disable_all_unit(); + adc_oneshot_ll_enable(hal->unit); + + adc_hal_onetime_start(hal->unit); + while (!adc_oneshot_ll_get_event(event)) { + ; + } + *out_raw = adc_oneshot_ll_get_raw_result(hal->unit); +#if (SOC_ADC_PERIPH_NUM == 2) + if (hal->unit == ADC_UNIT_2) { + valid = adc_oneshot_ll_raw_check_valid(ADC_UNIT_2, *out_raw); + if (!valid) { + *out_raw = -1; + } + } +#endif + + adc_oneshot_ll_disable_all_unit(); + return valid; +} + +/*--------------------------------------------------------------- + Workarounds +---------------------------------------------------------------*/ +#if SOC_DAC_SUPPORTED +static void s_disable_dac(adc_oneshot_hal_ctx_t *hal, adc_channel_t channel) +{ + /** + * Workaround: Disable the synchronization operation function of ADC1 and DAC. + * If enabled(default), ADC RTC controller sampling will cause the DAC channel output voltage. + */ + if (hal->unit == ADC_UNIT_1) { + dac_ll_rtc_sync_by_adc(false); + } + +#if CONFIG_IDF_TARGET_ESP32 + if (hal->unit == ADC_UNIT_2) { + if (channel == ADC_CHANNEL_8) { + dac_ll_power_down(DAC_CHANNEL_1); // the same as DAC channel 1 + } + if (channel == ADC_CHANNEL_9) { + dac_ll_power_down(DAC_CHANNEL_2); + } + } +#elif CONFIG_IDF_TARGET_ESP32S2 + if (hal->unit == ADC_UNIT_2) { + if (channel == ADC_CHANNEL_6) { + dac_ll_power_down(DAC_CHANNEL_1); // the same as DAC channel 1 + } + if (channel == ADC_CHANNEL_7) { + dac_ll_power_down(DAC_CHANNEL_2); + } + } +#else + //Nothing needed (DAC is only supported on ESP32 and ESP32S2), add this if future chips needs +#endif +} +#endif diff --git a/components/hal/esp32/adc_hal.c b/components/hal/esp32/adc_hal.c deleted file mode 100644 index 49882e205c..0000000000 --- a/components/hal/esp32/adc_hal.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// The HAL layer for ADC (common part) - -#include "hal/adc_hal.h" -#include "hal/adc_hal_conf.h" -#include "hal/adc_types.h" - - -int adc_hal_hall_convert(void) -{ - int Sens_Vp0; - int Sens_Vn0; - int Sens_Vp1; - int Sens_Vn1; - int hall_value; - // convert for 4 times with different phase and outputs - adc_ll_hall_phase_disable(); // hall phase - adc_hal_convert( ADC_UNIT_1, ADC_CHANNEL_0, &Sens_Vp0 ); - adc_hal_convert( ADC_UNIT_1, ADC_CHANNEL_3, &Sens_Vn0 ); - adc_ll_hall_phase_enable(); - adc_hal_convert( ADC_UNIT_1, ADC_CHANNEL_0, &Sens_Vp1 ); - adc_hal_convert( ADC_UNIT_1, ADC_CHANNEL_3, &Sens_Vn1 ); - hall_value = (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0); - return hall_value; -} diff --git a/components/hal/esp32/include/hal/adc_hal.h b/components/hal/esp32/include/hal/adc_hal.h deleted file mode 100644 index 53da0e034b..0000000000 --- a/components/hal/esp32/include/hal/adc_hal.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/******************************************************************************* - * NOTICE - * The hal is not public api, don't use in application code. - * See readme.md in hal/include/hal/readme.md - ******************************************************************************/ - -// The HAL layer for ADC (esp32 specific part) - -#pragma once - -#include "hal/adc_ll.h" -#include "hal/adc_types.h" - -#include_next "hal/adc_hal.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/*--------------------------------------------------------------- - Hall sensor setting ----------------------------------------------------------------*/ -/** - * Start hall convert and return the hall value. - * - * @return Hall value. - */ -int adc_hal_hall_convert(void); - -#ifdef __cplusplus -} -#endif diff --git a/components/hal/esp32/include/hal/adc_ll.h b/components/hal/esp32/include/hal/adc_ll.h index 0da20a58c2..23e9205e2a 100644 --- a/components/hal/esp32/include/hal/adc_ll.h +++ b/components/hal/esp32/include/hal/adc_ll.h @@ -23,6 +23,10 @@ extern "C" { #define ADC_LL_EVENT_ADC1_ONESHOT_DONE (1 << 0) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE (1 << 1) +//On esp32, ADC can only be continuously triggered when `ADC_LL_DEFAULT_CONV_LIMIT_EN == 1`, `ADC_LL_DEFAULT_CONV_LIMIT_NUM != 0` +#define ADC_LL_DEFAULT_CONV_LIMIT_EN 1 +#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 + typedef enum { ADC_POWER_BY_FSM, /*!< ADC XPD controlled by FSM. Used for polling mode */ ADC_POWER_SW_ON, /*!< ADC XPD controlled by SW. power on. Used for DMA mode */ @@ -131,19 +135,13 @@ static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num) /** * Enable max conversion number detection for digital controller. * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * @note On esp32, this should always be 1 to trigger the ADC continuously + * + * @param enable true: enable; false: disable */ -static inline void adc_ll_digi_convert_limit_enable(void) +static inline void adc_ll_digi_convert_limit_enable(bool enable) { - SYSCON.saradc_ctrl2.meas_num_limit = 1; -} - -/** - * Disable max conversion number detection for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - */ -static inline void adc_ll_digi_convert_limit_disable(void) -{ - SYSCON.saradc_ctrl2.meas_num_limit = 0; + SYSCON.saradc_ctrl2.meas_num_limit = enable; } /** @@ -339,7 +337,7 @@ static inline void adc_ll_set_sar_clk_div(adc_unit_t adc_n, uint32_t div) * Set adc output data format for RTC controller. * * @param adc_n ADC unit. - * @param bits Output data bits width option, see ``adc_bits_width_t``. + * @param bits Output data bits width option */ static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth_t bits) { @@ -357,6 +355,9 @@ static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth case ADC_BITWIDTH_12: reg_val = 3; break; + case ADC_BITWIDTH_DEFAULT: + reg_val = 3; + break; default: HAL_ASSERT(false); } diff --git a/components/hal/esp32c2/include/hal/adc_ll.h b/components/hal/esp32c2/include/hal/adc_ll.h index d8e194cac7..775200cf12 100644 --- a/components/hal/esp32c2/include/hal/adc_ll.h +++ b/components/hal/esp32c2/include/hal/adc_ll.h @@ -15,6 +15,7 @@ #include "soc/rtc_cntl_struct.h" #include "soc/rtc_cntl_reg.h" #include "hal/misc.h" +#include "hal/assert.h" #include "hal/adc_types.h" #include "hal/adc_types_private.h" #include "hal/regi2c_ctrl.h" @@ -24,9 +25,9 @@ extern "C" { #endif -#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 -#define ADC_LL_CLKM_DIV_B_DEFAULT 1 -#define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 +#define ADC_LL_CLKM_DIV_B_DEFAULT 1 +#define ADC_LL_CLKM_DIV_A_DEFAULT 0 #define ADC_LL_EVENT_ADC1_ONESHOT_DONE BIT(31) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE BIT(30) @@ -47,43 +48,8 @@ typedef enum { typedef enum { ADC_LL_CTRL_DIG = 0, ///< For ADC1. Select DIG controller. - ADC_LL_CTRL_ARB = 1, ///< For ADC2. The controller is selected by the arbiter. } adc_ll_controller_t; -/** - * @brief ADC digital controller (DMA mode) work mode. - * - * @note The conversion mode affects the sampling frequency: - * ESP32C2 only support ALTER_UNIT mode - * ALTER_UNIT : When the measurement is triggered, ADC1 or ADC2 samples alternately. - */ -typedef enum { - ADC_LL_DIGI_CONV_ALTER_UNIT = 0, // Use both ADC1 and ADC2 for conversion by turn. e.g. ADC1 -> ADC2 -> ADC1 -> ADC2 ..... -} adc_ll_digi_convert_mode_t; - -//These values should be set according to the HW -typedef enum { - ADC_LL_INTR_THRES1_LOW = BIT(26), - ADC_LL_INTR_THRES0_LOW = BIT(27), - ADC_LL_INTR_THRES1_HIGH = BIT(28), - ADC_LL_INTR_THRES0_HIGH = BIT(29), - ADC_LL_INTR_ADC2_DONE = BIT(30), - ADC_LL_INTR_ADC1_DONE = BIT(31), -} adc_ll_intr_t; -FLAG_ATTR(adc_ll_intr_t) - -typedef struct { - union { - struct { - uint8_t atten: 2; - uint8_t channel: 3; - uint8_t unit: 1; - uint8_t reserved: 2; - }; - uint8_t val; - }; -} __attribute__((packed)) adc_ll_digi_pattern_table_t; - /*--------------------------------------------------------------- Digital controller setting ---------------------------------------------------------------*/ @@ -97,13 +63,12 @@ typedef struct { */ static inline void adc_ll_digi_set_fsm_time(uint32_t rst_wait, uint32_t start_wait, uint32_t standby_wait) { - abort(); //TODO IDF-3908 - // // Internal FSM reset wait time - // HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.fsm_wait, rstb_wait, rst_wait); - // // Internal FSM start wait time - // HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.fsm_wait, xpd_wait, start_wait); - // // Internal FSM standby wait time - // HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.fsm_wait, standby_wait, standby_wait); + // Internal FSM reset wait time + HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_fsm_wait, saradc_saradc_rstb_wait, rst_wait); + // Internal FSM start wait time + HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_fsm_wait, saradc_saradc_xpd_wait, start_wait); + // Internal FSM standby wait time + HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_fsm_wait, saradc_saradc_standby_wait, standby_wait); } /** @@ -115,10 +80,9 @@ static inline void adc_ll_digi_set_fsm_time(uint32_t rst_wait, uint32_t start_wa */ static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle) { - abort(); //TODO IDF-3908 - // /* Should be called before writing I2C registers. */ - // SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_SAMPLE_CYCLE_ADDR, sample_cycle); + /* Should be called before writing I2C registers. */ + SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_SAMPLE_CYCLE_ADDR, sample_cycle); } /** @@ -129,105 +93,8 @@ static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle) */ static inline void adc_ll_digi_set_clk_div(uint32_t div) { - abort(); //TODO IDF-3908 - // /* ADC clock devided from digital controller clock clk */ - // HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.ctrl, sar_clk_div, div); -} - -/** - * Set adc max conversion number for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - * - * @param meas_num Max conversion number. Range: 0 ~ 255. - */ -static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num) -{ - abort(); //TODO IDF-3908 - // HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.ctrl2, max_meas_num, meas_num); -} - -/** - * Enable max conversion number detection for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - */ -static inline void adc_ll_digi_convert_limit_enable(void) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl2.meas_num_limit = 1; -} - -/** - * Disable max conversion number detection for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - */ -static inline void adc_ll_digi_convert_limit_disable(void) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl2.meas_num_limit = 0; -} - -/** - * Set adc conversion mode for digital controller. - * - * @note ESP32-C2 only support ADC1 single mode. - * - * @param mode Conversion mode select. - */ -static inline void adc_ll_digi_set_convert_mode(adc_ll_digi_convert_mode_t mode) -{ - //ESP32-C2 only supports ADC_CONV_ALTER_UNIT mode -} - -/** - * Set pattern table length for digital controller. - * The pattern table that defines the conversion rules for each SAR ADC. Each table has 8 items, in which channel selection, - * and attenuation are stored. When the conversion is started, the controller reads conversion rules from the - * pattern table one by one. For each controller the scan sequence has at most 8 different rules before repeating itself. - * - * @param adc_n ADC unit. - * @param patt_len Items range: 1 ~ 8. - */ -static inline void adc_ll_digi_set_pattern_table_len(adc_unit_t adc_n, uint32_t patt_len) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl.sar_patt_len = patt_len - 1; -} - -/** - * Set pattern table for digital controller. - * The pattern table that defines the conversion rules for each SAR ADC. Each table has 8 items, in which channel selection, - * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the - * pattern table one by one. For each controller the scan sequence has at most 8 different rules before repeating itself. - * - * @param adc_n ADC unit. - * @param pattern_index Items index. Range: 0 ~ 7. - * @param pattern Stored conversion rules. - */ -static inline void adc_ll_digi_set_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_config_t table) -{ - abort(); //TODO IDF-3908 - // uint32_t tab; - // uint8_t index = pattern_index / 4; - // uint8_t offset = (pattern_index % 4) * 6; - // adc_ll_digi_pattern_table_t pattern = {0}; - - // pattern.val = (table.atten & 0x3) | ((table.channel & 0x7) << 2) | ((table.unit & 0x1) << 5); - // tab = APB_SARADC.sar_patt_tab[index].sar_patt_tab1; // Read old register value - // tab &= (~(0xFC0000 >> offset)); // Clear old data - // tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; // Fill in the new data - // APB_SARADC.sar_patt_tab[index].sar_patt_tab1 = tab; // Write back -} - -/** - * Reset the pattern table pointer, then take the measurement rule from table header in next measurement. - * - * @param adc_n ADC unit. - */ -static inline void adc_ll_digi_clear_pattern_table(adc_unit_t adc_n) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl.sar_patt_p_clear = 1; - // APB_SARADC.ctrl.sar_patt_p_clear = 0; + /* ADC clock devided from digital controller clock clk */ + HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_ctrl, saradc_saradc_sar_clk_div, div); } /** @@ -238,8 +105,7 @@ static inline void adc_ll_digi_clear_pattern_table(adc_unit_t adc_n) */ static inline void adc_ll_digi_set_arbiter_stable_cycle(uint32_t cycle) { - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl.wait_arb_cycle = cycle; + APB_SARADC.saradc_ctrl.saradc_saradc_wait_arb_cycle = cycle; } /** @@ -250,43 +116,11 @@ static inline void adc_ll_digi_set_arbiter_stable_cycle(uint32_t cycle) */ static inline void adc_ll_digi_output_invert(adc_unit_t adc_n, bool inv_en) { - abort(); //TODO IDF-3908 - // if (adc_n == ADC_UNIT_1) { - // APB_SARADC.ctrl2.sar1_inv = inv_en; // Enable / Disable ADC data invert - // } else { // adc_n == ADC_UNIT_2 - // APB_SARADC.ctrl2.sar2_inv = inv_en; // Enable / Disable ADC data invert - // } -} - -/** - * Set the interval clock cycle for the digital controller to trigger the measurement. - * Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. - * - * @note The trigger interval should not be smaller than the sampling time of the SAR ADC. - * @param cycle The clock cycle (trigger interval) of the measurement. Range: 30 ~ 4095. - */ -static inline void adc_ll_digi_set_trigger_interval(uint32_t cycle) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl2.timer_target = cycle; -} - -/** - * Enable digital controller timer to trigger the measurement. - */ -static inline void adc_ll_digi_trigger_enable(void) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl2.timer_en = 1; -} - -/** - * Disable digital controller timer to trigger the measurement. - */ -static inline void adc_ll_digi_trigger_disable(void) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl2.timer_en = 0; + if (adc_n == ADC_UNIT_1) { + APB_SARADC.saradc_ctrl2.saradc_saradc_sar1_inv = inv_en; // Enable / Disable ADC data invert + } else { // adc_n == ADC_UNIT_2 + APB_SARADC.saradc_ctrl2.saradc_saradc_sar2_inv = inv_en; // Enable / Disable ADC data invert + } } /** @@ -300,9 +134,9 @@ static inline void adc_ll_digi_trigger_disable(void) static inline void adc_ll_digi_controller_clk_div(uint32_t div_num, uint32_t div_b, uint32_t div_a) { abort(); //TODO IDF-3908 - // HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.apb_adc_clkm_conf, clkm_div_num, div_num); - // APB_SARADC.apb_adc_clkm_conf.clkm_div_b = div_b; - // APB_SARADC.apb_adc_clkm_conf.clkm_div_a = div_a; + HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.saradc_apb_adc_clkm_conf, saradc_reg_clkm_div_num, div_num); + APB_SARADC.saradc_apb_adc_clkm_conf.saradc_reg_clkm_div_b = div_b; + APB_SARADC.saradc_apb_adc_clkm_conf.saradc_reg_clkm_div_a = div_a; } /** @@ -312,13 +146,12 @@ static inline void adc_ll_digi_controller_clk_div(uint32_t div_num, uint32_t div */ static inline void adc_ll_digi_clk_sel(bool use_apll) { - abort(); //TODO IDF-3908 - // if (use_apll) { - // APB_SARADC.apb_adc_clkm_conf.clk_sel = 1; // APLL clock - // } else { - // APB_SARADC.apb_adc_clkm_conf.clk_sel = 2; // APB clock - // } - // APB_SARADC.ctrl.sar_clk_gated = 1; + if (use_apll) { + APB_SARADC.saradc_apb_adc_clkm_conf.saradc_reg_clk_sel = 1; // APLL clock + } else { + APB_SARADC.saradc_apb_adc_clkm_conf.saradc_reg_clk_sel = 2; // APB clock + } + APB_SARADC.saradc_ctrl.saradc_saradc_sar_clk_gated = 1; } /** @@ -326,8 +159,7 @@ static inline void adc_ll_digi_clk_sel(bool use_apll) */ static inline void adc_ll_digi_controller_clk_disable(void) { - abort(); //TODO IDF-3908 - // APB_SARADC.ctrl.sar_clk_gated = 0; + APB_SARADC.saradc_ctrl.saradc_saradc_sar_clk_gated = 0; } /** @@ -337,8 +169,7 @@ static inline void adc_ll_digi_controller_clk_disable(void) */ static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) { - abort(); //TODO IDF-3908 - // APB_SARADC.filter_ctrl0.filter_reset = 1; + APB_SARADC.saradc_filter_ctrl0.saradc_filter_reset = 1; } /** @@ -350,14 +181,7 @@ static inline void adc_ll_digi_filter_reset(adc_unit_t adc_n) */ static inline void adc_ll_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) { - abort(); //TODO IDF-3908 - // 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; - // } + abort(); } /** @@ -368,16 +192,7 @@ static inline void adc_ll_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_ */ static inline void adc_ll_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) { - abort(); //TODO IDF-3908 - // 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; - // } + abort(); } /** @@ -389,14 +204,7 @@ static inline void adc_ll_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_ */ static inline void adc_ll_digi_filter_disable(adc_digi_filter_idx_t idx) { - abort(); //TODO IDF-3908 - // 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; - // } + abort(); } /** @@ -409,16 +217,15 @@ static inline void adc_ll_digi_filter_disable(adc_digi_filter_idx_t idx) */ static inline void adc_ll_digi_monitor_set_mode(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *cfg) { - abort(); //TODO IDF-3908 - // if (idx == ADC_DIGI_MONITOR_IDX0) { - // APB_SARADC.thres0_ctrl.thres0_channel = (cfg->adc_unit << 3) | (cfg->channel & 0x7); - // APB_SARADC.thres0_ctrl.thres0_high = cfg->h_threshold; - // APB_SARADC.thres0_ctrl.thres0_low = cfg->l_threshold; - // } else { // ADC_DIGI_MONITOR_IDX1 - // APB_SARADC.thres1_ctrl.thres1_channel = (cfg->adc_unit << 3) | (cfg->channel & 0x7); - // APB_SARADC.thres1_ctrl.thres1_high = cfg->h_threshold; - // APB_SARADC.thres1_ctrl.thres1_low = cfg->l_threshold; - // } + if (idx == ADC_DIGI_MONITOR_IDX0) { + APB_SARADC.saradc_thres0_ctrl.saradc_thres0_channel = (cfg->adc_unit << 3) | (cfg->channel & 0x7); + APB_SARADC.saradc_thres0_ctrl.saradc_thres0_high = cfg->h_threshold; + APB_SARADC.saradc_thres0_ctrl.saradc_thres0_low = cfg->l_threshold; + } else { // ADC_DIGI_MONITOR_IDX1 + APB_SARADC.saradc_thres1_ctrl.saradc_thres1_channel = (cfg->adc_unit << 3) | (cfg->channel & 0x7); + APB_SARADC.saradc_thres1_ctrl.saradc_thres1_high = cfg->h_threshold; + APB_SARADC.saradc_thres1_ctrl.saradc_thres1_low = cfg->l_threshold; + } } /** @@ -429,42 +236,11 @@ static inline void adc_ll_digi_monitor_set_mode(adc_digi_monitor_idx_t idx, adc_ */ static inline void adc_ll_digi_monitor_disable(adc_digi_monitor_idx_t idx) { - abort(); //TODO IDF-3908 - // if (idx == ADC_DIGI_MONITOR_IDX0) { - // APB_SARADC.thres0_ctrl.thres0_channel = 0xF; - // } else { // ADC_DIGI_MONITOR_IDX1 - // APB_SARADC.thres1_ctrl.thres1_channel = 0xF; - // } -} - -/** - * Set DMA eof num of adc digital controller. - * If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated. - * - * @param num eof num of DMA. - */ -static inline void adc_ll_digi_dma_set_eof_num(uint32_t num) -{ - abort(); //TODO IDF-3908 - // HAL_FORCE_MODIFY_U32_REG_FIELD(APB_SARADC.dma_conf, apb_adc_eof_num, num); -} - -/** - * Enable output data to DMA from adc digital controller. - */ -static inline void adc_ll_digi_dma_enable(void) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.dma_conf.apb_adc_trans = 1; -} - -/** - * Disable output data to DMA from adc digital controller. - */ -static inline void adc_ll_digi_dma_disable(void) -{ - abort(); //TODO IDF-3908 - // APB_SARADC.dma_conf.apb_adc_trans = 0; + if (idx == ADC_DIGI_MONITOR_IDX0) { + APB_SARADC.saradc_thres0_ctrl.saradc_thres0_channel = 0xF; + } else { // ADC_DIGI_MONITOR_IDX1 + APB_SARADC.saradc_thres1_ctrl.saradc_thres1_channel = 0xF; + } } /** @@ -472,9 +248,8 @@ static inline void adc_ll_digi_dma_disable(void) */ static inline void adc_ll_digi_reset(void) { - abort(); //TODO IDF-3908 - // APB_SARADC.dma_conf.apb_adc_reset_fsm = 1; - // APB_SARADC.dma_conf.apb_adc_reset_fsm = 0; + APB_SARADC.saradc_dma_conf.saradc_apb_adc_reset_fsm = 1; + APB_SARADC.saradc_dma_conf.saradc_apb_adc_reset_fsm = 0; } /*--------------------------------------------------------------- @@ -488,9 +263,8 @@ static inline void adc_ll_digi_reset(void) */ static inline void adc_ll_pwdet_set_cct(uint32_t cct) { - abort(); //TODO IDF-3908 - // /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ - // RTCCNTL.sensor_ctrl.sar2_pwdet_cct = cct; + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + RTCCNTL.sensor_ctrl.sar2_pwdet_cct = cct; } /** @@ -501,34 +275,8 @@ static inline void adc_ll_pwdet_set_cct(uint32_t cct) */ static inline uint32_t adc_ll_pwdet_get_cct(void) { - abort(); //TODO IDF-3908 - // /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ - // return RTCCNTL.sensor_ctrl.sar2_pwdet_cct; -} - -/** - * Analyze whether the obtained raw data is correct. - * ADC2 can use arbiter. The arbitration result is stored in the channel information of the returned data. - * - * @param adc_n ADC unit. - * @param raw_data ADC raw data input (convert value). - * @return - * - 0: The data is correct to use. - * - -1: The data is invalid. - */ -static inline adc_ll_rtc_raw_data_t adc_ll_analysis_raw_data(adc_unit_t adc_n, int raw_data) -{ - abort(); //TODO IDF-3908 - // if (adc_n == ADC_UNIT_1) { - // return ADC_RTC_DATA_OK; - // } - - // //The raw data API returns value without channel information. Read value directly from the register - // if (((APB_SARADC.apb_saradc2_data_status.adc2_data >> 13) & 0xF) > 9) { - // return ADC_RTC_DATA_FAIL; - // } - - // return ADC_RTC_DATA_OK; + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + return RTCCNTL.sensor_ctrl.sar2_pwdet_cct; } /*--------------------------------------------------------------- @@ -541,19 +289,18 @@ static inline adc_ll_rtc_raw_data_t adc_ll_analysis_raw_data(adc_unit_t adc_n, i */ static inline void adc_ll_set_power_manage(adc_ll_power_t manage) { - abort(); //TODO IDF-3908 - // /* Bit1 0:Fsm 1: SW mode - // Bit0 0:SW mode power down 1: SW mode power on */ - // if (manage == ADC_POWER_SW_ON) { - // APB_SARADC.ctrl.sar_clk_gated = 1; - // APB_SARADC.ctrl.xpd_sar_force = 3; - // } else if (manage == ADC_POWER_BY_FSM) { - // APB_SARADC.ctrl.sar_clk_gated = 1; - // APB_SARADC.ctrl.xpd_sar_force = 0; - // } else if (manage == ADC_POWER_SW_OFF) { - // APB_SARADC.ctrl.sar_clk_gated = 0; - // APB_SARADC.ctrl.xpd_sar_force = 2; - // } + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + if (manage == ADC_POWER_SW_ON) { + APB_SARADC.saradc_ctrl.saradc_saradc_sar_clk_gated = 1; + APB_SARADC.saradc_ctrl.saradc_saradc_xpd_sar_force = 3; + } else if (manage == ADC_POWER_BY_FSM) { + APB_SARADC.saradc_ctrl.saradc_saradc_sar_clk_gated = 1; + APB_SARADC.saradc_ctrl.saradc_saradc_xpd_sar_force = 0; + } else if (manage == ADC_POWER_SW_OFF) { + APB_SARADC.saradc_ctrl.saradc_saradc_sar_clk_gated = 0; + APB_SARADC.saradc_ctrl.saradc_saradc_xpd_sar_force = 2; + } } static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t ctrl) @@ -561,75 +308,6 @@ static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t c //Not used on ESP32-C2 } -/** - * Set ADC2 module arbiter work mode. - * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, - * the low priority controller will read the invalid ADC data, and the validity of the data can be judged by the flag bit in the data. - * - * @note Only ADC2 support arbiter. - * @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode. - * - * @param mode Refer to `adc_arbiter_mode_t`. - */ -static inline void adc_ll_set_arbiter_work_mode(adc_arbiter_mode_t mode) -{ - abort(); //TODO IDF-3908 - // if (mode == ADC_ARB_MODE_FIX) { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_grant_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_fix_priority = 1; - // } else if (mode == ADC_ARB_MODE_LOOP) { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_grant_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_fix_priority = 0; - // } else { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_grant_force = 1; // Shield arbiter. - // } -} - -/** - * Set ADC2 module controller priority in arbiter. - * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, - * the low priority controller will read the invalid ADC data, and the validity of the data can be judged by the flag bit in the data. - * - * @note Only ADC2 support arbiter. - * @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode. - * @note Default priority: Wi-Fi(2) > RTC(1) > Digital(0); - * - * @param pri_rtc RTC controller priority. Range: 0 ~ 2. - * @param pri_dig Digital controller priority. Range: 0 ~ 2. - * @param pri_pwdet Wi-Fi controller priority. Range: 0 ~ 2. - */ -static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig, uint8_t pri_pwdet) -{ - abort(); //TODO IDF-3908 - // if (pri_rtc != pri_dig && pri_rtc != pri_pwdet && pri_dig != pri_pwdet) { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_priority = pri_rtc; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_priority = pri_dig; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_priority = pri_pwdet; - // } - // /* Should select highest priority controller. */ - // if (pri_rtc > pri_dig) { - // if (pri_rtc > pri_pwdet) { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 1; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 0; - // } else { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 1; - // } - // } else { - // if (pri_dig > pri_pwdet) { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 1; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 0; - // } else { - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 0; - // APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 1; - // } - // } -} - /* ADC calibration code. */ /** * @brief Set common calibration configuration. Should be shared with other parts (PWDET). @@ -708,78 +386,21 @@ static inline void adc_ll_set_calibration_param(adc_unit_t adc_n, uint32_t param // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_LOW_ADDR, lsb); // } } -/* Temp code end. */ - -/** - * Output ADCn inter reference voltage to ADC2 channels. - * - * This function routes the internal reference voltage of ADCn to one of - * ADC1's channels. This reference voltage can then be manually measured - * for calibration purposes. - * - * @param[in] adc ADC unit select - * @param[in] channel ADC1 channel number - * @param[in] en Enable/disable the reference voltage output - */ -static inline void adc_ll_vref_output(adc_unit_t adc, adc_channel_t channel, bool en) -{ - abort(); //TODO IDF-3908 - // if (en) { - // REG_SET_FIELD(RTC_CNTL_SENSOR_CTRL_REG, RTC_CNTL_FORCE_XPD_SAR, 3); - // SET_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_REGULATOR_FORCE_PU); - - // REG_SET_FIELD(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_SEL, 2); - // SET_PERI_REG_MASK(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_EN); - // SET_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_GRANT_FORCE); - // SET_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_APB_FORCE); - // APB_SARADC.sar_patt_tab[0].sar_patt_tab1 = 0xFFFFFF; - // APB_SARADC.sar_patt_tab[1].sar_patt_tab1 = 0xFFFFFF; - // APB_SARADC.onetime_sample.adc1_onetime_sample = 1; - // APB_SARADC.onetime_sample.onetime_channel = channel; - // SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU); - // if (adc == ADC_UNIT_1) { - // /* Config test mux to route v_ref to ADC1 Channels */ - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, 1); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 1); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_TSENS_ADDR, 0); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 1); - // } else { - // /* Config test mux to route v_ref to ADC2 Channels */ - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 1); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 0); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_TSENS_ADDR, 0); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 0); - // } - // } else { - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 0); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, 0); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 0); - // REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 0); - // APB_SARADC.onetime_sample.adc1_onetime_sample = 0; - // APB_SARADC.onetime_sample.onetime_channel = 0xf; - // REG_SET_FIELD(RTC_CNTL_SENSOR_CTRL_REG, RTC_CNTL_FORCE_XPD_SAR, 0); - // REG_SET_FIELD(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_SEL, 0); - // CLEAR_PERI_REG_MASK(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_EN); - // CLEAR_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_GRANT_FORCE); - // CLEAR_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_APB_FORCE); - // } -} /*--------------------------------------------------------------- - Single Read + Oneshot Read ---------------------------------------------------------------*/ /** * Set adc output data format for oneshot mode * - * @note ESP32C3 Oneshot mode only supports 12bit. + * @note ESP32C2 Oneshot mode only supports 12bit. * @param adc_n ADC unit. * @param bits Output data bits width option. */ static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth_t bits) { - abort(); //TODO IDF-3908 - // //ESP32C3 only supports 12bit, leave here for compatibility - // HAL_ASSERT(bits == ADC_BITWIDTH_12); + //ESP32C2 only supports 12bit, leave here for compatibility + HAL_ASSERT(bits == ADC_BITWIDTH_12 || bits == ADC_BITWIDTH_DEFAULT); } /** @@ -792,8 +413,8 @@ static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth */ static inline void adc_oneshot_ll_set_channel(adc_unit_t adc_n, adc_channel_t channel) { - abort(); //TODO IDF-3908 - // APB_SARADC.onetime_sample.onetime_channel = ((adc_n << 3) | channel); + HAL_ASSERT(adc_n == ADC_UNIT_1); + APB_SARADC.saradc_onetime_sample.saradc_saradc_onetime_channel = ((adc_n << 3) | channel); } /** @@ -805,12 +426,8 @@ static inline void adc_oneshot_ll_set_channel(adc_unit_t adc_n, adc_channel_t ch */ static inline void adc_oneshot_ll_disable_channel(adc_unit_t adc_n) { - abort(); //TODO IDF-3908 - // if (adc_n == ADC_UNIT_1) { - // APB_SARADC.onetime_sample.onetime_channel = ((adc_n << 3) | 0xF); - // } else { // adc_n == ADC_UNIT_2 - // APB_SARADC.onetime_sample.onetime_channel = ((adc_n << 3) | 0x1); - // } + HAL_ASSERT(adc_n == ADC_UNIT_1); + APB_SARADC.saradc_onetime_sample.saradc_saradc_onetime_channel = ((adc_n << 3) | 0xF); } /** @@ -822,8 +439,7 @@ static inline void adc_oneshot_ll_disable_channel(adc_unit_t adc_n) */ static inline void adc_oneshot_ll_start(bool val) { - abort(); //TODO IDF-3908 - // APB_SARADC.onetime_sample.onetime_start = val; + APB_SARADC.saradc_onetime_sample.saradc_saradc_onetime_start = val; } /** @@ -833,8 +449,7 @@ static inline void adc_oneshot_ll_start(bool val) */ static inline void adc_oneshot_ll_clear_event(uint32_t event_mask) { - abort(); //TODO IDF-3908 - // APB_SARADC.int_clr.val |= event_mask; + APB_SARADC.saradc_int_clr.val |= event_mask; } /** @@ -848,8 +463,7 @@ static inline void adc_oneshot_ll_clear_event(uint32_t event_mask) */ static inline bool adc_oneshot_ll_get_event(uint32_t event_mask) { - abort(); //TODO IDF-3908 - // return (APB_SARADC.int_raw.val & event_mask); + return (APB_SARADC.saradc_int_raw.val & event_mask); } /** @@ -861,14 +475,10 @@ static inline bool adc_oneshot_ll_get_event(uint32_t event_mask) */ static inline uint32_t adc_oneshot_ll_get_raw_result(adc_unit_t adc_n) { - abort(); //TODO IDF-3908 - // uint32_t ret_val = 0; - // if (adc_n == ADC_UNIT_1) { - // ret_val = APB_SARADC.apb_saradc1_data_status.adc1_data & 0xfff; - // } else { // adc_n == ADC_UNIT_2 - // ret_val = APB_SARADC.apb_saradc2_data_status.adc2_data & 0xfff; - // } - // return ret_val; + HAL_ASSERT(adc_n == ADC_UNIT_1); + uint32_t ret_val = 0; + ret_val = APB_SARADC.saradc1_data_status.saradc1_data & 0xfff; + return ret_val; } /** @@ -883,17 +493,8 @@ static inline uint32_t adc_oneshot_ll_get_raw_result(adc_unit_t adc_n) */ static inline bool adc_oneshot_ll_raw_check_valid(adc_unit_t adc_n, uint32_t raw_data) { - abort(); //TODO IDF-3908 - // if (adc_n == ADC_UNIT_1) { - // return true; - // } - - // //The raw data API returns value without channel information. Read value directly from the register - // if (((APB_SARADC.apb_saradc2_data_status.adc2_data >> 13) & 0xF) > 9) { - // return false; - // } - - // return true; + HAL_ASSERT(adc_n == ADC_UNIT_1); + return true; } /** @@ -904,10 +505,9 @@ static inline bool adc_oneshot_ll_raw_check_valid(adc_unit_t adc_n, uint32_t raw */ static inline void adc_oneshot_ll_output_invert(adc_unit_t adc_n, bool inv_en) { - abort(); //TODO IDF-3908 - // (void)adc_n; - // (void)inv_en; - // //For compatibility + (void)adc_n; + (void)inv_en; + //For compatibility } /** @@ -917,12 +517,8 @@ static inline void adc_oneshot_ll_output_invert(adc_unit_t adc_n, bool inv_en) */ static inline void adc_oneshot_ll_enable(adc_unit_t adc_n) { - abort(); //TODO IDF-3908 - // if (adc_n == ADC_UNIT_1) { - // APB_SARADC.onetime_sample.adc1_onetime_sample = 1; - // } else { - // APB_SARADC.onetime_sample.adc2_onetime_sample = 1; - // } + HAL_ASSERT(adc_n == ADC_UNIT_1); + APB_SARADC.saradc_onetime_sample.saradc_saradc1_onetime_sample = 1; } /** @@ -930,9 +526,8 @@ static inline void adc_oneshot_ll_enable(adc_unit_t adc_n) */ static inline void adc_oneshot_ll_disable_all_unit(void) { - abort(); //TODO IDF-3908 - // APB_SARADC.onetime_sample.adc1_onetime_sample = 0; - // APB_SARADC.onetime_sample.adc2_onetime_sample = 0; + APB_SARADC.saradc_onetime_sample.saradc_saradc1_onetime_sample = 0; + APB_SARADC.saradc_onetime_sample.saradc_saradc2_onetime_sample = 0; } /** @@ -946,11 +541,24 @@ static inline void adc_oneshot_ll_disable_all_unit(void) */ static inline void adc_oneshot_ll_set_atten(adc_unit_t adc_n, adc_channel_t channel, adc_atten_t atten) { - abort(); //TODO IDF-3908 - // (void)adc_n; - // (void)channel; - // // Attenuation is for all channels, unit and channel are for compatibility - // APB_SARADC.onetime_sample.onetime_atten = atten; + (void)adc_n; + (void)channel; + // Attenuation is for all channels, unit and channel are for compatibility + APB_SARADC.saradc_onetime_sample.saradc_saradc_onetime_atten = atten; +} + +/** + * Get the attenuation of a particular channel on ADCn. + * + * @param adc_n ADC unit. + * @param channel ADCn channel number. + * @return atten The attenuation option. + */ +static inline adc_atten_t adc_ll_get_atten(adc_unit_t adc_n, adc_channel_t channel) +{ + (void)adc_n; + (void)channel; + return APB_SARADC.saradc_onetime_sample.saradc_saradc_onetime_atten; } #ifdef __cplusplus diff --git a/components/hal/esp32c3/adc_hal.c b/components/hal/esp32c3/adc_hal.c deleted file mode 100644 index 7b21a48d11..0000000000 --- a/components/hal/esp32c3/adc_hal.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// The HAL layer for ADC (ESP32-C3 specific part) - -#include -#include "soc/soc_caps.h" -#include "hal/adc_hal.h" -#include "hal/adc_types.h" -#include "soc/soc.h" - -//Currently we don't have context for the ADC HAL. So HAL variables are temporarily put here. But -//please don't follow this code. Create a context for your own HAL! - -static bool s_filter_enabled[SOC_ADC_DIGI_FILTER_NUM] = {}; -static adc_digi_filter_t s_filter[SOC_ADC_DIGI_FILTER_NUM] = {}; - -static bool s_monitor_enabled[SOC_ADC_DIGI_MONITOR_NUM] = {}; -static adc_digi_monitor_t s_monitor_config[SOC_ADC_DIGI_MONITOR_NUM] = {}; - -/*--------------------------------------------------------------- - Digital controller setting ----------------------------------------------------------------*/ -static void filter_update(adc_digi_filter_idx_t idx) -{ - //ESP32-C3 has no enable bit, the filter will be enabled when the filter channel is configured - if (s_filter_enabled[idx]) { - adc_ll_digi_filter_set_factor(idx, &s_filter[idx]); - } else { - adc_ll_digi_filter_disable(idx); - } -} - -/** - * Set adc digital controller filter factor. - * - * @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). - */ -void adc_hal_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) -{ - s_filter[idx] = *filter; - filter_update(idx); -} - -/** - * 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). - */ -void adc_hal_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter) -{ - *filter = s_filter[idx]; -} - -void adc_hal_digi_filter_enable(adc_digi_filter_idx_t filter_idx, bool enable) -{ - s_filter_enabled[filter_idx] = enable; - filter_update(filter_idx); -} - -static void update_monitor(adc_digi_monitor_idx_t idx) -{ - //ESP32-C3 has no enable bit, the monitor will be enabled when the monitor channel is configured - if (s_monitor_enabled[idx]) { - adc_ll_digi_monitor_set_mode(idx, &s_monitor_config[idx]); - } else { - adc_ll_digi_monitor_disable(idx); - } -} - -void adc_hal_digi_monitor_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config) -{ - s_monitor_config[idx] = *config; - update_monitor(idx); -} - -void adc_hal_digi_monitor_enable(adc_digi_monitor_idx_t mon_idx, bool enable) -{ - s_monitor_enabled[mon_idx] = enable; - update_monitor(mon_idx); -} diff --git a/components/hal/esp32c3/include/hal/adc_hal.h b/components/hal/esp32c3/include/hal/adc_hal.h deleted file mode 100644 index bf4794377a..0000000000 --- a/components/hal/esp32c3/include/hal/adc_hal.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/******************************************************************************* - * NOTICE - * The hal is not public api, don't use in application code. - * See readme.md in soc/include/hal/readme.md - ******************************************************************************/ - -// The HAL layer for ADC (esp32s2 specific part) - -#pragma once - -#include "hal/adc_ll.h" -#include "hal/adc_types.h" - -#include_next "hal/adc_hal.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/*--------------------------------------------------------------- - Digital controller setting ----------------------------------------------------------------*/ -/** - * Reset adc digital controller filter. - * - * @param filter_idx ADC filter unit. - */ -#define adc_hal_digi_filter_reset(filter_idx) adc_ll_digi_filter_reset(filter_idx) - -/** - * Set adc digital controller filter factor. - * - * @param filter_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). - */ -void adc_hal_digi_filter_set_factor(adc_digi_filter_idx_t filter_idx, adc_digi_filter_t *filter); - -/** - * Get adc digital controller filter factor. - * - * @param filter_idx ADC filter unit. - * @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64). - */ -void adc_hal_digi_filter_get_factor(adc_digi_filter_idx_t filter_idx, adc_digi_filter_t *filter); - -/** - * 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 filter_idx ADC filter unit. - * @param enable True to enable the filter, otherwise disable. - */ -void adc_hal_digi_filter_enable(adc_digi_filter_idx_t filter_idx, bool enable); - -/** - * Config monitor of adc digital controller. - * - * @note If the channel info is not supported, the monitor function will not be enabled. - * @param mon_idx ADC monitor index. - * @param config Refer to `adc_digi_monitor_t`. - */ -void adc_hal_digi_monitor_config(adc_digi_monitor_idx_t mon_idx, adc_digi_monitor_t *config); - -/** - * Enable/disable monitor of adc digital controller. - * - * @note The monitor will monitor all the enabled channel data of the each ADC unit at the same time. - * @param mon_idx ADC monitor index. - * @param enable True to enable the monitor, otherwise disable. - */ -void adc_hal_digi_monitor_enable(adc_digi_monitor_idx_t mon_idx, bool enable); - -#ifdef __cplusplus -} -#endif diff --git a/components/hal/esp32c3/include/hal/adc_ll.h b/components/hal/esp32c3/include/hal/adc_ll.h index 8bf642b3ef..2ebd50501d 100644 --- a/components/hal/esp32c3/include/hal/adc_ll.h +++ b/components/hal/esp32c3/include/hal/adc_ll.h @@ -26,9 +26,11 @@ extern "C" { #endif -#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 -#define ADC_LL_CLKM_DIV_B_DEFAULT 1 -#define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 +#define ADC_LL_CLKM_DIV_B_DEFAULT 1 +#define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_EN 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 #define ADC_LL_EVENT_ADC1_ONESHOT_DONE BIT(31) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE BIT(30) @@ -140,19 +142,12 @@ static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num) /** * Enable max conversion number detection for digital controller. * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param enable true: enable; false: disable */ -static inline void adc_ll_digi_convert_limit_enable(void) +static inline void adc_ll_digi_convert_limit_enable(bool enable) { - APB_SARADC.ctrl2.meas_num_limit = 1; -} - -/** - * Disable max conversion number detection for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - */ -static inline void adc_ll_digi_convert_limit_disable(void) -{ - APB_SARADC.ctrl2.meas_num_limit = 0; + APB_SARADC.ctrl2.meas_num_limit = enable; } /** @@ -710,7 +705,7 @@ static inline void adc_ll_vref_output(adc_unit_t adc, adc_channel_t channel, boo static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth_t bits) { //ESP32C3 only supports 12bit, leave here for compatibility - HAL_ASSERT(bits == ADC_BITWIDTH_12); + HAL_ASSERT(bits == ADC_BITWIDTH_12 || bits == ADC_BITWIDTH_DEFAULT); } /** @@ -873,6 +868,20 @@ static inline void adc_oneshot_ll_set_atten(adc_unit_t adc_n, adc_channel_t chan APB_SARADC.onetime_sample.onetime_atten = atten; } +/** + * Get the attenuation of a particular channel on ADCn. + * + * @param adc_n ADC unit. + * @param channel ADCn channel number. + * @return atten The attenuation option. + */ +static inline adc_atten_t adc_ll_get_atten(adc_unit_t adc_n, adc_channel_t channel) +{ + (void)adc_n; + (void)channel; + return APB_SARADC.onetime_sample.onetime_atten; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/adc_ll.h b/components/hal/esp32h2/include/hal/adc_ll.h index 086d70b578..bdef1ceac0 100644 --- a/components/hal/esp32h2/include/hal/adc_ll.h +++ b/components/hal/esp32h2/include/hal/adc_ll.h @@ -25,9 +25,11 @@ extern "C" { #endif -#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 -#define ADC_LL_CLKM_DIV_B_DEFAULT 1 -#define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 +#define ADC_LL_CLKM_DIV_B_DEFAULT 1 +#define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_EN 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 #define ADC_LL_EVENT_ADC1_ONESHOT_DONE BIT(31) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE BIT(30) @@ -146,19 +148,12 @@ static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num) /** * Enable max conversion number detection for digital controller. * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param enable true: enable; false: disable */ -static inline void adc_ll_digi_convert_limit_enable(void) +static inline void adc_ll_digi_convert_limit_enable(bool enable) { - APB_SARADC.ctrl2.meas_num_limit = 1; -} - -/** - * Disable max conversion number detection for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - */ -static inline void adc_ll_digi_convert_limit_disable(void) -{ - APB_SARADC.ctrl2.meas_num_limit = 0; + APB_SARADC.ctrl2.meas_num_limit = enable; } /** diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index 6fc82a2b11..2f99cf7b61 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -28,6 +28,8 @@ extern "C" { #define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 #define ADC_LL_CLKM_DIV_B_DEFAULT 1 #define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_EN 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 #define ADC_LL_EVENT_ADC1_ONESHOT_DONE (1 << 0) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE (1 << 1) @@ -161,19 +163,12 @@ static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num) /** * Enable max conversion number detection for digital controller. * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param enable true: enable; false: disable */ -static inline void adc_ll_digi_convert_limit_enable(void) +static inline void adc_ll_digi_convert_limit_enable(bool enable) { - APB_SARADC.ctrl2.meas_num_limit = 1; -} - -/** - * Disable max conversion number detection for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - */ -static inline void adc_ll_digi_convert_limit_disable(void) -{ - APB_SARADC.ctrl2.meas_num_limit = 0; + APB_SARADC.ctrl2.meas_num_limit = enable; } /** @@ -596,7 +591,7 @@ static inline void adc_ll_set_sar_clk_div(adc_unit_t adc_n, uint32_t div) static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth_t bits) { //ESP32S2 only supports 13bit, leave here for compatibility - HAL_ASSERT(bits == ADC_BITWIDTH_13); + HAL_ASSERT(bits == ADC_BITWIDTH_13 || bits == ADC_BITWIDTH_DEFAULT); } /** diff --git a/components/hal/esp32s3/include/hal/adc_ll.h b/components/hal/esp32s3/include/hal/adc_ll.h index c73f92ad88..ae4384c9bb 100644 --- a/components/hal/esp32s3/include/hal/adc_ll.h +++ b/components/hal/esp32s3/include/hal/adc_ll.h @@ -29,6 +29,8 @@ extern "C" { #define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 #define ADC_LL_CLKM_DIV_B_DEFAULT 1 #define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_EN 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 #define ADC_LL_EVENT_ADC1_ONESHOT_DONE (1 << 0) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE (1 << 1) @@ -172,19 +174,12 @@ static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num) /** * Enable max conversion number detection for digital controller. * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param enable true: enable; false: disable */ -static inline void adc_ll_digi_convert_limit_enable(void) +static inline void adc_ll_digi_convert_limit_enable(bool enable) { - APB_SARADC.ctrl2.meas_num_limit = 1; -} - -/** - * Disable max conversion number detection for digital controller. - * If the number of ADC conversion is equal to the maximum, the conversion is stopped. - */ -static inline void adc_ll_digi_convert_limit_disable(void) -{ - APB_SARADC.ctrl2.meas_num_limit = 0; + APB_SARADC.ctrl2.meas_num_limit = enable; } /** @@ -810,7 +805,7 @@ static inline void adc_ll_set_sar_clk_div(adc_unit_t adc_n, uint32_t div) static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth_t bits) { //ESP32S3 only supports 12bit, leave here for compatibility - HAL_ASSERT(bits == ADC_BITWIDTH_12); + HAL_ASSERT(bits == ADC_BITWIDTH_12 || bits == ADC_BITWIDTH_DEFAULT); } /** diff --git a/components/hal/include/hal/adc_hal.h b/components/hal/include/hal/adc_hal.h index 381b3fb5c6..a88b1e7669 100644 --- a/components/hal/include/hal/adc_hal.h +++ b/components/hal/include/hal/adc_hal.h @@ -41,9 +41,6 @@ extern "C" { #define ADC_HAL_DMA_INTR_MASK BIT(9) #endif -//For ADC module, each conversion contains 4 bytes -#define ADC_HAL_DATA_LEN_PER_CONV 4 - /** * @brief Enum for DMA descriptor status */ @@ -82,8 +79,6 @@ typedef struct adc_hal_dma_ctx_t { } adc_hal_dma_ctx_t; typedef struct adc_hal_digi_ctrlr_cfg_t { - bool conv_limit_en; //1: adc conversion will stop when `conv_limit_num` reaches. 0: won't stop. NOTE: esp32 should always be set to 1. - uint32_t conv_limit_num; //see `conv_limit_en` uint32_t adc_pattern_len; //total pattern item number, including ADC1 and ADC2 adc_digi_pattern_config_t *adc_pattern; //pattern item uint32_t sample_freq_hz; //ADC sample frequency @@ -231,25 +226,6 @@ void adc_hal_digi_dis_intr(adc_hal_dma_ctx_t *hal, uint32_t mask); */ void adc_hal_digi_stop(adc_hal_dma_ctx_t *hal); - -/*--------------------------------------------------------------- - ADC Single Read ----------------------------------------------------------------*/ -/** - * Start an ADC conversion and get the converted value. - * - * @note It may be block to wait conversion finish. - * - * @param adc_n ADC unit. - * @param channel ADC channel number. - * @param[out] out_raw ADC converted result - * - * @return - * - ESP_OK: The value is valid. - * - ESP_ERR_INVALID_STATE: The value is invalid. - */ -esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw); - #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/adc_hal_common.h b/components/hal/include/hal/adc_hal_common.h index 9329220805..11503873e9 100644 --- a/components/hal/include/hal/adc_hal_common.h +++ b/components/hal/include/hal/adc_hal_common.h @@ -23,10 +23,10 @@ extern "C" { * ADC work mode */ typedef enum adc_hal_work_mode_t { - ADC_HAL_ULP_MODE, ADC_HAL_SINGLE_READ_MODE, ADC_HAL_CONTINUOUS_READ_MODE, - ADC_HAL_PWDET_MODE + ADC_HAL_PWDET_MODE, + ADC_HAL_ULP_FSM_MODE, } adc_hal_work_mode_t; /** diff --git a/components/hal/include/hal/adc_oneshot_hal.h b/components/hal/include/hal/adc_oneshot_hal.h new file mode 100644 index 0000000000..850466d422 --- /dev/null +++ b/components/hal/include/hal/adc_oneshot_hal.h @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "hal/adc_types.h" +#include "hal/adc_hal_common.h" +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct sens_dev_t *adc_oneshot_soc_handle_t; + +typedef struct adc_oneshot_hal_cfg_t { + adc_unit_t unit; ///< ADC unit + adc_hal_work_mode_t work_mode; ///< ADC work mode +} adc_oneshot_hal_cfg_t; + +/** + * ADC channel configuration + */ +typedef struct adc_oneshot_hal_chan_cfg_t { + adc_atten_t atten; ///< ADC attenuation + adc_bitwidth_t bitwidth; ///< ADC conversion result bits +} adc_oneshot_hal_chan_cfg_t; + +/** + * Context of the ADC unit, should be maintained by both the driver and the HAL. + */ +typedef struct adc_oneshot_hal_ctx_t { + /* This should be configured by driver in initialisation, dou't touch again */ + adc_oneshot_soc_handle_t dev; ///< ADC SoC layer handle + + /* These should be malloced by the driver first */ + adc_unit_t unit; ///< ADC unit + adc_hal_work_mode_t work_mode; ///< ADC work mode + adc_oneshot_hal_chan_cfg_t chan_configs[SOC_ADC_MAX_CHANNEL_NUM]; ///< ADC configurations per channel +} adc_oneshot_hal_ctx_t; + +/** + * Initialise the context + * + * @param hal ADC Oneshot Hal context + * @param config ADC Oneshot Hal init config + */ +void adc_oneshot_hal_init(adc_oneshot_hal_ctx_t *hal, const adc_oneshot_hal_cfg_t *config); + +/** + * Prepare ADC Oneshot hal context + * + * @param hal ADC Oneshot Hal context + * @param config ADC Oneshot Hal configuration + * @param chan ADC Channel + */ +void adc_oneshot_hal_channel_config(adc_oneshot_hal_ctx_t *hal, const adc_oneshot_hal_chan_cfg_t *config, adc_channel_t chan); + +/** + * Set ADC Oneshot mode required registers + * + * @param hal ADC Oneshot Hal context + * @param channel ADC Channel + */ +void adc_oneshot_hal_setup(adc_oneshot_hal_ctx_t *hal, adc_channel_t channel); + +/** + * Start ADC conversion in Oneshot mode and get the raw result + * + * @param hal ADC Oneshot Hal context + * @param[out] out_raw ADC oneshot conversion raw result + * + * @return + * - true: ADC raw result is valid + * - false: ADC raw result is invalid + */ +bool adc_oneshot_hal_convert(adc_oneshot_hal_ctx_t *hal, int *out_raw); + + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/adc_types.h b/components/hal/include/hal/adc_types.h index 7762152ed0..fd27771223 100644 --- a/components/hal/include/hal/adc_types.h +++ b/components/hal/include/hal/adc_types.h @@ -36,42 +36,29 @@ typedef enum { } adc_channel_t; /** - * @brief ADC attenuation parameter. Different parameters determine the range of the ADC. See ``adc1_config_channel_atten``. + * @brief ADC attenuation parameter. Different parameters determine the range of the ADC. */ typedef enum { - ADC_ATTEN_DB_0 = 0, /// ADC2 -> ADC1 -> ADC2 ..... - ADC_CONV_UNIT_MAX, } adc_digi_convert_mode_t; /** * @brief ADC digital controller (DMA mode) output data format option. */ typedef enum { - ADC_DIGI_FORMAT_12BIT __attribute__((deprecated)), /*! ADC_CHANNEL_MAX), The data is invalid. */ uint16_t unit: 1; /*! ADC_CHANNEL_MAX), The data is invalid. */ uint32_t unit: 1; /*! ADC_CHANNEL_MAX), The data is invalid. */ uint32_t unit: 1; /*! threshold, Generates monitor interrupt. - * MONITOR_LOW: If ADC_OUT < threshold, Generates monitor interrupt. - */ -typedef enum { -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 - ADC_DIGI_MONITOR_DIS = 0, /*! threshold, Generates monitor interrupt. */ -#else - ADC_DIGI_MONITOR_HIGH = 0, /*! threshold, Generates monitor interrupt. */ - ADC_DIGI_MONITOR_LOW, /*! threshold, Generates monitor interrupt. + * MONITOR_LOW: If ADC_OUT < threshold, Generates monitor interrupt. + */ +typedef enum { +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 + ADC_DIGI_MONITOR_DIS = 0, /*! threshold, Generates monitor interrupt. */ +#else + ADC_DIGI_MONITOR_HIGH = 0, /*! threshold, Generates monitor interrupt. */ + ADC_DIGI_MONITOR_LOW, /*! #include #include #include "unity.h" -#include "driver/adc.h" #include #include #include "freertos/FreeRTOS.h" diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 0b2c939045..91a4e740ea 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -131,6 +131,10 @@ config SOC_ADC_DIG_CTRL_SUPPORTED bool default y +config SOC_ADC_DMA_SUPPORTED + bool + default y + config SOC_ADC_PERIPH_NUM int default 2 @@ -159,13 +163,21 @@ config SOC_ADC_DIGI_MAX_BITWIDTH int default 12 +config SOC_ADC_DIGI_RESULT_BYTES + int + default 2 + +config SOC_ADC_DIGI_DATA_BYTES_PER_CONV + int + default 4 + config SOC_ADC_SAMPLE_FREQ_THRES_HIGH int default 2 config SOC_ADC_SAMPLE_FREQ_THRES_LOW int - default 2000 + default 20 config SOC_ADC_RTC_MIN_BITWIDTH int diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 4dc8c4111c..26e5909fd2 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -96,17 +96,10 @@ #define SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL (5U) /*-------------------------- ADC CAPS ----------------------------------------*/ -/** - * TO BE REMOVED - * Check if adc support digital controller (DMA) mode. - * - 1 : support; - * - 0 : not support; - */ -#define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) ((PERIPH_NUM==0)? 1: 0) - /*!< SAR ADC Module*/ #define SOC_ADC_RTC_CTRL_SUPPORTED 1 #define SOC_ADC_DIG_CTRL_SUPPORTED 1 +#define SOC_ADC_DMA_SUPPORTED 1 #define SOC_ADC_PERIPH_NUM (2) #define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 8: 10) #define SOC_ADC_MAX_CHANNEL_NUM (10) @@ -117,9 +110,10 @@ #define SOC_ADC_PATT_LEN_MAX (16) //Two pattern table, each contains 16 items. Each item takes 1 byte. But only support ADC1 using DMA mode #define SOC_ADC_DIGI_MIN_BITWIDTH (9) #define SOC_ADC_DIGI_MAX_BITWIDTH (12) -/*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */ +#define SOC_ADC_DIGI_RESULT_BYTES (2) +#define SOC_ADC_DIGI_DATA_BYTES_PER_CONV (4) #define SOC_ADC_SAMPLE_FREQ_THRES_HIGH (2*1000*1000) -#define SOC_ADC_SAMPLE_FREQ_THRES_LOW (2000) +#define SOC_ADC_SAMPLE_FREQ_THRES_LOW (20*1000) /*!< RTC */ #define SOC_ADC_RTC_MIN_BITWIDTH (9) diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index f5d95c6429..50fc498e26 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -67,10 +67,6 @@ config SOC_ADC_DIG_CTRL_SUPPORTED bool default y -config SOC_ADC_ARBITER_SUPPORTED - bool - default y - config SOC_ADC_FILTER_SUPPORTED bool default y @@ -89,7 +85,7 @@ config SOC_ADC_MAX_CHANNEL_NUM config SOC_ADC_ATTEN_NUM int - default 2 + default 4 config SOC_ADC_DIGI_CONTROLLER_NUM int @@ -99,6 +95,10 @@ config SOC_ADC_PATT_LEN_MAX int default 8 +config SOC_ADC_DIGI_MIN_BITWIDTH + int + default 12 + config SOC_ADC_DIGI_MAX_BITWIDTH int default 12 diff --git a/components/soc/esp32c2/include/soc/adc_channel.h b/components/soc/esp32c2/include/soc/adc_channel.h index ca1182f47b..747d8a4b13 100644 --- a/components/soc/esp32c2/include/soc/adc_channel.h +++ b/components/soc/esp32c2/include/soc/adc_channel.h @@ -6,19 +6,19 @@ #pragma once -#define ADC1_GPIO1_CHANNEL ADC1_CHANNEL_0 +#define ADC1_GPIO0_CHANNEL ADC1_CHANNEL_0 #define ADC1_CHANNEL_0_GPIO_NUM 0 -#define ADC1_GPIO2_CHANNEL ADC1_CHANNEL_1 +#define ADC1_GPIO1_CHANNEL ADC1_CHANNEL_1 #define ADC1_CHANNEL_1_GPIO_NUM 1 -#define ADC1_GPIO3_CHANNEL ADC1_CHANNEL_2 +#define ADC1_GPIO2_CHANNEL ADC1_CHANNEL_2 #define ADC1_CHANNEL_2_GPIO_NUM 2 -#define ADC1_GPIO4_CHANNEL ADC1_CHANNEL_3 +#define ADC1_GPIO3_CHANNEL ADC1_CHANNEL_3 #define ADC1_CHANNEL_3_GPIO_NUM 3 -#define ADC1_GPIO5_CHANNEL ADC1_CHANNEL_4 +#define ADC1_GPIO4_CHANNEL ADC1_CHANNEL_4 #define ADC1_CHANNEL_4_GPIO_NUM 4 #define ADC2_GPIO5_CHANNEL ADC2_CHANNEL_0 diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 080debf2db..f59babe4f5 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -44,17 +44,17 @@ /*-------------------------- ADC CAPS -------------------------------*/ /*!< SAR ADC Module*/ #define SOC_ADC_DIG_CTRL_SUPPORTED 1 -#define SOC_ADC_ARBITER_SUPPORTED 1 #define SOC_ADC_FILTER_SUPPORTED 1 #define SOC_ADC_MONITOR_SUPPORTED 1 #define SOC_ADC_PERIPH_NUM (1U) -#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 5 : 0) +#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (5) #define SOC_ADC_MAX_CHANNEL_NUM (5) -#define SOC_ADC_ATTEN_NUM (2) +#define SOC_ADC_ATTEN_NUM (4) /*!< Digital */ #define SOC_ADC_DIGI_CONTROLLER_NUM (1U) #define SOC_ADC_PATT_LEN_MAX (8) /*!< One pattern table, each contains 8 items. Each item takes 1 byte */ +#define SOC_ADC_DIGI_MIN_BITWIDTH (12) #define SOC_ADC_DIGI_MAX_BITWIDTH (12) #define SOC_ADC_DIGI_FILTER_NUM (2) #define SOC_ADC_DIGI_MONITOR_NUM (2) diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index cfaa1a590a..e3a4b417c1 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -143,6 +143,10 @@ config SOC_ADC_MONITOR_SUPPORTED bool default y +config SOC_ADC_DMA_SUPPORTED + bool + default y + config SOC_ADC_PERIPH_NUM int default 2 @@ -163,10 +167,22 @@ config SOC_ADC_PATT_LEN_MAX int default 8 +config SOC_ADC_DIGI_MIN_BITWIDTH + int + default 12 + config SOC_ADC_DIGI_MAX_BITWIDTH int default 12 +config SOC_ADC_DIGI_RESULT_BYTES + int + default 4 + +config SOC_ADC_DIGI_DATA_BYTES_PER_CONV + int + default 4 + config SOC_ADC_DIGI_FILTER_NUM int default 2 diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 32b1dc836a..b05d35de52 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -71,6 +71,7 @@ #define SOC_ADC_ARBITER_SUPPORTED 1 #define SOC_ADC_FILTER_SUPPORTED 1 #define SOC_ADC_MONITOR_SUPPORTED 1 +#define SOC_ADC_DMA_SUPPORTED 1 #define SOC_ADC_PERIPH_NUM (2) #define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 5 : 1) #define SOC_ADC_MAX_CHANNEL_NUM (5) @@ -79,7 +80,10 @@ /*!< Digital */ #define SOC_ADC_DIGI_CONTROLLER_NUM (1U) #define SOC_ADC_PATT_LEN_MAX (8) /*!< One pattern table, each contains 8 items. Each item takes 1 byte */ +#define SOC_ADC_DIGI_MIN_BITWIDTH (12) #define SOC_ADC_DIGI_MAX_BITWIDTH (12) +#define SOC_ADC_DIGI_RESULT_BYTES (4) +#define SOC_ADC_DIGI_DATA_BYTES_PER_CONV (4) #define SOC_ADC_DIGI_FILTER_NUM (2) #define SOC_ADC_DIGI_MONITOR_NUM (2) /*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */ diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 47a9bf1f48..89df534a9b 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -131,6 +131,10 @@ config SOC_ADC_MONITOR_SUPPORTED bool default y +config SOC_ADC_DMA_SUPPORTED + bool + default y + config SOC_ADC_PERIPH_NUM int default 1 @@ -151,10 +155,22 @@ config SOC_ADC_PATT_LEN_MAX int default 8 +config SOC_ADC_DIGI_MIN_BITWIDTH + int + default 12 + config SOC_ADC_DIGI_MAX_BITWIDTH int default 12 +config SOC_ADC_DIGI_RESULT_BYTES + int + default 4 + +config SOC_ADC_DIGI_DATA_BYTES_PER_CONV + int + default 4 + config SOC_ADC_DIGI_FILTER_NUM int default 2 diff --git a/components/soc/esp32h2/include/soc/adc_channel.h b/components/soc/esp32h2/include/soc/adc_channel.h index ca1182f47b..747d8a4b13 100644 --- a/components/soc/esp32h2/include/soc/adc_channel.h +++ b/components/soc/esp32h2/include/soc/adc_channel.h @@ -6,19 +6,19 @@ #pragma once -#define ADC1_GPIO1_CHANNEL ADC1_CHANNEL_0 +#define ADC1_GPIO0_CHANNEL ADC1_CHANNEL_0 #define ADC1_CHANNEL_0_GPIO_NUM 0 -#define ADC1_GPIO2_CHANNEL ADC1_CHANNEL_1 +#define ADC1_GPIO1_CHANNEL ADC1_CHANNEL_1 #define ADC1_CHANNEL_1_GPIO_NUM 1 -#define ADC1_GPIO3_CHANNEL ADC1_CHANNEL_2 +#define ADC1_GPIO2_CHANNEL ADC1_CHANNEL_2 #define ADC1_CHANNEL_2_GPIO_NUM 2 -#define ADC1_GPIO4_CHANNEL ADC1_CHANNEL_3 +#define ADC1_GPIO3_CHANNEL ADC1_CHANNEL_3 #define ADC1_CHANNEL_3_GPIO_NUM 3 -#define ADC1_GPIO5_CHANNEL ADC1_CHANNEL_4 +#define ADC1_GPIO4_CHANNEL ADC1_CHANNEL_4 #define ADC1_CHANNEL_4_GPIO_NUM 4 #define ADC2_GPIO5_CHANNEL ADC2_CHANNEL_0 diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 1df1d6a6ec..7df0ea7e05 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -74,15 +74,19 @@ #define SOC_ADC_ARBITER_SUPPORTED 1 #define SOC_ADC_FILTER_SUPPORTED 1 #define SOC_ADC_MONITOR_SUPPORTED 1 +#define SOC_ADC_DMA_SUPPORTED 1 #define SOC_ADC_PERIPH_NUM (1U) -#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 5 : 0) +#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (5) #define SOC_ADC_MAX_CHANNEL_NUM (5) #define SOC_ADC_ATTEN_NUM (4) /*!< Digital */ #define SOC_ADC_DIGI_CONTROLLER_NUM (1U) #define SOC_ADC_PATT_LEN_MAX (8) /*!< One pattern table, each contains 8 items. Each item takes 1 byte */ +#define SOC_ADC_DIGI_MIN_BITWIDTH (12) #define SOC_ADC_DIGI_MAX_BITWIDTH (12) +#define SOC_ADC_DIGI_RESULT_BYTES (4) +#define SOC_ADC_DIGI_DATA_BYTES_PER_CONV (4) #define SOC_ADC_DIGI_FILTER_NUM (2) #define SOC_ADC_DIGI_MONITOR_NUM (2) /*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */ diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index 923a3eb2df..80ccedadbb 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -155,6 +155,10 @@ config SOC_ADC_MONITOR_SUPPORTED bool default y +config SOC_ADC_DMA_SUPPORTED + bool + default y + config SOC_ADC_PERIPH_NUM int default 2 @@ -175,10 +179,22 @@ config SOC_ADC_PATT_LEN_MAX int default 32 +config SOC_ADC_DIGI_MIN_BITWIDTH + int + default 12 + config SOC_ADC_DIGI_MAX_BITWIDTH int default 12 +config SOC_ADC_DIGI_RESULT_BYTES + int + default 2 + +config SOC_ADC_DIGI_DATA_BYTES_PER_CONV + int + default 2 + config SOC_ADC_SAMPLE_FREQ_THRES_HIGH int default 83333 diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index c7905ea55a..ada7d5bafb 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -81,6 +81,7 @@ #define SOC_ADC_ARBITER_SUPPORTED 1 #define SOC_ADC_FILTER_SUPPORTED 1 #define SOC_ADC_MONITOR_SUPPORTED 1 +#define SOC_ADC_DMA_SUPPORTED 1 #define SOC_ADC_PERIPH_NUM (2) #define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10) #define SOC_ADC_MAX_CHANNEL_NUM (10) @@ -89,7 +90,10 @@ /*!< Digital */ #define SOC_ADC_DIGI_CONTROLLER_NUM (2) #define SOC_ADC_PATT_LEN_MAX (32) /*!< Two pattern table, each contains 16 items. Each item takes 1 byte */ +#define SOC_ADC_DIGI_MIN_BITWIDTH (12) #define SOC_ADC_DIGI_MAX_BITWIDTH (12) +#define SOC_ADC_DIGI_RESULT_BYTES (2) +#define SOC_ADC_DIGI_DATA_BYTES_PER_CONV (2) /*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */ #define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333 #define SOC_ADC_SAMPLE_FREQ_THRES_LOW 611 diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index e8c06154a9..5de9528f46 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -215,6 +215,10 @@ config SOC_ADC_MONITOR_SUPPORTED bool default y +config SOC_ADC_DMA_SUPPORTED + bool + default y + config SOC_ADC_PERIPH_NUM int default 2 @@ -235,9 +239,21 @@ config SOC_ADC_PATT_LEN_MAX int default 24 +config SOC_ADC_DIGI_MIN_BITWIDTH + int + default 12 + config SOC_ADC_DIGI_MAX_BITWIDTH int - default 13 + default 12 + +config SOC_ADC_DIGI_RESULT_BYTES + int + default 4 + +config SOC_ADC_DIGI_DATA_BYTES_PER_CONV + int + default 4 config SOC_ADC_SAMPLE_FREQ_THRES_HIGH int diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 800330da5c..1d71288caa 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -74,6 +74,7 @@ #define SOC_ADC_ARBITER_SUPPORTED 1 #define SOC_ADC_FILTER_SUPPORTED 1 #define SOC_ADC_MONITOR_SUPPORTED 1 +#define SOC_ADC_DMA_SUPPORTED 1 #define SOC_ADC_PERIPH_NUM (2) #define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10) #define SOC_ADC_MAX_CHANNEL_NUM (10) @@ -82,7 +83,10 @@ /*!< Digital */ #define SOC_ADC_DIGI_CONTROLLER_NUM (2) #define SOC_ADC_PATT_LEN_MAX (24) //Two pattern table, each contains 12 items. Each item takes 1 byte -#define SOC_ADC_DIGI_MAX_BITWIDTH (13) +#define SOC_ADC_DIGI_MIN_BITWIDTH (12) +#define SOC_ADC_DIGI_MAX_BITWIDTH (12) +#define SOC_ADC_DIGI_RESULT_BYTES (4) +#define SOC_ADC_DIGI_DATA_BYTES_PER_CONV (4) /*!< F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 */ #define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333 #define SOC_ADC_SAMPLE_FREQ_THRES_LOW 611 diff --git a/components/ulp/CMakeLists.txt b/components/ulp/CMakeLists.txt index 971abfebfa..ae3f7bee33 100644 --- a/components/ulp/CMakeLists.txt +++ b/components/ulp/CMakeLists.txt @@ -33,4 +33,4 @@ endif() idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${includes} - REQUIRES driver) + REQUIRES driver esp_adc) diff --git a/components/ulp/ulp_riscv/include/ulp_riscv_adc.h b/components/ulp/ulp_riscv/include/ulp_riscv_adc.h index 6b0983c75a..336b114b25 100644 --- a/components/ulp/ulp_riscv/include/ulp_riscv_adc.h +++ b/components/ulp/ulp_riscv/include/ulp_riscv_adc.h @@ -17,7 +17,7 @@ typedef struct { adc_unit_t adc_n; // ADC Unit adc_channel_t channel; // ADC channel adc_atten_t atten; // ADC channel attenuation - adc_bits_width_t width; // ADC bit width, only used for ADC unit 1 + adc_bitwidth_t width; // ADC bit width, only used for ADC unit 1 } ulp_riscv_adc_cfg_t; // ULP Riscv ADC configuration parameters /** diff --git a/components/ulp/ulp_riscv/ulp_riscv_adc.c b/components/ulp/ulp_riscv/ulp_riscv_adc.c index d5fce3c4a0..32f0e9bdc9 100644 --- a/components/ulp/ulp_riscv/ulp_riscv_adc.c +++ b/components/ulp/ulp_riscv/ulp_riscv_adc.c @@ -8,15 +8,11 @@ #include "esp_err.h" #include "esp_check.h" #include "esp_log.h" -#include "driver/adc.h" +#include "esp_private/adc_private.h" +#include "esp_adc/adc_oneshot.h" #include "hal/adc_hal_common.h" #include "esp_private/esp_sleep_internal.h" - -/* Will be refactored when ADC NG is merged, TODO IDF-5513 */ -extern esp_err_t adc1_rtc_mode_acquire(void); -extern uint32_t get_calibration_offset(adc_unit_t adc_n, adc_channel_t chan); - static const char *TAG = "ulp_riscv_adc"; esp_err_t ulp_riscv_adc_init(const ulp_riscv_adc_cfg_t *cfg) @@ -26,15 +22,23 @@ esp_err_t ulp_riscv_adc_init(const ulp_riscv_adc_cfg_t *cfg) ESP_GOTO_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, err, TAG, "cfg == NULL"); ESP_GOTO_ON_FALSE(cfg->adc_n == ADC_UNIT_1, ESP_ERR_INVALID_ARG, err, TAG, "Only ADC_UNIT_1 is supported for now"); - adc1_config_channel_atten(cfg->channel, cfg->atten); - adc1_config_width(cfg->width); + //-------------ADC1 Init---------------// + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = cfg->adc_n, + .ulp_mode = ADC_ULP_MODE_RISCV, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + //-------------ADC1 Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = cfg->width, + .atten = cfg->atten, + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, cfg->channel, &config)); //Calibrate the ADC - uint32_t cal_val = get_calibration_offset(cfg->adc_n, cfg->channel); - adc_hal_set_calibration_param(cfg->adc_n, cal_val); - - adc1_rtc_mode_acquire(); - + adc_set_hw_calibration_code(cfg->adc_n, cfg->atten); esp_sleep_enable_adc_tsens_monitor(true); err: diff --git a/docs/_static/diagrams/adc/adc_conversion_frame.png b/docs/_static/diagrams/adc/adc_conversion_frame.png new file mode 100644 index 0000000000000000000000000000000000000000..1bee752c0347465863b13ef52233da1b8aad13e0 GIT binary patch literal 14426 zcmZ{LbwE__*6t7jf|P(DATgvMT@nK7ARQ7zH%Le*Af3`J-Jqm63@ISp-QqBWLw9$_ z-FW<+?>pz-yZ@NkGqYp%TI*f!TF>*mp(;w!__&m~AP@*&RtBO90%2eQ`(JU;fmei% zoiFf);rK#U9R~+zYEF3;`1sICO3O*j{*9B1v4c6t!p`2-oWs%7!Q9-=(bC>&2ct%7B2Xm zL8mo@Q41MGqA#mid(kBt+f}vgXl~W%GJocM&27AWA%5a9b0Mx7UA%qO$T`YS71?=s z`29&Ae}q!Of^!|puDWlDa`H36`pi?jdg_@I%qlfQscYj%M}RJSCCg`e=j6h(@r&-% zR#n%+o~sxX^+7+0u}99J1i9fPqNb(>#Si&vPy+jAU5Pjb>B18ct9Q|Yj1?3WwFOq4 z>nsM-Cu$rEG(5dQ9cXf~W{3vl#*zCo*c?-~bDh`qwXM! zqw@Z+jUaHpnH}2N%Bihm_h%)@w;!`j$*E(?wkd7xp&C%lt!k_FRiF zokSinHxkV{*QE$YP(uj7*fIXy&$}Fl_YVPIfj~C2D)-TDcRn-Tx)dZSi}~k`HT3ok zgu_Jq=bhM1G()L+O5k43=-NHok&UBvJR2xI7MB(;el4ol70-$F1!yLNSn^7U+bvMx z#IE}7hg1HK-h1A3B!>00-J2+=?-tGh>I^H$co)5$y7ayg)yyVermsQCibG8@AM0|E z#$`+KL$vutUi8!L7xWUo{yuO_x<7w*k#6RZ@Q(@MRkBxjt?ygdKEZ~Du}nC5?a(0Y zPAp)TES`Ci*VR+zn_!5G0f^Rz$aodXBi_HdhyN;664H-GK*_C}g7r&6^zw8{Fxd?A z^z^&keH~jSXH1&{A}+~xTG2aLS!VU1MLGu};Sj(^I<|SRSbu{#19J~%ieT3DEO{6z zIlqVc?!z3`p)S#63#Hsom)h>x7#7J!HwC1U0 z8y?XsYbbs@h<9QTkI2JQ-gS530N+M_N4B%;c!QYMFn+q9!$lVj{FD!cvU91PdZc@E-VlNG&C2o@J&ucL zW<eFo>tf{M>69NAF8eT=pi=rTr=CT zLH}CdYp4PbV{luKLUuVRHG8gsp20VWBf>_3-n!btPIx!3-|$MEO;^dhmFlq<|6+|{ zSi_*h-3?;X?yw^f6bR&72LaVz7J6^NZivKP>AqiM7!q*gff1fx}!|d`|sz zOB`#=1W1R9ud<&%hnAJWH)v@mh^g0|H{=HH04czPh>g z-2jrBFeOOt%FLJcpA%Y=&cG$oyOA&Kch>vZqt!E%wfg zgl>{N#feoJQYaC)g)%BJ=2G|_6=WG9--CV3w}Sb?^!qB=y!nWD?AoC|UX&7aF+Huq&rx-^z>_QR4cHSPwYSITLyfUinu&aGGFCHMz)IMoew*w!Hk zC;mjjTzLU_sI#HC5Fk#b=W!U>_&>x=q)!keX-FPwGOltNa%%oeC%;Y8v3ke>l=#8+?+O3af-<@cHu%GIy`DP=IjXyG8esF z64%HUJq^A}Ye97-4sxWo<7Kd_fP41H#fWK>PSehyE050CwMxCO<>{R35FL7A?c%Nj zAD`vm8F!<`at`)ELqh3BHG=fXy|7J2f7D%)*m9rtg~^6 z5wsU_!to)nJR1WgvqbQ>C$N}2r}XwW*<(Y@iKfrrYsvwcTPGv_U2S$!EL+`1`S{Tm zZKEqP>HSCrL`VD;1mbt93eF{pDZg;^aRigRHV3PcYL~oy%fL;gD~DyS`e3GZHY=K| z1B16PMoR|CpYh$KibBRbmR9aX?GkHD{Zbxe6bFnq~ zyH&YXM`AtZ=18by>2rZ}{)qLnt094{n|6OcZ+gT*uz}~7(bV;wrA}P~2F*>5!a0C@dmpNoCtprn=IW4i3cBxFqRXwC(f|HJn`8@(0X3_d3{+t zSvsq3+;O2fU7T7`i2I7P&A3ALxm=Z4=-P9;^LrdH)fxD3ilS&@7BdZm8sSiw123HE!ArygI-SC;{`VI)q)ERch>$hE|kyWr$t|%~1q&!?3a1y{er0 zu9@Y)DJ12p#_^>EvBR#;&~r}$1BNVrgRG$y=eh=ik|CkXHL0?1IHtN2Yfb@M3&U{W z%c(71{16$O()~AEP9k>IX=Nyz>M5X(kjtd7%=aTQ`fysc*Wp&a&dCfW=GhA*7A5gR za#3=lJb-hNrkKh3YrsrT8N$~c{SKH1F>y$Qm+ysPd=DGmat?gKjy5l1N#;X}MiU+U z5Dl0?q+QXf#u`W#XNQ1Hu_AGH#&wA*$>S1J%GGQz}X^O@qSA)wLC`MkF!u2%oZ#p2OMy;p2&~LsKx3zu|a`3XpiCl2HU!CH$uZD|BWG6PU4OIlo(3qTI zdT1GZd*FIfWZ_{7p@RIG`l596ciqfa{cm86RWIA|h$`GRJ23l0k(!iFE0JnK%D%P) zgFc6j*w>p|_8w`X73m?EWN@8cjso8JCs)gGJE0nVNU?Wptv-aa`XZ7xq^Im++e6w; zID72i(&;E)p8KEcM*n^W)WXyIeya_k z9yhxyj-jP`1K!-JP&~vYjPpB-`?0dbY2u4|Et$ZCl#P7Z!~zspum;ui?yT6SWlKuDb|kJm$7+7(38#VF5R#G@dBW z>~>V&9OC(0qowQagbInPWse(m zSu**xQUyk7-av)VpKu<_vA)JJ!%e|CaHykJ+8k>tx#_)tFfgTZaI)99s>EQF)yHxg zF!Lt&bHdKFRALarsvLph#-@+*6NI%NU&#kLE1xV*1AdR1f zN6WI(Q?yTa4Fk&qc^(mhK)M)7R;iJ%Ox@jes&+StPBxO)%MsS0hBHBSWGACzc9Xih zmj^=^SKcsDoh@hG-)fcX#T&JZvi-;;r2;+yfe!VqBX@lbE-zyX-z~H%9S+z?&h?|d z!otTeER@|ze+r+d%l7xMA;Qm3C1qoaYNw{TfrPR$l$DiIv$|0g3ZBdP4X&7ew;Omrb)(dpk@`_Gs{+PeJ_hYfRZFwRN2_Mb z1*-8^bjP5x5t3fp;G}5D&C_vQ3P|aFZaK_+G>KL!u;gaoN&5IEap}=w>7%T&J4AnL zbTGD%1a?D)Qo+;~F8h1-FPur?gp39w->vBcd7vBp(}fbM^(nP*V$lVEJND+yrY4I@ z#FE1vN^vYSoz|zEO7gw6%^hxwVeWgcnm>zX-AiLJ`qbZ#6XC$Ipp2#+{UzkdG?<2~ z(XzSU_)noO0~G9^M}=AMwKvd2clC}urzqpI!)@jAcv zbOk;)#?>OAbH4_Ev>M{qPBgF3|CP$su_|DOE$(ltARrFqE#zyB1D z>DplM>I>YPILp3y$oT!K0`8|HlRNyaq?NY5|8Cn>998b|IF@&)6Wz0Irix6vLfCdX ztrcjWKz?md4a|| z8&vF9D6HY;YR6~mt)a)oR<$Vn&h5!0Us!v4;#dr?)-~-XS}oZVA^s+-G14?OE14eX ze!in&w+C@Q?(6Ft5xQ#+MnBh5<@LS?bmJ*0DP@zrctqGw1q93y`Zz`k z-`yLgYaCZdrOLwWDX$>jBYbl0>>as$`rv5YWnM!iW2W#XyFy~^}p z5s%}|s7Inj%y<7rx1Bn{*v8RG)6Eq|!5Xju|Lyh}l6=mRT(*Drv|HeY0yF=b6Qe9p z6fAQ)5?lTm-Y$TZ9Jv|}fByPKx-i+J(2j4lJ0H&FeSMI1(@NerY*&r#jEZGMc^(Xu zxDC9epz>&0#1G)xT<&nu14Sou5=8l)_Rs3K3MTlGO*3~?KcY2g7U0I9_r(VK;`(JZ zqv2-m2$n3*{aA$5_K$_AnJd&x!$Op3QEhl?>_i~kL!j){%gar>2pUD~Ds`aq zRsmcgki*T2p=sc+LUqs9)5vEXY5=6cn8Neyw5b(2RV^-X!n?FFR0iX^YbB)FcN34Ip>|b1`rN>ca^!pHCSRe>uksA$H z$5X%)wa75O&}GK19$P>_a#?#>B+hye2!yidJPCkO5sIIF&bLwuza8Aoxn{g6*9+WrHMX}#%r}e zMh>sqhi;n$@f?gV?Col@8~9F~=$pSvMsmgaHR&d9nJEsf20OrN+|e12E@A?6g_ zg7Go@P{@8~9&dhpPkN?rT$d#a6u0R``pG{H+uJo}gHk~oj%B4zKNM_2Nd(|} zhz}W|%^O0Bacg!{k`xUG#5U67P!L~zkTH<;VK{GQ&F3gjgAEFsF*?JQDrTnLlV;O-oDKDO-9Gm-PD}aUBG^r z=s;vU;sRmm^;#;5yAgKzkP-ZEIPx|$kRnBsd-zzk$#8x@fpu1t+f@#0dV5X6OdU66 z^_KWC+T^)Il*4&4j(;N*|F@k`1$BlEOf%&lHLJ~A;6pvw6#f#sb|9U?9+4Ut_*tP;jIhCIus57RuN|eiJUwGNM&J8Ut z9rEIzz?@xP`CL7^=2WNO#$BX9e^&U)OIP;I=Ro^>1Qg7B&)lv<6MmZpWf+=^RY;QK?#KBE8iZ<6t$Z)Y|}htNCfEp zBjfr@pkW6Z^oXBs6+Y`jAK1~VP}158K>9H`=Rps#jP1ZYMa%WZrNf3--Qx5CfT!%d z2@J+t7NM*CnWx*H{w)o?W$<>}I||u85L;8i9Xhm55~C?E2ef(2iC#x*^zlyG)pW=l z>t4!Hs0|qyJ7xP%X8T0$OTAb}C^)xgeLGS?|5@Yx1M>eJv7g~8_d~0N;0CmnUQznV zOx!~$;nnw&aRB(p$1&PR*3U=&#SimcVw*d=gzG2n&z2Fx&oT4;iZ@~zBRM4NQN8We zUNP-Zkc2P5UK~@~u0NiYHi{PpOlGD{qugv1%ZDBkV)ai|t1FCMLOGc9uSkq)n|Ppq zC%||K*>ruh<8yQIlIq?!`TT3L2g*?0o^4URYG78L8XX-q#WR{G+=Ql}Yg2^idOat8 zVBIeS8u2Z|sUQRH^V_Z(K~5?zPJEX{@Rjc=RvTpa0}4p#84z*tqoyzWEFm{Rzib4V zWXmT5;h;8d3i2PXZRQ8FByPeq>szhaeSBYlOrLiuzXq=#xz`pOx}ZKNxcnWDzc;Bb z$GgM@`S@NIajfLe>*(v-3Z_L^EeG^83+=j!H5l06Twejrow2cT1jeng0R%Rf#(gzy z=5qP1;e}4E%^bm0wsU-HKfmHs_AtN?<%}d}W>%dCF-H7M$(BA1;WJbTAQV!&_Gp;) z*sfX0p}qQ=0DWhB&`zRUf6}nyb-q@R@c^CL^!@wyZfFIPZd_X}u1C8e91N ze8A`nUsJL3)f_&)+eWb7GtQQtJ`v};JI&xGmtWTt_ffm*p)84Li+^!EyZ>Sbd>5iM zF(e_?)9xEN(cTy*vD>P_({zW&_X=zp}iWR_1f{6 zan!l~r0(>H`YC}Ncvei}w1rUoVq!?-_OO?P&oIe@w)$Nf4>F`_+}f?kjOrHN z$?|ho-qsJz&TnQ5SK~nd;>mk22W5AV|49L7ls{$rBhVlp?ru+cXH7- zS31h(8&|)kXkWXQpOy|qqkgHO@x%xuk`eXw0cQzrfG)#m^({ur0fU*PN#80ERw z#-6yp>)rq@j;g|Q$5EDjb3|)gVT0$(UXng1fDQByJbLef1^DCEf={npD={n+^mr)&-U0f{h%p6bNpQDt1?*7t zIU3bOk)%)liA;c0K1p!iDC|8`dZDf4=NPy7P!@xmbEM(GvtsFzWwo+T-@40-uv$YE z3b*59?-oFW$+UzR^uj13@^LHihc%S$d@St6!Zgv+({r-v8RBqM{A?|f%Peo|f^;B8 zN|6UjKFvgh)ZbrHZt#ZnsASKM7qn?)Cx!>cF$pAaA*~T6g2m=0WeSLg9C6BbZ!%4<9+v40 zN^MNI@;3Qdl%_|umsduHS2K;jKw{zow2YZ$EY8o?7Bv%Ge#*-ESez*Y2TmHr1fg9yccuWfnx(J2vY2|9%*GxGkRv@dI8#`j zf*7?rLh@||-8iyVbX;wH zmoOaOC!b(h9IpuZ_>B@rO07mAH?=46(d!B{wHHtmF-xebIs$fk5PQw_1Rua8misF)y6QWuEYQYB2aG ztOf#!FnJmSTLrEYK&jo!{IR@`3HHUc>YEx9naccCR^6eA9)50bn{rEsS~gTB^l?tm z{6v`2MnQY2zTsK?Cs}4GVrdDlYN>dp&umynzojFbWKGQ~={8s*t1fivIP z3yq%YcXxiYeo}%j+w(yp9U(7Yred@e3*P_GU2Gd;9!vKA^^Z$RsiU8~C(*t$8M`1Q(=YXCZiUN=}d=IFQg5?tL?Vy-+}vZ&gffu**dwg0K|SRNl-w*%2P& zr;>KT6JXdmH&NO=D!G`mIXc|)I;g0NDo)Oy@VspPy;=N{MKf&x5f|)ywsM?hlNwE% zoQCpRbjq2~6RvXM_}z0=ffuZFvapq=FILWm&P8LuGqAk(>}PQfjLL_miU214AWvU9 zh}Ps_@mlz1z9o)5vU9!XWw;6HK-|UU;>?HBy&$XN%yFTW8OM67Oc8F0x)aDKzhZ@( z$ZpFJ^HmCdS>{UJ-u}K$yZ#2^M zZZ#e-$l6Q1>p%<^DCGd6D|$0C1LaZAW22N>K*)K>QvK&1KD+TaVm`C+Zao1t%s=Me zeynkDeI2`e^2pFCbzn5uwHx@dv+yVEY4z@tC)ve`-Z zLB^1cihVE|l&IU74Nb_mB9QMH4SvvWr7v9GCsBQ}S{Uw5ICaz!7QG$&fFNUi$QPj| zebPU${cKuGG+Dmn^#F;-mE%QJ34dDT^B=c1+s=usbnSAM_lOeU(j)0dFw|XoMBATQ zz5BFW_UxxQ#>C36FL!P(0cRrjJDXOt+NjUK+)vi}JIhe9KE^X6YWR+;r)ez5=Pr-5 z8)Eeh+u!J8D$(jBqg-0~g^s}7e0&FoqsoLRGhG>=p4Ughs{q-`TvPXE1H$_1v`bJmzEXj1$&pSQ4-jonY{jj#^aB0D5^^aXDQPA?<2N!e#8QYNZB$DPNJJ{x!;V46pR zCv#w_rkKejBuMf%P{Wt-G{E3z@mf)L$iP2Cof@DptK3%=8gQbduJI%D?4}#+o8!(~ zAZ=}p%J7VDhm}=6#no4a%lyCrTtWKUTs!hf-U8!dY%#+6Lk9YuX9J*0xc+SC^`k^< zNzZS7ZAnJ*^{;MK=I4QWz;MhAFHkcMl!@$Y%|!^{GMUIdHvAcSs9K!Me4oBgt<+AA zXbmVFU~%`AG!Io(D`zUN;-6k5xD*Y9tWo(aZxC(Y|hEDLCU{u)O<^Jx>SCYx~nvUYLb&d1L%=#IGF$R!7ebC3p9J^-4 zM*jvSPomRkSezpez8`Jf;TgEz;mMR90aGtQ3_%ka(4KQ^K+X1y*K5ta%yG;aly&lKF@2?%DLi=7J7cu9hVr2_<9q37lIi)bd?nf|| zFVPQSJUzZBHSKHs=I5&i*Sl={3{{XanfPW<^49v@ZjLt{#qj!vj1ZZ-$I9|PrmQq- zVQ1yVNe+3EV4Ckw??5*415&%mV&mll0FQJejx~{*G`yX9JU8QE@<}gJt}Vgh`gtE~msrUeaSz2ys*G44&DAwxTA_qamwWdBK}0{o>Qq23 z>P>i`p9x!0uQh9G@6-)$Md;JYO&B%K*CXq#?3c*CHA{Z|{J#6IOG*^|h&j<;#zlp2 zn(+u-YnE@wyPg?fe%;yfJS$N(*%<$TbCeNzDhOEwa8-aUF^@E+2r}lzcWIJ}r%SF)9kA*L4@~sdrREIjp8Xh_`)m6QMGK5-wh87d| zgt1{K^`qkzcxC$7;c)Yi*6 z)KQFj6P8eGz*XSCWM;A@mEB^bH}G(Fyu9R#milA!F^QA{O^1otVoVv01b15%4#Zo5 z^{k+OIcw~siqZ#MTduEruwRQq6k|+bq8KeNcSj!y00ecYWp?~GFk2=D-22r}`fedA z#tHPYv0wyLI}u>_03>RrnXQpgHkMJp^3Jng5azr^laV~n8Xe?%LaVB0A+?U2lo=Cc z^cZiUjnwFo&U>rEukG`RE-_2*z&b-LKNBo@zY)byDnfeK%o?+SRFxhjbw5zP;58FT zIAb}PV*NeI{Xmn@VoM}-Id~&AKaN@!vax1XrH7P-nUTzC<-bxl2n%C@m`g#&NLj;F z*&o0}UN`)Re~hnvDb*BY$Uz5IHCb~iO%7pp%(K>qX@;k0m49YV%Ek>O;pyed>-(Tz zk~AtW9L7|XWQ^Bg>Oh~u7I^=CLiaqW9^_e8NIUORtM0MjD3q~68g^E?Xe-k36MJF_02(^a1YM)lowg0b_mF^=eLfi zmlellv+@%6K+3aO5iiP=a*_M;DFvK_g>TOV1nw+$JBX+%z9N}0$;-E@bP$Z`e(m|V zSQSVpK%w7}TKqP_hD|@5Ir(IPs|M$uVr@8u;Pu8wAeq&)dAR9g=I7@_G~P)C27G0@ zh3Pbk^gBt}vInZ%>nHgYM{UHs&1Q;)n;?v5E6!V@`>v*?bGy?W!cB`=88ekP<8q_? z1IuNo4H^NlTKUO}V0{2p+e=ixof#Qb zyuHQ(w)4ORlkENw$F`^ga7=!U`+W1HR{xf8sf9OEDq1tGAbK-3;W9k!MhyN#{`-VS zS+?8y>NV=1!sOMH?PpF7N3B6#;RhA5{Gv@icD_=S#a+B1M`q?U>@wy8byK1L!6HzF zNu&j3eLPaj-aDOphF9SY+>dip+|{H*Pl73EYtmUx%-hKB>Y3xHP3HJYlJg^N9-vq| zAHUWIuDh6}KklKWaNf6)Yb8h{@!eyZOBPa5N4Tl`V{vaCVd}BMxHfN9{XC=&LPhIB zTD+KQ1Qez9+`R>a9Q{XG4))Yj3?r8u`@ntA%SfcV`DowB{}Wol&}YrGwnHDm%dd$I2`c`cl4HxeY4`S zB~c|PAHAiUoWKaSGM>2x^n?-yD9_8;kB0j@)2B$zcKz(gC=u|jiBF#N%Rz2$EAHx< zH!<_h=BD^e8*sYr=E^`fxu3Bt@@bXsq*u|1{kyYM!g>9P;tQKGsoB;AM4Bt{IBv9N zox-RMKP3Q+k$WlXOBak1_eE);`m8E-#IvHcbs*?9#h7SjM?EtDnG6}4gDa>hLM;)PfG&Yz5TQXg?EY-KYpwRDAJC^6)C8QxCdl2wGB(&)Oe0JheqY}Jyrf2# zA8if-x>urs0lv@f?OKqZUvIGU>(4gqoMwyYhG0zvSXZ8VG@W=5N?exSLUg}9b{aw< z^HHMP?`{FSrql2y*Uhr7pKITNU*k>zak*U>gN}es0#A;X!2Q>CsLlmMv)f?iGhNQ4 zttr2^Nw-uipp7iMH8LROE6AiQ&!q%ulKdOqZGJF|DDghBzwETXHE&O_#O2&AwE73q z1NizT08ad%b7y?pHRAyYgmUQP&^mNUJNQEA)opdRS=O#@t7^)wZs3nM04eS5#v0oE z0Myrr{^X)|pryRTh#g?^o)RW{-O)P!kmhf0*aH2>VQztL{0n$i8=M^HI+et_z|=Ji zs8ci#uNEY(O|hF8COPM;COirv4Sp^yG0g(nfQyl6@5R{*=0PP84qdj-d4bRQVS&We zYEHCBxl5Ot5j)O1XY`^!+bp=$_D*uX8=#Z_qtp*wja}kz|7HRWZ2#=1@sI&JLPQK` z-|J8S5#xS5VUaeFKeTe-9^B-`3>7j(e;7o+34izn;DlGTJj5~$N?hjKLus#fgCkTr z=X8EKLSZo~K6%96bobgmF@~-IZa++Z=TRS;AFfs9IXJq(64*#lv$x=4zRH#dcQZ97{+mp2vqou#;|E1MwH#< zzpX1fAI$E#x}seYMS^{4CHD^4xs245(In7w`q5-#o%Ct{MJ#;vS#W3lLwOJh|44A$ z{Wj0d$1e=c|Uhn<8hk|~EC5FQXta^q7d_sC!S&-A^qskCjQy$(Q0KYW(& zR})nRur9;L_ki|w>O|W{+Vw!GWsz@~U-24rhJ|4p7Xfm37YooWx`8?TMwq)Ozz_ft zOW+QqlG~bFtKphulBZ-S#fyQr(GTFU?t55tzHqW|ZfPgaG5X;25#R>-OA$l$V!~k{ zW2)W=35iyd-^|2x%f4HfvtIIN+x4x^bpz=iUlY8G$Lgnk&{pSu>RTbPwG^t=q?O?jAXGuKY56FEi;OPdk7X*>CNv3Q%p((CyH z>~5E8{i(oc?s1Xn)8wnl$mDI4!{ov@RDRk@%DHV5F@3sEp+9o0$*~Yy2j|! z3r2uzzFnMgON>RWd`7&vO-8<37=I;Z|4wf(ZHCf2eEQ@+#c-=dlcuoZqmiDMNH&}GY7Z5lEFg~P7tJ8xBevqD zvIm<)EEd{__q4Cv8SmV2uB%cyu8$G+@vXw`pq|b6bp|oPyeGoz_&y$S&lRnm=JStF zd*OF~ptj4%Nhp>Mf|`>5wQ>hwp#a(4p<>jq&knaR76 zP5ql4d12&qo9q9xVCRoC@GraUT2J}MCx4Y5|K*bZTNZFiUZcmUOU0?1!=2AHlVNX^ znqR6~s`0c6G>tV-C0e0zuLwSnYI|9BM=ua-9@Ey^a|$O-1Vj3DcSJMm<2O?v;cgcT zfIk&tY_!D$%(Y9|{k&wC>%Nkn0?xFc6DhfEC;c~M*SF`@Q%lhSp+mYTLP(UYhxKGl z{v3fs&_hs&?=)K1|Nxjj8b3_Ej1#fDuX0>;g#m>!-g zR6RnwCOS3ayWmE*QS;4es48%c$NHPTLa5C?8U|7yo_mT%cQMrW!&CQPEdzpvlQTiZ zI3Zq_I#dK`l;4fv01y`(oVhYM-g4ApG=z?)z(Hj{$w%XN>?p7#>M!R=V&E~tfU7ZH z`BE6euo^}lkQiZ(b21xI1X-m*iHloJ&`myS-zB;*e?US6NLnE6T+IK_v$t!-i2f2$ rvyps%Jo*1obo?EO|D_uUS-rv74AOf?!ZjFtd$z2U5~TQr(Z~M-+eWuV literal 0 HcmV?d00001 diff --git a/docs/conf_common.py b/docs/conf_common.py index 70cf3af0c6..2e1c528c1c 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -106,6 +106,10 @@ I2S_DOCS = ['api-reference/peripherals/i2s.rst'] RTC_MEM_DOCS = ['api-guides/deep-sleep-stub.rst'] +ADC_DOCS = ['api-reference/peripherals/adc_oneshot.rst', + 'api-reference/peripherals/adc_calibration.rst'] +ADC_DMA_DOCS = ['api-reference/peripherals/adc_continuous.rst'] + ESP32_DOCS = ['api-reference/system/himem.rst', 'api-guides/romconsole.rst', 'api-reference/system/ipc.rst', @@ -165,6 +169,8 @@ conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS, 'SOC_I2S_SUPPORTED':I2S_DOCS, 'SOC_SIGMADELTA_SUPPORTED':SIGMADELTA_DOCS, 'SOC_RTC_MEM_SUPPORTED': RTC_MEM_DOCS, + 'SOC_ADC_SUPPORTED':ADC_DOCS, + 'SOC_ADC_DMA_SUPPORTED':ADC_DMA_DOCS, 'esp32':ESP32_DOCS, 'esp32s2':ESP32S2_DOCS, 'esp32s3':ESP32S3_DOCS, diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index b1e18ac928..3e0dda2381 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -61,7 +61,6 @@ INPUT = \ $(PROJECT_PATH)/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h \ $(PROJECT_PATH)/components/bt/include/esp32/include/esp_bt.h \ $(PROJECT_PATH)/components/console/esp_console.h \ - $(PROJECT_PATH)/components/driver/include/driver/adc.h \ $(PROJECT_PATH)/components/driver/include/driver/dac_common.h \ $(PROJECT_PATH)/components/driver/include/driver/dedic_gpio.h \ $(PROJECT_PATH)/components/driver/include/driver/gpio.h \ @@ -83,7 +82,10 @@ INPUT = \ $(PROJECT_PATH)/components/driver/include/driver/uart.h \ $(PROJECT_PATH)/components/efuse/$(IDF_TARGET)/include/esp_efuse.h \ $(PROJECT_PATH)/components/efuse/include/esp_efuse.h \ - $(PROJECT_PATH)/components/esp_adc_cal/include/esp_adc_cal.h \ + $(PROJECT_PATH)/components/esp_adc/include/esp_adc/adc_cali_scheme.h \ + $(PROJECT_PATH)/components/esp_adc/include/esp_adc/adc_cali.h \ + $(PROJECT_PATH)/components/esp_adc/include/esp_adc/adc_continuous.h \ + $(PROJECT_PATH)/components/esp_adc/include/esp_adc/adc_oneshot.h \ $(PROJECT_PATH)/components/esp_common/include/esp_check.h \ $(PROJECT_PATH)/components/esp_common/include/esp_err.h \ $(PROJECT_PATH)/components/esp_common/include/esp_idf_version.h \ diff --git a/docs/en/api-reference/peripherals/adc.rst b/docs/en/api-reference/peripherals/adc.rst deleted file mode 100644 index e7c77a5690..0000000000 --- a/docs/en/api-reference/peripherals/adc.rst +++ /dev/null @@ -1,463 +0,0 @@ -Analog to Digital Converter (ADC) -================================= - -{IDF_TARGET_ADC1_CH0: default="GPIO 0", esp32="GPIO 36"} -{IDF_TARGET_ADC2_CH7: default="GPIO 0", esp32="GPIO 27"} - - -ADC Channels ------------- - -{IDF_TARGET_ADC_TOTAL_CHAN:default="20", esp32="18", esp32s2="20", esp32c3="6"} -{IDF_TARGET_ADC_UNIT_NUM:default="2"} - -The {IDF_TARGET_NAME} integrates {IDF_TARGET_ADC_UNIT_NUM} SAR (`Successive Approximation Register `_) ADCs, supporting a total of {IDF_TARGET_ADC_TOTAL_CHAN} measurement channels (analog enabled pins). - -These channels are supported: - -.. only:: esp32 - - ADC1: - - 8 channels: GPIO32 - GPIO39 - ADC2: - - 10 channels: GPIO0, GPIO2, GPIO4, GPIO12 - GPIO15, GOIO25 - GPIO27 - -.. only:: esp32s2 or esp32s3 - - ADC1: - - 10 channels: GPIO1 - GPIO10 - ADC2: - - 10 channels: GPIO11 - GPIO20 - -.. only:: esp32c3 - - ADC1: - - 5 channels: GPIO0 - GPIO4 - ADC2: - - 1 channels: GPIO5 - - -.. _adc_attenuation: - -ADC Attenuation ---------------- -{IDF_TARGET_ADC_V_MIN_ATTEN0:default="0", esp32="100"} -{IDF_TARGET_ADC_V_MAX_ATTEN0:default="950", esp32s2="750", esp32c3="750", esp32s3="950"} - -{IDF_TARGET_ADC_V_MIN_ATTEN1:default="0", esp32="100"} -{IDF_TARGET_ADC_V_MAX_ATTEN1:default="1250", esp32s2="1050", esp32c3="1050", esp32s3="1250"} - -{IDF_TARGET_ADC_V_MIN_ATTEN2:default="0", esp32="150"} -{IDF_TARGET_ADC_V_MAX_ATTEN2:default="1750", esp32s2="1300", esp32c3="1300", esp32s3="1750"} - -{IDF_TARGET_ADC_V_MIN_ATTEN3:default="0", esp32="150"} -{IDF_TARGET_ADC_V_MAX_ATTEN3:default="2450", esp32s2="2500", esp32c3="2500", esp32s3="3100"} - - -Vref is the reference voltage used internally by {IDF_TARGET_NAME} ADCs for measuring the input voltage. The {IDF_TARGET_NAME} ADCs can measure analog voltages from 0 V to Vref. Among different chips, the Vref varies, the median is 1.1 V. In order to convert voltages larger than Vref, input voltages can be attenuated before being input to the ADCs. There are 4 available attenuation options, the higher the attenuation is, the higher the measurable input voltage could be. - -===================== ========================================================================================================= -Attenuation Measurable input voltage range -===================== ========================================================================================================= -``ADC_ATTEN_DB_0`` {IDF_TARGET_ADC_V_MIN_ATTEN0} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN0} mV -``ADC_ATTEN_DB_2_5`` {IDF_TARGET_ADC_V_MIN_ATTEN1} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN1} mV -``ADC_ATTEN_DB_6`` {IDF_TARGET_ADC_V_MIN_ATTEN2} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN2} mV -``ADC_ATTEN_DB_11`` {IDF_TARGET_ADC_V_MIN_ATTEN3} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN3} mV -===================== ========================================================================================================= - - -.. _adc_conversion: - -ADC Conversion --------------- - -{IDF_TARGET_ADC_SINGLE_MAX_WIDTH:default="12", esp32s2="13} -{IDF_TARGET_ADC_SINGLE_RAW_MAX:default="4095", esp32s2="8191"} -{IDF_TARGET_ADC_CONTINUOUS_MAX_WIDTH:default="12", esp32s3="13} -{IDF_TARGET_ADC_CONTINUOUS_RAW_MAX:default="4095", esp32s3="8191"} - - -An ADC conversion is to convert the input analog voltage to a digital value. The ADC conversion results provided by the ADC driver APIs are raw data. Resolution of {IDF_TARGET_NAME} ADC raw results under Single Read mode is {IDF_TARGET_ADC_SINGLE_MAX_WIDTH}-bit. - -- :cpp:func:`adc1_get_raw` -- :cpp:func:`adc2_get_raw` - -.. only:: esp32c3 - - - :cpp:func:`adc_digi_read_bytes` - -To calculate the voltage based on the ADC raw results, this formula can be used: - -.. parsed-literal:: - - Vout = Dout * Vmax / Dmax (1) - -where: - -====== ============================================================= -Vout Digital output result, standing for the voltage. -Dout ADC raw digital reading result. -Vmax Maximum measurable input analog voltage, see :ref:`adc_attenuation`. -Dmax Maximum of the output ADC raw digital reading result, which is {IDF_TARGET_ADC_SINGLE_RAW_MAX} under Single Read mode, {IDF_TARGET_ADC_CONTINUOUS_RAW_MAX} under Continuous Read mode. -====== ============================================================= - -For boards with eFuse ADC calibration bits, :cpp:func:`esp_adc_cal_raw_to_voltage` can be used to get the calibrated conversion results. These results stand for the actual voltage (in mV). No need to transform these data via the formula (1). -If ADC calibration APIs are used on boards without eFuse ADC calibration bits, warnings will be generated. See :ref:`adc_calibration`. - - -.. _adc_limitations: - -ADC Limitations ---------------- - -.. note:: - - .. only:: esp32 - - - Some of the ADC2 pins are used as strapping pins (GPIO 0, 2, 15) thus cannot be used freely. Such is the case in the following official Development Kits: - - ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits. - - ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes. - - Since the ADC2 module is also used by the Wi-Fi, only one of them could get the preemption when using together, which means the :cpp:func:`adc2_get_raw` may get blocked until Wi-Fi stops, and vice versa. - - .. only:: not esp32 - - - Since the ADC2 module is also used by the Wi-Fi, reading operation of :cpp:func:`adc2_get_raw` may fail between :cpp:func:`esp_wifi_start()` and :cpp:func:`esp_wifi_stop()`. Use the return code to see whether the reading is successful. - - .. only:: esp32c3 - - - A specific ADC module can only work under one operating mode at any one time, either Continuous Read Mode or Single Read Mode. - - ADC1 and ADC2 can not work under Singel Read Mode simultaneously. One of them will get blocked until another one finishes. - - For continuous (DMA) read mode, the ADC sampling frequency (the ``sample_freq_hz`` member of :cpp:type:`adc_digi_config_t`) should be within ``SOC_ADC_SAMPLE_FREQ_THRES_LOW`` and ``SOC_ADC_SAMPLE_FREQ_THRES_HIGH``. - -Driver Usage ------------- - -.. only:: esp32c3 - - Each ADC unit supports two work modes, ADC single read mode and ADC continuous (DMA) mode. ADC single read mode is suitable for low-frequency sampling operations. ADC continuous (DMA) read mode is suitable for high-frequency continuous sampling actions. - -.. only:: not esp32c3 - - Both of the ADC units support single read mode, which is suitable for low-frequency sampling operations. - -.. note:: - - ADC readings from a pin not connected to any signal are random. - -.. only:: esp32c3 - - ADC Continuous (DMA) Read mode - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - To use the ADC continuous read mode driver, execute the following steps: - - 1. Initialize the ADC driver by calling the function :cpp:func:`adc_digi_initialize`. - 2. Initialize the ADC controller by calling the function :cpp:func:`adc_digi_controller_config`. - 3. Start the ADC continuous reading by calling the function :cpp:func:`adc_digi_start`. - 4. After starting the ADC, you can get the ADC reading result by calling the function :cpp:func:`adc_digi_read_bytes`. Before stopping the ADC (by calling :cpp:func:`adc_digi_stop`), the driver will keep converting the analog data to digital data. - 5. Stop the ADC reading by calling the function :cpp:func:`adc_digi_stop`. - 6. Deinitialize the ADC driver by calling the function :cpp:func:`adc_digi_deinitialize`. - - - .. only:: esp32c3 - - The code example for using ADC continuous (DMA) read mode can be found in the :example:`peripherals/adc/dma_read` directory of ESP-IDF examples. - - .. note:: See :ref:`adc_limitations` for the limitation of using ADC continuous (DMA) read mode. - -ADC Single Read mode -^^^^^^^^^^^^^^^^^^^^ - -The ADC should be configured before reading is taken. - - - For ADC1, configure desired precision and attenuation by calling functions :cpp:func:`adc1_config_width` and :cpp:func:`adc1_config_channel_atten`. - - For ADC2, configure the attenuation by :cpp:func:`adc2_config_channel_atten`. The reading width of ADC2 is configured every time you take the reading. - -Attenuation configuration is done per channel, see :cpp:type:`adc1_channel_t` and :cpp:type:`adc2_channel_t`, set as a parameter of above functions. - -Then it is possible to read ADC conversion result with :cpp:func:`adc1_get_raw` and :cpp:func:`adc2_get_raw`. Reading width of ADC2 should be set as a parameter of :cpp:func:`adc2_get_raw` instead of in the configuration functions. - -Single Read mode ADC example can be found in :example:`peripherals/adc/single_read` directory of ESP-IDF examples. - -.. only:: esp32 - - It is also possible to read the internal hall effect sensor via ADC1 by calling dedicated function :cpp:func:`hall_sensor_read`. Note that even the hall sensor is internal to ESP32, reading from it uses channels 0 and 3 of ADC1 (GPIO 36 and 39). Do not connect anything else to these pins and do not change their configuration. Otherwise it may affect the measurement of low value signal from the sensor. - -.. only:: SOC_ULP_SUPPORTED - - This API provides convenient way to configure ADC1 for reading from :doc:`ULP <../../api-reference/system/ulp>`. To do so, call function :cpp:func:`adc1_ulp_enable` and then set precision and attenuation as discussed above. - -.. only:: esp32 or esp32s2 - - There is another specific function :cpp:func:`adc_vref_to_gpio` used to route internal reference voltage to a GPIO pin. It comes handy to calibrate ADC reading and this is discussed in section :ref:`adc_calibration`. - - -.. note:: See :ref:`adc_limitations` for the limitation of using ADC single read mode. - - -Minimizing Noise ----------------- - -The {IDF_TARGET_NAME} ADC can be sensitive to noise leading to large discrepancies in ADC readings. Depending on the usage scenario, users may connect a bypass capacitor (e.g. a 100 nF ceramic capacitor) to the ADC input pad in use, to minimize noise. Besides, multisampling may also be used to further mitigate the effects of noise. - -.. only:: esp32 - - .. figure:: ../../../_static/diagrams/adc/adc-noise-graph.jpg - :align: center - :alt: ADC noise mitigation - - Graph illustrating noise mitigation using capacitor and multisampling of 64 samples. - - -.. _adc_calibration: - -ADC Calibration ---------------- - -.. only:: esp32 or esp32s2 - - The :component_file:`esp_adc_cal/include/esp_adc_cal.h` API provides functions to correct for differences in measured voltages caused by variation of ADC reference voltages (Vref) between chips. Per design the ADC reference voltage is 1100 mV, however the true reference voltage can range from 1000 mV to 1200 mV amongst different {IDF_TARGET_NAME}s. - - .. figure:: ../../../_static/diagrams/adc/adc-vref-graph.jpg - :align: center - :alt: ADC reference voltage comparison - - Graph illustrating effect of differing reference voltages on the ADC voltage curve. - - Correcting ADC readings using this API involves characterizing one of the ADCs at a given attenuation to obtain a characteristics curve (ADC-Voltage curve) that takes into account the difference in ADC reference voltage. The characteristics curve is in the form of ``y = coeff_a * x + coeff_b`` and is used to convert ADC readings to voltages in mV. Calculation of the characteristics curve is based on calibration values which can be stored in eFuse or provided by the user. - - Calibration Values - ^^^^^^^^^^^^^^^^^^ - - {IDF_TARGET_ADC_CALI_SOURCE: default="3", esp32="3", esp32s2="1"} - - Calibration values are used to generate characteristic curves that account for the variation of ADC reference voltage of a particular {IDF_TARGET_NAME} chip. There are currently {IDF_TARGET_ADC_CALI_SOURCE} source(s) of calibration values on {IDF_TARGET_NAME}. The availability of these calibration values will depend on the type and production date of the {IDF_TARGET_NAME} chip/module. - - .. only:: esp32 - - * **Two Point** values represent each of the ADCs’ readings at 150 mV and 850 mV. To obtain more accurate calibration results these values should be measured by user and burned into eFuse ``BLOCK3``. - - * **eFuse Vref** represents the true ADC reference voltage. This value is measured and burned into eFuse ``BLOCK0`` during factory calibration. - - * **Default Vref** is an estimate of the ADC reference voltage provided by the user as a parameter during characterization. If Two Point or eFuse Vref values are unavailable, **Default Vref** will be used. - - Individual measurement and burning of the **eFuse Vref** has been applied to ESP32-D0WD and ESP32-D0WDQ6 chips produced on/after the 1st week of 2018. Such chips may be recognized by date codes on/later than 012018 (see Line 4 on figure below). - - .. figure:: ../../../_static/chip_surface_marking.png - :align: center - :alt: ESP32 Chip Surface Marking - - ESP32 Chip Surface Marking - - If you would like to purchase chips or modules with calibration, double check with distributor or Espressif (sales@espressif.com) directly. - - .. highlight:: none - - If you are unable to check the date code (i.e. the chip may be enclosed inside a canned module, etc.), you can still verify if **eFuse Vref** is present by running the `espefuse.py `_ tool with ``adc_info`` parameter :: - - $IDF_PATH/components/esptool_py/esptool/espefuse.py --port /dev/ttyUSB0 adc_info - - Replace ``/dev/ttyUSB0`` with {IDF_TARGET_NAME} board's port name. - - A chip that has specific **eFuse Vref** value programmed (in this case 1093 mV) will be reported as follows:: - - ADC VRef calibration: 1093 mV - - In another example below the **eFuse Vref** is not programmed:: - - ADC VRef calibration: None (1100 mV nominal) - - For a chip with two point calibration the message will look similar to:: - - ADC VRef calibration: 1149 mV - ADC readings stored in efuse BLK3: - ADC1 Low reading (150 mV): 306 - ADC1 High reading (850 mV): 3153 - ADC2 Low reading (150 mV): 389 - ADC2 High reading (850 mV): 3206 - - .. only:: esp32s2 - - * **eFuse Two Point** values calibrates the ADC output at two different voltages. This value is measured and burned into eFuse ``BLOCK0`` during factory calibration on newly manufactured ESP32-S2 chips and modules. If you would like to purchase chips or modules with calibration, double check with distributor or Espressif (sales@espressif.com) directly. - - .. highlight:: none - - You can verify if **eFuse Two Point** is present by running the `espefuse.py `_ tool with ``adc_info`` parameter :: - - $IDF_PATH/components/esptool_py/esptool/espefuse.py --port /dev/ttyUSB0 adc_info - - Replace ``/dev/ttyUSB0`` with {IDF_TARGET_NAME} board's port name. - - - -.. only:: esp32c3 or esp32s3 - - {IDF_TARGET_NAME} ADC Calibration contains 2 steps: Hardware Calibration and Software Calibration. - - - Hardware Calibration - ^^^^^^^^^^^^^^^^^^^^ - - Based on series of comparisons with the reference voltage, {IDF_TARGET_NAME} ADC determines each bit of the output digital result. Per design the {IDF_TARGET_NAME} ADC reference voltage is 1100 mV, however the true reference voltage can range from 1000 mV to 1200 mV among different chips. To minimize this difference, hardware calibration is introduced. - - Hardware calibration contains 2 steps: - - 1. Set an auto-calibration parameter of bandgap voltage reference. In this way, the difference mentioned above can be minimized. - 2. Correct the offset of the ADC Vin-Dout characteristics. ADC characteristics is generally a function: f(x) = A * x + B, where B is the offset. - - .. only:: esp32c3 - - An uncalibrated ADC characteristics is as follows: - - .. figure:: ../../../_static/diagrams/adc/adc-uncali-raw-c3.png - :align: center - :alt: ADC uncalibrated conversion result - - .. only:: esp32s3 - - An uncalibrated ADC characteristics is as follows: - - .. figure:: ../../../_static/diagrams/adc/adc-uncali-raw-s3.png - :align: center - :alt: ADC uncalibrated conversion result - - - The offset in the uncalibrated characteristics is significant. Step 2 is to correct the offset to 0. - - .. only:: esp32c3 - - After hardware calibration, the ADC characteristics would be like: - - .. figure:: ../../../_static/diagrams/adc/adc-hw-cali-c3.png - :align: center - :alt: ADC conversion results after hardware calibration - - .. only:: esp32s3 - - After hardware calibration, the ADC characteristics would be like: - - .. figure:: ../../../_static/diagrams/adc/adc-hw-cali-s3.png - :align: center - :alt: ADC conversion results after hardware calibration - - Hardware calibration is done internally by the ADC driver. The consequent results are raw data. A transformation is needed to get the final result, see :ref:`adc_conversion`. - - - Software Calibration - ^^^^^^^^^^^^^^^^^^^^ - - To convert ADC raw data to calibrated digital data, following steps should be followed: - - 1. Check the eFuse to know if the software calibration is supported via :cpp:func:`esp_adc_cal_check_efuse`. - 2. Calculate the ADC calibration characteristics via :cpp:func:`esp_adc_cal_characterize`. The ADC software calibration characteristics are per ADC module and per attenuation. For example, characteristics of ADC1 channel 0 under 11 dB attenuation are the same as characteristics of ADC1 channel 2 under 11 dB attenuation. But characteristics of ADC1 channel 0 under 11 dB attenuation are different with characteristics of ADC2 channel 0 under 11 dB attenuation. Also characteristics of ADC1 channel 0 under 11 dB attenuation are different with characteristics of ADC1 channel 0 under 6 dB attenuation. - 3. Get the actual voltage value via :cpp:func:`esp_adc_cal_raw_to_voltage`. - - .. only:: esp32c3 - - After software calibration, the ADC characteristics would be like: - - .. figure:: ../../../_static/diagrams/adc/adc-all-cali-c3.png - :align: center - :alt: ADC conversion results after hardware calibration - - .. only:: esp32s3 - - After software calibration, the ADC characteristics would be like: - - .. figure:: ../../../_static/diagrams/adc/adc-all-cali-s3.png - :align: center - :alt: ADC conversion results after hardware calibration - - - The results provided by the ADC calibration APIs indicate the actual voltage values. ADC software calibration example can be found in :example:`peripherals/adc/single_read` directory of ESP-IDF examples. - - -.. only:: esp32 or esp32s2 - - Application Extensions - ---------------------- - - For a full example see esp-idf: :example:`peripherals/adc/single_read` - - Characterizing an ADC at a particular attenuation:: - - #include "driver/adc.h" - #include "esp_adc_cal.h" - - ... - - //Characterize ADC at particular atten - esp_adc_cal_characteristics_t *adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); - esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars); - //Check type of calibration value used to characterize ADC - if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { - printf("eFuse Vref"); - } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { - printf("Two Point"); - } else { - printf("Default"); - } - - Reading an ADC then converting the reading to a voltage:: - - #include "driver/adc.h" - #include "esp_adc_cal.h" - - ... - uint32_t reading = adc1_get_raw(ADC1_CHANNEL_5); - uint32_t voltage = esp_adc_cal_raw_to_voltage(reading, adc_chars); - - Routing ADC reference voltage to GPIO, so it can be manually measured (for **Default Vref**):: - - #include "driver/adc.h" - - ... - - esp_err_t status = adc_vref_to_gpio(ADC_UNIT_1, GPIO_NUM_25); - if (status == ESP_OK) { - printf("v_ref routed to GPIO\n"); - } else { - printf("failed to route v_ref\n"); - } - -GPIO Lookup Macros ------------------- - -There are macros available to specify the GPIO number of a ADC channel, or vice versa. -e.g. - -1. ``ADC1_CHANNEL_0_GPIO_NUM`` is the GPIO number of ADC1 channel 0. -2. ``ADC1_GPIOn_CHANNEL`` is the ADC1 channel number of GPIO n. - -API Reference -------------- - -This reference covers three components: - -* :ref:`adc-api-reference-adc-driver` -* :ref:`adc-api-reference-adc-calibration` -* :ref:`adc-api-reference-gpio-lookup-macros` - - -.. _adc-api-reference-adc-driver: - -ADC driver -^^^^^^^^^^ - -.. include-build-file:: inc/adc.inc - -.. include-build-file:: inc/adc_types.inc - -.. _adc-api-reference-adc-calibration: - -ADC Calibration -^^^^^^^^^^^^^^^ - -.. include-build-file:: inc/esp_adc_cal.inc - -.. _adc-api-reference-gpio-lookup-macros: - -GPIO Lookup Macros -^^^^^^^^^^^^^^^^^^ - -.. include-build-file:: inc/adc_channel.inc diff --git a/docs/en/api-reference/peripherals/adc_calibration.rst b/docs/en/api-reference/peripherals/adc_calibration.rst new file mode 100644 index 0000000000..92b6bb4729 --- /dev/null +++ b/docs/en/api-reference/peripherals/adc_calibration.rst @@ -0,0 +1,184 @@ +Analog to Digital Converter (ADC) Calibration Driver +==================================================== + + +Introduction +------------ + +Based on series of comparisons with the reference voltage, {IDF_TARGET_NAME} ADC determines each bit of the output digital result. Per design the {IDF_TARGET_NAME} ADC reference voltage is 1100 mV, however the true reference voltage can range from 1000 mV to 1200 mV among different chips. This guide will introduce an ADC calibration driver to minimize this difference. + + +Functional Overview +------------------- + +The following sections of this document cover the typical steps to install and use the ADC calibration driver: + +- `Calibration Scheme Creation <#calibration-scheme-creation>`__ - covers how to create a calibration scheme handle and delete the calibration scheme handle. +- `Calibration Configuration <#calibration-configuration>`__ - covers how to configure the calibration driver to calculate necessary characteristics used for calibration. +- `Result Conversion <#result-conversion>`__ - convers how to convert ADC raw result to calibrated result. +- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. +- `Minimize Noise <#minimize-noise>`__ - describes a general way to minimize the noise. + +.. only:: esp32 + + - `Kconfig Options <#kconfig-options>`__ - lists the supported Kconfig options that can be used to make a different effect on driver behavior. + + +Calibration Scheme Creation +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ADC calibration driver provides ADC calibration scheme(s). From calibration driver's point of view, an ADC calibration scheme is created to an ADC calibration handle :cpp:type:`adc_cali_handle_t`. + +:cpp:func:`adc_cali_check_scheme` can be used to know which calibration scheme is supported on the chip. For those users who are already aware of the supported scheme, this step can be skipped. Just call the corresponding function to create the scheme handle. + +For those users who use their custom ADC calibration schemes, you could either modify this function :cpp:func:`adc_cali_check_scheme`, or just skip this step and call your custom creation function. + +.. only:: esp32 or esp32s2 + + ADC Calibration Line Fitting Scheme + ``````````````````````````````````` + + {IDF_TARGET_NAME} supports :c:macro:`ADC_CALI_SCHEME_VER_LINE_FITTING` scheme. To create this scheme, set up :cpp:type:`adc_cali_line_fitting_config_t` first. + + - :cpp:member:`adc_cali_line_fitting_config_t::unit_id`, the ADC that your ADC raw results are from. + - :cpp:member:`adc_cali_line_fitting_config_t::atten`, ADC attenuation that your ADC raw results use. + - :cpp:member:`adc_cali_line_fitting_config_t::bitwidth`, the ADC raw result bitwidth. + + .. only:: esp32 + + There is also a configuration :cpp:member:`adc_cali_line_fitting_config_t::default_vref`. Normally this can be simply set to 0. Line Fitting scheme doesn't rely on this value. However, if the Line Fitting scheme required eFuse bits are not burnt on your board, driver will rely on this value to do the calibration. + + You can use :cpp:func:`adc_cali_scheme_line_fitting_check_efuse` to check the eFuse bits. Normally the Line Fitting scheme eFuse value will be :c:macro:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP` or :c:macro:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF`. This means Line Fitting scheme will use calibration parameters burnt in the eFuse to do the calibration. + + When the Line Fitting scheme eFuse value is :c:macro:`ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF`, you need to set the :cpp:member:`esp_adc_cali_line_fitting_init::default_vref`. Default vref is an estimate of the ADC reference voltage provided by the users as a parameter during calibration. + + After setting up the configuration structure, call :cpp:func:`adc_cali_create_scheme_line_fitting` to create a Line Fitting calibration scheme handle. + + .. only:: esp32s2 + + This function may fail due to reasons such as :c:macro:`ESP_ERR_INVALID_ARG` or :c:macro:`ESP_ERR_NO_MEM`. Especially, when the function return :c:macro:`ESP_ERR_NOT_SUPPORTED`, this means the calibration scheme required eFuse bits are not burnt on your board. + + .. code:: c + + ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting"); + adc_cali_line_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(&cali_config, &handle)); + + + When the ADC calibration is no longer used, please delete the calibration scheme handle by calling :cpp:func:`adc_cali_delete_scheme_line_fitting`. + + + Delete Line Fitting Scheme + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. code:: c + + ESP_LOGI(TAG, "delete %s calibration scheme", "Line Fitting"); + ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle)); + + +.. only:: esp32c3 or esp32s3 + + ADC Calibration Curve Fitting Scheme + ```````````````````````````````````` + + {IDF_TARGET_NAME} supports :c:macro:`ADC_CALI_SCHEME_VER_CURVE_FITTING` scheme. To create this scheme, set up :cpp:type:`adc_cali_curve_fitting_config_t` first. + + - :cpp:member:`adc_cali_curve_fitting_config_t::unit_id`, the ADC that your ADC raw results are from. + - :cpp:member:`adc_cali_curve_fitting_config_t::atten`, ADC attenuation that your ADC raw results use. + - :cpp:member:`adc_cali_curve_fitting_config_t::bitwidth`, the ADC raw result bitwidth. + + After setting up the configuration structure, call :cpp:func:`adc_cali_create_scheme_curve_fitting` to create a Curve Fitting calibration scheme handle. This function may fail due to reasons such as :c:macro:`ESP_ERR_INVALID_ARG` or :c:macro:`ESP_ERR_NO_MEM`. Especially, when the function return :c:macro:`ESP_ERR_NOT_SUPPORTED`, this means the calibration scheme required eFuse bits are not burnt on your board. + + Create Curve Fitting Scheme + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. code:: c + + ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting"); + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &handle)); + + + When the ADC calibration is no longer used, please delete the calibration scheme driver from the calibration handle by calling :cpp:func:`adc_cali_delete_scheme_curve_fitting`. + + + Delete Curve Fitting Scheme + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + .. code:: c + + ESP_LOGI(TAG, "delete %s calibration scheme", "Curve Fitting"); + ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle)); + + +.. only:: esp32c2 or esp32h2 + + There is no supported calibration scheme yet. + +.. note:: + + For users who want to use their custom calibration schemes, you could provide a creation function to create your calibration scheme handle. Check the function table `adc_cali_scheme_t` in `components/esp_adc/interface/adc_cali_interface.h` to know the ESP ADC calibration interface. + + +Result Conversion +^^^^^^^^^^^^^^^^^ + +After setting up the calibration characteristics, you can call :cpp:func:`adc_cali_raw_to_voltage` to convert the ADC raw result into calibrated result. The calibrated result is in the unit of mV. This function may fail due to invalid argument. Especailly, if this function returns :c:macro:`ESP_ERR_INVALID_STATE`, this means the calibration scheme isn't created. You need to create a calibration scheme handle, use :cpp:func:`adc_cali_check_scheme` to know the supported calibration scheme. On the other hand, you could also provide a custom calibration scheme and create the handle. + + +Get Voltage +~~~~~~~~~~~ + +.. code:: c + + ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle, adc_raw[0][0], &voltage[0][0])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, voltage[0][0]); + + +Thread Safety +^^^^^^^^^^^^^ + +The factory function :cpp:func:`esp_adc_cali_new_scheme` is guaranteed to be thread safe by the driver. Therefore, you can call them from different RTOS tasks without protection by extra locks. + +Other functions that take the :cpp:type:`adc_cali_handle_t` as the first positional parameter are not thread safe, you should avoid calling them from multiple tasks. + + +.. only:: esp32 + + Kconfig Options + ^^^^^^^^^^^^^^^ + + - :ref:`CONFIG_ADC_CAL_EFUSE_TP_ENABLE`, disable this to decrease the code size, if you are aware of the calibration eFuse value :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP` isn't this one. + - :ref:`CONFIG_ADC_CAL_EFUSE_VREF_ENABLE`, disable this to decrease the code size, if you are aware of the calibration eFuse value :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF` isn't this one. + - :ref:`CONFIG_ADC_CAL_LUT_ENABLE`, disable this to decrease the code size, if you don't calibrate the ADC raw results under :c:macro:`ADC_ATTEN_DB_11`. + + +Minimize Noise +^^^^^^^^^^^^^^ + +The {IDF_TARGET_NAME} ADC can be sensitive to noise leading to large discrepancies in ADC readings. Depending on the usage scenario, you may need to connect a bypass capacitor (e.g. a 100 nF ceramic capacitor) to the ADC input pad in use, to minimize noise. Besides, multisampling may also be used to further mitigate the effects of noise. + +.. only:: esp32 + + .. figure:: ../../../_static/diagrams/adc/adc-noise-graph.jpg + :align: center + :alt: ADC noise mitigation + + Graph illustrating noise mitigation using capacitor and multisampling of 64 samples. + + +API Reference +------------- + + +.. include-build-file:: inc/adc_cali.inc +.. include-build-file:: inc/adc_cali_scheme.inc diff --git a/docs/en/api-reference/peripherals/adc_continuous.rst b/docs/en/api-reference/peripherals/adc_continuous.rst new file mode 100644 index 0000000000..6f30edafbe --- /dev/null +++ b/docs/en/api-reference/peripherals/adc_continuous.rst @@ -0,0 +1,256 @@ +Analog to Digital Converter (ADC) Continuous Mode Driver +======================================================== + + +Introduction +------------ + +The Analog to Digital Converter is an on-chip sensor which is able to measure analog signals from specific analog IO pads. + +The ADC on {IDF_TARGET_NAME} can be used in scenario(s) like: + +- Generate one-shot ADC conversion result +- Generate continuous ADC conversion results + +This guide will introduce ADC continuous mode conversion. + +Driver Concepts +^^^^^^^^^^^^^^^ + +ADC continuous mode conversion is made up with multiple Conversion Frames. +- Conversion Frame: One Conversion Frame contains multiple Conversion Results. Conversion Frame size is configured in :cpp:func:`adc_continuous_new_handle`, in bytes. +- Conversion Result: One Conversion Result contains multiple bytes (see :c:macro:`SOC_ADC_DIGI_RESULT_BYTES`). Its structure is :cpp:type:`adc_digi_output_data_t`, including ADC unit, ADC channel and raw data. + +.. image:: /../_static/diagrams/adc/adc_conversion_frame.png + :scale: 100 % + :align: center + +Functional Overview +------------------- + +The following sections of this document cover the typical steps to install the ADC continuous mode driver, and read ADC conversion results from group of ADC channels continuously: + +- `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to initialize the ADC continuous mode driver and how to deinitialize it. +- `ADC Configurations <#adc-configurations>`__ - describes how to configure the ADC(s) to make it work under continuous mode. +- `ADC Control <#adc-control>`__ - describes ADC control functions. +- `Register Event Callbacks <#register-event-callbacks>`__ - describes how to hook user specific code to an ADC continuous mode event callback function. +- `Read Conversion Result <#read-conversion-result>`__ - covers how to get ADC conversion result. +- `Hardware Limitations <#hardware-limitations>`__ - describes the ADC related hardware limitations. +- `Power Management <#power-management>`__ - covers power management related. +- `IRAM Safe <#iram-safe>`__ - covers the IRAM safe functions. +- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. + + +Resource Allocation +^^^^^^^^^^^^^^^^^^^ + +The ADC continuous mode driver is implemented based on {IDF_TARGET_NAME} SAR ADC module. Different ESP targets might have different number of independent ADCs. + +To create an ADC continuous mode driver handle, set up the required configuration structure :cpp:type:`adc_continuous_handle_cfg_t`: + +- :cpp:member:`adc_continuous_handle_cfg_t::max_store_buf_size` set the maximum size (in bytes) of the pool that the driver saves ADC conversion result into. If this pool is full, new conversion results will be lost. +- :cpp:member:`adc_continuous_handle_cfg_t::conv_frame_size` set the size of the ADC conversion frame, in bytes. + + +After setting up above configurations for the ADC, call :cpp:func:`adc_continuous_new_handle` with the prepared :cpp:type:`adc_continuous_handle_cfg_t`. This function may fail due to various errors such as invalid argumemts, insufficient memory, etc. + +.. only:: esp32 + + Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the I2S0 peripheral is in use. See `Hardware Limitations <#hardware-limitations>`__ for more information. + +.. only:: esp32s2 + + Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the SPI3 peripheral is in use. See `Hardware Limitations <#hardware-limitations>`__ for more information. + +.. only:: SOC_GDMA_SUPPORTED + + Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means there is no free GDMA channel. + +If the ADC continuous mode driver is no longer used, you should deinitialize the driver by calling :cpp:func:`adc_continuous_deinit`. + + +Initialize the ADC Continuous Mode Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: c + + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = 1024, + .conv_frame_size = 100, + }; + ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config)); + + +Recycle the ADC Unit +~~~~~~~~~~~~~~~~~~~~ + +.. code:: c + + ESP_ERROR_CHECK(adc_continuous_deinit()); + + +ADC Configurations +^^^^^^^^^^^^^^^^^^ + +After the ADC continuous mode driver is initialized, set up the :cpp:type:`adc_continuous_config_t` to configure ADC IOs to measure analog signal: + +- :cpp:member:`adc_continuous_config_t::pattern_num`, number of ADC channels that will be used. +- :cpp:member:`adc_continuous_config_t::adc_pattern`, list of configs for each ADC channel that will be used, see below description. +- :cpp:member:`adc_continuous_config_t::sample_freq_hz`, expected ADC sampling frequency in Hz. +- :cpp:member:`adc_continuous_config_t::conv_mode`, continuous conversion mode. +- :cpp:member:`adc_continuous_config_t::format`, conversion output format. + +For :cpp:type:`adc_digi_pattern_config_t`: + +- :cpp:member:`adc_digi_pattern_config_t::atten`, ADC attenuation. Refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. +- :cpp:member:`adc_digi_pattern_config_t::channel`, the IO corresponding ADC channel number. See below note. +- :cpp:member:`adc_digi_pattern_config_t::unit`, the ADC that the IO is subordinate to. +- :cpp:member:`adc_digi_pattern_config_t::bit_width`, the bitwidth of the raw conversion result. + +.. note:: + + For the IO corresponding ADC channel number. Check `datasheet <{IDF_TARGET_TRM_EN_URL}>`__ to acquire the ADC IOs. + On the other hand, :cpp:func:`adc_continuous_io_to_channel` and :cpp:func:`adc_continuous_channel_to_io` can be used to acquire the ADC channels and ADC IOs. + +To make these settings take effect, call :cpp:func:`adc_continuous_config` with the configuration structure above. +This API may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. When it returns :c:macro:`ESP_ERR_INVALID_STATE`, this means the ADC continuous mode driver is started, you shouldn't call this API at this moment. + +See ADC continuous mode example :example:`peripherals/adc/continuous_read` to see configuration codes. + + +ADC Control +^^^^^^^^^^^ + +Start and Stop +~~~~~~~~~~~~~~ + +Calling :cpp:func:`adc_continuous_start` will make the ADC start to measure analog signals from the configured ADC channels, and generate the conversion results. +On the contrary, calling :cpp:func:`adc_continuous_stop` will stop the ADC conversion. + +.. code::c + + ESP_ERROR_CHECK(adc_continuous_start()); + +.. code:: c + + ESP_ERROR_CHECK(adc_continuous_stop()); + + +Register Event Callbacks +^^^^^^^^^^^^^^^^^^^^^^^^ + +By calling :cpp:func:`adc_continuous_register_event_callbacks`, you can hook your own function to the driver ISR. Supported event callbacks are listed in :cpp:type:`adc_continuous_evt_cbs_t` +- :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done`, this is invoked when one conversion frame finishes. +- :cpp:member:`adc_continuous_evt_cbs_t::on_pool_ovf`, this is invoked when internal pool is full. Newer conversion results will be discarded. + +As above callbacks are called in an ISR context, you should always ensure the callback function is suitable for an ISR context. Blocking logics should not appear in these callbacks. Callback function prototype is declared in :cpp:type:`adc_continuous_callback_t`. + +You can also register your own context when calling :cpp:func:`adc_continuous_register_event_callbacks`, by the parameter ``user_data``. This user data will be passed to the callback functions directly. + +This function may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. Specially, when :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` is enabled, this error may indicate that the callback functions aren't in internal RAM. Check error log to know this. Besides, when it fails due to :c:macro:`ESP_ERR_INVALID_STATE`, this means the ADC continuous mode driver is started, you shouldn't add callback at this moment. + + +Conversion Done Event +~~~~~~~~~~~~~~~~~~~~~ + +The driver will fill in the event data of a :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done` event. Event data contains a buffer pointer to a conversion frame buffer, together with the size. Refer to :cpp:type:`adc_continuous_evt_data_t` to know the event data structure. + +.. note:: + + It is worth noting that, the data buffer :cpp:member:`adc_continuous_evt_data_t::conv_frame_buffer` is maintained by the driver itself. Therefore, never free this piece of memory. + +.. note:: + + When the Kconfig option :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` is enabled, the registered callbacks and the functions called by the callbacks should be placed in IRAM. The involved variables should be placed in internal RAM as well. + +Pool Overflow Event +~~~~~~~~~~~~~~~~~~~ + +The ADC continuous mode driver has an internal pool to save the conversion results. When the pool is full, a pool overflow event will emerge. Under this condition, the driver won't fill in the event data. This usually happens the speed to read data from the pool (by calling :cpp:func:`adc_continuous_read`) is much slower than the ADC conversion speed. + + +Read Conversion Result +^^^^^^^^^^^^^^^^^^^^^^ + +After calling :cpp:func:`adc_continuous_start`, the ADC continuous conversion starts. Call :cpp:func:`adc_continuous_read` to get the conversion results of the ADC channels. You need to provide a buffer to get the raw results. + +This function will try to read the expected length of conversion results each time. + +- If the requested length isn't reached, the function will still move the data from the internal pool to the buffer you prepared. Therefore, check the `out_length` to know the actual size of conversion results. +- If there is no conversion result generated in the internal pool, the function will block for `timeout_ms` until the conversion results are generated. If there is still no generated results, the function will return :c:macro:`ESP_ERR_TIMEOUT`. +- If the generated results fill up the internal pool, new generated results will be lost. Next time when the :cpp:func:`adc_continuous_read` is called, this function will return :c:macro:`ESP_ERR_INVALID_STATE` indicating this situation. + +This API aims to give you a chance to read all the ADC continuous conversion results. + +The ADC conversion results read from above function are raw data. To calculate the voltage based on the ADC raw results, this formula can be used: + +.. parsed-literal:: + + Vout = Dout * Vmax / Dmax (1) + +where: + +====== ============================================================= +Vout Digital output result, standing for the voltage. +Dout ADC raw digital reading result. +Vmax Maximum measurable input analog voltage, this is related to the ADC attenuation, please refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. +Dmax Maximum of the output ADC raw digital reading result, which is 2^bitwidth, where bitwidth is the :cpp:member::`adc_digi_pattern_config_t:bit_width` configured before. +====== ============================================================= + +To do further calbration to convert the ADC raw result to voltage in mV, please refer to calibration doc :doc:`adc_calibration`. + + +Hardware Limitations +^^^^^^^^^^^^^^^^^^^^ + +- A specific ADC unit can only work under one operating mode at any one time, either Continuous Mode or Oneshot Mode. :cpp:func:`adc_continuous_start` has provided the protection. + +- Random Number Generator uses ADC as an input source. When ADC continuous mode driver works, the random number generated from RNG will be less random. + +.. only:: esp32s2 or esp32c3 or esp32s3 + + - ADC2 is also used by the Wi-Fi. :cpp:func:`adc_continuous_start` has provided the protection between Wi-Fi driver and ADC continuous mode driver. + +.. only:: esp32 + + - ADC continuous mode driver uses I2S0 peripheral as hardware DMA fifo. Therefore, if I2S0 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`. + + - ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits. + + - ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes. + +.. only:: esp32s2 + + - ADC continuous mode driver uses SPI3 peripheral as hardware DMA fifo. Therefore, if SPI3 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`. + + +Power Management +^^^^^^^^^^^^^^^^ + +When power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the APB clock frequency may be adjusted when the system is in an idle state, thus potentially changing the behavior of ADC continuous conversion. + +However, the continuous mode driver can prevent this change by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. The lock is acquired after the continuous conversion is started by :cpp:func:`adc_continuous_start`. Similarly, the lock will be released after :cpp:func:`adc_continuous_stop`. Therefore, :cpp:func:`adc_continuous_start` and :cpp:func:`adc_continuous_stop` should appear in pairs, otherwise the power management will be out of action. + + +IRAM Safe +^^^^^^^^^ + +All the ADC continuous mode driver APIs are not IRAM-safe. They are not supposed to be run when the Cache is disabled. By enabling the Kconfig option :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE`, driver internal ISR handler is IRAM-safe, which means even when the Cache is disabled, the driver will still save the conversion results into its internal pool. + + +Thread Safety +^^^^^^^^^^^^^ + +ADC continuous mode driver APIs are not guaranteed to be thread safe. However, the share hardware mutual exclusion is provided by the driver. See `Hardware Limitations <#hardware-limitations>`__ for more details. + + +Application Examples +-------------------- + +* ADC continuous mode example: :example:`peripherals/adc/continuous_read`. + + +API Reference +------------- + +.. include-build-file:: inc/adc_continuous.inc \ No newline at end of file diff --git a/docs/en/api-reference/peripherals/adc_oneshot.rst b/docs/en/api-reference/peripherals/adc_oneshot.rst new file mode 100644 index 0000000000..506d922e88 --- /dev/null +++ b/docs/en/api-reference/peripherals/adc_oneshot.rst @@ -0,0 +1,210 @@ +Analog to Digital Converter (ADC) Oneshot Mode Driver +===================================================== + + +Introduction +------------ + +The Analog to Digital Converter is an on-chip sensor which is able to measure analog signals from dedicated analog IO pads. + +The ADC on {IDF_TARGET_NAME} can be used in scenario(s) like: + +- Generate one-shot ADC conversion result + +.. only:: SOC_ADC_DMA_SUPPORTED + + - Generate continuous ADC conversion results + +This guide will introduce ADC oneshot mode conversion. + + +Functional Overview +------------------- + +The following sections of this document cover the typical steps to install and operate an ADC: + +- `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to get an ADC handle and how to recycle the resources when ADC finishes working. +- `Unit Configuration <#unit-configuration>`__ - covers the parameters that should be set up to configure the ADC unit, so as to get ADC conversion raw result. +- `Read Conversion Result <#read-conversion-result>`__ - covers how to get ADC conversion raw result. +- `Hardware Limitations <#hardware-limitations>`__ - describes the ADC related hardware limitations. +- `Power Management <#power-management>`__ - covers power management related. +- `IRAM Safe <#iram-safe>`__ - describes tips on how to read ADC conversion raw result when cache is disabled. +- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. +- `Kconfig Options <#kconfig-options>`__ - lists the supported Kconfig options that can be used to make a different effect on driver behavior. + + +Resource Allocation +^^^^^^^^^^^^^^^^^^^ + +The ADC oneshot mode driver is implemented based on {IDF_TARGET_NAME} SAR ADC module. Different ESP chips might have different number of independent ADCs. From oneshot mode driver's point of view, an ADC instance is represented by :cpp:type:`adc_oneshot_unit_handle_t`. + +To install an ADC instance, set up the required initial configuration structure :cpp:type:`adc_oneshot_unit_init_cfg_t`: + +- :cpp:member:`adc_oneshot_unit_init_cfg_t::unit_id` selects the ADC. Please refer to the `datasheet <{IDF_TARGET_TRM_EN_URL}>`__ to know dedicated analog IOs for this ADC. +- :cpp:member:`adc_oneshot_unit_init_cfg_t::ulp_mode` sets if the ADC will be working under super low power mode. + +.. todo:: + + Add ULP ADC related docs here. + +After setting up the initial configurations for the ADC, call :cpp:func:`adc_oneshot_new_unit` with the prepared :cpp:type:`adc_oneshot_unit_init_cfg_t`. This function will return an ADC unit handle, if the allocation is successful. + +This function may fail due to various errors such as invalid argumemts, insufficient memory, etc. Specifically, when the to-be-allocated ADC instance is registered already, this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. Number of available ADC(s) is recorded by :c:macro:`SOC_ADC_PERIPH_NUM`. + +If a previously created ADC instance is no loger required, you should recycle the ADC instance by calling :cpp:func:`adc_oneshot_del_unit`, related hardware and software resources will be recycled as well. + + +Create an ADC Unit Handle under Normal Oneshot Mode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: c + + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = false, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + +Recycle the ADC Unit +~~~~~~~~~~~~~~~~~~~~ + +.. code:: c + + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle)); + + +Unit Configuration +^^^^^^^^^^^^^^^^^^ + +After an ADC instance is created, set up the :cpp:type:`adc_oneshot_chan_cfg_t` to configure ADC IO to measure analog signal: + +- :cpp:member:`adc_oneshot_chan_cfg_t::atten`, ADC attenuation. Refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. +- :cpp:member:`adc_oneshot_chan_cfg_t::channel`, the IO corresponding ADC channel number. See below note. +- :cpp:member:`adc_oneshot_chan_cfg_t::bitwidth`, the bitwidth of the raw conversion result. + +.. note:: + + For the IO corresponding ADC channel number. Check `datasheet <{IDF_TARGET_TRM_EN_URL}>`__ to know the ADC IOs. + On the other hand, :cpp:func:`adc_continuous_io_to_channel` and :cpp:func:`adc_continuous_channel_to_io` can be used to know the ADC channels and ADC IOs. + +To make these settings take effect, call :cpp:func:`adc_oneshot_config_channel` with above configuration structure. Especially, this :cpp:func:`adc_oneshot_config_channel` can be called multiple times to configure different ADC channels. Drvier will save these per channel configurations internally. + + +Configure Two ADC Channels +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: c + + adc_oneshot_chan_cfg_t config = { + .channel = EXAMPLE_ADC1_CHAN0, + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, &config)); + + config.channel = EXAMPLE_ADC1_CHAN1; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, &config)); + + +Read Conversion Result +^^^^^^^^^^^^^^^^^^^^^^ + +After above configurations, the ADC is ready to measure the analog siganl(s) from the configured ADC channel(s). Call :cpp:func:`adc_oneshot_read` to get the conversion raw result of an ADC channel. + +- :cpp:func:`adc_oneshot_read` is safer. ADC(s) are shared by some other drivers / peripherals, see `Hardware Limitations <#hardware-limitations>`__. This function takes some mutexes, to avoid concurrent hardware usage. Therefore, this function should not be used in an ISR context. This function may fail when the ADC is in use by other drivers / peripherals, and return :c:macro:`ESP_ERR_TIMEOUT`. Under this condition, the ADC raw result is invalid. + +These two functions will both fail due to invalid arguments. + +The ADC conversion results read from these two functions are raw data. To calculate the voltage based on the ADC raw results, this formula can be used: + +.. parsed-literal:: + + Vout = Dout * Vmax / Dmax (1) + +where: + +====== ============================================================= +Vout Digital output result, standing for the voltage. +Dout ADC raw digital reading result. +Vmax Maximum measurable input analog voltage, this is related to the ADC attenuation, please refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__. +Dmax Maximum of the output ADC raw digital reading result, which is 2^bitwidth, where bitwidth is the :cpp:member::`adc_oneshot_chan_cfg_t:bitwidth` configured before. +====== ============================================================= + +To do further calbration to convert the ADC raw result to voltage in mV, please refer to calibration doc :doc:`adc_calibration`. + + +Read Raw Result +~~~~~~~~~~~~~~~ + +.. code:: c + + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0][0])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, adc_raw[0][0]); + + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN1, &adc_raw[0][1])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN1, adc_raw[0][1]); + + +Hardware Limitations +^^^^^^^^^^^^^^^^^^^^ + +- Random Number Generator uses ADC as a input source. When ADC :cpp:func:`adc_oneshot_read` works, the random number generated from RNG will be less random. + +.. only:: SOC_ADC_DMA_SUPPORTED + + - A specific ADC unit can only work under one operating mode at any one time, either Continuous Mode or Oneshot Mode. :cpp:func:`adc_oneshot_read` has provided the protection. + +.. only:: esp32s2 or esp32c3 or esp32s3 + + - ADC2 is also used by the Wi-Fi. :cpp:func:`adc_oneshot_read` has provided the protection between Wi-Fi driver and ADC continuous mode driver. + +.. only:: esp32 + + - ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits. + + - ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes. + + +Power Management +^^^^^^^^^^^^^^^^ + +When power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the system clock frequency may be adjusted when the system is in an idle state. However, the ADC oneshot mode driver works in a polling routine, the :cpp:func:`adc_oneshot_read` will poll the CPU until the function returns. During this period of time, the task in which ADC oneshot mode driver resides won't be blocked. Therefore the clock frequency is stable when reading. + + +IRAM Safe +^^^^^^^^^ + +By default, all the ADC oneshot mode driver APIs are not supposed to be run when the Cache is disabled (Cache may be disabled due to many reasons, such as Flash writing/erasing, OTA, etc.). If these APIs executes when the Cache is disabled, you will probably see errors like Illegal Instruction or Load/Store Prohibited. + + +Thread Safety +^^^^^^^^^^^^^ + +- :cpp:func:`adc_oneshot_new_unit` +- :cpp:func:`adc_oneshot_config_channel` +- :cpp:func:`adc_oneshot_read` + +Above functions are guaranteed to be thread safe. Therefore, you can call them from different RTOS tasks without protection by extra locks. + +- :cpp:func:`adc_oneshot_del_unit` is not thread safe. Besides, concurrently calling this function may result in thread-safe APIs fail. + + +Kconfig Options +^^^^^^^^^^^^^^^ + +- :ref:`CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM` controls where to place the ADC fast read function (IRAM or Flash), see `IRAM Safe <#iram-safe>`__ for more details. + + +Application Examples +-------------------- + +* ADC oneshot mode example: :example:`peripherals/adc/oneshot_read`. + + +API Reference +------------- + +.. include-build-file:: inc/adc_types.inc +.. include-build-file:: inc/adc_oneshot.inc \ No newline at end of file diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index 5274eaf295..305cbb1d95 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -6,7 +6,9 @@ Peripherals API .. toctree:: :maxdepth: 1 - adc + adc_oneshot + :SOC_ADC_DMA_SUPPORTED: adc_continuous + adc_calibration clk_tree :SOC_DAC_SUPPORTED: dac gpio @@ -38,4 +40,4 @@ Peripherals API :SOC_USB_OTG_SUPPORTED: usb_device :SOC_USB_OTG_SUPPORTED: usb_host -Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples. \ No newline at end of file +Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples. diff --git a/docs/en/migration-guides/peripherals.rst b/docs/en/migration-guides/peripherals.rst index 564c5a6e41..504ec9e7c8 100644 --- a/docs/en/migration-guides/peripherals.rst +++ b/docs/en/migration-guides/peripherals.rst @@ -62,11 +62,17 @@ Header ``esp_spi_flash.h`` has been deprecated, system functions are no longer p ADC --- +- ADC oneshot mode driver has been redesigned. New driver is in ``esp_adc`` component and the include path is ``esp_adc/adc_oneshot.h``. Legacy driver is still available in the previous include path ``driver/adc.h``. However, by default, including ``driver/adc.h`` will bring a build warning like `legacy adc driver is deprecated, please migrate to use esp_adc/adc_oneshot.h and esp_adc/adc_continuous.h for oneshot mode and continuous mode drivers respectively`. The warning can be suppressed by the Kconfig option :ref:`CONFIG_ADC_SUPPRESS_DEPRECATE_WARN`. +- ADC continuous mode driver has been moved from ``driver`` component to ``esp_adc`` component. Include path has been changed from ``driver/adc.h`` to ``esp_adc/adc_continuous.h``. Legacy driver is still available in the previous include path ``driver/adc.h``. Similarly, including it will bring a build warning, and it can be suppressed by the Kconfig option :ref:`CONFIG_ADC_SUPPRESS_DEPRECATE_WARN`. +- ADC calibration driver has been redesigned. New driver is in ``esp_adc`` component and the include path is ``esp_adc/adc_cali.h`` and ``esp_adc/adc_cali_scheme.h``. Legacy driver is still available by including ``esp_adc_cal.h``. However, by default, including ``esp_adc_cal.h`` will bring a build warning like `legacy adc calibration driver is deprecated, please migrate to use esp_adc/adc_cali.h and esp_adc/adc_cali_scheme.h`. The warning can be suppressed by the Kconfig option :ref:`CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN`. +- API ``adc_power_acquire`` and ``adc_power_release`` have been deprecated. These two are used by other drivers to maintain ADC power due to hardware limitation. After this change, ADC power will still be handled by the drivers. However, for users who are interested in this, the include path has been changed from ``driver/adc.h`` to ``esp_private/adc_private.h``. - Previous ``driver/adc2_wifi_private.h`` has been moved to ``esp_private/adc2_wifi.h``. -- Enums ``ADC_UNIT_BOTH``, ``ADC_UNIT_ALTER`` and ``ADC_UNIT_MAX`` in ``adc_unit_t`` are removed. -- Enum ``ADC_CHANNEL_MAX`` in ``adc_channel_t`` are removed. Some channels are not supported on some chips, driver will give a dynamic error if an unsupported channels are used. -- Enum ``ADC_ATTEN_MAX`` is removed. Some attenuations are not supported on some chips, driver will give a dynamic error if an unsupported attenuation is used. -- Enum ``ADC_CONV_UNIT_MAX`` is removed. Some convert mode are not supported on some chips, driver will give a dynamic error if an unsupported convert mode is used. +- Enums ``ADC_UNIT_BOTH``, ``ADC_UNIT_ALTER`` and ``ADC_UNIT_MAX`` in ``adc_unit_t`` have been removed. +- Enum ``ADC_CHANNEL_MAX`` in ``adc_channel_t`` has been removed. Some channels are not supported on some chips, driver will give a dynamic error if an unsupported channels are used. +- Enum ``ADC_ATTEN_MAX`` has been removed. Some attenuations are not supported on some chips, driver will give a dynamic error if an unsupported attenuation is used. +- Enum ``ADC_CONV_UNIT_MAX`` has been removed. Some convert mode are not supported on some chips, driver will give a dynamic error if an unsupported convert mode is used. +- API ``hall_sensor_read`` on ESP32 has been removed. Hall sensor is no more 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``. GPIO ---- diff --git a/docs/zh_CN/api-reference/peripherals/adc.rst b/docs/zh_CN/api-reference/peripherals/adc.rst deleted file mode 100644 index 992087787b..0000000000 --- a/docs/zh_CN/api-reference/peripherals/adc.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../../en/api-reference/peripherals/adc.rst \ No newline at end of file diff --git a/docs/zh_CN/api-reference/peripherals/adc_calibration.rst b/docs/zh_CN/api-reference/peripherals/adc_calibration.rst new file mode 100644 index 0000000000..2c86bc1d28 --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/adc_calibration.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/peripherals/adc_calibration.rst \ No newline at end of file diff --git a/docs/zh_CN/api-reference/peripherals/adc_continuous.rst b/docs/zh_CN/api-reference/peripherals/adc_continuous.rst new file mode 100644 index 0000000000..890cb0cf7f --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/adc_continuous.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/peripherals/adc_continuous.rst \ No newline at end of file diff --git a/docs/zh_CN/api-reference/peripherals/adc_oneshot.rst b/docs/zh_CN/api-reference/peripherals/adc_oneshot.rst new file mode 100644 index 0000000000..d8d198e1eb --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/adc_oneshot.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/peripherals/adc_oneshot.rst \ No newline at end of file diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index c189070375..a02b00ca35 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -6,7 +6,9 @@ .. toctree:: :maxdepth: 1 - adc + adc_oneshot + :SOC_ADC_DMA_SUPPORTED: adc_continuous + adc_calibration clk_tree :SOC_DAC_SUPPORTED: dac gpio @@ -38,4 +40,4 @@ :SOC_USB_OTG_SUPPORTED: usb_device :SOC_USB_OTG_SUPPORTED: usb_host -本部分的 API 示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals` 目录下。 \ No newline at end of file +本部分的 API 示例代码存放在 ESP-IDF 示例项目的 :example:`peripherals` 目录下。 diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 44b93d935b..20f9de29b9 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -1,28 +1,10 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps -examples/peripherals/adc/dma_read: +examples/peripherals/adc/continuous_read: disable: - if: IDF_TARGET == "esp32c2" temporary: true - reason: target esp32c2 is not supported yet - -examples/peripherals/adc/single_read/adc: - enable: - - if: IDF_TARGET == "esp32" - temporary: true - reason: the other targets are not tested yet - -examples/peripherals/adc/single_read/adc2: - enable: - - if: IDF_TARGET == "esp32" - temporary: true - reason: the other targets are not tested yet - -examples/peripherals/adc/single_read/single_read: - disable: - - if: IDF_TARGET == "esp32c2" - temporary: true - reason: target esp32c2 is not supported yet + reason: adc dma mode isn't supported on these targets examples/peripherals/gpio/generic_gpio: disable_test: diff --git a/examples/peripherals/adc/single_read/adc2/CMakeLists.txt b/examples/peripherals/adc/continuous_read/CMakeLists.txt similarity index 89% rename from examples/peripherals/adc/single_read/adc2/CMakeLists.txt rename to examples/peripherals/adc/continuous_read/CMakeLists.txt index 8d781eb6f8..2d54383253 100644 --- a/examples/peripherals/adc/single_read/adc2/CMakeLists.txt +++ b/examples/peripherals/adc/continuous_read/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(adc2) +project(continuous_read) diff --git a/examples/peripherals/adc/dma_read/README.md b/examples/peripherals/adc/continuous_read/README.md similarity index 98% rename from examples/peripherals/adc/dma_read/README.md rename to examples/peripherals/adc/continuous_read/README.md index f5851bcdf7..29d7a3f0a2 100644 --- a/examples/peripherals/adc/dma_read/README.md +++ b/examples/peripherals/adc/continuous_read/README.md @@ -48,7 +48,7 @@ I (368) ADC DMA: adc_pattern[1].unit is :0 I (368) ADC DMA: adc_pattern[2].atten is :0 I (378) ADC DMA: adc_pattern[2].channel is :0 I (378) ADC DMA: adc_pattern[2].unit is :1 -I (388) TASK:: ret is 0, ret_num is 256 +I (388) TASK: ret is 0, ret_num is 256 I (388) ADC DMA: Unit: 1,_Channel: 2, Value: bec I (398) ADC DMA: Unit: 2,_Channel: 0, Value: 9cb I (398) ADC DMA: Unit: 1,_Channel: 3, Value: acb diff --git a/examples/peripherals/adc/continuous_read/main/CMakeLists.txt b/examples/peripherals/adc/continuous_read/main/CMakeLists.txt new file mode 100644 index 0000000000..902872a063 --- /dev/null +++ b/examples/peripherals/adc/continuous_read/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "continuous_read_main.c" + INCLUDE_DIRS ".") diff --git a/examples/peripherals/adc/continuous_read/main/continuous_read_main.c b/examples/peripherals/adc/continuous_read/main/continuous_read_main.c new file mode 100644 index 0000000000..47f51edb61 --- /dev/null +++ b/examples/peripherals/adc/continuous_read/main/continuous_read_main.c @@ -0,0 +1,173 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_adc/adc_continuous.h" + +#define EXAMPLE_READ_LEN 256 +#define GET_UNIT(x) ((x>>3) & 0x1) + +#if CONFIG_IDF_TARGET_ESP32 +#define ADC_CONV_MODE ADC_CONV_SINGLE_UNIT_1 //ESP32 only supports ADC1 DMA mode +#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1 +#elif CONFIG_IDF_TARGET_ESP32S2 +#define ADC_CONV_MODE ADC_CONV_BOTH_UNIT +#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 +#define ADC_CONV_MODE ADC_CONV_ALTER_UNIT //ESP32C3 only supports alter mode +#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 +#elif CONFIG_IDF_TARGET_ESP32S3 +#define ADC_CONV_MODE ADC_CONV_BOTH_UNIT +#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 +#endif + +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 +static adc_channel_t channel[3] = {ADC_CHANNEL_2, ADC_CHANNEL_3, (ADC_CHANNEL_0 | 1 << 3)}; +#endif +#if CONFIG_IDF_TARGET_ESP32S2 +static adc_channel_t channel[3] = {ADC_CHANNEL_2, ADC_CHANNEL_3, (ADC_CHANNEL_0 | 1 << 3)}; +#endif +#if CONFIG_IDF_TARGET_ESP32 +static adc_channel_t channel[1] = {ADC_CHANNEL_7}; +#endif + +static TaskHandle_t s_task_handle; +static const char *TAG = "EXAMPLE"; + + +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; + //Notify that ADC continuous driver has done enough number of conversions + vTaskNotifyGiveFromISR(s_task_handle, &mustYield); + + return (mustYield == pdTRUE); +} + +static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num, adc_continuous_handle_t *out_handle) +{ + adc_continuous_handle_t handle = NULL; + + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = 1024, + .conv_frame_size = EXAMPLE_READ_LEN, + }; + ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config, &handle)); + + adc_continuous_config_t dig_cfg = { + .sample_freq_hz = 20 * 1000, + .conv_mode = ADC_CONV_MODE, + .format = ADC_OUTPUT_TYPE, + }; + + adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0}; + dig_cfg.pattern_num = channel_num; + for (int i = 0; i < channel_num; i++) { + uint8_t unit = GET_UNIT(channel[i]); + uint8_t ch = channel[i] & 0x7; + adc_pattern[i].atten = ADC_ATTEN_DB_0; + adc_pattern[i].channel = ch; + adc_pattern[i].unit = unit; + adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH; + + ESP_LOGI(TAG, "adc_pattern[%d].atten is :%x", i, adc_pattern[i].atten); + ESP_LOGI(TAG, "adc_pattern[%d].channel is :%x", i, adc_pattern[i].channel); + ESP_LOGI(TAG, "adc_pattern[%d].unit is :%x", i, adc_pattern[i].unit); + } + dig_cfg.adc_pattern = adc_pattern; + ESP_ERROR_CHECK(adc_continuous_config(handle, &dig_cfg)); + + *out_handle = handle; +} + +#if !CONFIG_IDF_TARGET_ESP32 +static bool check_valid_data(const adc_digi_output_data_t *data) +{ + const unsigned int unit = data->type2.unit; + if (unit > 2) return false; + if (data->type2.channel >= SOC_ADC_CHANNEL_NUM(unit)) return false; + + return true; +} +#endif + +void app_main(void) +{ + esp_err_t ret; + uint32_t ret_num = 0; + uint8_t result[EXAMPLE_READ_LEN] = {0}; + memset(result, 0xcc, EXAMPLE_READ_LEN); + + s_task_handle = xTaskGetCurrentTaskHandle(); + + adc_continuous_handle_t handle = NULL; + continuous_adc_init(channel, sizeof(channel) / sizeof(adc_channel_t), &handle); + + adc_continuous_evt_cbs_t cbs = { + .on_conv_done = s_conv_done_cb, + }; + ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(handle, &cbs, NULL)); + ESP_ERROR_CHECK(adc_continuous_start(handle)); + + while(1) { + + /** + * This is to show you the way to use the ADC continuous mode driver event callback. + * This `ulTaskNotifyTake` will block when the data processing in the task is fast. + * However in this example, the data processing (print) is slow, so you barely block here. + * + * Without using this event callback (to notify this task), you can still just call + * `adc_continuous_read()` here in a loop, with/without a certain block timeout. + */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + while (1) { + ret = adc_continuous_read(handle, result, EXAMPLE_READ_LEN, &ret_num, 0); + if (ret == ESP_OK) { + ESP_LOGI("TASK", "ret is %x, ret_num is %d", ret, ret_num); + for (int i = 0; i < ret_num; i += SOC_ADC_DIGI_RESULT_BYTES) { + adc_digi_output_data_t *p = (void*)&result[i]; + #if CONFIG_IDF_TARGET_ESP32 + ESP_LOGI(TAG, "Unit: %d, Channel: %d, Value: %x", 1, p->type1.channel, p->type1.data); + #else + if (ADC_CONV_MODE == ADC_CONV_BOTH_UNIT || ADC_CONV_MODE == ADC_CONV_ALTER_UNIT) { + if (check_valid_data(p)) { + ESP_LOGI(TAG, "Unit: %d,_Channel: %d, Value: %x", p->type2.unit+1, p->type2.channel, p->type2.data); + } else { + ESP_LOGI(TAG, "Invalid data [%d_%d_%x]", p->type2.unit+1, p->type2.channel, p->type2.data); + } + } + #if CONFIG_IDF_TARGET_ESP32S2 + else if (ADC_CONV_MODE == ADC_CONV_SINGLE_UNIT_2) { + ESP_LOGI(TAG, "Unit: %d, Channel: %d, Value: %x", 2, p->type1.channel, p->type1.data); + } else if (ADC_CONV_MODE == ADC_CONV_SINGLE_UNIT_1) { + ESP_LOGI(TAG, "Unit: %d, Channel: %d, Value: %x", 1, p->type1.channel, p->type1.data); + } + #endif //#if CONFIG_IDF_TARGET_ESP32S2 + #endif + } + /** + * Because printing is slow, so every time you call `ulTaskNotifyTake`, it will immediately return. + * To avoid a task watchdog timeout, add a delay here. When you replace the way you process the data, + * usually you don't need this delay (as this task will block for a while). + */ + vTaskDelay(1); + } else if (ret == ESP_ERR_TIMEOUT) { + //We try to read `EXAMPLE_READ_LEN` until API returns timeout, which means there's no available data + break; + } + } + } + + ESP_ERROR_CHECK(adc_continuous_stop(handle)); + ESP_ERROR_CHECK(adc_continuous_deinit(handle)); +} diff --git a/examples/peripherals/adc/continuous_read/pytest_adc_continuous.py b/examples/peripherals/adc/continuous_read/pytest_adc_continuous.py new file mode 100644 index 0000000000..92fd226664 --- /dev/null +++ b/examples/peripherals/adc/continuous_read/pytest_adc_continuous.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded.dut import Dut + + +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.esp32c3 +def test_adc_continuous(dut: Dut) -> None: + res = dut.expect(r'TASK: ret is 0, ret_num is (\d+)') + num = res.group(1).decode('utf8') + assert int(num) == 256 diff --git a/examples/peripherals/adc/dma_read/CMakeLists.txt b/examples/peripherals/adc/dma_read/CMakeLists.txt deleted file mode 100644 index 6b79940d47..0000000000 --- a/examples/peripherals/adc/dma_read/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# The following 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(adc) diff --git a/examples/peripherals/adc/dma_read/main/CMakeLists.txt b/examples/peripherals/adc/dma_read/main/CMakeLists.txt deleted file mode 100644 index 72b0d08bf0..0000000000 --- a/examples/peripherals/adc/dma_read/main/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -idf_component_register(SRCS "adc_dma_example_main.c" - INCLUDE_DIRS ".") diff --git a/examples/peripherals/adc/dma_read/main/adc_dma_example_main.c b/examples/peripherals/adc/dma_read/main/adc_dma_example_main.c deleted file mode 100644 index 6116facb0b..0000000000 --- a/examples/peripherals/adc/dma_read/main/adc_dma_example_main.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "sdkconfig.h" -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "driver/adc.h" - -#define TIMES 256 -#define GET_UNIT(x) ((x>>3) & 0x1) - -#if CONFIG_IDF_TARGET_ESP32 -#define ADC_RESULT_BYTE 2 -#define ADC_CONV_LIMIT_EN 1 //For ESP32, this should always be set to 1 -#define ADC_CONV_MODE ADC_CONV_SINGLE_UNIT_1 //ESP32 only supports ADC1 DMA mode -#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1 -#elif CONFIG_IDF_TARGET_ESP32S2 -#define ADC_RESULT_BYTE 2 -#define ADC_CONV_LIMIT_EN 0 -#define ADC_CONV_MODE ADC_CONV_BOTH_UNIT -#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 -#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 -#define ADC_RESULT_BYTE 4 -#define ADC_CONV_LIMIT_EN 0 -#define ADC_CONV_MODE ADC_CONV_ALTER_UNIT //ESP32C3 only supports alter mode -#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 -#elif CONFIG_IDF_TARGET_ESP32S3 -#define ADC_RESULT_BYTE 4 -#define ADC_CONV_LIMIT_EN 0 -#define ADC_CONV_MODE ADC_CONV_BOTH_UNIT -#define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 -#endif - -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 -static uint16_t adc1_chan_mask = BIT(2) | BIT(3); -static uint16_t adc2_chan_mask = BIT(0); -static adc_channel_t channel[3] = {ADC1_CHANNEL_2, ADC1_CHANNEL_3, (ADC2_CHANNEL_0 | 1 << 3)}; -#endif -#if CONFIG_IDF_TARGET_ESP32S2 -static uint16_t adc1_chan_mask = BIT(2) | BIT(3); -static uint16_t adc2_chan_mask = BIT(0); -static adc_channel_t channel[3] = {ADC1_CHANNEL_2, ADC1_CHANNEL_3, (ADC2_CHANNEL_0 | 1 << 3)}; -#endif -#if CONFIG_IDF_TARGET_ESP32 -static uint16_t adc1_chan_mask = BIT(7); -static uint16_t adc2_chan_mask = 0; -static adc_channel_t channel[1] = {ADC1_CHANNEL_7}; -#endif - -static const char *TAG = "ADC DMA"; - -static void continuous_adc_init(uint16_t adc1_chan_mask, uint16_t adc2_chan_mask, adc_channel_t *channel, uint8_t channel_num) -{ - adc_digi_init_config_t adc_dma_config = { - .max_store_buf_size = 1024, - .conv_num_each_intr = TIMES, - .adc1_chan_mask = adc1_chan_mask, - .adc2_chan_mask = adc2_chan_mask, - }; - ESP_ERROR_CHECK(adc_digi_initialize(&adc_dma_config)); - - adc_digi_configuration_t dig_cfg = { - .conv_limit_en = ADC_CONV_LIMIT_EN, - .conv_limit_num = 250, - .sample_freq_hz = 10 * 1000, - .conv_mode = ADC_CONV_MODE, - .format = ADC_OUTPUT_TYPE, - }; - - adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0}; - dig_cfg.pattern_num = channel_num; - for (int i = 0; i < channel_num; i++) { - uint8_t unit = GET_UNIT(channel[i]); - uint8_t ch = channel[i] & 0x7; - adc_pattern[i].atten = ADC_ATTEN_DB_0; - adc_pattern[i].channel = ch; - adc_pattern[i].unit = unit; - adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH; - - ESP_LOGI(TAG, "adc_pattern[%d].atten is :%x", i, adc_pattern[i].atten); - ESP_LOGI(TAG, "adc_pattern[%d].channel is :%x", i, adc_pattern[i].channel); - ESP_LOGI(TAG, "adc_pattern[%d].unit is :%x", i, adc_pattern[i].unit); - } - dig_cfg.adc_pattern = adc_pattern; - ESP_ERROR_CHECK(adc_digi_controller_configure(&dig_cfg)); -} - -#if !CONFIG_IDF_TARGET_ESP32 -static bool check_valid_data(const adc_digi_output_data_t *data) -{ - const unsigned int unit = data->type2.unit; - if (unit > 2) return false; - if (data->type2.channel >= SOC_ADC_CHANNEL_NUM(unit)) return false; - - return true; -} -#endif - -void app_main(void) -{ - esp_err_t ret; - uint32_t ret_num = 0; - uint8_t result[TIMES] = {0}; - memset(result, 0xcc, TIMES); - - continuous_adc_init(adc1_chan_mask, adc2_chan_mask, channel, sizeof(channel) / sizeof(adc_channel_t)); - adc_digi_start(); - - while(1) { - ret = adc_digi_read_bytes(result, TIMES, &ret_num, ADC_MAX_DELAY); - if (ret == ESP_OK || ret == ESP_ERR_INVALID_STATE) { - if (ret == ESP_ERR_INVALID_STATE) { - /** - * @note 1 - * Issue: - * As an example, we simply print the result out, which is super slow. Therefore the conversion is too - * fast for the task to handle. In this condition, some conversion results lost. - * - * Reason: - * When this error occurs, you will usually see the task watchdog timeout issue also. - * Because the conversion is too fast, whereas the task calling `adc_digi_read_bytes` is slow. - * So `adc_digi_read_bytes` will hardly block. Therefore Idle Task hardly has chance to run. In this - * example, we add a `vTaskDelay(1)` below, to prevent the task watchdog timeout. - * - * Solution: - * Either decrease the conversion speed, or increase the frequency you call `adc_digi_read_bytes` - */ - } - - ESP_LOGI("TASK:", "ret is %x, ret_num is %d", ret, ret_num); - for (int i = 0; i < ret_num; i += ADC_RESULT_BYTE) { - adc_digi_output_data_t *p = (void*)&result[i]; - #if CONFIG_IDF_TARGET_ESP32 - ESP_LOGI(TAG, "Unit: %d, Channel: %d, Value: %x", 1, p->type1.channel, p->type1.data); - #else - if (ADC_CONV_MODE == ADC_CONV_BOTH_UNIT || ADC_CONV_MODE == ADC_CONV_ALTER_UNIT) { - if (check_valid_data(p)) { - ESP_LOGI(TAG, "Unit: %d,_Channel: %d, Value: %x", p->type2.unit+1, p->type2.channel, p->type2.data); - } else { - // abort(); - ESP_LOGI(TAG, "Invalid data [%d_%d_%x]", p->type2.unit+1, p->type2.channel, p->type2.data); - } - } - #if CONFIG_IDF_TARGET_ESP32S2 - else if (ADC_CONV_MODE == ADC_CONV_SINGLE_UNIT_2) { - ESP_LOGI(TAG, "Unit: %d, Channel: %d, Value: %x", 2, p->type1.channel, p->type1.data); - } else if (ADC_CONV_MODE == ADC_CONV_SINGLE_UNIT_1) { - ESP_LOGI(TAG, "Unit: %d, Channel: %d, Value: %x", 1, p->type1.channel, p->type1.data); - } - #endif //#if CONFIG_IDF_TARGET_ESP32S2 - #endif - } - //See `note 1` - vTaskDelay(1); - } else if (ret == ESP_ERR_TIMEOUT) { - /** - * ``ESP_ERR_TIMEOUT``: If ADC conversion is not finished until Timeout, you'll get this return error. - * Here we set Timeout ``portMAX_DELAY``, so you'll never reach this branch. - */ - ESP_LOGW(TAG, "No data, increase timeout or reduce conv_num_each_intr"); - vTaskDelay(1000); - } - - } - - adc_digi_stop(); - ret = adc_digi_deinitialize(); - assert(ret == ESP_OK); -} diff --git a/examples/peripherals/adc/single_read/single_read/CMakeLists.txt b/examples/peripherals/adc/oneshot_read/CMakeLists.txt similarity index 90% rename from examples/peripherals/adc/single_read/single_read/CMakeLists.txt rename to examples/peripherals/adc/oneshot_read/CMakeLists.txt index 9a4b4e79fd..a76caf2c71 100644 --- a/examples/peripherals/adc/single_read/single_read/CMakeLists.txt +++ b/examples/peripherals/adc/oneshot_read/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(single_read) +project(oneshot_read) diff --git a/examples/peripherals/adc/oneshot_read/README.md b/examples/peripherals/adc/oneshot_read/README.md new file mode 100644 index 0000000000..93700344f8 --- /dev/null +++ b/examples/peripherals/adc/oneshot_read/README.md @@ -0,0 +1,62 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | + +# ADC Single Read Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates the following: + +- How to obtain a oneshot ADC reading from a GPIO pin using the ADC oneshot mode driver +- How to use the ADC Calibration functions to obtain a calibrated result (in mV) + +## How to use example + +### Hardware Required + +* A development board with ESP SoC +* A USB cable for power supply and programming + +In this example, you need to connect a voltage source (e.g. a DC power supply) to the GPIO pins specified in `oneshot_read_main.c` (see the macros defined on the top of the source file). Feel free to modify the pin setting. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT 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 + +Running this example, you will see the following log output on the serial monitor: + +``` +I (304) ADC_ONESHOT: calibration scheme version is Curve Fitting +I (304) ADC_ONESHOT: calibration scheme version is Curve Fitting +I (314) ADC_ONESHOT: ADC1 Channel[2] Raw Data: 0 +I (314) ADC_ONESHOT: ADC1 Channel[2] Cali Voltage: 0 mV +I (1324) ADC_ONESHOT: ADC1 Channel[3] Raw Data: 664 +I (1324) ADC_ONESHOT: ADC1 Channel[3] Cali Voltage: 559 mV +I (2324) ADC_ONESHOT: ADC2 Channel[0] Raw Data: 580 +I (2324) ADC_ONESHOT: ADC2 Channel[0] Cali Voltage: 498 mV +I (3324) ADC_ONESHOT: ADC1 Channel[2] Raw Data: 0 +I (3324) ADC_ONESHOT: ADC1 Channel[2] Cali Voltage: 0 mV +I (4324) ADC_ONESHOT: ADC1 Channel[3] Raw Data: 666 +I (4324) ADC_ONESHOT: ADC1 Channel[3] Cali Voltage: 561 mV +I (5324) ADC_ONESHOT: ADC2 Channel[0] Raw Data: 575 +I (5324) ADC_ONESHOT: ADC2 Channel[0] Cali Voltage: 495 mV +... +``` + +## Troubleshooting + +If following warning is printed out, it means the calibration required eFuse bits are not burnt correctly on your board. The calibration will be skipped. Only raw data will be printed out. +``` +W (300) ADC_ONESHOT: eFuse not burnt, skip calibration +I (1310) ADC_ONESHOT: ADC1 Channel[2] Raw Data: 0 +``` \ No newline at end of file diff --git a/examples/peripherals/adc/oneshot_read/main/CMakeLists.txt b/examples/peripherals/adc/oneshot_read/main/CMakeLists.txt new file mode 100644 index 0000000000..6d708b2e3e --- /dev/null +++ b/examples/peripherals/adc/oneshot_read/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "oneshot_read_main.c" + INCLUDE_DIRS ".") diff --git a/examples/peripherals/adc/oneshot_read/main/oneshot_read_main.c b/examples/peripherals/adc/oneshot_read/main/oneshot_read_main.c new file mode 100644 index 0000000000..a7ac30a7b6 --- /dev/null +++ b/examples/peripherals/adc/oneshot_read/main/oneshot_read_main.c @@ -0,0 +1,189 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "soc/soc_caps.h" +#include "esp_log.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_cali_scheme.h" + +const static char *TAG = "EXAMPLE"; + +/*--------------------------------------------------------------- + ADC General Macros +---------------------------------------------------------------*/ +//ADC1 Channels +#if CONFIG_IDF_TARGET_ESP32 +#define EXAMPLE_ADC1_CHAN0 ADC_CHANNEL_4 +#define EXAMPLE_ADC1_CHAN1 ADC_CHANNEL_5 +#else +#define EXAMPLE_ADC1_CHAN0 ADC_CHANNEL_2 +#define EXAMPLE_ADC1_CHAN1 ADC_CHANNEL_3 +#endif + +#if (SOC_ADC_PERIPH_NUM >= 2) +//ADC2 Channels +#if CONFIG_IDF_TARGET_ESP32 +#define EXAMPLE_ADC2_CHAN0 ADC_CHANNEL_0 +#else +#define EXAMPLE_ADC2_CHAN0 ADC_CHANNEL_0 +#endif +#endif + +static int adc_raw[2][10]; +static int voltage[2][10]; +static bool example_adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle); +static void example_adc_calibration_deinit(adc_cali_handle_t handle); + + +void app_main(void) +{ + //-------------ADC1 Init---------------// + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + //-------------ADC1 Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN0, &config)); + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN1, &config)); + + //-------------ADC1 Calibration Init---------------// + adc_cali_handle_t adc1_cali_handle = NULL; + bool do_calibration1 = example_adc_calibration_init(ADC_UNIT_1, ADC_ATTEN_DB_11, &adc1_cali_handle); + + +#if (SOC_ADC_PERIPH_NUM >= 2) + //-------------ADC2 Init---------------// + adc_oneshot_unit_handle_t adc2_handle; + adc_oneshot_unit_init_cfg_t init_config2 = { + .unit_id = ADC_UNIT_2, + .ulp_mode = false, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config2, &adc2_handle)); + + //-------------ADC2 Calibration Init---------------// + adc_cali_handle_t adc2_cali_handle = NULL; + bool do_calibration2 = example_adc_calibration_init(ADC_UNIT_2, ADC_ATTEN_DB_11, &adc2_cali_handle); + + //-------------ADC2 Config---------------// + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc2_handle, EXAMPLE_ADC2_CHAN0, &config)); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) + + while (1) { + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0][0])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, adc_raw[0][0]); + if (do_calibration1) { + ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_handle, adc_raw[0][0], &voltage[0][0])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, voltage[0][0]); + } + vTaskDelay(pdMS_TO_TICKS(1000)); + + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN1, &adc_raw[0][1])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN1, adc_raw[0][1]); + if (do_calibration1) { + ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_handle, adc_raw[0][1], &voltage[0][1])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN1, voltage[0][1]); + } + vTaskDelay(pdMS_TO_TICKS(1000)); + +#if (SOC_ADC_PERIPH_NUM >= 2) + ESP_ERROR_CHECK(adc_oneshot_read(adc2_handle, EXAMPLE_ADC2_CHAN0, &adc_raw[1][0])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_2 + 1, EXAMPLE_ADC2_CHAN0, adc_raw[1][0]); + if (do_calibration2) { + ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc2_cali_handle, adc_raw[1][0], &voltage[1][0])); + ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_2 + 1, EXAMPLE_ADC2_CHAN0, voltage[1][0]); + } + vTaskDelay(pdMS_TO_TICKS(1000)); +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) + } + + //Tear Down + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle)); + if (do_calibration1) { + example_adc_calibration_deinit(adc1_cali_handle); + } + +#if (SOC_ADC_PERIPH_NUM >= 2) + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc2_handle)); + if (do_calibration2) { + example_adc_calibration_deinit(adc2_cali_handle); + } +#endif //#if (SOC_ADC_PERIPH_NUM >= 2) +} + + +/*--------------------------------------------------------------- + ADC Calibration +---------------------------------------------------------------*/ +static bool example_adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle) +{ + adc_cali_handle_t handle = NULL; + esp_err_t ret = ESP_FAIL; + bool calibrated = false; + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + if (!calibrated) { + ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting"); + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle); + if (ret == ESP_OK) { + calibrated = true; + } + } +#endif + +#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + if (!calibrated) { + ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting"); + adc_cali_line_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle); + if (ret == ESP_OK) { + calibrated = true; + } + } +#endif + + *out_handle = handle; + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Calibration Success"); + } else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) { + ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); + } else { + ESP_LOGE(TAG, "Invalid arg or no memory"); + } + + return calibrated; +} + +static void example_adc_calibration_deinit(adc_cali_handle_t handle) +{ +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + ESP_LOGI(TAG, "deregister %s calibration scheme", "Curve Fitting"); + ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle)); + +#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + ESP_LOGI(TAG, "deregister %s calibration scheme", "Line Fitting"); + ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle)); +#endif +} diff --git a/examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py b/examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py new file mode 100644 index 0000000000..562a3a800d --- /dev/null +++ b/examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded.dut import Dut + + +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.esp32c3 +@pytest.mark.esp32c2 +def test_adc_oneshot(dut: Dut) -> None: + dut.expect(r'ADC_ONESHOT: ADC1 Channel\[(\d+)]\ Raw Data: (\d+)', timeout=5) diff --git a/examples/peripherals/adc/single_read/adc/CMakeLists.txt b/examples/peripherals/adc/single_read/adc/CMakeLists.txt deleted file mode 100644 index 6b79940d47..0000000000 --- a/examples/peripherals/adc/single_read/adc/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# The following 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(adc) diff --git a/examples/peripherals/adc/single_read/adc/README.md b/examples/peripherals/adc/single_read/adc/README.md deleted file mode 100644 index 7e28784758..0000000000 --- a/examples/peripherals/adc/single_read/adc/README.md +++ /dev/null @@ -1,55 +0,0 @@ -| Supported Targets | ESP32 | -| ----------------- | ----- | - -# ADC1 Example - -(See the README.md file in the upper level 'examples' directory for more information about examples.) - -This example shows how to configure ADC1 and read the voltage connected to GPIO pin. - -## How to use example - -### Hardware Required - -* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) -* A USB cable for power supply and programming - -In this example, we use `ADC_UNIT_1` by default, we need to connect a voltage source (0 ~ 3.3v) to GPIO34. If another ADC unit is selected in your application, you need to change the GPIO pin (please refer to Chapter 4.11 of the `ESP32 Technical Reference Manual`). - -### Configure the project - -``` -idf.py menuconfig -``` - -### Build and Flash - -Build the project and flash it to the board, then run monitor tool to view serial output: - -``` -idf.py -p PORT 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 - -Running this example, you will see the following log output on the serial monitor: - -``` -Raw: 486 Voltage: 189mV -Raw: 435 Voltage: 177mV -Raw: 225 Voltage: 128mV -Raw: 18 Voltage: 79mV -``` - -## Troubleshooting - -* program upload failure - - * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. - * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. - -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/adc/single_read/adc/main/CMakeLists.txt b/examples/peripherals/adc/single_read/adc/main/CMakeLists.txt deleted file mode 100644 index 19ed60c765..0000000000 --- a/examples/peripherals/adc/single_read/adc/main/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -idf_component_register(SRCS "adc1_example_main.c" - INCLUDE_DIRS ".") diff --git a/examples/peripherals/adc/single_read/adc/main/adc1_example_main.c b/examples/peripherals/adc/single_read/adc/main/adc1_example_main.c deleted file mode 100644 index 704032ea4d..0000000000 --- a/examples/peripherals/adc/single_read/adc/main/adc1_example_main.c +++ /dev/null @@ -1,108 +0,0 @@ -/* ADC1 Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/gpio.h" -#include "driver/adc.h" -#include "esp_adc_cal.h" - -#define DEFAULT_VREF 1100 //Use adc2_vref_to_gpio() to obtain a better estimate -#define NO_OF_SAMPLES 64 //Multisampling - -static esp_adc_cal_characteristics_t *adc_chars; -#if CONFIG_IDF_TARGET_ESP32 -static const adc_channel_t channel = ADC_CHANNEL_6; //GPIO34 if ADC1, GPIO14 if ADC2 -static const adc_bits_width_t width = ADC_WIDTH_BIT_12; -#elif CONFIG_IDF_TARGET_ESP32S2 -static const adc_channel_t channel = ADC_CHANNEL_6; // GPIO7 if ADC1, GPIO17 if ADC2 -static const adc_bits_width_t width = ADC_WIDTH_BIT_13; -#endif -static const adc_atten_t atten = ADC_ATTEN_DB_0; -static const adc_unit_t unit = ADC_UNIT_1; - - -static void check_efuse(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - //Check if TP is burned into eFuse - if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { - printf("eFuse Two Point: Supported\n"); - } else { - printf("eFuse Two Point: NOT supported\n"); - } - //Check Vref is burned into eFuse - if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { - printf("eFuse Vref: Supported\n"); - } else { - printf("eFuse Vref: NOT supported\n"); - } -#elif CONFIG_IDF_TARGET_ESP32S2 - if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { - printf("eFuse Two Point: Supported\n"); - } else { - printf("Cannot retrieve eFuse Two Point calibration values. Default calibration values will be used.\n"); - } -#else -#error "This example is configured for ESP32/ESP32S2." -#endif -} - - -static void print_char_val_type(esp_adc_cal_value_t val_type) -{ - if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { - printf("Characterized using Two Point Value\n"); - } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { - printf("Characterized using eFuse Vref\n"); - } else { - printf("Characterized using Default Vref\n"); - } -} - - -void app_main(void) -{ - //Check if Two Point or Vref are burned into eFuse - check_efuse(); - - //Configure ADC - if (unit == ADC_UNIT_1) { - adc1_config_width(width); - adc1_config_channel_atten(channel, atten); - } else { - adc2_config_channel_atten((adc2_channel_t)channel, atten); - } - - //Characterize ADC - adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); - esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars); - print_char_val_type(val_type); - - //Continuously sample ADC1 - while (1) { - uint32_t adc_reading = 0; - //Multisampling - for (int i = 0; i < NO_OF_SAMPLES; i++) { - if (unit == ADC_UNIT_1) { - adc_reading += adc1_get_raw((adc1_channel_t)channel); - } else { - int raw; - adc2_get_raw((adc2_channel_t)channel, width, &raw); - adc_reading += raw; - } - } - adc_reading /= NO_OF_SAMPLES; - //Convert adc_reading to voltage in mV - uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars); - printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage); - vTaskDelay(pdMS_TO_TICKS(1000)); - } -} diff --git a/examples/peripherals/adc/single_read/adc2/README.md b/examples/peripherals/adc/single_read/adc2/README.md deleted file mode 100644 index 5e5e13d909..0000000000 --- a/examples/peripherals/adc/single_read/adc2/README.md +++ /dev/null @@ -1,96 +0,0 @@ -| Supported Targets | ESP32 | -| ----------------- | ----- | - -# ADC2 Example - -(See the README.md file in the upper level 'examples' directory for more information about examples.) - -In this example, we use ADC2 to measure the output of DAC. - -## How to use example - -### Hardware Required - -#### ESP32 platform - -* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) -* A USB cable for power supply and programming - -We use ADC1_CHANNEL_7 (GPIO27) and DAC_CHANNEL_1 (GPIO25) by default, you need to short the two GPIOs (if you have changed the ADC2 and DAC channel, please refer to Chapter 4.11 of the `ESP32 Technical Reference Manual` to get the pin number). - -#### ESP32-S2 platform - -* A development board with ESP32S2 SoC -* A USB cable for power supply and programming - -We use ADC1_CHANNEL_7 (GPIO18) and DAC_CHANNEL_1 (GPIO17) by default, you need to short the two GPIOs (if you have changed the ADC2 and DAC channel, please refer to the `ESP32S2 Technical Reference Manual` to get the pin number). - -### Configure the project - -``` -idf.py menuconfig -``` -* Set ADC2 and DAC channel in "Example Configuration" - -### Build and Flash - -Build the project and flash it to the board, then run monitor tool to view serial output: - -``` -idf.py -p PORT 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 - -Running this example, you will see the following log output on the serial monitor: - -### ESP32 platform - -``` -ADC channel 7 @ GPIO 27, DAC channel 1 @ GPIO 25. -adc2_init... -start conversion. -1: 150 -2: 203 -3: 250 -4: 300 -5: 351 -6: 400 -7: 441 -8: 491 -9: 547 -10: 595 -... -``` - -#### ESP32-S2 platform - -``` -ADC channel 7 @ GPIO 18, DAC channel 1 @ GPIO 17. -adc2_init... -start conversion. -1: 150 -2: 203 -3: 250 -4: 300 -5: 351 -6: 400 -7: 441 -8: 491 -9: 547 -10: 595 -... -``` - -## Troubleshooting - -* program upload failure - - * Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs. - * The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again. - -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/adc/single_read/adc2/main/CMakeLists.txt b/examples/peripherals/adc/single_read/adc2/main/CMakeLists.txt deleted file mode 100644 index 8a9ead9672..0000000000 --- a/examples/peripherals/adc/single_read/adc2/main/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -idf_component_register(SRCS "adc2_example_main.c" - INCLUDE_DIRS ".") diff --git a/examples/peripherals/adc/single_read/adc2/main/Kconfig.projbuild b/examples/peripherals/adc/single_read/adc2/main/Kconfig.projbuild deleted file mode 100644 index 0226be75cc..0000000000 --- a/examples/peripherals/adc/single_read/adc2/main/Kconfig.projbuild +++ /dev/null @@ -1,105 +0,0 @@ -menu "Example Configuration" - - choice EXAMPLE_ADC2_CHANNEL - bool "ADC2 Channel Num" - depends on IDF_TARGET_ESP32 - default EXAMPLE_ADC2_CHANNEL_7 - help - The channel of ADC2 used in this example. - - config EXAMPLE_ADC2_CHANNEL_0 - bool "ADC2 Channel 0 (GPIO 4)" - config EXAMPLE_ADC2_CHANNEL_1 - bool "ADC2 Channel 1 (GPIO 0)" - config EXAMPLE_ADC2_CHANNEL_2 - bool "ADC2 Channel 2 (GPIO 2)" - config EXAMPLE_ADC2_CHANNEL_3 - bool "ADC2 Channel 3 (GPIO 15)" - config EXAMPLE_ADC2_CHANNEL_4 - bool "ADC2 Channel 4 (GPIO 13)" - config EXAMPLE_ADC2_CHANNEL_5 - bool "ADC2 Channel 5 (GPIO 12)" - config EXAMPLE_ADC2_CHANNEL_6 - bool "ADC2 Channel 6 (GPIO 14)" - config EXAMPLE_ADC2_CHANNEL_7 - bool "ADC2 Channel 7 (GPIO 27)" - config EXAMPLE_ADC2_CHANNEL_8 - bool "ADC2 Channel 8 (GPIO 25)" - config EXAMPLE_ADC2_CHANNEL_9 - bool "ADC2 Channel 9 (GPIO 26)" - endchoice - - choice EXAMPLE_ADC2_CHANNEL - bool "ADC2 Channel Num" - depends on IDF_TARGET_ESP32S2 - default EXAMPLE_ADC2_CHANNEL_7 - help - The channel of ADC2 used in this example. - - config EXAMPLE_ADC2_CHANNEL_0 - bool "ADC2 Channel 0 (GPIO 11)" - config EXAMPLE_ADC2_CHANNEL_1 - bool "ADC2 Channel 1 (GPIO 12)" - config EXAMPLE_ADC2_CHANNEL_2 - bool "ADC2 Channel 2 (GPIO 13)" - config EXAMPLE_ADC2_CHANNEL_3 - bool "ADC2 Channel 3 (GPIO 14)" - config EXAMPLE_ADC2_CHANNEL_4 - bool "ADC2 Channel 4 (GPIO 15)" - config EXAMPLE_ADC2_CHANNEL_5 - bool "ADC2 Channel 5 (GPIO 16)" - config EXAMPLE_ADC2_CHANNEL_6 - bool "ADC2 Channel 6 (GPIO 17)" - config EXAMPLE_ADC2_CHANNEL_7 - bool "ADC2 Channel 7 (GPIO 18)" - config EXAMPLE_ADC2_CHANNEL_8 - bool "ADC2 Channel 8 (GPIO 19)" - config EXAMPLE_ADC2_CHANNEL_9 - bool "ADC2 Channel 9 (GPIO 20)" - endchoice - - config EXAMPLE_ADC2_CHANNEL - int - default 0 if EXAMPLE_ADC2_CHANNEL_0 - default 1 if EXAMPLE_ADC2_CHANNEL_1 - default 2 if EXAMPLE_ADC2_CHANNEL_2 - default 3 if EXAMPLE_ADC2_CHANNEL_3 - default 4 if EXAMPLE_ADC2_CHANNEL_4 - default 5 if EXAMPLE_ADC2_CHANNEL_5 - default 6 if EXAMPLE_ADC2_CHANNEL_6 - default 7 if EXAMPLE_ADC2_CHANNEL_7 - default 8 if EXAMPLE_ADC2_CHANNEL_8 - default 9 if EXAMPLE_ADC2_CHANNEL_9 - - choice EXAMPLE_DAC_CHANNEL - bool "DAC Channel Num" - depends on IDF_TARGET_ESP32 - default EXAMPLE_DAC_CHANNEL_1 - help - The channel of DAC used in this example. - - config EXAMPLE_DAC_CHANNEL_1 - bool "DAC Channel 1 (GPIO25)" - config EXAMPLE_DAC_CHANNEL_2 - bool "DAC Channel 2 (GPIO26)" - endchoice - - choice EXAMPLE_DAC_CHANNEL - bool "DAC Channel Num" - depends on IDF_TARGET_ESP32S2 - default EXAMPLE_DAC_CHANNEL_1 - help - The channel of DAC used in this example. - - config EXAMPLE_DAC_CHANNEL_1 - bool "DAC Channel 1 (GPIO17)" - config EXAMPLE_DAC_CHANNEL_2 - bool "DAC Channel 2 (GPIO18)" - endchoice - - config EXAMPLE_DAC_CHANNEL - int - default 0 if EXAMPLE_DAC_CHANNEL_1 - default 1 if EXAMPLE_DAC_CHANNEL_2 - -endmenu diff --git a/examples/peripherals/adc/single_read/adc2/main/adc2_example_main.c b/examples/peripherals/adc/single_read/adc2/main/adc2_example_main.c deleted file mode 100644 index 9b1a5003fa..0000000000 --- a/examples/peripherals/adc/single_read/adc2/main/adc2_example_main.c +++ /dev/null @@ -1,69 +0,0 @@ -/* ADC2 Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "driver/gpio.h" -#include "driver/adc.h" -#include "driver/dac.h" -#include "esp_system.h" - -#define DAC_EXAMPLE_CHANNEL CONFIG_EXAMPLE_DAC_CHANNEL -#define ADC2_EXAMPLE_CHANNEL CONFIG_EXAMPLE_ADC2_CHANNEL - -#if CONFIG_IDF_TARGET_ESP32 -static const adc_bits_width_t width = ADC_WIDTH_BIT_12; -#elif CONFIG_IDF_TARGET_ESP32S2 -static const adc_bits_width_t width = ADC_WIDTH_BIT_13; -#endif - -void app_main(void) -{ - uint8_t output_data=0; - int read_raw; - esp_err_t r; - - gpio_num_t adc_gpio_num, dac_gpio_num; - - r = adc2_pad_get_io_num( ADC2_EXAMPLE_CHANNEL, &adc_gpio_num ); - assert( r == ESP_OK ); - r = dac_pad_get_io_num( DAC_EXAMPLE_CHANNEL, &dac_gpio_num ); - assert( r == ESP_OK ); - - printf("ADC2 channel %d @ GPIO %d, DAC channel %d @ GPIO %d.\n", ADC2_EXAMPLE_CHANNEL, adc_gpio_num, - DAC_EXAMPLE_CHANNEL + 1, dac_gpio_num ); - - dac_output_enable( DAC_EXAMPLE_CHANNEL ); - - //be sure to do the init before using adc2. - printf("adc2_init...\n"); - adc2_config_channel_atten( ADC2_EXAMPLE_CHANNEL, ADC_ATTEN_11db ); - - vTaskDelay(2 * portTICK_PERIOD_MS); - - printf("start conversion.\n"); - while(1) { - dac_output_voltage( DAC_EXAMPLE_CHANNEL, output_data++ ); - r = adc2_get_raw( ADC2_EXAMPLE_CHANNEL, width, &read_raw); - if ( r == ESP_OK ) { - printf("%d: %d\n", output_data, read_raw ); - } else if ( r == ESP_ERR_INVALID_STATE ) { - printf("%s: ADC2 not initialized yet.\n", esp_err_to_name(r)); - } else if ( r == ESP_ERR_TIMEOUT ) { - //This can not happen in this example. But if WiFi is in use, such error code could be returned. - printf("%s: ADC2 is in use by Wi-Fi.\n", esp_err_to_name(r)); - } else { - printf("%s\n", esp_err_to_name(r)); - } - - vTaskDelay( 2 * portTICK_PERIOD_MS ); - } -} diff --git a/examples/peripherals/adc/single_read/single_read/README.md b/examples/peripherals/adc/single_read/single_read/README.md deleted file mode 100644 index 388ee4430e..0000000000 --- a/examples/peripherals/adc/single_read/single_read/README.md +++ /dev/null @@ -1,58 +0,0 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | - -# ADC Single Read Example - -(See the README.md file in the upper level 'examples' directory for more information about examples.) - -This example demonstrates the following: - -- How to obtain a single ADC reading from a GPIO pin using the ADC Driver's Single Read function -- How to use the ADC Calibration functions to obtain a calibrated result (in mV) - -## How to use example - -### Hardware Required - -* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) -* A USB cable for power supply and programming - -In this example, you need to connect a voltage source (e.g. a DC power supply) to the GPIO pins specified in `single_read.c` (see the macros defined on the top of the source file). Feel free to modify the pin setting. - -### Build and Flash - -Build the project and flash it to the board, then run monitor tool to view serial output: - -``` -idf.py -p PORT 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 - -Running this example, you will see the following log output on the serial monitor: - -``` -I (302) ADC1_CH2: raw data: 4095 -I (302) ADC1_CH2: cali data: 3109 mV -I (1302) ADC2_CH0: raw data: 0 -I (1302) ADC2_CH0: cali data: 0 mV -I (2302) ADC1_CH2: raw data: 4095 -I (2302) ADC1_CH2: cali data: 3109 mV -I (3302) ADC2_CH0: raw data: 0 -I (3302) ADC2_CH0: cali data: 0 mV -I (4302) ADC1_CH2: raw data: 4095 -I (4302) ADC1_CH2: cali data: 3109 mV -... -``` - -## Troubleshooting - -If following warning is printed out, it means the calibration required eFuse bits are not burnt correctly on your board. The calibration will be skipped. Only raw data will be printed out. -``` -W (300) ADC SINGLE: eFuse not burnt, skip calibration -I (1310) ADC2_CH0: raw data: 2715 -``` \ No newline at end of file diff --git a/examples/peripherals/adc/single_read/single_read/main/CMakeLists.txt b/examples/peripherals/adc/single_read/single_read/main/CMakeLists.txt deleted file mode 100644 index 995f58e522..0000000000 --- a/examples/peripherals/adc/single_read/single_read/main/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -idf_component_register(SRCS "single_read.c" - INCLUDE_DIRS ".") diff --git a/examples/peripherals/adc/single_read/single_read/main/single_read.c b/examples/peripherals/adc/single_read/single_read/main/single_read.c deleted file mode 100644 index a40821e849..0000000000 --- a/examples/peripherals/adc/single_read/single_read/main/single_read.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* ADC1 Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ -#include -#include -#include "esp_log.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/adc.h" -#include "esp_adc_cal.h" - - -//ADC Channels -#if CONFIG_IDF_TARGET_ESP32 -#define ADC1_EXAMPLE_CHAN0 ADC1_CHANNEL_6 -#define ADC2_EXAMPLE_CHAN0 ADC2_CHANNEL_0 -static const char *TAG_CH[2][10] = {{"ADC1_CH6"}, {"ADC2_CH0"}}; -#else -#define ADC1_EXAMPLE_CHAN0 ADC1_CHANNEL_2 -#define ADC2_EXAMPLE_CHAN0 ADC2_CHANNEL_0 -static const char *TAG_CH[2][10] = {{"ADC1_CH2"}, {"ADC2_CH0"}}; -#endif - -//ADC Attenuation -#define ADC_EXAMPLE_ATTEN ADC_ATTEN_DB_11 - -//ADC Calibration -#if CONFIG_IDF_TARGET_ESP32 -#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF -#elif CONFIG_IDF_TARGET_ESP32S2 -#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP -#elif CONFIG_IDF_TARGET_ESP32C3 -#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP -#elif CONFIG_IDF_TARGET_ESP32S3 -#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT -#endif - - -static int adc_raw[2][10]; -static const char *TAG = "ADC SINGLE"; - -static esp_adc_cal_characteristics_t adc1_chars; -static esp_adc_cal_characteristics_t adc2_chars; - -static bool adc_calibration_init(void) -{ - esp_err_t ret; - bool cali_enable = false; - - ret = esp_adc_cal_check_efuse(ADC_EXAMPLE_CALI_SCHEME); - if (ret == ESP_ERR_NOT_SUPPORTED) { - ESP_LOGW(TAG, "Calibration scheme not supported, skip software calibration"); - } else if (ret == ESP_ERR_INVALID_VERSION) { - ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); - } else if (ret == ESP_OK) { - cali_enable = true; - esp_adc_cal_characterize(ADC_UNIT_1, ADC_EXAMPLE_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars); - esp_adc_cal_characterize(ADC_UNIT_2, ADC_EXAMPLE_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc2_chars); - } else { - ESP_LOGE(TAG, "Invalid arg"); - } - - return cali_enable; -} - -void app_main(void) -{ - esp_err_t ret = ESP_OK; - uint32_t voltage = 0; - bool cali_enable = adc_calibration_init(); - - //ADC1 config - ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT)); - ESP_ERROR_CHECK(adc1_config_channel_atten(ADC1_EXAMPLE_CHAN0, ADC_EXAMPLE_ATTEN)); - //ADC2 config - ESP_ERROR_CHECK(adc2_config_channel_atten(ADC2_EXAMPLE_CHAN0, ADC_EXAMPLE_ATTEN)); - - while (1) { - adc_raw[0][0] = adc1_get_raw(ADC1_EXAMPLE_CHAN0); - ESP_LOGI(TAG_CH[0][0], "raw data: %d", adc_raw[0][0]); - if (cali_enable) { - voltage = esp_adc_cal_raw_to_voltage(adc_raw[0][0], &adc1_chars); - ESP_LOGI(TAG_CH[0][0], "cali data: %d mV", voltage); - } - vTaskDelay(pdMS_TO_TICKS(1000)); - - do { - ret = adc2_get_raw(ADC2_EXAMPLE_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw[1][0]); - } while (ret == ESP_ERR_INVALID_STATE); - ESP_ERROR_CHECK(ret); - - ESP_LOGI(TAG_CH[1][0], "raw data: %d", adc_raw[1][0]); - if (cali_enable) { - voltage = esp_adc_cal_raw_to_voltage(adc_raw[1][0], &adc2_chars); - ESP_LOGI(TAG_CH[1][0], "cali data: %d mV", voltage); - } - vTaskDelay(pdMS_TO_TICKS(1000)); - } -} diff --git a/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c b/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c index e04b713728..645c975503 100644 --- a/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c +++ b/examples/peripherals/i2s/i2s_adc_dac/main/app_main.c @@ -17,10 +17,10 @@ #include "esp_log.h" #include "esp_partition.h" #include "driver/i2s.h" -#include "driver/adc.h" #include "audio_example_file.h" -#include "esp_adc_cal.h" #include "esp_rom_sys.h" +#include "driver/adc.h" +#include "esp_adc_cal.h" #if CONFIG_IDF_TARGET_ESP32 static const char* TAG = "ad/da"; @@ -280,8 +280,8 @@ void example_i2s_adc_dac(void*arg) void adc_read_task(void* arg) { - adc1_config_width(ADC_WIDTH_12Bit); - adc1_config_channel_atten(ADC1_TEST_CHANNEL, ADC_ATTEN_11db); + adc1_config_width(ADC_WIDTH_BIT_12); + adc1_config_channel_atten(ADC1_TEST_CHANNEL, ADC_ATTEN_DB_11); esp_adc_cal_characteristics_t characteristics; esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, V_REF, &characteristics); while(1) { diff --git a/examples/peripherals/i2s/i2s_adc_dac/sdkconfig.defaults b/examples/peripherals/i2s/i2s_adc_dac/sdkconfig.defaults index 9b35e20017..6e9a6a59e2 100644 --- a/examples/peripherals/i2s/i2s_adc_dac/sdkconfig.defaults +++ b/examples/peripherals/i2s/i2s_adc_dac/sdkconfig.defaults @@ -4,3 +4,4 @@ CONFIG_PARTITION_TABLE_FILENAME="partitions_adc_dac_example.csv" CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y # ADC/DAC are only supported in the legacy driver, suppress the warnings while using the legacy driver CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y +CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y diff --git a/examples/system/app_trace_to_host/README.md b/examples/system/app_trace_to_host/README.md index a461f3fd47..b029ea48a4 100644 --- a/examples/system/app_trace_to_host/README.md +++ b/examples/system/app_trace_to_host/README.md @@ -179,7 +179,9 @@ int sampling_period = 20; int i = 0; uint32_t sampling_start = esp_log_timestamp(); //this clock counts milliseconds do { - ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc1_get_raw(ADC1_TEST_CHANNEL)); + int adc_raw = 0; + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHANNEL, &adc_raw)); + ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc_raw); } while (esp_log_timestamp() - sampling_start < sampling_period); ``` diff --git a/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c b/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c index 9a27b2faec..e1c31ddf24 100644 --- a/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c +++ b/examples/system/app_trace_to_host/main/app_trace_to_host_example_main.c @@ -14,12 +14,12 @@ #include "esp_log.h" #include "soc/rtc_periph.h" #include "soc/sens_periph.h" -#include "driver/adc.h" +#include "esp_adc/adc_oneshot.h" #include "driver/dac.h" #include "soc/adc_channel.h" #include "soc/dac_channel.h" -#define ADC1_TEST_CHANNEL (ADC1_CHANNEL_6) +#define ADC1_TEST_CHANNEL (ADC_CHANNEL_6) #define TEST_SAMPLING_PERIOD 20 @@ -73,12 +73,14 @@ static void enable_cosine_generator(void) * Print out sampling result using standard ESP_LOGI() function. * Return the number of samples collected. */ -static int adc1_sample_and_show(int sampling_period) +static int adc1_sample_and_show(adc_oneshot_unit_handle_t adc1_handle, int sampling_period) { int i = 0; uint32_t sampling_start = esp_log_timestamp(); do { - ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc1_get_raw(ADC1_TEST_CHANNEL)); + int adc_raw = 0; + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_TEST_CHANNEL, &adc_raw)); + ESP_LOGI(TAG, "Sample:%d, Value:%d", ++i, adc_raw); } while (esp_log_timestamp() - sampling_start < sampling_period); return i; } @@ -91,12 +93,20 @@ static int adc1_sample_and_show(int sampling_period) void app_main(void) { ESP_LOGI(TAG, "Enabling ADC1 on channel 6 / GPIO%d.", ADC1_CHANNEL_6_GPIO_NUM); -#if CONFIG_IDF_TARGET_ESP32 - adc1_config_width(ADC_WIDTH_BIT_12); -#elif CONFIG_IDF_TARGET_ESP32S2 - adc1_config_width(ADC_WIDTH_BIT_13); -#endif - adc1_config_channel_atten(ADC1_TEST_CHANNEL, ADC_ATTEN_DB_11); + + //-------------ADC1 Init---------------// + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + //-------------ADC1 Channel Config---------------// + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_TEST_CHANNEL, &config)); ESP_LOGI(TAG, "Enabling CW generator on DAC channel 1 / GPIO%d.", DAC_CHANNEL_1_GPIO_NUM); enable_cosine_generator(); @@ -108,7 +118,7 @@ void app_main(void) ESP_LOGI(TAG, "Sampling ADC and sending data to the host..."); // Route LOGx() to the host esp_log_set_vprintf(esp_apptrace_vprintf); - int samples_collected = adc1_sample_and_show(TEST_SAMPLING_PERIOD); + int samples_collected = adc1_sample_and_show(adc1_handle, TEST_SAMPLING_PERIOD); // Route LOGx() back to UART esp_log_set_vprintf(vprintf); // Flush collected data to the host @@ -119,9 +129,10 @@ void app_main(void) * Logging to UART */ ESP_LOGI(TAG, "Sampling ADC and sending data to the UART..."); - samples_collected = adc1_sample_and_show(TEST_SAMPLING_PERIOD); + samples_collected = adc1_sample_and_show(adc1_handle, TEST_SAMPLING_PERIOD); ESP_LOGI(TAG, "Collected %d samples in %d ms.\n", samples_collected, TEST_SAMPLING_PERIOD); vTaskDelay(2000 / portTICK_PERIOD_MS); } + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle)); } diff --git a/examples/system/deep_sleep/main/deep_sleep_example_main.c b/examples/system/deep_sleep/main/deep_sleep_example_main.c index aa9fe11346..e310b9e4d3 100644 --- a/examples/system/deep_sleep/main/deep_sleep_example_main.c +++ b/examples/system/deep_sleep/main/deep_sleep_example_main.c @@ -18,7 +18,6 @@ #include "freertos/task.h" #include "esp_sleep.h" #include "esp_log.h" -#include "driver/adc.h" #include "driver/rtc_io.h" #include "soc/rtc.h" diff --git a/examples/system/ulp_fsm/ulp_adc/main/CMakeLists.txt b/examples/system/ulp_fsm/ulp_adc/main/CMakeLists.txt index c2da076199..b5768ee1a9 100644 --- a/examples/system/ulp_fsm/ulp_adc/main/CMakeLists.txt +++ b/examples/system/ulp_fsm/ulp_adc/main/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register(SRCS "ulp_adc_example_main.c" INCLUDE_DIRS "" - REQUIRES soc nvs_flash ulp driver) + REQUIRES soc nvs_flash ulp driver esp_adc) # # ULP support additions to component CMakeLists.txt. # diff --git a/examples/system/ulp_fsm/ulp_adc/main/ulp_adc_example_main.c b/examples/system/ulp_fsm/ulp_adc/main/ulp_adc_example_main.c index 6eb7a9bb10..6b3ff56485 100644 --- a/examples/system/ulp_fsm/ulp_adc/main/ulp_adc_example_main.c +++ b/examples/system/ulp_fsm/ulp_adc/main/ulp_adc_example_main.c @@ -16,10 +16,10 @@ #include "soc/sens_reg.h" #include "driver/gpio.h" #include "driver/rtc_io.h" -#include "driver/adc.h" #include "driver/dac.h" #include "esp32/ulp.h" #include "ulp_main.h" +#include "esp_adc/adc_oneshot.h" extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); @@ -60,16 +60,21 @@ static void init_ulp_program(void) (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t)); ESP_ERROR_CHECK(err); - /* Configure ADC channel */ - /* Note: when changing channel here, also change 'adc_channel' constant - in adc.S */ - adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); -#if CONFIG_IDF_TARGET_ESP32 - adc1_config_width(ADC_WIDTH_BIT_12); -#elif CONFIG_IDF_TARGET_ESP32S2 - adc1_config_width(ADC_WIDTH_BIT_13); -#endif - adc1_ulp_enable(); + //-------------ADC1 Init---------------// + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = ADC_ULP_MODE_FSM, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + //-------------ADC1 Channel Config---------------// + // Note: when changing channel here, also change 'adc_channel' constant in adc.S + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, + }; + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_6, &config)); /* Set low and high thresholds, approx. 1.35V - 1.75V*/ ulp_low_thr = 1500; diff --git a/examples/system/ulp_riscv/adc/main/CMakeLists.txt b/examples/system/ulp_riscv/adc/main/CMakeLists.txt index f14a569f2e..5865c37743 100644 --- a/examples/system/ulp_riscv/adc/main/CMakeLists.txt +++ b/examples/system/ulp_riscv/adc/main/CMakeLists.txt @@ -1,6 +1,6 @@ idf_component_register(SRCS "ulp_riscv_adc_example_main.c" INCLUDE_DIRS "" - REQUIRES soc ulp esp_adc_cal) + REQUIRES soc ulp esp_adc) # diff --git a/examples/system/ulp_riscv/adc/main/ulp/example_config.h b/examples/system/ulp_riscv/adc/main/ulp/example_config.h index 8fa84cd26e..e7fa16c916 100644 --- a/examples/system/ulp_riscv/adc/main/ulp/example_config.h +++ b/examples/system/ulp_riscv/adc/main/ulp/example_config.h @@ -10,7 +10,7 @@ #define EXAMPLE_ADC_CHANNEL ADC_CHANNEL_0 #define EXAMPLE_ADC_UNIT ADC_UNIT_1 #define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_11 -#define EXAMPLE_ADC_WIDTH ADC_WIDTH_BIT_12 +#define EXAMPLE_ADC_WIDTH ADC_BITWIDTH_DEFAULT /* Set high threshold, approx. 1.75V*/ #define EXAMPLE_ADC_TRESHOLD 2000 diff --git a/tools/test_apps/system/g1_components/CMakeLists.txt b/tools/test_apps/system/g1_components/CMakeLists.txt index 7c69876019..f27b001a15 100644 --- a/tools/test_apps/system/g1_components/CMakeLists.txt +++ b/tools/test_apps/system/g1_components/CMakeLists.txt @@ -40,6 +40,11 @@ set(extra_components_which_shouldnt_be_included # Figure out if these components can exist without a dependency on efuse. # If not, see if esp_hw_support can provide minimal efuse component replacement in G1 build. efuse + # [refactor-todo]: esp_adc is a dependency of driver, esp_phy and esp_wii. + # Driver dependency only exists in legacy drivers. After removing deprecated drivers, this dependency can be fixed + # esp_phy requires esp_adc to maintain the ADC power for PWDET usage + # esp_wifi requires esp_adc to do the initial calibration for PWDET usage + esp_adc # esp_pm is pulled in by freertos, can be made a weak dependency # conditional on related Kconfig option. It is also used by esp_wifi, driver, mbedtls, # all of which should be removed from G1-only build.