ADC Oneshot Read Example

[中文]

Note

This document is automatically translated using AI. Please excuse any detailed errors. The official English version is still in progress.

Example Description

This example demonstrates how to initialize, configure, calibrate ADC, and how to use ADC to sample analog input signals in oneshot mode and process them. For instructions on ADC continuous conversion mode, refer to Analog-to-Digital Converter (ADC) Oneshot Conversion Mode Driver.

Running Method

The complete code of the example can be found at ADC Oneshot Read Example. For configuration instructions, build and burn process before running, refer to the README.md file in the adc directory.

For custom configuration items and default values, refer to the Global Variables/Macro Definitions Description section.

Header File Description

The header files used in this example cover FreeRTOS task management, common system tools, and ADC driver and other basic modules. They provide support for task creation, ADC initialization, sampling, and calibration.

The header files are categorized by function as follows:

  1. FreeRTOS Task Scheduling: Provides task management functions for creating and managing tasks.

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
  1. System Tools: Provides support for input and output, string processing, memory management, logging, and fixed-length integer types.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_log.h"
  1. ADC Driver and Calibration: Provides functions for ADC oneshot sampling mode initialization, channel configuration, raw sampling reading, software calibration, and voltage conversion.

#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "soc/soc_caps.h"

Global Variables/Macro Definitions Description

The macro definitions involved in this example are mainly used to define GPIO input and output pins and interrupt flags.

The macro definitions are categorized by function as follows:

  1. ADC1 Channel Selection

  • Different ADC1 channels are selected according to the chip model. ESP32 chips use channels 4 and 5, while other models use channels 2 and 3.

#if CONFIG_IDF_TARGET_ESP32
#define EXAMPLE_ADC1_CHAN0          ADC_CHANNEL_4
#define EXAMPLE_ADC1_CHAN1          ADC_CHANNEL_5
#else
#define EXAMPLE_ADC1_CHAN0          ADC_CHANNEL_2
#define EXAMPLE_ADC1_CHAN1          ADC_CHANNEL_3
#endif
  1. ADC2 Channel Selection:

  • Determine whether the chip supports the second ADC peripheral (ADC2). If ADC2 is supported, enable EXAMPLE_USE_ADC2.

#if (SOC_ADC_PERIPH_NUM >= 2) && !CONFIG_IDF_TARGET_ESP32C3
#define EXAMPLE_USE_ADC2            1
#endif

Note

The ESP32-C3 chip does not support ADC2 due to hardware limitations.

  • Determine whether EXAMPLE_USE_ADC2 is enabled. If it is, specify channel 0 for ADC2.

#if EXAMPLE_USE_ADC2
#if CONFIG_IDF_TARGET_ESP32
#define EXAMPLE_ADC2_CHAN0          ADC_CHANNEL_0
#else
#define EXAMPLE_ADC2_CHAN0          ADC_CHANNEL_0
#endif
#endif
  1. ADC Attenuation Setting: The attenuation configuration determines the measurable voltage range and linear accuracy of the ADC. Different attenuation levels correspond to different effective voltage measurement ranges. For specific levels, refer to ADC Driver. The correspondence between each attenuation level and the effective input voltage measurement range of the ADC can be found in the Datasheet > ADC Characteristics.

  • Set the attenuation of the ADC channel to 12 dB to expand the measurable voltage range.

#define EXAMPLE_ADC_ATTEN           ADC_ATTEN_DB_12
  1. Define global variables to save data:

  • Define the variable adc_raw[][] to store the original ADC sampling results. The first dimension of the two-dimensional array represents the channel number, and this example supports up to 2 channels; the second dimension represents the number of continuous sampling data points for each channel, which is 10 in this example.

  • Define the variable voltage[][] to store the results of converting the original sampling values into voltages. The array structure corresponds to adc_raw, that is, the elements of adc_raw and voltage at the same index position represent the correspondence between the original value and the voltage value of the same sampling.

Task Function Description

Before using ADC to collect analog input signals, it is necessary to calibrate the peripherals to correct sampling errors. Calibration can improve measurement accuracy, convert raw data into actual voltage values, adapt to different hardware conditions, and enhance the reliability of the overall application.

This example provides two related task functions: one for performing software calibration and generating a calibration handle, and the other for deregistering the created calibration scheme and releasing related resources.

Perform Software Calibration

example_adc_calibration_init() is the ADC calibration initialization function, which is used to specify the calibration configuration of the ADC unit and channel, and create the corresponding calibration handle.

Parameter Explanation

Input Parameter

Parameter Function

Parameter Description

unit

Specifies the ADC unit to be calibrated

For example, ADC_UNIT_1 or ADC_UNIT_2, determines the ADC peripheral to be calibrated.

channel

Specifies the ADC channel number to be calibrated

Corresponds to the specific channel in the ADC peripheral, used to collect analog input signals.

atten

Sets the attenuation value of the channel

Adjusts the measurable input voltage range.

out_handle

ADC calibration handle

Output parameter, returns the handle of the successfully created calibration scheme, which is used to convert the original sample values into voltage later.

The execution logic of this function is:

  1. Create variables:

  • Create the ADC calibration handle handle and initialize it to NULL.

  • Create the return value variable ret and initialize it to ESP_FAIL for error checking and log output, ensuring that the caller can take different actions based on different return values.

  • Create the flag calibrated and initialize it to false. In this example, it is used to mark whether the calibration has been successfully completed to avoid repeated calibration.

  1. Curve fitting scheme: Execute when the macro ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED is valid and has not been calibrated.

  • Print the current scheme log.

  • Configure the calibration parameters through the structure adc_cali_curve_fitting_config_t. The members of the structure include the ADC unit used, the channel, the attenuation coefficient, and the resolution of the original data output.

  • Call adc_cali_create_scheme_curve_fitting() to create a curve fitting calibration scheme based on the configured structure, and save the return value to the variable ret.

  • When the return value is ESP_OK, modify the flag to true, indicating that the calibration has been completed, and save the generated calibration handle to handle.

  1. Linear fitting scheme: Execute when the macro ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED is valid and has not been calibrated.

  • Print the current scheme log.

  • Configure the calibration parameters through the structure adc_cali_line_fitting_config_t. The members of the structure include the ADC unit used, the attenuation coefficient, and the resolution of the original data output.

  • Call adc_cali_create_scheme_line_fitting() to create a curve fitting calibration scheme based on the configured structure, and save the return value to the variable ret.

  • When the return value is ESP_OK, modify the flag to true, indicating that the calibration has been completed, and save the generated calibration handle to handle.

  1. Output the result and return the status

  • Save the calibration handle generated in the function to the parameter out_handle.

  • Print the corresponding log according to the return value of the fitting scheme (calibration successful, skip calibration, or calibration failed).

  • Return the flag calibrated, which is used to indicate whether the calibration was successful.

Deregister the created calibration scheme

example_adc_calibration_deinit() is used to deregister the created ADC calibration scheme, release related resources, and ensure that the system will not cause memory leaks or occupancy when it no longer uses this calibration handle.

Parameter explanation

Input parameter

Parameter function

Parameter description

handle

Created ADC calibration handle

Used to specify the calibration scheme that needs to be deregistered and release related resources.

The execution logic of this function is:

  1. Deregister the curve fitting scheme: Execute when the macro ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED is valid.

  • Print the log of the current deregistered calibration scheme.

  • Call adc_cali_delete_scheme_curve_fitting() to deregister the specified calibration scheme, and check whether the operation is successful through the return value to ensure correct resource release.

  1. Deregister the linear fitting scheme: Execute when the macro ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED is valid.

  • Print the log of the current deregistered calibration scheme.

  • Call adc_cali_delete_scheme_line_fitting() to deregister the specified calibration scheme, and check whether the operation is successful through the return value to ensure correct resource release.

Main function description

This function demonstrates how to initialize the ADC unit, configure the channel, perform software calibration, and continuously collect ADC raw data and calibrated voltage values.

  1. Initialize ADC1 Peripheral

  2. Configure ADC1 Channel

  3. Calibrate and initialize ADC1:

  • Create an ADC calibration handle adc_cali_handle_t for each channel that needs calibration to save the successfully created calibration scheme instance. It can be initialized to NULL.

  • Call the calibration initialization function example_adc_calibration_init() for each channel to get the corresponding calibration handle, which is used to convert the original ADC value into a voltage value later.

  1. Initialize ADC2 Peripheral: Execute when the macro EXAMPLE_USE_ADC2 is valid.

  2. Configure ADC2 Channel: Execute when the macro EXAMPLE_USE_ADC2 is valid.

  3. Calibrate and initialize ADC2: Execute when the macro EXAMPLE_USE_ADC2 is valid.

  • Create an ADC calibration handle adc_cali_handle_t for each channel that needs calibration to save the successfully created calibration scheme instance. It can be initialized to NULL.

  • Call the calibration initialization function example_adc_calibration_init() for each channel to get the corresponding calibration handle, which is used to convert the original ADC value into a voltage value later.

  1. Loop collection and printing: This step is executed in the data processing loop.

  • Call adc_oneshot_read() to get the original sampling data of ADC1 channel 0 and save it to adc_raw[0][0]. For further introduction and parameter description, please refer to ADC Driver.

  • Print the original sampling data.

  • Judge the current calibration status through the calibration flag bit. If the calibration is successful, call adc_cali_raw_to_voltage() to convert the original sampling data into voltage value, save it to voltage[0][0] and print it. For further introduction and parameter description, please refer to ADC Driver.

  • After a delay of 1 second, repeat the above process to get the original sampling data and voltage value of ADC1 channel 1 and save them to the corresponding array.

  • If the ADC2 channel is enabled, repeat the above process to obtain the original sampling data and voltage value of ADC2 and save it to the corresponding array after a delay of 1 second.

  1. Resource release:

  • At the end or exit of the loop, call adc_oneshot_del_unit() to delete the specified ADC unit. When multiple ADC units are created, this function must be called separately to delete them one by one. For further introduction and parameter description, please refer to ADC driver.

  • Call example_adc_calibration_deinit() to unregister the created calibration scheme, so each channel needs to call the unregister function correspondingly.

Note

In actual applications, the ADC data collection task is usually a long-term or resident task, so this step is generally not executed, but it can be used to prevent potential program exceptions or memory leaks.