From 0c3d1761fcd0a347183ad64afd8da4a691726a11 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:11:19 +0200 Subject: [PATCH 01/14] Adds Analog Continuous mode API --- cores/esp32/esp32-hal-adc.c | 406 ++++++++++++++++++++++++++++++++++-- cores/esp32/esp32-hal-adc.h | 50 +++++ 2 files changed, 434 insertions(+), 22 deletions(-) diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index b53eb868d3d..b357b6d6004 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -18,14 +18,28 @@ #include "esp32-hal.h" #include "esp32-hal-periman.h" #include "esp_adc/adc_oneshot.h" +#include "esp_adc/adc_continuous.h" #include "esp_adc/adc_cali_scheme.h" static uint8_t __analogAttenuation = ADC_11db; static uint8_t __analogWidth = SOC_ADC_RTC_MAX_BITWIDTH; static uint8_t __analogReturnedWidth = SOC_ADC_RTC_MAX_BITWIDTH; -adc_oneshot_unit_handle_t adc_handle[SOC_ADC_PERIPH_NUM]; -adc_cali_handle_t adc_cali_handle[SOC_ADC_PERIPH_NUM]; +typedef struct { + voidFuncPtr fn; + void* arg; +} interrupt_config_t; + +typedef struct { + adc_oneshot_unit_handle_t adc_oneshot_handle; + adc_continuous_handle_t adc_continuous_handle; + interrupt_config_t adc_interrupt_handle; + adc_cali_handle_t adc_cali_handle; + uint32_t buffer_size; + uint32_t conversion_frame_size; +} adc_handle_t; + +adc_handle_t adc_handle[SOC_ADC_PERIPH_NUM]; static bool adcDetachBus(void * pin){ adc_channel_t adc_channel; @@ -42,11 +56,23 @@ static bool adcDetachBus(void * pin){ } if(used_channels == 1){ //only 1 channel is used - esp_err_t err = adc_oneshot_del_unit(adc_handle[adc_unit]); + esp_err_t err = adc_oneshot_del_unit(adc_handle[adc_unit].adc_oneshot_handle); + if(err != ESP_OK){ + return false; + } + adc_handle[adc_unit].adc_oneshot_handle = NULL; + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); if(err != ESP_OK){ return false; } - adc_handle[adc_unit] = NULL; + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) + err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + return false; + } + #endif + adc_handle[adc_unit].adc_cali_handle = NULL; } return true; } @@ -59,12 +85,12 @@ esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, i }; if(pin == -1){ //Reconfigure all used analog pins/channels for(int adc_unit = 0 ; adc_unit < SOC_ADC_PERIPH_NUM; adc_unit++){ - if(adc_handle[adc_unit] != NULL){ + if(adc_handle[adc_unit].adc_oneshot_handle != NULL){ for (uint8_t channel = 0; channel < SOC_ADC_CHANNEL_NUM(adc_unit); channel++){ int io_pin; adc_oneshot_channel_to_io( adc_unit, channel, &io_pin); if(perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_ONESHOT){ - err = adc_oneshot_config_channel(adc_handle[adc_unit], channel, &config); + err = adc_oneshot_config_channel(adc_handle[adc_unit].adc_oneshot_handle, channel, &config); if(err != ESP_OK){ log_e("adc_oneshot_config_channel failed with error: %d", err); return err; @@ -72,10 +98,10 @@ esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, i } } //ADC calibration reconfig only if all channels are updated - if(adc_cali_handle[adc_unit] != NULL){ + if(adc_handle[adc_unit].adc_cali_handle != NULL){ #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED log_d("Deleting ADC_UNIT_%d cali handle",adc_unit); - err = adc_cali_delete_scheme_curve_fitting(adc_cali_handle[adc_unit]); + err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); if(err != ESP_OK){ log_e("adc_cali_delete_scheme_curve_fitting failed with error: %d", err); return err; @@ -86,14 +112,14 @@ esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, i .bitwidth = width, }; log_d("Creating ADC_UNIT_%d curve cali handle",adc_unit); - err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle[adc_unit]); + err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); if(err != ESP_OK){ log_e("adc_cali_create_scheme_curve_fitting failed with error: %d", err); return err; } - #elif !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED log_d("Deleting ADC_UNIT_%d line cali handle",adc_unit); - err = adc_cali_delete_scheme_line_fitting(adc_cali_handle[adc_unit]); + err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); if(err != ESP_OK){ log_e("adc_cali_delete_scheme_line_fitting failed with error: %d", err); return err; @@ -104,7 +130,7 @@ esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, i .bitwidth = width, }; log_d("Creating ADC_UNIT_%d line cali handle",adc_unit); - err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_cali_handle[adc_unit]); + err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); if(err != ESP_OK){ log_e("adc_cali_create_scheme_line_fitting failed with error: %d", err); return err; @@ -128,7 +154,7 @@ esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, i log_e("Pin %u is not ADC pin!", pin); return err; } - err = adc_oneshot_config_channel(adc_handle[adc_unit], channel, &config); + err = adc_oneshot_config_channel(adc_handle[adc_unit].adc_oneshot_handle, channel, &config); if(err != ESP_OK){ log_e("adc_oneshot_config_channel failed with error: %d", err); return err; @@ -174,12 +200,12 @@ void __analogSetWidth(uint8_t bits){ esp_err_t __analogInit(uint8_t pin, adc_channel_t channel, adc_unit_t adc_unit){ esp_err_t err = ESP_OK; - if(adc_handle[adc_unit] == NULL) { + if(adc_handle[adc_unit].adc_oneshot_handle == NULL) { adc_oneshot_unit_init_cfg_t init_config1 = { .unit_id = adc_unit, .ulp_mode = ADC_ULP_MODE_DISABLE, }; - err = adc_oneshot_new_unit(&init_config1, &adc_handle[adc_unit]); + err = adc_oneshot_new_unit(&init_config1, &adc_handle[adc_unit].adc_oneshot_handle); if(err != ESP_OK){ log_e("adc_oneshot_new_unit failed with error: %d", err); @@ -197,7 +223,7 @@ esp_err_t __analogInit(uint8_t pin, adc_channel_t channel, adc_unit_t adc_unit){ .atten = __analogAttenuation, }; - err = adc_oneshot_config_channel(adc_handle[adc_unit], channel, &config); + err = adc_oneshot_config_channel(adc_handle[adc_unit].adc_oneshot_handle, channel, &config); if(err != ESP_OK){ log_e("adc_oneshot_config_channel failed with error: %d", err); return err; @@ -245,7 +271,7 @@ uint16_t __analogRead(uint8_t pin){ } } - adc_oneshot_read(adc_handle[adc_unit], channel, &value); + adc_oneshot_read(adc_handle[adc_unit].adc_oneshot_handle, channel, &value); return mapResolution(value); } @@ -269,7 +295,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin){ } } - if(adc_cali_handle[adc_unit] == NULL){ + if(adc_handle[adc_unit].adc_cali_handle == NULL){ log_d("Creating cali handle for ADC_%d", adc_unit); #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED adc_cali_curve_fitting_config_t cali_config = { @@ -277,14 +303,14 @@ uint32_t __analogReadMilliVolts(uint8_t pin){ .atten = __analogAttenuation, .bitwidth = __analogWidth, }; - err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle[adc_unit]); - #elif !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED adc_cali_line_fitting_config_t cali_config = { .unit_id = adc_unit, .bitwidth = __analogWidth, .atten = __analogAttenuation, }; - err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_cali_handle[adc_unit]); + err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); #endif if(err != ESP_OK){ log_e("adc_cali_create_scheme_x failed!"); @@ -292,7 +318,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin){ } } - err = adc_oneshot_get_calibrated_result(adc_handle[adc_unit], adc_cali_handle[adc_unit], channel, &value); + err = adc_oneshot_get_calibrated_result(adc_handle[adc_unit].adc_oneshot_handle, adc_handle[adc_unit].adc_cali_handle, channel, &value); if(err != ESP_OK){ log_e("adc_oneshot_get_calibrated_result failed!"); return 0; @@ -310,4 +336,340 @@ extern void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth"))); #endif +/* + * ADC Continuous mode + */ + +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + #define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1 + #define ADC_GET_CHANNEL(p_data) ((p_data)->type1.channel) + #define ADC_GET_DATA(p_data) ((p_data)->type1.data) +#else + #define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 + #define ADC_GET_CHANNEL(p_data) ((p_data)->type2.channel) + #define ADC_GET_DATA(p_data) ((p_data)->type2.data) +#endif + +static uint8_t __adcContinuousAtten = ADC_11db; +static uint8_t __adcContinuousWidth = SOC_ADC_DIGI_MAX_BITWIDTH; + +static uint8_t used_adc_channels = 0; +adc_continuos_data_t * adc_result = NULL; + +static bool adcContinuousDetachBus(void * adc_unit_number){ + adc_unit_t adc_unit = (adc_unit_t)adc_unit_number - 1; + + if(adc_handle[adc_unit].adc_continuous_handle == NULL){ + return true; + } + else + { + esp_err_t err = adc_continuous_deinit(adc_handle[adc_unit].adc_continuous_handle); + if(err != ESP_OK){ + return false; + } + adc_handle[adc_unit].adc_continuous_handle = NULL; + + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + return false; + } + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) + err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + return false; + } + #endif + adc_handle[adc_unit].adc_cali_handle = NULL; + + //set all used pins to INIT state + for (uint8_t channel = 0; channel < SOC_ADC_CHANNEL_NUM(adc_unit); channel++){ + int io_pin; + adc_oneshot_channel_to_io(adc_unit, channel, &io_pin); + if(perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_CONT){ + if(!perimanSetPinBus(io_pin, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + } + } + } + return true; +} + +bool IRAM_ATTR adcFnWrapper(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *args){ + interrupt_config_t * isr = (interrupt_config_t*)args; + if(isr->fn) { + if(isr->arg){ + ((voidFuncPtrArg)isr->fn)(isr->arg); + } else { + isr->fn(); + } + } + return false; +} + +esp_err_t __analogContinuousInit(adc_channel_t *channel, uint8_t channel_num, adc_unit_t adc_unit, uint32_t sampling_freq_hz){ + //Create new ADC continuous handle + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = adc_handle[adc_unit].buffer_size, + .conv_frame_size = adc_handle[adc_unit].conversion_frame_size, + }; + + esp_err_t err = adc_continuous_new_handle(&adc_config, &adc_handle[adc_unit].adc_continuous_handle); + if(err != ESP_OK){ + log_e("adc_continuous_new_handle failed with error: %d", err); + return ESP_FAIL; + } + + //Configure adc pins + adc_continuous_config_t dig_cfg = { + .sample_freq_hz = sampling_freq_hz, + .conv_mode = ADC_CONV_SINGLE_UNIT_1, + .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++) { + adc_pattern[i].atten = __adcContinuousAtten; + adc_pattern[i].channel = channel[i] & 0x7; + adc_pattern[i].unit = ADC_UNIT_1; + adc_pattern[i].bit_width = __adcContinuousWidth; + } + dig_cfg.adc_pattern = adc_pattern; + err = adc_continuous_config(adc_handle[adc_unit].adc_continuous_handle, &dig_cfg); + + if(err != ESP_OK){ + log_e("adc_continuous_config failed with error: %d", err); + return ESP_FAIL; + } + + used_adc_channels = channel_num; + return ESP_OK; +} + + +bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_per_pin, uint32_t sampling_freq_hz, void (*userFunc)(void)){ + adc_channel_t channel[pins_count]; + adc_unit_t adc_unit; + esp_err_t err = ESP_OK; + + //Convert pins to channels and check if all are ADC1s unit + for(int i = 0; i < pins_count; i++){ + err = adc_continuous_io_to_channel(pins[i], &adc_unit, &channel[i]); + if(err != ESP_OK){ + log_e("Pin %u is not ADC pin!", pins[i]); + return ESP_FAIL; + } + if(adc_unit != 0){ + log_e("Only ADC1 pins are supported in continuous mode!"); + return ESP_FAIL; + } + } + + //Check if Oneshot and Continous handle exists + if(adc_handle[adc_unit].adc_oneshot_handle != NULL){ + log_e("ADC%d is running in oneshot mode. Aborting.", adc_unit+1); + return ESP_FAIL; + } + if(adc_handle[adc_unit].adc_continuous_handle != NULL){ + log_e("ADC%d continuous is already initialized. To reconfigure call analogContinuousDeinit() first.", adc_unit+1); + return ESP_FAIL; + } + + //Check sampling frequency + if((sampling_freq_hz < SOC_ADC_SAMPLE_FREQ_THRES_LOW) || (sampling_freq_hz > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)){ + log_e("Sampling frequency is out of range. Supported sampling frequencies are %d - %d", SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); + return ESP_FAIL; + } + + //Set periman deinit function and reset all pins to init state. + perimanSetBusDeinit(ESP32_BUS_TYPE_ADC_CONT, adcContinuousDetachBus); + for(int j = 0; j < pins_count; j++){ + if(!perimanSetPinBus(pins[j], ESP32_BUS_TYPE_INIT, NULL)){ + return ESP_FAIL; + } + } + + //Set conversion frame and buffer size (conversion frame must be in multiples of SOC_ADC_DIGI_DATA_BYTES_PER_CONV) + adc_handle[adc_unit].conversion_frame_size = conversions_per_pin * pins_count * SOC_ADC_DIGI_RESULT_BYTES; + +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + uint8_t calc_multiple = adc_handle[adc_unit].conversion_frame_size % SOC_ADC_DIGI_DATA_BYTES_PER_CONV; + if(calc_multiple != 0){ + adc_handle[adc_unit].conversion_frame_size = (adc_handle[adc_unit].conversion_frame_size + calc_multiple); + } +#endif + + adc_handle[adc_unit].buffer_size = adc_handle[adc_unit].conversion_frame_size; + + //Initialize continuous handle and pins + err = __analogContinuousInit(channel, sizeof(channel) / sizeof(adc_channel_t), adc_unit, sampling_freq_hz); + if(err != ESP_OK){ + log_e("Analog initialization failed!"); + return ESP_FAIL; + } + + //Setup callbacks for complete event + adc_continuous_evt_cbs_t cbs = { + .on_conv_done = adcFnWrapper, + }; + adc_handle[adc_unit].adc_interrupt_handle.fn = (voidFuncPtr)userFunc; + err = adc_continuous_register_event_callbacks(adc_handle[adc_unit].adc_continuous_handle, &cbs, &adc_handle[adc_unit].adc_interrupt_handle); + if(err != ESP_OK){ + log_e("adc_continuous_register_event_callbacks failed!"); + return ESP_FAIL; + } + + //Allocate and prepare result structure for adc readings + adc_result = malloc(pins_count * sizeof(adc_continuos_data_t)); + for(int k = 0; k < pins_count; k++){ + adc_result[k].pin = pins[k]; + adc_result[k].channel = channel[k]; + } + + //Initialize ADC calibration handle + if(adc_handle[adc_unit].adc_cali_handle == NULL){ + log_d("Creating cali handle for ADC_%d", adc_unit); + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = adc_unit, + .atten = __adcContinuousAtten, + .bitwidth = __adcContinuousWidth, + }; + err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + adc_cali_line_fitting_config_t cali_config = { + .unit_id = adc_unit, + .bitwidth = __adcContinuousWidth, + .atten = __adcContinuousAtten, + }; + err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + #endif + if(err != ESP_OK){ + log_e("adc_cali_create_scheme_x failed!"); + return ESP_FAIL; + } + } + + for(int k = 0; k < pins_count; k++){ + if(!perimanSetPinBus(pins[k], ESP32_BUS_TYPE_ADC_CONT, (void *)(adc_unit+1))){ + log_e("perimanSetPinBus to ADC Continuous failed!"); + adcContinuousDetachBus((void *)(adc_unit+1)); + return ESP_FAIL; + } + } + + return ESP_OK; +} + +bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + uint32_t bytes_read = 0; + uint32_t read_raw[used_adc_channels]; + uint8_t adc_read[adc_handle[ADC_UNIT_1].conversion_frame_size]; + memset(adc_read, 0xcc, sizeof(adc_read)); + memset(read_raw, 0, sizeof(read_raw)); + + esp_err_t err = adc_continuous_read(adc_handle[ADC_UNIT_1].adc_continuous_handle, adc_read, adc_handle[0].conversion_frame_size, &bytes_read, timeout_ms); + if(err != ESP_OK){ + if(err == ESP_ERR_TIMEOUT){ + log_e("Reading data failed: No data, increase timeout"); + } + else { + log_e("Reading data failed with error: %X", err); + } + return ESP_FAIL; + } + + for (int i = 0; i < bytes_read; i += SOC_ADC_DIGI_RESULT_BYTES) { + adc_digi_output_data_t *p = (adc_digi_output_data_t*)&adc_read[i]; + uint32_t chan_num = ADC_GET_CHANNEL(p); + uint32_t data = ADC_GET_DATA(p); + + /* Check the channel number validation, the data is invalid if the channel num exceed the maximum channel */ + if(chan_num >= SOC_ADC_CHANNEL_NUM(0)){ + log_e("Invalid data [%d_%d]", chan_num, data); + return ESP_FAIL; + } + if(data >= (1 << SOC_ADC_DIGI_MAX_BITWIDTH)) + { + data = 0; + log_e("Invalid data"); + } + + for(int j = 0; j < used_adc_channels; j++){ + if(adc_result[j].channel == chan_num){ + read_raw[j] += data; + //log_d("Pin: %d, Channel: %d, Value: %d", adc_result[j].pin, chan_num, data); + break; + } + } + } + + for (int j = 0; j < used_adc_channels; j++){ + //log_d("Pin: %d, read_raw[]: %d, bytes_read: %d, used_adc_channels: %d" , adc_result[j].pin, read_raw[j], bytes_read, used_adc_channels); + adc_result[j].avg_read_raw = read_raw[j] / (bytes_read / (SOC_ADC_DIGI_RESULT_BYTES * used_adc_channels)); + adc_cali_raw_to_voltage(adc_handle[ADC_UNIT_1].adc_cali_handle, adc_result[j].avg_read_raw, &adc_result[j].avg_read_mvolts); + } + + *buffer = adc_result; + return ESP_OK; + + } + else { + log_e("ADC Continuous is not initialized!"); + return ESP_FAIL; + } +} + +bool analogContinuousStart(){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + if(adc_continuous_start(adc_handle[ADC_UNIT_1].adc_continuous_handle) == ESP_OK){ + return ESP_OK; + } + } else { + log_e("ADC Continuous is not initialized!"); + } + return ESP_FAIL; +} + +bool analogContinuousStop(){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + if(adc_continuous_stop(adc_handle[ADC_UNIT_1].adc_continuous_handle) == ESP_OK){ + return ESP_OK; + } + } else { + log_e("ADC Continuous is not initialized!"); + } + return ESP_FAIL; +} + +bool analogContinuousDeinit(){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + esp_err_t err = adc_continuous_deinit(adc_handle[ADC_UNIT_1].adc_continuous_handle); + if (err != ESP_OK){ + return ESP_FAIL; + } + free(adc_result); + adc_handle[ADC_UNIT_1].adc_continuous_handle = NULL; + } else { + log_i("ADC Continuous was not initialized"); + } + return ESP_OK; +} + +void analogContinuousSetAtten(adc_attenuation_t attenuation){ + __adcContinuousAtten = attenuation; +} + +void analogContinuousSetWidth(uint8_t bits){ + if ((bits < SOC_ADC_DIGI_MIN_BITWIDTH) && (bits > SOC_ADC_DIGI_MAX_BITWIDTH)){ + log_e("Selected width cannot be set. Range is from %d to %d", SOC_ADC_DIGI_MIN_BITWIDTH, SOC_ADC_DIGI_MAX_BITWIDTH); + return; + } + __adcContinuousWidth = bits; +} + #endif diff --git a/cores/esp32/esp32-hal-adc.h b/cores/esp32/esp32-hal-adc.h index f25e1abce41..0cc212828ef 100644 --- a/cores/esp32/esp32-hal-adc.h +++ b/cores/esp32/esp32-hal-adc.h @@ -77,6 +77,56 @@ void analogSetWidth(uint8_t bits); #endif +/* + * Analog Continuous mode + * */ + +typedef struct { + uint8_t pin; /*! Date: Thu, 10 Aug 2023 10:40:34 +0200 Subject: [PATCH 02/14] fix when stopping/starting ADC data are not complete --- cores/esp32/esp32-hal-adc.c | 39 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index b357b6d6004..28d186b9abe 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -399,11 +399,14 @@ static bool adcContinuousDetachBus(void * adc_unit_number){ bool IRAM_ATTR adcFnWrapper(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *args){ interrupt_config_t * isr = (interrupt_config_t*)args; - if(isr->fn) { - if(isr->arg){ - ((voidFuncPtrArg)isr->fn)(isr->arg); - } else { - isr->fn(); + //Check if edata->size matches conversion_frame_size, else just return from ISR + if(edata->size == adc_handle[0].conversion_frame_size){ + if(isr->fn) { + if(isr->arg){ + ((voidFuncPtrArg)isr->fn)(isr->arg); + } else { + isr->fn(); + } } } return false; @@ -428,7 +431,6 @@ esp_err_t __analogContinuousInit(adc_channel_t *channel, uint8_t channel_num, ad .conv_mode = ADC_CONV_SINGLE_UNIT_1, .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++) { @@ -502,7 +504,13 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe } #endif - adc_handle[adc_unit].buffer_size = adc_handle[adc_unit].conversion_frame_size; + adc_handle[adc_unit].buffer_size = adc_handle[adc_unit].conversion_frame_size * 2; + + //Conversion frame size buffer cant be bigger than 4092 bytes + if(adc_handle[adc_unit].conversion_frame_size < 4092){ + log_e("Buffers are too big. Please set lower conversions per pin."); + return ESP_FAIL; + } //Initialize continuous handle and pins err = __analogContinuousInit(channel, sizeof(channel) / sizeof(adc_channel_t), adc_unit, sampling_freq_hz); @@ -514,6 +522,7 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe //Setup callbacks for complete event adc_continuous_evt_cbs_t cbs = { .on_conv_done = adcFnWrapper, + //.on_pool_ovf can be used in future }; adc_handle[adc_unit].adc_interrupt_handle.fn = (voidFuncPtr)userFunc; err = adc_continuous_register_event_callbacks(adc_handle[adc_unit].adc_continuous_handle, &cbs, &adc_handle[adc_unit].adc_interrupt_handle); @@ -568,9 +577,11 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ uint32_t bytes_read = 0; uint32_t read_raw[used_adc_channels]; + uint32_t read_count[used_adc_channels]; uint8_t adc_read[adc_handle[ADC_UNIT_1].conversion_frame_size]; memset(adc_read, 0xcc, sizeof(adc_read)); memset(read_raw, 0, sizeof(read_raw)); + memset(read_count, 0, sizeof(read_count)); esp_err_t err = adc_continuous_read(adc_handle[ADC_UNIT_1].adc_continuous_handle, adc_read, adc_handle[0].conversion_frame_size, &bytes_read, timeout_ms); if(err != ESP_OK){ @@ -602,16 +613,20 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ for(int j = 0; j < used_adc_channels; j++){ if(adc_result[j].channel == chan_num){ read_raw[j] += data; - //log_d("Pin: %d, Channel: %d, Value: %d", adc_result[j].pin, chan_num, data); + read_count[j] += 1; break; } } } for (int j = 0; j < used_adc_channels; j++){ - //log_d("Pin: %d, read_raw[]: %d, bytes_read: %d, used_adc_channels: %d" , adc_result[j].pin, read_raw[j], bytes_read, used_adc_channels); - adc_result[j].avg_read_raw = read_raw[j] / (bytes_read / (SOC_ADC_DIGI_RESULT_BYTES * used_adc_channels)); - adc_cali_raw_to_voltage(adc_handle[ADC_UNIT_1].adc_cali_handle, adc_result[j].avg_read_raw, &adc_result[j].avg_read_mvolts); + if (read_count[j] != 0){ + adc_result[j].avg_read_raw = read_raw[j] / read_count[j]; + adc_cali_raw_to_voltage(adc_handle[ADC_UNIT_1].adc_cali_handle, adc_result[j].avg_read_raw, &adc_result[j].avg_read_mvolts); + } + else { + log_w("No data read for pin %d", adc_result[j].pin); + } } *buffer = adc_result; From 8f3292531563e5be5627a8341872166df271e184 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 10 Aug 2023 13:44:34 +0200 Subject: [PATCH 03/14] Added example --- cores/esp32/esp32-hal-adc.h | 2 +- .../AnalogReadContinuous.ino | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino diff --git a/cores/esp32/esp32-hal-adc.h b/cores/esp32/esp32-hal-adc.h index 0cc212828ef..41122b2d4bb 100644 --- a/cores/esp32/esp32-hal-adc.h +++ b/cores/esp32/esp32-hal-adc.h @@ -94,7 +94,7 @@ typedef struct { bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_per_pin, uint32_t sampling_freq_hz, void (*userFunc)(void)); /* - * Get ADC continuous readings + * Read ADC continuous conversion data * */ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms); diff --git a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino new file mode 100644 index 00000000000..faedd10f454 --- /dev/null +++ b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino @@ -0,0 +1,71 @@ +// Define how many conversion per pin will happen and reading the data will be and average of all conversions +#define CONVERSIONS_PER_PIN 5 + +// Declare array of ADC pins that will be used for ADC Continuous mode - ONLY ADC1 pins are supported +// Number of selected pins can be from 1 to ALL ADC1 pins. +#ifdef CONFIG_IDF_TARGET_ESP32 +uint8_t adc_pins[] = {36, 39, 34, 35}; //some of ADC1 pins for ESP32 +#else +uint8_t adc_pins[] = {1, 2, 3, 4}; //ADC1 common pins for ESP32S2/S3 + ESP32C3/C6 + ESP32H2 +#endif + +// Calculate how many pins are declared in the array - needed as input for the setup function of ADC Continuous +uint8_t adc_pins_count = sizeof(adc_pins) / sizeof(uint8_t); + +// Flag which will be set in ISR when conversion is done +volatile bool adc_coversion_done = false; + +// Result structure for ADC Continuous reading +adc_continuos_data_t * result = NULL; + +// ISR Function that will be triggered when ADC conversion is done +void ARDUINO_ISR_ATTR adcComplete() { + adc_coversion_done = true; +} + +void setup() { + // Initialize serial communication at 115200 bits per second: + Serial.begin(115200); + + // Optional for ESP32: Set the resolution to 9-12 bits (default is 12 bits) + analogContinuousSetWidth(12); + + // Optional: Set different attenaution (default is ADC_11db) + analogContinuousSetAtten(ADC_11db); + + // Setup ADC Continuous with following input: + // array of pins, count of the pins, how many conversions per pin in one cycle will happen, sampling frequency, callback function + analogContinuous(adc_pins, adc_pins_count, CONVERSIONS_PER_PIN, 83000, &adcComplete); + + // Start ADC Continuous conversions + analogContinuousStart(); +} + +void loop() { + // Check if conversion is done and try to read data + if (adc_coversion_done == true) { + adc_coversion_done = false; + + // Read data from ADC + if (!analogContinuousRead(&result, 0)) { + + // Optional: Stop ADC Continuous conversions and process the data + analogContinuousStop(); + + for (int i = 0; i < adc_pins_count; i++) { + Serial.printf("\nADC PIN %d data:", result[i].pin); + Serial.printf("\n Avg raw value = %d", result[i].avg_read_raw); + Serial.printf("\n Avg milivolts value = %d", result[i].avg_read_mvolts); + } + } + else { + Serial.println("Error occured during reading data. Set Core Debug Level to error or lower for more informations.");s + } + + // Delay for better readability of ADC data + delay(1000); + + // Optional: Start ADC conversions and wait for callback function to set adc_coversion_done to true + analogContinuousStart(); + } +} \ No newline at end of file From 0df34bf9e7b42a0334ccc755c074785789c07ee6 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 10 Aug 2023 13:48:41 +0200 Subject: [PATCH 04/14] fix size check --- cores/esp32/esp32-hal-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index 28d186b9abe..1e44f2538ad 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -507,7 +507,7 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe adc_handle[adc_unit].buffer_size = adc_handle[adc_unit].conversion_frame_size * 2; //Conversion frame size buffer cant be bigger than 4092 bytes - if(adc_handle[adc_unit].conversion_frame_size < 4092){ + if(adc_handle[adc_unit].conversion_frame_size > 4092){ log_e("Buffers are too big. Please set lower conversions per pin."); return ESP_FAIL; } From 15987b0c16a48001842c6b3000fc76b07fc7f11a Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 10 Aug 2023 13:59:36 +0200 Subject: [PATCH 05/14] update frequency in example --- .../examples/AnalogReadContinuous/AnalogReadContinuous.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino index faedd10f454..fb436785597 100644 --- a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino +++ b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino @@ -35,7 +35,7 @@ void setup() { // Setup ADC Continuous with following input: // array of pins, count of the pins, how many conversions per pin in one cycle will happen, sampling frequency, callback function - analogContinuous(adc_pins, adc_pins_count, CONVERSIONS_PER_PIN, 83000, &adcComplete); + analogContinuous(adc_pins, adc_pins_count, CONVERSIONS_PER_PIN, 20000, &adcComplete); // Start ADC Continuous conversions analogContinuousStart(); From 390e8028026911c2dc44ee64d48bb2cd8b0d2a45 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:08:15 +0200 Subject: [PATCH 06/14] set buffer to NULL if error occurs --- cores/esp32/esp32-hal-adc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index 1e44f2538ad..cf221d47248 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -591,6 +591,7 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ else { log_e("Reading data failed with error: %X", err); } + *buffer == NULL; return ESP_FAIL; } @@ -602,6 +603,7 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ /* Check the channel number validation, the data is invalid if the channel num exceed the maximum channel */ if(chan_num >= SOC_ADC_CHANNEL_NUM(0)){ log_e("Invalid data [%d_%d]", chan_num, data); + *buffer == NULL; return ESP_FAIL; } if(data >= (1 << SOC_ADC_DIGI_MAX_BITWIDTH)) From 428661ed1bdb30d6e22998e3287f19b7b621836d Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:25:56 +0200 Subject: [PATCH 07/14] add docs --- docs/source/api/adc.rst | 141 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 7 deletions(-) diff --git a/docs/source/api/adc.rst b/docs/source/api/adc.rst index c50104fabad..1aca9a689f4 100644 --- a/docs/source/api/adc.rst +++ b/docs/source/api/adc.rst @@ -16,8 +16,8 @@ ADCs are very useful in control and monitoring applications since most sensors Arduino-ESP32 ADC API --------------------- -ADC common API -************** +ADC OneShot mode +**************** analogRead ^^^^^^^^^^ @@ -135,13 +135,12 @@ This function is used to set the attenuation for a specific pin/ADC channel. For * ``pin`` selects specific pin for attenuation settings. * ``attenuation`` sets the attenuation. - -ADC API specific for ESP32 chip -******************************* analogSetWidth ^^^^^^^^^^^^^^ +.. note:: This function is only available for ESP32 chip. + This function is used to set the hardware sample bits and read resolution. Default is 12bit (0 - 4095). Range is 9 - 12. @@ -149,13 +148,141 @@ Range is 9 - 12. .. code-block:: arduino void analogSetWidth(uint8_t bits); + +ADC Continuous mode +******************* + +analogContinuous +^^^^^^^^^^^^^^^^ + +This function is used to configure ADC continuous peripheral on selected pins. + +.. code-block:: arduino + + bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_per_pin, uint32_t sampling_freq_hz, void (*userFunc)(void)); + +* ``pins[]`` array of pins to be set up +* ``pins_count`` count of pins in array +* ``conversions_per_pin`` sets how many conversions per pin will run each ADC cycle +* ``sampling_freq_hz`` sets sampling frequency of ADC in Hz +* ``userFunc`` sets callback function to be called after adc conversion is done (can be set to ``NULL``) + +This function will return ``true`` if configuration is successful. +If ``false`` is returned, error occurs and ADC continuous was not configured. + +analogContinuous +^^^^^^^^^^^^^^^^ + +This function is used to set up ADC continuous mode on selected pins. + +.. code-block:: arduino + + bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_per_pin, uint32_t sampling_freq_hz, void (*userFunc)(void)); + +* ``pins[]`` array of pins to be set up +* ``pins_count`` count of pins in array +* ``conversions_per_pin`` sets how many conversions per pin will run each ADC cycle +* ``sampling_freq_hz`` sets sampling frequency of ADC in Hz +* ``userFunc`` sets callback function to be called after adc conversion is done (can be set to ``NULL``) + +This function will return ``true`` if configuration is successful. +If ``false`` is returned, error occurs and ADC continuous was not configured. + +analogContinuousRead +^^^^^^^^^^^^^^^^^^^^ + +This function is used to read ADC continuous data to the result buffer. The result buffer is an array of adc_continuos_data_t. + +.. code-block:: arduino + + typedef struct { + uint8_t pin; /*! AnalogReadSerial. .. literalinclude:: ../../../libraries/ESP32/examples/AnalogRead/AnalogRead.ino :language: arduino -Or you can run Arduino example 01.Basics -> AnalogReadSerial. +Here is an example of how to use the ADC in Continuous mode. + +.. literalinclude:: ../../../libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino + :language: arduino From 622c2617bf2b42cb63630738ee121d4b300814ba Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:26:56 +0200 Subject: [PATCH 08/14] set buffer to null on error --- cores/esp32/esp32-hal-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index cf221d47248..e2620783ade 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -591,7 +591,7 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ else { log_e("Reading data failed with error: %X", err); } - *buffer == NULL; + *buffer = NULL; return ESP_FAIL; } @@ -603,7 +603,7 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ /* Check the channel number validation, the data is invalid if the channel num exceed the maximum channel */ if(chan_num >= SOC_ADC_CHANNEL_NUM(0)){ log_e("Invalid data [%d_%d]", chan_num, data); - *buffer == NULL; + *buffer = NULL; return ESP_FAIL; } if(data >= (1 << SOC_ADC_DIGI_MAX_BITWIDTH)) From 30c3345a67d2d08c370635b44491d1a17623a26a Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:30:58 +0200 Subject: [PATCH 09/14] fix example --- .../examples/AnalogReadContinuous/AnalogReadContinuous.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino index fb436785597..31dc8f32ee6 100644 --- a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino +++ b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino @@ -59,7 +59,7 @@ void loop() { } } else { - Serial.println("Error occured during reading data. Set Core Debug Level to error or lower for more informations.");s + Serial.println("Error occured during reading data. Set Core Debug Level to error or lower for more informations."); } // Delay for better readability of ADC data From cd90e17d542709fe1dc62681b28d087c96b6cc7e Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:01:01 +0200 Subject: [PATCH 10/14] update docs --- docs/source/api/adc.rst | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/docs/source/api/adc.rst b/docs/source/api/adc.rst index 1aca9a689f4..f58db8f40ef 100644 --- a/docs/source/api/adc.rst +++ b/docs/source/api/adc.rst @@ -11,7 +11,7 @@ to a digital form so that it can be read and processed by a microcontroller. ADCs are very useful in control and monitoring applications since most sensors (e.g., temperature, pressure, force) produce analogue output voltages. -.. note:: Each SoC or module has a different number of ADC's with a different number of channels and pins availible. Refer to datasheet of each board for more info. +.. note:: Each SoC or module has a different number of ADC's with a different number of channels and pins available. Refer to datasheet of each board for more info. Arduino-ESP32 ADC API --------------------- @@ -19,6 +19,8 @@ Arduino-ESP32 ADC API ADC OneShot mode **************** +ADC OneShot mode API is fully compatible with the Arduino's ``analogRead``. When you call ``analogRead`` or ``analogReadMillivolts`` funtion will return a result of a single conversion on requested pin. + analogRead ^^^^^^^^^^ @@ -82,7 +84,7 @@ The measurable input voltage differs for each chip, see table below for detailed ``ADC_ATTEN_DB_0`` 100 mV ~ 950 mV ``ADC_ATTEN_DB_2_5`` 100 mV ~ 1250 mV ``ADC_ATTEN_DB_6`` 150 mV ~ 1750 mV - ``ADC_ATTEN_DB_11`` 150 mV ~ 2450 mV + ``ADC_ATTEN_DB_11`` 150 mV ~ 3100 mV ===================== =========================================== .. tab:: ESP32-S2 @@ -152,28 +154,14 @@ Range is 9 - 12. ADC Continuous mode ******************* -analogContinuous -^^^^^^^^^^^^^^^^ - -This function is used to configure ADC continuous peripheral on selected pins. - -.. code-block:: arduino - - bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_per_pin, uint32_t sampling_freq_hz, void (*userFunc)(void)); - -* ``pins[]`` array of pins to be set up -* ``pins_count`` count of pins in array -* ``conversions_per_pin`` sets how many conversions per pin will run each ADC cycle -* ``sampling_freq_hz`` sets sampling frequency of ADC in Hz -* ``userFunc`` sets callback function to be called after adc conversion is done (can be set to ``NULL``) - -This function will return ``true`` if configuration is successful. -If ``false`` is returned, error occurs and ADC continuous was not configured. +ADC Continuous mode is a new API for doing analog conversions on multiple pins in background and get a callback when those conversions are done to read the results. +You can specify how many conversions per pin will be done in only cycle and it's sampling rate. The result from ``analogContinuousRead`` is an array of ``adc_continuos_data_t`` +structure which hold raw average value and average value in milivolts for each pin. analogContinuous ^^^^^^^^^^^^^^^^ -This function is used to set up ADC continuous mode on selected pins. +This function is used to configure ADC continuous peripheral on selected pins. .. code-block:: arduino @@ -191,7 +179,7 @@ If ``false`` is returned, error occurs and ADC continuous was not configured. analogContinuousRead ^^^^^^^^^^^^^^^^^^^^ -This function is used to read ADC continuous data to the result buffer. The result buffer is an array of adc_continuos_data_t. +This function is used to read ADC continuous data to the result buffer. The result buffer is an array of ``adc_continuos_data_t``. .. code-block:: arduino From 799054e76f2250742c60dfe08f549aeaf55623d2 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Mon, 14 Aug 2023 13:04:18 +0200 Subject: [PATCH 11/14] fix example --- .../AnalogReadContinuous.ino | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino index 31dc8f32ee6..ce989e2420f 100644 --- a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino +++ b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino @@ -44,28 +44,28 @@ void setup() { void loop() { // Check if conversion is done and try to read data if (adc_coversion_done == true) { - adc_coversion_done = false; + // Set ISR flag back to false + adc_coversion_done = false; + // Read data from ADC + if (analogContinuousRead(&result, 0)) { - // Read data from ADC - if (!analogContinuousRead(&result, 0)) { + // Optional: Stop ADC Continuous conversions to have more time to process (print) the data + analogContinuousStop(); - // Optional: Stop ADC Continuous conversions and process the data - analogContinuousStop(); + for (int i = 0; i < adc_pins_count; i++) { + Serial.printf("\nADC PIN %d data:", result[i].pin); + Serial.printf("\n Avg raw value = %d", result[i].avg_read_raw); + Serial.printf("\n Avg milivolts value = %d", result[i].avg_read_mvolts); + } - for (int i = 0; i < adc_pins_count; i++) { - Serial.printf("\nADC PIN %d data:", result[i].pin); - Serial.printf("\n Avg raw value = %d", result[i].avg_read_raw); - Serial.printf("\n Avg milivolts value = %d", result[i].avg_read_mvolts); - } - } - else { - Serial.println("Error occured during reading data. Set Core Debug Level to error or lower for more informations."); - } - - // Delay for better readability of ADC data - delay(1000); + // Delay for better readability of ADC data + delay(1000); - // Optional: Start ADC conversions and wait for callback function to set adc_coversion_done to true - analogContinuousStart(); + // Optional: If ADC was stopped, start ADC conversions and wait for callback function to set adc_coversion_done flag to true + analogContinuousStart(); + } + else { + Serial.println("Error occured during reading data. Set Core Debug Level to error or lower for more informations."); + } } } \ No newline at end of file From 554b09940c05ade8d048c74adedc6eaff41a85fc Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Mon, 14 Aug 2023 13:29:06 +0200 Subject: [PATCH 12/14] change return value to bool type --- cores/esp32/esp32-hal-adc.c | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/cores/esp32/esp32-hal-adc.c b/cores/esp32/esp32-hal-adc.c index e2620783ade..4278b2d1a78 100644 --- a/cores/esp32/esp32-hal-adc.c +++ b/cores/esp32/esp32-hal-adc.c @@ -462,35 +462,35 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe err = adc_continuous_io_to_channel(pins[i], &adc_unit, &channel[i]); if(err != ESP_OK){ log_e("Pin %u is not ADC pin!", pins[i]); - return ESP_FAIL; + return false; } if(adc_unit != 0){ log_e("Only ADC1 pins are supported in continuous mode!"); - return ESP_FAIL; + return false; } } //Check if Oneshot and Continous handle exists if(adc_handle[adc_unit].adc_oneshot_handle != NULL){ log_e("ADC%d is running in oneshot mode. Aborting.", adc_unit+1); - return ESP_FAIL; + return false; } if(adc_handle[adc_unit].adc_continuous_handle != NULL){ log_e("ADC%d continuous is already initialized. To reconfigure call analogContinuousDeinit() first.", adc_unit+1); - return ESP_FAIL; + return false; } //Check sampling frequency if((sampling_freq_hz < SOC_ADC_SAMPLE_FREQ_THRES_LOW) || (sampling_freq_hz > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)){ log_e("Sampling frequency is out of range. Supported sampling frequencies are %d - %d", SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); - return ESP_FAIL; + return false; } //Set periman deinit function and reset all pins to init state. perimanSetBusDeinit(ESP32_BUS_TYPE_ADC_CONT, adcContinuousDetachBus); for(int j = 0; j < pins_count; j++){ if(!perimanSetPinBus(pins[j], ESP32_BUS_TYPE_INIT, NULL)){ - return ESP_FAIL; + return false; } } @@ -509,14 +509,14 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe //Conversion frame size buffer cant be bigger than 4092 bytes if(adc_handle[adc_unit].conversion_frame_size > 4092){ log_e("Buffers are too big. Please set lower conversions per pin."); - return ESP_FAIL; + return false; } //Initialize continuous handle and pins err = __analogContinuousInit(channel, sizeof(channel) / sizeof(adc_channel_t), adc_unit, sampling_freq_hz); if(err != ESP_OK){ log_e("Analog initialization failed!"); - return ESP_FAIL; + return false; } //Setup callbacks for complete event @@ -528,7 +528,7 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe err = adc_continuous_register_event_callbacks(adc_handle[adc_unit].adc_continuous_handle, &cbs, &adc_handle[adc_unit].adc_interrupt_handle); if(err != ESP_OK){ log_e("adc_continuous_register_event_callbacks failed!"); - return ESP_FAIL; + return false; } //Allocate and prepare result structure for adc readings @@ -558,7 +558,7 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe #endif if(err != ESP_OK){ log_e("adc_cali_create_scheme_x failed!"); - return ESP_FAIL; + return false; } } @@ -566,11 +566,11 @@ bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_pe if(!perimanSetPinBus(pins[k], ESP32_BUS_TYPE_ADC_CONT, (void *)(adc_unit+1))){ log_e("perimanSetPinBus to ADC Continuous failed!"); adcContinuousDetachBus((void *)(adc_unit+1)); - return ESP_FAIL; + return false; } } - return ESP_OK; + return true; } bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ @@ -592,7 +592,7 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ log_e("Reading data failed with error: %X", err); } *buffer = NULL; - return ESP_FAIL; + return false; } for (int i = 0; i < bytes_read; i += SOC_ADC_DIGI_RESULT_BYTES) { @@ -604,7 +604,7 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ if(chan_num >= SOC_ADC_CHANNEL_NUM(0)){ log_e("Invalid data [%d_%d]", chan_num, data); *buffer = NULL; - return ESP_FAIL; + return false; } if(data >= (1 << SOC_ADC_DIGI_MAX_BITWIDTH)) { @@ -632,49 +632,49 @@ bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ } *buffer = adc_result; - return ESP_OK; + return true; } else { log_e("ADC Continuous is not initialized!"); - return ESP_FAIL; + return false; } } bool analogContinuousStart(){ if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ if(adc_continuous_start(adc_handle[ADC_UNIT_1].adc_continuous_handle) == ESP_OK){ - return ESP_OK; + return true; } } else { log_e("ADC Continuous is not initialized!"); } - return ESP_FAIL; + return false; } bool analogContinuousStop(){ if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ if(adc_continuous_stop(adc_handle[ADC_UNIT_1].adc_continuous_handle) == ESP_OK){ - return ESP_OK; + return true; } } else { log_e("ADC Continuous is not initialized!"); } - return ESP_FAIL; + return false; } bool analogContinuousDeinit(){ if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ esp_err_t err = adc_continuous_deinit(adc_handle[ADC_UNIT_1].adc_continuous_handle); if (err != ESP_OK){ - return ESP_FAIL; + return false; } free(adc_result); adc_handle[ADC_UNIT_1].adc_continuous_handle = NULL; } else { log_i("ADC Continuous was not initialized"); } - return ESP_OK; + return true; } void analogContinuousSetAtten(adc_attenuation_t attenuation){ From dd412392bc5cc30a87f978a849a03c869d783e56 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Tue, 15 Aug 2023 13:38:09 +0200 Subject: [PATCH 13/14] updated adc modes description in docs --- docs/source/api/adc.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/source/api/adc.rst b/docs/source/api/adc.rst index f58db8f40ef..8ab252e181b 100644 --- a/docs/source/api/adc.rst +++ b/docs/source/api/adc.rst @@ -19,7 +19,9 @@ Arduino-ESP32 ADC API ADC OneShot mode **************** -ADC OneShot mode API is fully compatible with the Arduino's ``analogRead``. When you call ``analogRead`` or ``analogReadMillivolts`` funtion will return a result of a single conversion on requested pin. + +The ADC OneShot mode API is fully compatible with Arduino's ``analogRead`` function. +When you call the ``analogRead`` or ``analogReadMillivolts`` function, it returns the result of a single conversion on the requested pin. analogRead ^^^^^^^^^^ @@ -154,9 +156,12 @@ Range is 9 - 12. ADC Continuous mode ******************* -ADC Continuous mode is a new API for doing analog conversions on multiple pins in background and get a callback when those conversions are done to read the results. -You can specify how many conversions per pin will be done in only cycle and it's sampling rate. The result from ``analogContinuousRead`` is an array of ``adc_continuos_data_t`` -structure which hold raw average value and average value in milivolts for each pin. +ADC Continuous mode is an API designed for performing analog conversions on multiple pins in the background, +with the feature of receiving a callback upon completion of these conversions to access the results. + +This API allows you to specify the desired number of conversions per pin within a single cycle, along with its corresponding sampling rate. +The outcome of the ``analogContinuousRead`` function is an array of ``adc_continuous_data_t`` structures. +These structures hold both the raw average value and the average value in millivolts for each pin. analogContinuous ^^^^^^^^^^^^^^^^ From 03e5c53b8bbfeeaaf1ae1bf2eba64e144ffd83b4 Mon Sep 17 00:00:00 2001 From: Jan Prochazka <90197375+P-R-O-C-H-Y@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:42:06 +0200 Subject: [PATCH 14/14] Add empty line at the end of sketch --- .../examples/AnalogReadContinuous/AnalogReadContinuous.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino index ce989e2420f..c0928318fb6 100644 --- a/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino +++ b/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino @@ -68,4 +68,4 @@ void loop() { Serial.println("Error occured during reading data. Set Core Debug Level to error or lower for more informations."); } } -} \ No newline at end of file +}