9. ADC
9.1 What Is an ADC
ADC stands for Analog-to-Digital Converter. It is a device used to convert analog signals into digital signals. As we know, analog signals are continuous and their values can vary freely within a certain range, such as sound and light signals. Digital signals, on the other hand, are discrete binary signals, like the data 0s and 1s in a computer, and can only take a limited number of values.
The working principle of an ADC is to convert an analog signal into a discrete digital signal by sampling, then process it through quantization and encoding to obtain a corresponding digital representation. The higher the sampling frequency of the ADC, the closer the resulting digital signal is to the original analog signal, that is, the higher the fidelity, but this also requires more resources and computing power.
ADCs are commonly used to read analog signals from external analog sensors and convert them into digital signals for processing by embedded systems or computers, for example, to measure physical quantities such as temperature, humidity, and pressure.
9.2 ADC Introduction of the ESP32S3
The ESP32-S3 integrates two 12-bit SAR ADCs, each with 10 channels, supporting a total of 20 analog channel inputs. It can measure analog signals from up to 20 pins as well as internal signals such as internal voltages. To achieve lower power consumption, the ULP coprocessor of the ESP32-S3 can also measure voltages in sleep mode, and the CPU can be woken up by setting a threshold or by other trigger methods.
The voltage range that the ADC can convert is determined by VREF, which is typically 0 to 3.3 V on the ESP32-S3. However, the actual maximum rated input voltage of the ESP32 may be slightly different, so it is important to check the corresponding datasheet for specific information. It is generally recommended to use the attenuation feature or extra hardware such as a voltage divider to keep the input voltage within the specified range.
The ESP32-S3 also has a built-in temperature sensor that produces a voltage that varies with temperature. The internal ADC converts the sensor voltage into a digital value. The measuring range of the temperature sensor is –20 °C to 110 °C. The temperature sensor is suitable for monitoring temperature changes inside the chip. The temperature value varies with the microcontroller clock frequency and the IO load. Generally, the internal temperature of the chip is higher than the external temperature.
9.3 Basic Parameters of an ADC
The basic parameters of an ADC usually include the following:
- Resolution: refers to the number of digital output bits of the ADC, also known as the quantization bits. For example, a 12-bit ADC has 4096 discrete digital outputs.
- Sampling rate: refers to the maximum rate at which the ADC can sample. For the ESP32-S3, the maximum sampling rate is 2.5 MS/s.
- Input range: refers to the voltage range of the input signal that the ADC can measure. For the ESP32-S3, the input range is 0–3.3 V.
- Noise: refers to the error in resolution and the impact of interference during ADC sampling. The lower the noise, the more accurate the ADC measurement.
- Stability: refers to the stability of the ADC output. A more stable ADC has less output variation and more accurate measurement results.
9.4 ADC Usage Flow
9.4.1 Include the Relevant Header Files
First, include the necessary header files in your code, including esp_adc_cal.h and driver/adc.h.
#include "esp_adc_cal.h"
#include "driver/adc.h"2
9.4.2 Configure ADC Parameters
Configure the required precision and attenuation by calling the functions adc1_config_width() and adc1_config_channel_atten(). adc1_config_width is one of the configuration functions of the ADC1 module on the ESP32S3. It is used to set the precision (number of bits) of ADC1. Through this function, you can set the precision of ADC1 to 9 bits, 10 bits, 11 bits, or 12 bits.
void adc1_config_width(adc_bits_width_t width);The width parameter specifies the resolution bits to set. It can be one of the following values:
ADC_WIDTH_BIT_9: sets the precision of ADC1 to 9 bitsADC_WIDTH_BIT_10: sets the precision of ADC1 to 10 bitsADC_WIDTH_BIT_11: sets the precision of ADC1 to 11 bitsADC_WIDTH_BIT_12: sets the precision of ADC1 to 12 bits For example, to set the precision of ADC1 to 12 bits, do the following: // Set the precision of ADC1 to 12 bits
adc1_config_width(ADC_WIDTH_BIT_12);This function should be called before using ADC1 to ensure that the precision of ADC1 is set correctly.
adc1_config_channel_atten is one of the configuration functions of the ADC1 module on the ESP32S3. It is used to set the attenuation parameter for a specific channel of ADC1. The function prototype is as follows:
void adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten);The function takes two parameters:
channel: the ADC1 channel to be configured, of typeadc1_channel_t.atten: the attenuation parameter, of typeadc_atten_t. The attenuation parameterattendetermines the voltage range of the ADC input signal. The available values are:ADC_ATTEN_DB_0: 0 dB attenuation, input voltage range 0–1.1 V.ADC_ATTEN_DB_2_5: 2.5 dB attenuation, input voltage range 0–1.5 V.ADC_ATTEN_DB_6: 6 dB attenuation, input voltage range 0–2.2 V.ADC_ATTEN_DB_11: 11 dB attenuation, input voltage range 0–3.3 V. For example, to configure channel 0 of ADC1 with 11 dB attenuation, do the following:
// Configure channel 0 of ADC1 with 11 dB attenuation
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);2
This function should be called before using a specific channel of ADC1 to ensure that the required attenuation parameter is set correctly.
9.4.3 Read the ADC Value
- Use the
adc1_get_rawfunction to obtain the ADC value.adc1_get_rawis one of the ADC1 module functions on the ESP32S3. It is used to read the measured value of a specified channel of ADC1 as a raw 12-bit ADC value. The function prototype is as follows:
int adc1_get_raw(adc1_channel_t channel);The function takes a single parameter:
channel: the ADC1 channel to read, of typeadc1_channel_t. The function returns an integer representing the raw 12-bit ADC value of the measurement. Even after ADC characterization, the measured value is provided in raw 12-bit digital form. For example, to take an ADC measurement on channel 2 of ADC1 and store the raw 12-bit ADC value in the variableraw_value, do the following:
// Read the raw 12-bit ADC value of the measurement from channel 2 of ADC1
int raw_value = adc1_get_raw(ADC1_CHANNEL_2);2
Note that converting the raw ADC value to readable units and physical measurement units requires some extra calculation and conversion. Handle it according to your actual situation.
9.5 Hardware Connection and Preparation
This example uses GPIO1 as the ADC reading pin to test an external voltage through GPIO1, then uses the onboard UART0 to print the value read by the ADC and convert it into the actual voltage for display.
ADC readings from a pin that is not connected to any signal are random.
9.6 ADC Read Verification
#include <string.h>
#include <stdio.h>
#include "sdkconfig.h"
#include <esp_log.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define DEFAULT_VREF 1100 // Default reference voltage in mV
static esp_adc_cal_characteristics_t *adc_chars;
#define channel ADC_CHANNEL_0 // ADC measurement channel
#define width ADC_WIDTH_BIT_12 // ADC resolution
#define atten ADC_ATTEN_DB_11 // ADC attenuation
#define unit ADC_UNIT_1 // ADC1
void app_main(void)
{
int read_raw_1=0, read_raw_2=0, read_raw_3=0;
uint32_t voltage =0;
float voltage_f = 0;
adc1_config_width(width);// 12-bit resolution
// ADC_ATTEN_DB_0: reference voltage is 1.1 V
// ADC_ATTEN_DB_2_5: reference voltage is 1.5 V
// ADC_ATTEN_DB_6: reference voltage is 2.2 V
// ADC_ATTEN_DB_11: reference voltage is 3.3 V
// adc1_config_channel_atten( channel,atten);// Set channel 0 and 3.3 V reference voltage
// Allocate memory
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
// Initialize ADC characteristics so that the conversion result and compensation factors can be calculated correctly
esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars);
while(1)
{
// Sample the ADC values of three channels
read_raw_1 = adc1_get_raw(ADC1_CHANNEL_0); // GPIO1
read_raw_2 = adc1_get_raw(ADC1_CHANNEL_1); // GPIO2
read_raw_3 = adc1_get_raw(ADC1_CHANNEL_2); // GPIO3
// Convert the result of ADC1 channel 0 (GPIO1) to a voltage, in mV
voltage = esp_adc_cal_raw_to_voltage(read_raw_1, adc_chars);
// Print the ADC values and the actual voltage of ADC1 channel 0 (GPIO1)
printf("read_raw_1 = %d\tread_raw_2 = %d\tread_raw_3 = %d\tvoltage: %f\n",read_raw_1,read_raw_2,read_raw_3,voltage/1000.0);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
The example above uses another function, esp_adc_cal_characterize(), which calculates the characterization information of the ADC based on a set of parameters and stores the result in the specified esp_adc_cal_characteristics_t structure. During sampling, the ADC hardware module converts the measurement information into a digital value, which usually needs some calibration and conversion to obtain accurate measurement results. By using esp_adc_cal_characterize(), these calibration and conversion processes can be performed automatically to obtain more accurate ADC measurement values.
9.7 ADC Read Effect
Connect GPIO1 and GPIO3 to a voltage around 1.48 V, and connect GPIO2 to GND. The result is as follows: