From 0b6a922f317488d00d185c160785e6a040875edf Mon Sep 17 00:00:00 2001 From: Adrian Soundy Date: Thu, 2 Oct 2025 15:26:29 +1300 Subject: [PATCH 1/9] Update ADC to latest ESP32 api --- CMake/Modules/FindSystem.Device.Adc.cmake | 12 ++ CMake/binutils.ESP32.cmake | 2 + CMake/riscv-esp32c6.json | 2 +- CMake/riscv-esp32h2.json | 2 +- .../ESP32/_common/ESP32_C6_DeviceMapping.cpp | 10 +- .../ESP32/_common/ESP32_H2_DeviceMapping.cpp | 14 +- .../ESP32/_common/ESP32_P4_DeviceMapping.cpp | 10 +- targets/ESP32/_include/esp32_idf.h | 7 +- ...dc_native_System_Device_Adc_AdcChannel.cpp | 65 +++---- ...ve_System_Device_Adc_AdcChannel_legacy.cpp | 83 +++++++++ ...native_System_Device_Adc_AdcController.cpp | 128 +++++++++----- ...System_Device_Adc_AdcController_legacy.cpp | 164 ++++++++++++++++++ 12 files changed, 405 insertions(+), 94 deletions(-) create mode 100644 targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp create mode 100644 targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp diff --git a/CMake/Modules/FindSystem.Device.Adc.cmake b/CMake/Modules/FindSystem.Device.Adc.cmake index 9b756bd98b..606f6f8ac6 100644 --- a/CMake/Modules/FindSystem.Device.Adc.cmake +++ b/CMake/Modules/FindSystem.Device.Adc.cmake @@ -16,15 +16,27 @@ list(APPEND System.Device.Adc_INCLUDE_DIRS ${BASE_PATH_FOR_THIS_MODULE}) list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device.Adc) # source files +# ESP32 uses legacy ADC driver for now as there is a dependency to legacy I2S due to internal DAC on ESP32 +if(${TARGET_SERIES_SHORT} STREQUAL "esp32") set(System.Device.Adc_SRCS sys_dev_adc_native.cpp + sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp + sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp + + target_system_device_adc_config.cpp +) +else() +set(System.Device.Adc_SRCS + sys_dev_adc_native.cpp + sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp sys_dev_adc_native_System_Device_Adc_AdcController.cpp target_system_device_adc_config.cpp ) +endif() foreach(SRC_FILE ${System.Device.Adc_SRCS}) diff --git a/CMake/binutils.ESP32.cmake b/CMake/binutils.ESP32.cmake index f7303fdd5d..5cbf98a3e0 100644 --- a/CMake/binutils.ESP32.cmake +++ b/CMake/binutils.ESP32.cmake @@ -687,6 +687,7 @@ macro(nf_add_idf_as_library) esp_netif esp_eth esp_psram + esp_adc littlefs ) @@ -702,6 +703,7 @@ macro(nf_add_idf_as_library) idf::esp_netif idf::esp_eth idf::esp_psram + idf::esp_adc idf::littlefs ) diff --git a/CMake/riscv-esp32c6.json b/CMake/riscv-esp32c6.json index b6b7f7f3dc..ecfa772e9e 100644 --- a/CMake/riscv-esp32c6.json +++ b/CMake/riscv-esp32c6.json @@ -25,7 +25,7 @@ "SUPPORT_ANY_BASE_CONVERSION": "ON", "API_System.Net": "ON", "API_System.Math": "ON", - "API_System.Device.Adc": "OFF", + "API_System.Device.Adc": "ON", "API_System.Device.Gpio": "ON", "API_System.Device.I2c": "ON", "API_System.Device.I2c.Slave": "ON", diff --git a/CMake/riscv-esp32h2.json b/CMake/riscv-esp32h2.json index b538afd256..1190c40783 100644 --- a/CMake/riscv-esp32h2.json +++ b/CMake/riscv-esp32h2.json @@ -25,7 +25,7 @@ "SUPPORT_ANY_BASE_CONVERSION": "ON", "API_System.Net": "ON", "API_System.Math": "ON", - "API_System.Device.Adc": "OFF", + "API_System.Device.Adc": "ON", "API_System.Device.Gpio": "ON", "API_System.Device.I2c": "ON", "API_System.Device.I2c.Slave": "ON", diff --git a/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp b/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp index a318d6eec6..4281772afd 100644 --- a/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp +++ b/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp @@ -56,15 +56,13 @@ int8_t Esp32_LED_DevicePinMap[6] = { -1, // 6 }; -// We use "ADC1" for 20 logical channels -// Mapped to ESP32 controllers +// We use "ADC1" for 7 logical channels +// Mapped to ESP32_C6 controllers // ESP32 ADC1 channels 0 - 6 -// " ADC1 channel 7 - Internal Temperature sensor ? -// " ADC1 channel 8 - vdd33 ? -// TODO review ADC channels for ESP32_C3 , Internal Temperature sensor (VP) & Vdd33 int8_t Esp32_ADC_DevicePinMap[7] = { // 0 1 2 3 4 5 - 0, 1, 2, 3, 4, 5, 6}; + 0, 1, 2, 3, 4, 5, 6 +}; // I2S // 1 device I2S1 diff --git a/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp b/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp index b1413c95e0..2de430d338 100644 --- a/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp +++ b/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp @@ -58,16 +58,12 @@ int8_t Esp32_LED_DevicePinMap[TARGET_LED_NUM_PINS] = { -1, // 8 }; -// We use "ADC1" for 20 logical channels -// Mapped to ESP32 controllers -// ESP32 ADC1 channels 0 - 7 -// " ADC1 channel 8 - Internal Temperature sensor (VP) -// " ADC1 channel 9 - Internal Hall Sensor (VN) -// " ADC2 channels 10 - 19 -// TODO review ADC channels for ESP32_C3 +// We use "ADC1" for 5 logical channels +// Mapped to ESP32_H2 controllers +// ESP32_H2 ADC1 channels 1 - 5 int8_t Esp32_ADC_DevicePinMap[TARGET_ADC_NUM_PINS] = { - // 0 1 2 3 4 5 - }; + 1, 2, 3, 4, 5 +}; // I2S // 1 device I2S1 diff --git a/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp b/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp index d214a22663..aeacd7334a 100644 --- a/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp +++ b/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp @@ -59,15 +59,17 @@ int8_t Esp32_LED_DevicePinMap[8] = { -1 // 8 }; +// ESP32_P4 ADC1 with 8 channels (GPIO 16,17,18,19,20,21,22,23) +// plus 6 channels (GPIO 49,50,51,52,53,54) + // ESP32P4 ADC1 channels 0 - 9 // ADC2 channels 10 - 19 int8_t Esp32_ADC_DevicePinMap[TARGET_ADC_NUM_PINS] = { // ADC1 - ADC1_CHANNEL_0_GPIO_NUM, ADC1_CHANNEL_1_GPIO_NUM, ADC1_CHANNEL_2_GPIO_NUM, ADC1_CHANNEL_3_GPIO_NUM, - ADC1_CHANNEL_4_GPIO_NUM, ADC1_CHANNEL_5_GPIO_NUM, ADC1_CHANNEL_6_GPIO_NUM, ADC1_CHANNEL_7_GPIO_NUM, + 16,17,18,19,20,21,22,23 // ADC2 - ADC2_CHANNEL_0_GPIO_NUM, ADC2_CHANNEL_1_GPIO_NUM, ADC2_CHANNEL_2_GPIO_NUM, ADC2_CHANNEL_3_GPIO_NUM, - ADC2_CHANNEL_4_GPIO_NUM, ADC2_CHANNEL_5_GPIO_NUM}; + 49,50,51,52,53,54 +}; // I2S // 1 device I2S1 diff --git a/targets/ESP32/_include/esp32_idf.h b/targets/ESP32/_include/esp32_idf.h index 0662e6ca2f..0f82db9417 100644 --- a/targets/ESP32/_include/esp32_idf.h +++ b/targets/ESP32/_include/esp32_idf.h @@ -63,8 +63,13 @@ #include #include +#if defined(CONFIG_IDF_TARGET_ESP32) +// Use legacy ADC driver for ESP32 for now as the new one also requires the new I2S driver due to dependcy because of internal DAC +// other ESP32 variants don't have DAC so use the new ADC driver #include -// #include +#else +#include +#endif #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) #include diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp index 8c0a7542e2..842e3c3ac5 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp @@ -5,17 +5,20 @@ // #include +#include -#if defined(IDF_TARGET_ESP32) -extern "C" uint8_t temprature_sens_read(); +#if defined(CONFIG_IDF_TARGET_ESP32) +extern "C" uint8_t temperature_sens_read(); #endif +adc_oneshot_unit_handle_t GetAdcHandle(adc_unit_t unit); + HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue___I4(CLR_RT_StackFrame &stack) { NANOCLR_HEADER(); int channelNumber; - int adcNumber; + adc_unit_t adcNumber; int reading = 0; // get a pointer to the managed object instance and check that it's not NULL @@ -24,48 +27,46 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue // Get channel from _channelNumber field channelNumber = pThis[FIELD___channelNumber].NumericByRef().s4; + if (channelNumber < 0 || channelNumber > TARGET_ADC_NUM_PINS) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } // Calculate internal ADC number based on channel number, 0->(CONFIG_SOC_ADC_MAX_CHANNEL_NUM - 1) - adcNumber = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; + adcNumber = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? ADC_UNIT_1 : ADC_UNIT_2; - if (adcNumber == 1) +#if defined(CONFIG_IDF_TARGET_ESP32) + // Handle internal channels for ESP32 only + if (adcNumber == ADC_UNIT_1 && (channelNumber == 8 || channelNumber == 9)) { - switch (channelNumber) + if (channelNumber == 8) { - -#if defined(IDF_TARGET_ESP32) - case 8: - reading = temperature_sens_read(); - break; - - case 9: - reading = hall_sensor_read(); - break; -#endif - - default: - reading = adc1_get_raw((adc1_channel_t)channelNumber); - break; + //reading = temperature_sens_read(); + reading = 0; + } + else + { + // Hall sensor no longer available + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); } } -#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) - else if (adcNumber == 2) - { - // Adjust channel number for ADC2 - channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; - esp_err_t result = adc2_get_raw((adc2_channel_t)channelNumber, (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH, &reading); + else +#endif + { + if (adcNumber == ADC_UNIT_2) + { + // Adjust channel number for ADC2 + channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; + } - if (result != ESP_OK) + // Read the value + if (adc_oneshot_read(GetAdcHandle(adcNumber), (adc_channel_t)channelNumber, &reading) != ESP_OK) { NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); } } -#endif - else - { - NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); - } + // Return value to the managed application stack.SetResult_I4(reading); NANOCLR_NOCLEANUP(); diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp new file mode 100644 index 0000000000..8c0a7542e2 --- /dev/null +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp @@ -0,0 +1,83 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#include + +#if defined(IDF_TARGET_ESP32) +extern "C" uint8_t temprature_sens_read(); +#endif + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channelNumber; + int adcNumber; + int reading = 0; + + // get a pointer to the managed object instance and check that it's not NULL + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // Get channel from _channelNumber field + channelNumber = pThis[FIELD___channelNumber].NumericByRef().s4; + + // Calculate internal ADC number based on channel number, 0->(CONFIG_SOC_ADC_MAX_CHANNEL_NUM - 1) + adcNumber = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; + + if (adcNumber == 1) + { + switch (channelNumber) + { + +#if defined(IDF_TARGET_ESP32) + case 8: + reading = temperature_sens_read(); + break; + + case 9: + reading = hall_sensor_read(); + break; +#endif + + default: + reading = adc1_get_raw((adc1_channel_t)channelNumber); + break; + } + } +#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) + else if (adcNumber == 2) + { + // Adjust channel number for ADC2 + channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; + esp_err_t result = adc2_get_raw((adc2_channel_t)channelNumber, (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH, &reading); + + if (result != ESP_OK) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + } +#endif + else + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + stack.SetResult_I4(reading); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeDisposeChannel___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + // left empty on purpose, nothing to do here + + NANOCLR_NOCLEANUP_NOLABEL(); +} diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp index 5b6c800b58..956028d444 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp @@ -24,13 +24,61 @@ // VN - GPIO39 ( channel 3 ) // From managed code we treat all ADC channels as 1 logical ADC unit (ADC1) -// Logical channels -// ADC1 / 0 - 7 - 8 channels - ( GPIO 32 - 39 ) 0=36, 1=37, 2=38, 3=39, 4=32, 5=33, 6=34, 7=35 -// 8 - Internal Temperture sensor -// 9 - Internal Hall Sensor -// ADC2 / 10 - 19 - 10 Channels -( GPIOs 0, 2, 4, 12 - 15 and 25 - 27. ) -// Note: ESP32-H2 and ESP32-C6 have only 1 ADC and limited number of channels +// ESP32 ADC1 with 8 channels (GPIO 36,37,38,39,32,33,34,35) +// plus 2 channels (Temp sensor, Hall sensor) ( no longer available with IDF 5.x) +// plus 10 channels (GPIO 4,0,2,12,13,14,15,27,25,26) +// ESP32_S2 ADC1 with 10 channels (GPIO 1,2,3,4,5,6,7,8,9,10) +// plus 10 channels (GPIO 11,12,13,14, XTAL_32K_P, XTAL_32K_N, DAC_1, DAC_2, 19, 20) +// ESP32_S3 ADC1 with 10 channels (GPIO 1,2,3,4,5,6,7,8,9,10) +// plus 10 channels (GPIO 11,12,13,14,15,16,17,18,19,20) +// ESP32_P4 ADC1 with 8 channels (GPIO 16,17,18,19,20,21,22,23) +// plus 6 channels (GPIO 49,50,51,52,53,54) +// ESP32_C3 ADC1 with 5 channels (GPIO 0,1,2,3,4) +// plus 1 channel (GPIO 5) +// ESP32_C6 ADC1 with 7 channels (GPIO X32K_P(0),X32K_N(1),2,3,4,5,6) +// ESP32_H2 ADC1 with 5 channels (GPIO 1,2,3,4,5) + +// Config parameters from sdkconfig +// CONFIG_SOC_ADC_SUPPORTED +// CONFIG_SOC_ADC_PERIPH_NUM +// CONFIG_SOC_ADC_MAX_CHANNEL_NUM + +adc_oneshot_unit_handle_t adc_handles[SOC_ADC_PERIPH_NUM] = {NULL}; + +adc_oneshot_unit_handle_t GetAdcHandle(adc_unit_t unit) +{ + if (unit < 0 || unit >= SOC_ADC_PERIPH_NUM) + { + return NULL; + } + + return adc_handles[unit]; +} + +void AdcController_Initialize(adc_unit_t unit) +{ + if (adc_handles[unit] != NULL) + { + // already initialized + return; + } + + adc_oneshot_unit_init_cfg_t init_config1 = {}; + init_config1.unit_id = unit; + init_config1.ulp_mode = ADC_ULP_MODE_DISABLE; + + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc_handles[unit])); +} + +void AdcController_delete(adc_unit_t unit) +{ + if (adc_handles[unit] != NULL) + { + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handles[unit])); + adc_handles[unit] = NULL; + } +} HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenChannel___VOID__I4( CLR_RT_StackFrame &stack) @@ -38,11 +86,14 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenCh NANOCLR_HEADER(); int channelNumber; - int adcUnit; + adc_unit_t adcUnit; esp_err_t result; - // default to MAX bit width for SoC - adc_bits_width_t width_bit = (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH; - adc_atten_t atten = ADC_ATTEN_DB_12; + + // Set up channel configuration + adc_oneshot_chan_cfg_t config = {}; + + config.bitwidth = ADC_BITWIDTH_12; + config.atten = ADC_ATTEN_DB_12; // get a pointer to the managed object instance and check that it's not NULL CLR_RT_HeapBlock *pThis = stack.This(); @@ -57,40 +108,37 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenCh } // Get ADC device number from channel - adcUnit = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; + adcUnit = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? ADC_UNIT_1 : ADC_UNIT_2; - switch (adcUnit) +#if (CONFIG_SOC_ADC_PERIPH_NUM == 1) + // Only ADC1 supported + if (adcUnit == ADC_UNIT_2) { -#if (CONFIG_SOC_ADC_PERIPH_NUM >= 1) - case 1: - // Normal channel 0-7 ? - if (channelNumber <= 7) - { - adc1_config_width(width_bit); - - result = adc1_config_channel_atten((adc1_channel_t)channelNumber, atten); - if (result != ESP_OK) - { - NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); - } - } - break; + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } #endif -#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) - case 2: - // Adjust for ADC2 - channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; - result = adc2_config_channel_atten((adc2_channel_t)channelNumber, atten); - - if (result != ESP_OK) - { - NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); - } - break; + // Initialize ADC unit if required + AdcController_Initialize(adcUnit); + + if (adcUnit == ADC_UNIT_2) + { + // Adjust channel number for ADC2 + channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; + } + +#if defined(CONFIG_IDF_TARGET_ESP32) + // Handle internal channels for ESP32 only, no longer used with IDF 5.x + if (adcUnit == ADC_UNIT_1 && (channelNumber == 8 || channelNumber == 9)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } #endif - default: - NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + + result = adc_oneshot_config_channel(GetAdcHandle(adcUnit), (adc_channel_t)channelNumber, &config); + if (result != ESP_OK) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); } NANOCLR_NOCLEANUP(); @@ -100,7 +148,7 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetCha { NANOCLR_HEADER(); - int channelCount = 20; + int channelCount = CONFIG_SOC_ADC_MAX_CHANNEL_NUM * CONFIG_SOC_ADC_PERIPH_NUM; // Return value to the managed application stack.SetResult_I4(channelCount); diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp new file mode 100644 index 0000000000..5b6c800b58 --- /dev/null +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp @@ -0,0 +1,164 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#include +#include + +// Details for ESP32 ADC controllers +// +// Contains ADC1 and ADC2 +// ADC1 with 8 channels ( GPIO 32 - 39 ) 0=36, 1=37, 2=38, 3=39, 4=32, 5=33, 6=34, 7=35 +// channel 8/9 are logical channles for temperture sensor and is the built in Esp32 Hall sensor. +// For hall sensor there is a restriction channel 0 and 3 must be unused +// ADC2 with 10 channels (GPIO 0,2,4,12-15 and 25-27) +// Note : ADC2 cannot be used if Wifi started and other restrictions as pins used for other things. +// +// ESP_DevKitC Gpio 0 cannot be used +// ESP-Wrover_kit V3 GPIO 0,2,4 and 15 can't be used + +// Typical marked inputs on boards +// VP - GPIO36 ( channel 0 ) +// VN - GPIO39 ( channel 3 ) + +// From managed code we treat all ADC channels as 1 logical ADC unit (ADC1) +// Logical channels +// ADC1 / 0 - 7 - 8 channels - ( GPIO 32 - 39 ) 0=36, 1=37, 2=38, 3=39, 4=32, 5=33, 6=34, 7=35 +// 8 - Internal Temperture sensor +// 9 - Internal Hall Sensor +// ADC2 / 10 - 19 - 10 Channels -( GPIOs 0, 2, 4, 12 - 15 and 25 - 27. ) + +// Note: ESP32-H2 and ESP32-C6 have only 1 ADC and limited number of channels + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenChannel___VOID__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channelNumber; + int adcUnit; + esp_err_t result; + // default to MAX bit width for SoC + adc_bits_width_t width_bit = (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH; + adc_atten_t atten = ADC_ATTEN_DB_12; + + // get a pointer to the managed object instance and check that it's not NULL + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // Get channel from argument + channelNumber = stack.Arg1().NumericByRef().s4; + + if (channelNumber < ADC_CHANNEL_0 || channelNumber > TARGET_ADC_NUM_PINS) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + // Get ADC device number from channel + adcUnit = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; + + switch (adcUnit) + { +#if (CONFIG_SOC_ADC_PERIPH_NUM >= 1) + case 1: + // Normal channel 0-7 ? + if (channelNumber <= 7) + { + adc1_config_width(width_bit); + + result = adc1_config_channel_atten((adc1_channel_t)channelNumber, atten); + if (result != ESP_OK) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + } + break; +#endif + +#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) + case 2: + // Adjust for ADC2 + channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; + result = adc2_config_channel_atten((adc2_channel_t)channelNumber, atten); + + if (result != ESP_OK) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + break; +#endif + default: + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetChannelCount___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channelCount = 20; + + // Return value to the managed application + stack.SetResult_I4(channelCount); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMaxValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // Currently fixed 12 bit so return 4095 + stack.SetResult_I4(4095); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMinValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // Return 0 for now, is this signed ? + stack.SetResult_I4(0); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeIsChannelModeSupported___BOOLEAN__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int mode = stack.Arg1().NumericByRef().s4; + + // Only support Single ended mode for now + stack.SetResult_Boolean((mode == (int)AdcChannelMode_SingleEnded)); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetResolutionInBits___I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // Fixed at 12 bit for now + stack.SetResult_I4(12); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeInit___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + // all required initialization for ADC are already handled + + NANOCLR_NOCLEANUP_NOLABEL(); +} From 566019ce6db3846ca62df46286878eb8b68e931f Mon Sep 17 00:00:00 2001 From: Adrian Soundy Date: Thu, 2 Oct 2025 16:16:11 +1300 Subject: [PATCH 2/9] Fix temperature and hall sensor code issues for ADC --- ...ev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp index 8c0a7542e2..3764e48d39 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp @@ -6,7 +6,7 @@ #include -#if defined(IDF_TARGET_ESP32) +#if defined(CONFIG_IDF_TARGET_ESP32) extern "C" uint8_t temprature_sens_read(); #endif @@ -33,13 +33,14 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue switch (channelNumber) { -#if defined(IDF_TARGET_ESP32) +#if defined(CONFIG_IDF_TARGET_ESP32) case 8: - reading = temperature_sens_read(); + reading = temprature_sens_read(); break; case 9: - reading = hall_sensor_read(); + // Hall sensor no longer available in IDF 5.x + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); break; #endif From 1cc0e41ef2badc79d3832cf3fb528331234535df Mon Sep 17 00:00:00 2001 From: nfbot Date: Thu, 2 Oct 2025 03:18:22 +0000 Subject: [PATCH 3/9] Code style fixes Automated fixes for code style. --- .../ESP32/_common/ESP32_C6_DeviceMapping.cpp | 16 ++++++++------ .../ESP32/_common/ESP32_H2_DeviceMapping.cpp | 11 +++------- .../ESP32/_common/ESP32_P4_DeviceMapping.cpp | 22 +++++++++++++------ targets/ESP32/_include/esp32_idf.h | 4 ++-- ...dc_native_System_Device_Adc_AdcChannel.cpp | 10 ++++----- ...ve_System_Device_Adc_AdcChannel_legacy.cpp | 3 ++- ...native_System_Device_Adc_AdcController.cpp | 4 ++-- 7 files changed, 38 insertions(+), 32 deletions(-) diff --git a/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp b/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp index 4281772afd..cdf589018d 100644 --- a/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp +++ b/targets/ESP32/_common/ESP32_C6_DeviceMapping.cpp @@ -23,10 +23,7 @@ int8_t Esp32_SPI_DevicePinMap[MAX_SPI_DEVICES][Esp32SpiPin_Max] = { // others assign as NONE because the default pins can be shared with serial flash and PSRAM int8_t Esp32_SERIAL_DevicePinMap[UART_NUM_MAX][Esp32SerialPin_Max] = { // COM 1 - pins 21, 20 - {UART_NUM_0_TXD_DIRECT_GPIO_NUM, - UART_NUM_0_RXD_DIRECT_GPIO_NUM, - UART_PIN_NO_CHANGE, - UART_PIN_NO_CHANGE}, + {UART_NUM_0_TXD_DIRECT_GPIO_NUM, UART_NUM_0_RXD_DIRECT_GPIO_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE}, #if defined(UART_NUM_2) // COM 2 - all set to UART_PIN_NO_CHANGE @@ -60,9 +57,14 @@ int8_t Esp32_LED_DevicePinMap[6] = { // Mapped to ESP32_C6 controllers // ESP32 ADC1 channels 0 - 6 int8_t Esp32_ADC_DevicePinMap[7] = { - // 0 1 2 3 4 5 - 0, 1, 2, 3, 4, 5, 6 -}; + // 0 1 2 3 4 5 + 0, + 1, + 2, + 3, + 4, + 5, + 6}; // I2S // 1 device I2S1 diff --git a/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp b/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp index 2de430d338..712d0da350 100644 --- a/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp +++ b/targets/ESP32/_common/ESP32_H2_DeviceMapping.cpp @@ -23,10 +23,7 @@ int8_t Esp32_SPI_DevicePinMap[MAX_SPI_DEVICES][Esp32SpiPin_Max] = { // others assign as NONE because the default pins can be shared with serial flash and PSRAM int8_t Esp32_SERIAL_DevicePinMap[UART_NUM_MAX][Esp32SerialPin_Max] = { // COM 1 - pins 21, 20 - {UART_NUM_0_TXD_DIRECT_GPIO_NUM, - UART_NUM_0_RXD_DIRECT_GPIO_NUM, - UART_PIN_NO_CHANGE, - UART_PIN_NO_CHANGE}, + {UART_NUM_0_TXD_DIRECT_GPIO_NUM, UART_NUM_0_RXD_DIRECT_GPIO_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE}, #if defined(UART_NUM_2) // COM 2 - all set to UART_PIN_NO_CHANGE @@ -56,14 +53,12 @@ int8_t Esp32_LED_DevicePinMap[TARGET_LED_NUM_PINS] = { -1, // 6 -1, // 7 -1, // 8 - }; +}; // We use "ADC1" for 5 logical channels // Mapped to ESP32_H2 controllers // ESP32_H2 ADC1 channels 1 - 5 -int8_t Esp32_ADC_DevicePinMap[TARGET_ADC_NUM_PINS] = { - 1, 2, 3, 4, 5 -}; +int8_t Esp32_ADC_DevicePinMap[TARGET_ADC_NUM_PINS] = {1, 2, 3, 4, 5}; // I2S // 1 device I2S1 diff --git a/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp b/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp index aeacd7334a..8d908e1255 100644 --- a/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp +++ b/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp @@ -24,10 +24,7 @@ int8_t Esp32_SPI_DevicePinMap[MAX_SPI_DEVICES][Esp32SpiPin_Max] = { // others assign as NONE because the default pins can be shared with serial flash and PSRAM int8_t Esp32_SERIAL_DevicePinMap[UART_NUM_MAX][Esp32SerialPin_Max] = { // COM 1 - pins 21, 20 - {UART_NUM_0_TXD_DIRECT_GPIO_NUM, - UART_NUM_0_RXD_DIRECT_GPIO_NUM, - UART_PIN_NO_CHANGE, - UART_PIN_NO_CHANGE}, + {UART_NUM_0_TXD_DIRECT_GPIO_NUM, UART_NUM_0_RXD_DIRECT_GPIO_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE}, #if defined(UART_NUM_2) // COM 2 - all set to UART_PIN_NO_CHANGE @@ -66,10 +63,21 @@ int8_t Esp32_LED_DevicePinMap[8] = { // ADC2 channels 10 - 19 int8_t Esp32_ADC_DevicePinMap[TARGET_ADC_NUM_PINS] = { // ADC1 - 16,17,18,19,20,21,22,23 + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 // ADC2 - 49,50,51,52,53,54 -}; + 49, + 50, + 51, + 52, + 53, + 54}; // I2S // 1 device I2S1 diff --git a/targets/ESP32/_include/esp32_idf.h b/targets/ESP32/_include/esp32_idf.h index 0f82db9417..ccd422719b 100644 --- a/targets/ESP32/_include/esp32_idf.h +++ b/targets/ESP32/_include/esp32_idf.h @@ -64,8 +64,8 @@ #include #if defined(CONFIG_IDF_TARGET_ESP32) -// Use legacy ADC driver for ESP32 for now as the new one also requires the new I2S driver due to dependcy because of internal DAC -// other ESP32 variants don't have DAC so use the new ADC driver +// Use legacy ADC driver for ESP32 for now as the new one also requires the new I2S driver due to dependcy because of +// internal DAC other ESP32 variants don't have DAC so use the new ADC driver #include #else #include diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp index 842e3c3ac5..3207e5b681 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp @@ -30,7 +30,7 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue if (channelNumber < 0 || channelNumber > TARGET_ADC_NUM_PINS) { NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); - } + } // Calculate internal ADC number based on channel number, 0->(CONFIG_SOC_ADC_MAX_CHANNEL_NUM - 1) adcNumber = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? ADC_UNIT_1 : ADC_UNIT_2; @@ -41,18 +41,18 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue { if (channelNumber == 8) { - //reading = temperature_sens_read(); + // reading = temperature_sens_read(); reading = 0; } - else + else { // Hall sensor no longer available NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); } } else -#endif - { +#endif + { if (adcNumber == ADC_UNIT_2) { // Adjust channel number for ADC2 diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp index 3764e48d39..3cdb1fb752 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp @@ -54,7 +54,8 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue { // Adjust channel number for ADC2 channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; - esp_err_t result = adc2_get_raw((adc2_channel_t)channelNumber, (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH, &reading); + esp_err_t result = + adc2_get_raw((adc2_channel_t)channelNumber, (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH, &reading); if (result != ESP_OK) { diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp index 956028d444..968b833297 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp @@ -62,7 +62,7 @@ void AdcController_Initialize(adc_unit_t unit) { // already initialized return; - } + } adc_oneshot_unit_init_cfg_t init_config1 = {}; init_config1.unit_id = unit; @@ -77,7 +77,7 @@ void AdcController_delete(adc_unit_t unit) { ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handles[unit])); adc_handles[unit] = NULL; - } + } } HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenChannel___VOID__I4( From 5e295459e3bda08c6b747c26043f83a9833a1756 Mon Sep 17 00:00:00 2001 From: Adrian Soundy Date: Sat, 4 Oct 2025 11:02:41 +1300 Subject: [PATCH 4/9] Adjust findsystem for adc --- CMake/Modules/FindSystem.Device.Adc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/Modules/FindSystem.Device.Adc.cmake b/CMake/Modules/FindSystem.Device.Adc.cmake index 606f6f8ac6..d9ec6a4aee 100644 --- a/CMake/Modules/FindSystem.Device.Adc.cmake +++ b/CMake/Modules/FindSystem.Device.Adc.cmake @@ -17,7 +17,7 @@ list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device # source files # ESP32 uses legacy ADC driver for now as there is a dependency to legacy I2S due to internal DAC on ESP32 -if(${TARGET_SERIES_SHORT} STREQUAL "esp32") +if(TARGET_SERIES_SHORT AND ${TARGET_SERIES_SHORT} STREQUAL "esp32") set(System.Device.Adc_SRCS sys_dev_adc_native.cpp From ca4bd3da11aeccd80ce8039b60d3f923d0180051 Mon Sep 17 00:00:00 2001 From: Adrian Soundy Date: Sat, 4 Oct 2025 11:22:01 +1300 Subject: [PATCH 5/9] Update FindSystem.Device.Adc.cmake --- CMake/Modules/FindSystem.Device.Adc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMake/Modules/FindSystem.Device.Adc.cmake b/CMake/Modules/FindSystem.Device.Adc.cmake index d9ec6a4aee..be5c82eb90 100644 --- a/CMake/Modules/FindSystem.Device.Adc.cmake +++ b/CMake/Modules/FindSystem.Device.Adc.cmake @@ -17,7 +17,7 @@ list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device # source files # ESP32 uses legacy ADC driver for now as there is a dependency to legacy I2S due to internal DAC on ESP32 -if(TARGET_SERIES_SHORT AND ${TARGET_SERIES_SHORT} STREQUAL "esp32") +if(DEFINED TARGET_SERIES_SHORT AND ${TARGET_SERIES_SHORT} STREQUAL "esp32") set(System.Device.Adc_SRCS sys_dev_adc_native.cpp From 13b1539c51e9992522a67bada7759b6b84ac9c6d Mon Sep 17 00:00:00 2001 From: Adrian Soundy Date: Sat, 4 Oct 2025 11:43:43 +1300 Subject: [PATCH 6/9] Fix error from code style auto fix --- targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp b/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp index 8d908e1255..d9055a04b9 100644 --- a/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp +++ b/targets/ESP32/_common/ESP32_P4_DeviceMapping.cpp @@ -70,7 +70,7 @@ int8_t Esp32_ADC_DevicePinMap[TARGET_ADC_NUM_PINS] = { 20, 21, 22, - 23 + 23, // ADC2 49, 50, From 3e669c3598cd7e0eb2f2ce0899067960e4a3349a Mon Sep 17 00:00:00 2001 From: Adrian Soundy Date: Sat, 4 Oct 2025 12:10:08 +1300 Subject: [PATCH 7/9] Reset ADC cmake logic and add legacy and new to same file --- CMake/Modules/FindSystem.Device.Adc.cmake | 13 -- ...dc_native_System_Device_Adc_AdcChannel.cpp | 81 ++++++++- ...ve_System_Device_Adc_AdcChannel_legacy.cpp | 85 --------- ...native_System_Device_Adc_AdcController.cpp | 137 +++++++++++++++ ...System_Device_Adc_AdcController_legacy.cpp | 164 ------------------ 5 files changed, 217 insertions(+), 263 deletions(-) delete mode 100644 targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp delete mode 100644 targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp diff --git a/CMake/Modules/FindSystem.Device.Adc.cmake b/CMake/Modules/FindSystem.Device.Adc.cmake index be5c82eb90..5f8e53c7ee 100644 --- a/CMake/Modules/FindSystem.Device.Adc.cmake +++ b/CMake/Modules/FindSystem.Device.Adc.cmake @@ -16,18 +16,6 @@ list(APPEND System.Device.Adc_INCLUDE_DIRS ${BASE_PATH_FOR_THIS_MODULE}) list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device.Adc) # source files -# ESP32 uses legacy ADC driver for now as there is a dependency to legacy I2S due to internal DAC on ESP32 -if(DEFINED TARGET_SERIES_SHORT AND ${TARGET_SERIES_SHORT} STREQUAL "esp32") -set(System.Device.Adc_SRCS - - sys_dev_adc_native.cpp - - sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp - sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp - - target_system_device_adc_config.cpp -) -else() set(System.Device.Adc_SRCS sys_dev_adc_native.cpp @@ -36,7 +24,6 @@ set(System.Device.Adc_SRCS target_system_device_adc_config.cpp ) -endif() foreach(SRC_FILE ${System.Device.Adc_SRCS}) diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp index 3207e5b681..e9c39459e6 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp @@ -7,9 +7,86 @@ #include #include +// The ESP32 still uses the legacy ADC driver for now as dependency between ADC and I2S due to internal DAC etc #if defined(CONFIG_IDF_TARGET_ESP32) -extern "C" uint8_t temperature_sens_read(); + +extern "C" uint8_t temprature_sens_read(); + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channelNumber; + int adcNumber; + int reading = 0; + + // get a pointer to the managed object instance and check that it's not NULL + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // Get channel from _channelNumber field + channelNumber = pThis[FIELD___channelNumber].NumericByRef().s4; + + // Calculate internal ADC number based on channel number, 0->(CONFIG_SOC_ADC_MAX_CHANNEL_NUM - 1) + adcNumber = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; + + if (adcNumber == 1) + { + switch (channelNumber) + { + +#if defined(CONFIG_IDF_TARGET_ESP32) + case 8: + reading = temprature_sens_read(); + break; + + case 9: + // Hall sensor no longer available in IDF 5.x + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + break; +#endif + + default: + reading = adc1_get_raw((adc1_channel_t)channelNumber); + break; + } + } +#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) + else if (adcNumber == 2) + { + // Adjust channel number for ADC2 + channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; + esp_err_t result = + adc2_get_raw((adc2_channel_t)channelNumber, (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH, &reading); + + if (result != ESP_OK) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + } #endif + else + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + stack.SetResult_I4(reading); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeDisposeChannel___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + // left empty on purpose, nothing to do here + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +#else // !defined(CONFIG_IDF_TARGET_ESP32) adc_oneshot_unit_handle_t GetAdcHandle(adc_unit_t unit); @@ -82,3 +159,5 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeDisposeCh NANOCLR_NOCLEANUP_NOLABEL(); } + +#endif // !defined(CONFIG_IDF_TARGET_ESP32) diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp deleted file mode 100644 index 3cdb1fb752..0000000000 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcChannel_legacy.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright (c) .NET Foundation and Contributors -// Portions Copyright (c) Microsoft Corporation. All rights reserved. -// See LICENSE file in the project root for full license information. -// - -#include - -#if defined(CONFIG_IDF_TARGET_ESP32) -extern "C" uint8_t temprature_sens_read(); -#endif - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue___I4(CLR_RT_StackFrame &stack) -{ - NANOCLR_HEADER(); - - int channelNumber; - int adcNumber; - int reading = 0; - - // get a pointer to the managed object instance and check that it's not NULL - CLR_RT_HeapBlock *pThis = stack.This(); - FAULT_ON_NULL(pThis); - - // Get channel from _channelNumber field - channelNumber = pThis[FIELD___channelNumber].NumericByRef().s4; - - // Calculate internal ADC number based on channel number, 0->(CONFIG_SOC_ADC_MAX_CHANNEL_NUM - 1) - adcNumber = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; - - if (adcNumber == 1) - { - switch (channelNumber) - { - -#if defined(CONFIG_IDF_TARGET_ESP32) - case 8: - reading = temprature_sens_read(); - break; - - case 9: - // Hall sensor no longer available in IDF 5.x - NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); - break; -#endif - - default: - reading = adc1_get_raw((adc1_channel_t)channelNumber); - break; - } - } -#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) - else if (adcNumber == 2) - { - // Adjust channel number for ADC2 - channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; - esp_err_t result = - adc2_get_raw((adc2_channel_t)channelNumber, (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH, &reading); - - if (result != ESP_OK) - { - NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); - } - } -#endif - else - { - NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); - } - - stack.SetResult_I4(reading); - - NANOCLR_NOCLEANUP(); -} - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeDisposeChannel___VOID(CLR_RT_StackFrame &stack) -{ - (void)stack; - - NANOCLR_HEADER(); - - // left empty on purpose, nothing to do here - - NANOCLR_NOCLEANUP_NOLABEL(); -} diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp index 968b833297..67a3c15716 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp @@ -44,6 +44,142 @@ // CONFIG_SOC_ADC_PERIPH_NUM // CONFIG_SOC_ADC_MAX_CHANNEL_NUM +// The ESP32 still uses the legacy ADC driver for now as dependency between ADC and I2S due to internal DAC etc +#if defined(CONFIG_IDF_TARGET_ESP32) + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenChannel___VOID__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channelNumber; + int adcUnit; + esp_err_t result; + // default to MAX bit width for SoC + adc_bits_width_t width_bit = (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH; + adc_atten_t atten = ADC_ATTEN_DB_12; + + // get a pointer to the managed object instance and check that it's not NULL + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + // Get channel from argument + channelNumber = stack.Arg1().NumericByRef().s4; + + if (channelNumber < ADC_CHANNEL_0 || channelNumber > TARGET_ADC_NUM_PINS) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + // Get ADC device number from channel + adcUnit = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; + + switch (adcUnit) + { +#if (CONFIG_SOC_ADC_PERIPH_NUM >= 1) + case 1: + // Normal channel 0-7 ? + if (channelNumber <= 7) + { + adc1_config_width(width_bit); + + result = adc1_config_channel_atten((adc1_channel_t)channelNumber, atten); + if (result != ESP_OK) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + } + break; +#endif + +#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) + case 2: + // Adjust for ADC2 + channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; + result = adc2_config_channel_atten((adc2_channel_t)channelNumber, atten); + + if (result != ESP_OK) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + break; +#endif + default: + NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); + } + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetChannelCount___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channelCount = 20; + + // Return value to the managed application + stack.SetResult_I4(channelCount); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMaxValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // Currently fixed 12 bit so return 4095 + stack.SetResult_I4(4095); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMinValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // Return 0 for now, is this signed ? + stack.SetResult_I4(0); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeIsChannelModeSupported___BOOLEAN__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int mode = stack.Arg1().NumericByRef().s4; + + // Only support Single ended mode for now + stack.SetResult_Boolean((mode == (int)AdcChannelMode_SingleEnded)); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetResolutionInBits___I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // Fixed at 12 bit for now + stack.SetResult_I4(12); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeInit___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + // all required initialization for ADC are already handled + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +#else + adc_oneshot_unit_handle_t adc_handles[SOC_ADC_PERIPH_NUM] = {NULL}; adc_oneshot_unit_handle_t GetAdcHandle(adc_unit_t unit) @@ -210,3 +346,4 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeInit__ NANOCLR_NOCLEANUP_NOLABEL(); } +#endif // #if defined(CONFIG_IDF_TARGET_ESP32) \ No newline at end of file diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp deleted file mode 100644 index 5b6c800b58..0000000000 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController_legacy.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// -// Copyright (c) .NET Foundation and Contributors -// Portions Copyright (c) Microsoft Corporation. All rights reserved. -// See LICENSE file in the project root for full license information. -// - -#include -#include - -// Details for ESP32 ADC controllers -// -// Contains ADC1 and ADC2 -// ADC1 with 8 channels ( GPIO 32 - 39 ) 0=36, 1=37, 2=38, 3=39, 4=32, 5=33, 6=34, 7=35 -// channel 8/9 are logical channles for temperture sensor and is the built in Esp32 Hall sensor. -// For hall sensor there is a restriction channel 0 and 3 must be unused -// ADC2 with 10 channels (GPIO 0,2,4,12-15 and 25-27) -// Note : ADC2 cannot be used if Wifi started and other restrictions as pins used for other things. -// -// ESP_DevKitC Gpio 0 cannot be used -// ESP-Wrover_kit V3 GPIO 0,2,4 and 15 can't be used - -// Typical marked inputs on boards -// VP - GPIO36 ( channel 0 ) -// VN - GPIO39 ( channel 3 ) - -// From managed code we treat all ADC channels as 1 logical ADC unit (ADC1) -// Logical channels -// ADC1 / 0 - 7 - 8 channels - ( GPIO 32 - 39 ) 0=36, 1=37, 2=38, 3=39, 4=32, 5=33, 6=34, 7=35 -// 8 - Internal Temperture sensor -// 9 - Internal Hall Sensor -// ADC2 / 10 - 19 - 10 Channels -( GPIOs 0, 2, 4, 12 - 15 and 25 - 27. ) - -// Note: ESP32-H2 and ESP32-C6 have only 1 ADC and limited number of channels - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenChannel___VOID__I4( - CLR_RT_StackFrame &stack) -{ - NANOCLR_HEADER(); - - int channelNumber; - int adcUnit; - esp_err_t result; - // default to MAX bit width for SoC - adc_bits_width_t width_bit = (adc_bits_width_t)SOC_ADC_RTC_MAX_BITWIDTH; - adc_atten_t atten = ADC_ATTEN_DB_12; - - // get a pointer to the managed object instance and check that it's not NULL - CLR_RT_HeapBlock *pThis = stack.This(); - FAULT_ON_NULL(pThis); - - // Get channel from argument - channelNumber = stack.Arg1().NumericByRef().s4; - - if (channelNumber < ADC_CHANNEL_0 || channelNumber > TARGET_ADC_NUM_PINS) - { - NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); - } - - // Get ADC device number from channel - adcUnit = channelNumber < CONFIG_SOC_ADC_MAX_CHANNEL_NUM ? 1 : 2; - - switch (adcUnit) - { -#if (CONFIG_SOC_ADC_PERIPH_NUM >= 1) - case 1: - // Normal channel 0-7 ? - if (channelNumber <= 7) - { - adc1_config_width(width_bit); - - result = adc1_config_channel_atten((adc1_channel_t)channelNumber, atten); - if (result != ESP_OK) - { - NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); - } - } - break; -#endif - -#if (CONFIG_SOC_ADC_PERIPH_NUM >= 2) - case 2: - // Adjust for ADC2 - channelNumber -= CONFIG_SOC_ADC_MAX_CHANNEL_NUM; - result = adc2_config_channel_atten((adc2_channel_t)channelNumber, atten); - - if (result != ESP_OK) - { - NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); - } - break; -#endif - default: - NANOCLR_SET_AND_LEAVE(CLR_E_PIN_UNAVAILABLE); - } - - NANOCLR_NOCLEANUP(); -} - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetChannelCount___I4(CLR_RT_StackFrame &stack) -{ - NANOCLR_HEADER(); - - int channelCount = 20; - - // Return value to the managed application - stack.SetResult_I4(channelCount); - - NANOCLR_NOCLEANUP_NOLABEL(); -} - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMaxValue___I4(CLR_RT_StackFrame &stack) -{ - NANOCLR_HEADER(); - - // Currently fixed 12 bit so return 4095 - stack.SetResult_I4(4095); - - NANOCLR_NOCLEANUP_NOLABEL(); -} - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMinValue___I4(CLR_RT_StackFrame &stack) -{ - NANOCLR_HEADER(); - - // Return 0 for now, is this signed ? - stack.SetResult_I4(0); - - NANOCLR_NOCLEANUP_NOLABEL(); -} - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeIsChannelModeSupported___BOOLEAN__I4( - CLR_RT_StackFrame &stack) -{ - NANOCLR_HEADER(); - - int mode = stack.Arg1().NumericByRef().s4; - - // Only support Single ended mode for now - stack.SetResult_Boolean((mode == (int)AdcChannelMode_SingleEnded)); - - NANOCLR_NOCLEANUP_NOLABEL(); -} - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetResolutionInBits___I4( - CLR_RT_StackFrame &stack) -{ - NANOCLR_HEADER(); - - // Fixed at 12 bit for now - stack.SetResult_I4(12); - - NANOCLR_NOCLEANUP_NOLABEL(); -} - -HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeInit___VOID(CLR_RT_StackFrame &stack) -{ - (void)stack; - - NANOCLR_HEADER(); - - // all required initialization for ADC are already handled - - NANOCLR_NOCLEANUP_NOLABEL(); -} From 1ef3624e5ca2ab03ec8675a79ce4beddae8365b1 Mon Sep 17 00:00:00 2001 From: nfbot Date: Fri, 3 Oct 2025 23:12:00 +0000 Subject: [PATCH 8/9] Code style fixes Automated fixes for code style. --- .../sys_dev_adc_native_System_Device_Adc_AdcController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp index 67a3c15716..46c148da4c 100644 --- a/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.Adc/sys_dev_adc_native_System_Device_Adc_AdcController.cpp @@ -346,4 +346,4 @@ HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeInit__ NANOCLR_NOCLEANUP_NOLABEL(); } -#endif // #if defined(CONFIG_IDF_TARGET_ESP32) \ No newline at end of file +#endif // #if defined(CONFIG_IDF_TARGET_ESP32) \ No newline at end of file From 47c569a702209826f1a4965a31632fa52976be5a Mon Sep 17 00:00:00 2001 From: Adrian Soundy Date: Fri, 17 Oct 2025 22:51:38 -0500 Subject: [PATCH 9/9] Update targets/ESP32/_include/esp32_idf.h Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- targets/ESP32/_include/esp32_idf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/ESP32/_include/esp32_idf.h b/targets/ESP32/_include/esp32_idf.h index ccd422719b..9f34fbb9e0 100644 --- a/targets/ESP32/_include/esp32_idf.h +++ b/targets/ESP32/_include/esp32_idf.h @@ -64,7 +64,7 @@ #include #if defined(CONFIG_IDF_TARGET_ESP32) -// Use legacy ADC driver for ESP32 for now as the new one also requires the new I2S driver due to dependcy because of +// Use legacy ADC driver for ESP32 for now as the new one also requires the new I2S driver due to dependency because of // internal DAC other ESP32 variants don't have DAC so use the new ADC driver #include #else