10.ADC
10.1 What Is ADC?
ADC stands for Analog-to-Digital Converter. It is 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 optical signals. Digital signals are discrete binary signals, such as data 0 and 1 in a computer, and can only take a limited set of values. The operating principle of an ADC is to convert an analog signal into a discrete digital signal through sampling, then process it through quantization, encoding, and other steps to obtain the corresponding digital representation. The higher the ADC sampling frequency, the closer the resulting digital signal is to the original analog signal, meaning higher fidelity. However, this requires more resources and computing power. ADCs are usually used to read analog signals from external analog sensors and convert them into digital signals for embedded systems or computers to process, such as measuring temperature, humidity, pressure, and other physical quantities.
10.2 ESP32S3 ADC Introduction
ESP32-S3 integrates two 12-bit SAR ADCs. Each ADC has 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 voltage. To achieve lower power consumption, the ESP32-S3 ULP coprocessor can also measure voltage in sleep mode. In this case, the CPU can be woken up by setting thresholds or other trigger methods. The voltage range that the ADC can convert is determined by VREF. For ESP32-S3, it is usually 0 to 3.3 V. However, note that the exact maximum rated input voltage of an ESP32 may differ slightly, so it is important to check the specific information in the corresponding datasheet. It is usually recommended to use attenuation or additional hardware such as a voltage divider to ensure the input voltage stays within the specified range. ESP32-S3 also has an internal temperature sensor that generates a voltage varying with temperature. The internal ADC converts the sensor voltage into a digital value. The measurement range of the temperature sensor is -20 C to 110 C. The temperature sensor is suitable for monitoring changes in the internal chip temperature, and this temperature value changes with microcontroller clock frequency or IO load. Generally, the internal chip temperature is higher than the external temperature. Pins that support ADC sampling are shown below:
10.3 Basic ADC Parameters
Basic ADC parameters usually include the following:
- Channels and pins: not all GPIOs can be used for ADC readings. Check the ESP32S3 pinout to determine which pins support ADC functions.
- Resolution: the number of bits in the ADC digital output, also called the quantization bit width. For example, a 12-bit ADC has 4096 discrete digital output values.
- Sampling rate: the maximum rate at which the ADC can sample. For ESP32-S3, the maximum sampling rate is 2.5 MS/s.
- Input range: the voltage range of the input signal that the ADC can measure. For ESP32-S3, the input range is 0 to 3.3 V.
- Noise: errors and interference that affect ADC resolution during acquisition. Lower noise means more accurate ADC measurement results.
- Stability: the stability of the ADC output. An ADC with good stability has smaller output variation and more accurate measurement results.
10.4 ADC Usage Flow
10.4.1 Read Values Using Arduino Internal Library Functions
analogRead() is one of the Arduino functions used to read analog input signals. Its prototype is:
int analogRead(uint8_t pin); The parameter pin is an integer value representing the analog pin to read. On ESP32-S3, different pins can be used as analog pins, but only GPIO1 to GPIO20 are supported. analogRead() returns an integer representing the ADC value read from the analog input pin. For ESP32-S3, this value ranges from 0 to 4095, corresponding to 12-bit ADC resolution. The following is a simple example of reading analog input using analogRead():
// Define the analog input pin as GPIO1
const int analogPin = 1;
int sensorValue = 0;
void setup() {
// Enable debug serial port 0 and set the baud rate to 9600
Serial.begin(9600);
// Set GPIO1 as floating input mode
pinMode(analogPin, INPUT);
}
void loop() {
// Read the analog value of GPIO1
sensorValue = analogRead(analogPin);
// Print the read value through serial port 0
Serial.println(sensorValue);
// Delay for 1 second
delay(1000);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
In the example above, GPIO1 is set as an analog input pin. In the loop() function, analogRead(analogPin) reads the analog input value and prints it to the Serial Monitor. After a 1-second delay, the value is read and printed again. The loop repeats continuously to implement continuous analog input reading.
10.4.2 Read Values Through the ADC Peripheral Library
After opening the esp32_hal_adc.h file, you can see all ADC control functions:
analogReadResolution(bits): sets analog input resolution. For ESP32-S3 and ESP32, the default ADC, analog-to-digital conversion, resolution is 12 bits, ranging from 0 to 4095. Calling this function allows you to change the resolution.bitsis the desired resolution in bits. It can be a value between 9 bits, 0 to 511, and 12 bits, 0 to 4095. For example, if you set the resolution to 10 bits,analogRead()returns a value from 0 to 1023. Changing the reading resolution can adapt to application scenarios that require different precision. Lower resolution can make ADC reading faster, while higher resolution can provide more detailed voltage readings, but at the cost of some performance. Note that increasing resolution does not improve ADC accuracy, which is still limited by hardware and noise.analogSetWidth(width): sets the ADC bit width. Valid bit width parameters are usually from 9 to 12 bits, and the default is 12 bits. This function appears similar toanalogReadResolution, but they come from different contexts.analogSetWidth(width)is an ESP32-specific function that lets you set the internal ADC bit width of ESP32. It directly sets the sampling bit width of the ADC hardware.analogReadResolution(resolution)is a more common function in the Arduino environment. It sets the resolution of the value returned byanalogRead(). On some Arduino-compatible boards with variable ADC resolution, this function can be used to change the returned value width ofanalogRead(). Simply put,analogSetWidth()is ESP32-specific and actually changes how the hardware ADC module works.analogReadResolution()is part of the Arduino API and sets the resolution of the return value fromanalogRead(). Their specific implementations may differ between devices and library versions. For example, usinganalogSetWidth(10)on ESP32 changes the ADC bit width to 10 bits, meaning the ADC performs analog-to-digital conversion with 10-bit precision. On an Arduino-compatible device that supportsanalogReadResolution(), callinganalogReadResolution(10)means that subsequent calls toanalogRead()return a maximum 10-bit digital value, that is, 0 to 1023, even if the hardware actually returns 12-bit data. Therefore, note that for some Arduino-compatible boards, changinganalogReadResolution()does not actually change the ADC hardware resolution itself, but changes the range of values returned to the Arduino program. If the hardware ADC resolution is actually 12 bits, then whenanalogReadResolution(10)is set, the Arduino API maps, or scales, the native 12-bit ADC value into a 10-bit range. On ESP32,analogSetWidth()actually changes the bit width of the internal ADC hardware.analogSetCycles(cycles): sets the number of cycles per sample. The default is 8. Valid range: 1 to 255.analogSetSamples(samples): sets the number of samples within the range. The default is 1 sample. It can increase sensitivity.analogSetClockDiv(attenuation): sets the ADC clock divider. The default value is 1. Valid range: 1 to 255.adcAttachPin(pin): attaches a pin to the ADC and clears any other analog mode that may be on. Returns TRUE or FALSE.analogSetAttenuation(attenuation): sets the attenuation of the ADC so it can read a wider input voltage range.Attenuation is the process of reducing signal strength. In the ESP32S3 ADC, this is implemented by a hardware attenuator, which increases the maximum voltage the ADC can measure and allows higher-voltage signals to be measured without exceeding ADC input limits. This function expands the input voltage range of the ESP32S3 ADC. The ESP32 SDK usually provides the following attenuation options:
ADC_ATTEN_DB_0: no attenuation. The maximum voltage range is 1.1 V. In ESP32S3, 0 dB attenuation corresponds to a maximum voltage of about 1.1 V.ADC_ATTEN_DB_2_5: maximum measurable voltage of about 1.5 V.ADC_ATTEN_DB_6: maximum measurable voltage of about 2.2 V.ADC_ATTEN_DB_11: maximum measurable voltage of about 3.9 V.If you want to measure voltages higher than 1.1 V, you must set an attenuation value. For example, if you want to measure a signal up to 3.3 V, set the attenuation to
ADC_ATTEN_DB_11.analogSetPinAttenuation(pin, attenuation): sets the input attenuation for a specified pin. The default is ADC_11db. The attenuation values are the same as the previous function. Example:
#define POT 1
// Initialize analog input value
int pot_value;
void setup() {
// Initialize serial port 0 with a baud rate of 9600
Serial.begin(9600);
// Initialize ADC pin
pinMode(POT,INPUT);
// Set ADC resolution
analogReadResolution(12);
// Configure attenuation
analogSetAttenuation(ADC_11db);
}
void loop() {
// Get analog input value
pot_value = analogRead(POT);
// Print ADC value through serial port 0
Serial.println(pot_value);
delay(1000);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In the example above, serial port 0 is initialized to print the collected ADC value, and GPIO1 is initialized as the ADC interface for collecting an external analog value.
10.5 Hardware Connection and Preparation
In this example, GPIO1 is used as the ADC reading pin. GPIO1 is used to test an external voltage, and onboard serial port 0 prints the ADC reading and converts it to the actual voltage for display.
10.6 ADC Reading Verification
#define POT 1
// Initialize analog input value
int adc_value;
void setup() {
// Initialize serial port 0 with a baud rate of 9600
Serial.begin(9600);
// Initialize ADC pin
pinMode(POT,INPUT);
// Set ADC resolution
analogReadResolution(12);
// Configure attenuation
analogSetAttenuation(ADC_11db);
}
void loop() {
// Get analog input value
adc_value= analogRead(POT);
// Print ADC value through serial port 0
Serial.write("ADC_value = ");
Serial.println(adc_value);
// Print the actual voltage value through serial port 0
Serial.write("voltage(V) = ");
Serial.println(adc_value/4095.0\*3.3);
delay(1000);
}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
10.7 ADC Reading Effect
Open the serial debugging assistant, set the baud rate to 9600, and view the data. Connect GPIO1 to 3.3 V and GND using a Dupont wire for testing.