Phipps Electronics

Order within the next 

FREE SHIPPING OVER $199

50,000+ ORDERS

WORLDWIDE SHIPPING

SSL SECURED

ESP32-S3 Basic ADC Programming

Contents

Get to know how to get your ESP32’s ADC up and running through this basic ESP32 ADC programming guide.

Introduction

Your ESP32-S3 has 2 SAR (Successive Approximation Register) ADCs inside them. Knowing how to use them can help you make versatile projects. With these ADCs, you’ll be able to measure analog readings. These readings can be anything from sensor-level data, power supply voltages, or even analog levels from a voltage divider. Here, you’ll learn about basic ESP32 ADC programming.

esp32-s3 ADC

Above you can see the two ADCs, namely, ADC1 and ADC2. ADC1 is widely used by users. ADC2 has some handicaps because it is also used by the Wi-Fi module. Here we’ll discuss basic configuration and how to use ADC1

USing your ESP32's ADC

Know where your ADC Pins are

Before you can use the ADC, you must know what pins on your ESP32 to use as ADC inputs. Generally speaking, below are the GPIO pins used by both ADC1 and ADC2:

  • ADC1: 10 channels (GPIO1 – GPIO10)
  • ADC2: 10 channels (GPIO11 – GPIO20)

To be more specific, you can check the ESP32-S3-WROOM datasheet to know which ADC input maps to which I/O pin as seen below:

ESP32-S3 -WROOM ADC pin layout

Setup your Circuit

Setting up your circuit could be as simple as an ESP32-S3 DevKit-C1 wired on a breadboard with a potentiometer as seen below. Note that ADC1_CHANNEL_0 will be used as input which maps to GPIO1.

ESP32-S3 ADC test on breadboard with potentiometer

Creating your Code

Below is a basic guide to get your ESP32-S3 ADC up and running reading a single ADC input pin in one-shot mode. This is the simplest ADC input capture type. One-shot meaning single ADC values are captured by the user. It’s up to him how to initiate and terminate those single-shot ADC capture processes.

Include the necessary Header Files

You’ll want to include the source files below. Some files are necessary to get your ADC capture running. Some are required to output ADC values as string data. You’ll need adc_oneshot.h, adc_cali.h, and adc_cali_scheme.h to successfully configure, calibrate, and capture data with your ADC.

				
					#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/soc_caps.h"

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

				
			

Create some Definitions and Variables

ADC_CHANNEL_0 is used for the channel definition while integer variables adc_raw and voltage are used to hold both adc raw and voltage type readings. You’ll see later how an ADC raw reading converts to a voltage type.

				
					#define MY_ADC_CHANNEL  ADC_CHANNEL_0

static int adc_raw;     // adc raw reading
static int voltage;     // adc raw coverted to voltage

				
			

Initialize the ADC in one-shot mode

On the main code, initialize the ADC in one-shot mode using the handles and configuration types below. There are two modes you can use, one-shot and continuous. Here, for simplicity’s sake, we’ll concentrate on the simple one-shot mode. ADC1 is ADC_UNIT_1. The ADC is initialized through the adc_oneshot_new_unit() API.

				
					    // 1 -- Initialize the ADC
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config1 = {
        .unit_id = ADC_UNIT_1,
    };
    adc_oneshot_new_unit(&init_config1, &adc1_handle);
				
			

Configure the ADC and the Channel to use

ADC1 is configured to have a maximum bit width (which can go up to 13 bits max) and an attenuation level of 12db. Attenuation levels are important since the ADC reference voltage can go as low as 1.1V. With this, the ADC input pin must be attenuated to some degree if you’re using the VDD pin (3.3V) of the ESP32-S3 as the source voltage for your ADC readings. 

ESP32-S3 ADC attenuation levels

Below, the adc_oneshot_config_channel() API is used to configure the ADC.

				
					    // 2 -- Configure the ADC
    adc_oneshot_chan_cfg_t config = {
        .bitwidth = ADC_BITWIDTH_DEFAULT,
        .atten = ADC_ATTEN_DB_12,
    };
    adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_0, &config);
				
			

CalibratE the ADC

The ADC reference voltage can swing in small amounts due to internal and external factors. With this, you’ll need some form of calibration to make your ADC readings more precise. Different kinds of calibration schemes are implemented by the ESP-IDF framework. One such scheme is the Curve Fitting Calibration Scheme.

Below is a config type and handle used as parameters for the adc_cali_create_scheme_curve_fitting() API. This calibration API is executed before doing your first ADC reading.

				
					    // 3 -- Calibrate the ADC
    adc_cali_handle_t adc1_cali_chan0_handle = NULL;
    adc_cali_curve_fitting_config_t cali_config = {
        .unit_id = ADC_UNIT_1,
        .chan = ADC_CHANNEL_0,
        .atten = ADC_ATTEN_DB_12,
        .bitwidth = ADC_BITWIDTH_DEFAULT,
    };
    adc_cali_create_scheme_curve_fitting(&cali_config, &adc1_cali_chan0_handle);
				
			

Read athe ADC Values

In a loop, you can start reading and displaying the ADC values. Raw data is output by adc_oneshot_read() while adc_cali_raw_to_voltage() converts the value to voltage. Note that the API adc_cali_raw_to_voltage() is related to the calibration scheme you defined previously.

				
					        // 4 -- Read raw ADC value
        adc_oneshot_read(adc1_handle, ADC_CHANNEL_0, &adc_raw);
    
        // 5 -- Convert raw to voltage
        adc_cali_raw_to_voltage(adc1_cali_chan0_handle, adc_raw, &voltage);

        printf("ADC Reading is: %dmV\n", voltage);
				
			

Referrence Code

Use the complete reference code below to review basic one shot ESP32 ADC programming on :).

				
					#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/soc_caps.h"

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

#define MY_ADC_CHANNEL  ADC_CHANNEL_0

static int adc_raw;     // adc raw reading
static int voltage;     // adc raw coverted to voltage


void app_main(void)
{
    // 1 -- Initialize the ADC
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config1 = {
        .unit_id = ADC_UNIT_1,
    };
    adc_oneshot_new_unit(&init_config1, &adc1_handle);

    // 2 -- Configure the ADC
    adc_oneshot_chan_cfg_t config = {
        .bitwidth = ADC_BITWIDTH_DEFAULT, 
        .atten = ADC_ATTEN_DB_12,
    };
    adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_0, &config);

    // 3 -- Calibrate the ADC
    adc_cali_handle_t adc1_cali_chan0_handle = NULL;
    adc_cali_curve_fitting_config_t cali_config = {
        .unit_id = ADC_UNIT_1,
        .chan = ADC_CHANNEL_0,
        .atten = ADC_ATTEN_DB_12,
        .bitwidth = ADC_BITWIDTH_DEFAULT,
    };
    adc_cali_create_scheme_curve_fitting(&cali_config, &adc1_cali_chan0_handle);

    while(1)
    {
        // 4 -- Read raw ADC value
        adc_oneshot_read(adc1_handle, ADC_CHANNEL_0, &adc_raw);
    
        // 5 -- Convert raw to voltage
        adc_cali_raw_to_voltage(adc1_cali_chan0_handle, adc_raw, &voltage);

        printf("ADC Reading is: %dmV\n", voltage);

        vTaskDelay(1000/portTICK_PERIOD_MS);
    }

    // 6 -- Delete Calibration scheme
    adc_cali_delete_scheme_curve_fitting(adc1_cali_chan0_handle);

}
				
			

SUBSCRIBE FOR NEW POST ALERTS

Subscribe to be the first to know when we publish a new article!
List Subscriptions(Required)

POPULAR POSTS

Scroll to Top