Documentation

https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/adc_oneshot.html

Hardware Limitations

Note that ADC1 and ADC2 usage are shared by some peripherals, such as the random number generator and WiFi.

Speed

adc_oneshot_read() was fast in our tests, taking approx 130uS on an ESP32 S3

CMakeLists.txt REQUIRES

Ensure the following is added to the REQUIRES section of your CMakeLists.txt file in the \main folder:

	REQUIRES

			esp_adc

Example setting up, with calibration and performing a read

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

#define ADC1_ATTEN           ADC_ATTEN_DB_11	//ADC_ATTEN_DB_0 = No input attenuation, ADC can measure up to Vref which is approx 1100mV (factory test value burnt into eFuse)
												//ADC_ATTEN_DB_2_5 = input attenuated extending the range of measurement by about 2.5 dB (1.33 x)
												//ADC_ATTEN_DB_6 = input attenuated extending the range of measurement by about 6 dB (2 x)
												//ADC_ATTEN_DB_11 = input attenuated extending the range of measurement by about 11 dB (3.55 x)

adc_oneshot_unit_handle_t Adc1Handle;
adc_cali_handle_t Adc1CalibrationHandle = NULL;
bool Adc1DoCalibration = false;
int AdcRawValueChannel_0 = 0;
int AdcRawValueChannel_3 = 0;
int AdcVoltageChannel_0 = 0;
int AdcVoltageChannel_3 = 0;


//**************************************
//**************************************
//********** INITIALSE A TO D **********
//**************************************
//**************************************
void InitialiseAtoD (void)
{

	//----- SETUP ADC1 -----
	adc_oneshot_unit_init_cfg_t Adc1InitConfig = {
		.unit_id = ADC_UNIT_1,
	};
	adc_oneshot_new_unit(&Adc1InitConfig, &Adc1Handle);

	adc_oneshot_chan_cfg_t Adc1Config = {
		.bitwidth = ADC_BITWIDTH_DEFAULT,
		.atten = ADC1_ATTEN,
	};
	ESP_ERROR_CHECK(adc_oneshot_config_channel(Adc1Handle, ADC_CHANNEL_0, &Adc1Config));
	ESP_ERROR_CHECK(adc_oneshot_config_channel(Adc1Handle, ADC_CHANNEL_3, &Adc1Config));

	//Calibration Init
	Adc1DoCalibration = AtoDCalibrationInitialise(ADC_UNIT_1, ADC1_ATTEN, &Adc1CalibrationHandle);
}


//*********************************
//*********************************
//********** READ A TO D **********
//*********************************
//*********************************
void ReadAtoD (void)
{

	//----- READ ADC_CHANNEL_0 -----
	if (adc_oneshot_read(Adc1Handle, ADC_CHANNEL_0, &AdcRawValueChannel_0) == ESP_OK)		//<<Takes approx 130uS on ESP32S3
	{
		ESP_LOGI(TAG, "ADC%d Channel %d - Raw Data: %d", (ADC_UNIT_1 + 1), ADC_CHANNEL_0, AdcRawValueChannel_0);
		if (Adc1DoCalibration)
		{
			adc_cali_raw_to_voltage(Adc1CalibrationHandle, AdcRawValueChannel_0, &AdcVoltageChannel_0);
			ESP_LOGI(TAG, "ADC%d Channel %d - Calibrated Voltage: %d mV", (ADC_UNIT_1 + 1), ADC_CHANNEL_0, AdcVoltageChannel_0);
		}
		else
		{
			//Calibration wasn't possible (this is an issue, measurement will likley be very non accurate!)
			AdcVoltageChannel_0 = ((double)3300 / 8192) * AdcRawValueChannel_0;		//<<<<<<<SET MAX VALUE BASED ON ADC BIT WIDTH (8192 = 13bit)<<<<<<<<<<<<<<<<<<
			ESP_LOGI(TAG, "ADC%d Channel %d - Uncalibrated Voltage: %d mV", (ADC_UNIT_1 + 1), ADC_CHANNEL_0, AdcVoltageChannel_0);
		}
	}

	//----- READ ADC_CHANNEL_3 -----
	if (adc_oneshot_read(Adc1Handle, ADC_CHANNEL_3, &AdcRawValueChannel_3) == ESP_OK)		//<<Takes approx 130uS on ESP32S3
	{
		ESP_LOGI(TAG, "ADC%d Channel %d - Raw Data: %d", (ADC_UNIT_1 + 1), ADC_CHANNEL_3, AdcRawValueChannel_3);
		if (Adc1DoCalibration)
		{
			adc_cali_raw_to_voltage(Adc1CalibrationHandle, AdcRawValueChannel_3, &AdcVoltageChannel_3);
			ESP_LOGI(TAG, "ADC%d Channel %d - Calibrated Voltage: %d mV", (ADC_UNIT_1 + 1), ADC_CHANNEL_3, AdcVoltageChannel_3);
		}
		else
		{
			//Calibration wasn't possible (this is an issue, measurement will likley be very non accurate!)
			AdcVoltageChannel_3 = ((double)3300 / 8192) * AdcRawValueChannel_3;		//<<<<<<<SET MAX VALUE BASED ON ADC BIT WIDTH (8192 = 13bit)<<<<<<<<<<<<<<<<<<
			ESP_LOGI(TAG, "ADC%d Channel %d - Uncalibrated Voltage: %d mV", (ADC_UNIT_1 + 1), ADC_CHANNEL_3, AdcVoltageChannel_3);
		}
	}
}


//***************************************************
//***************************************************
//********** A TO D CALIBRATION INITIALISE **********
//***************************************************
//***************************************************
bool AtoDCalibrationInitialise (adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
	adc_cali_handle_t handle = NULL;
	esp_err_t ret = ESP_FAIL;
	bool calibrated = false;

#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
	if (!calibrated)
	{
		ESP_LOGI(TAG, "AtoD Calibrate - Calibration scheme version is %s", "Curve Fitting");
		adc_cali_curve_fitting_config_t cali_config = {
			.unit_id = unit,
			.atten = atten,
			.bitwidth = ADC_BITWIDTH_DEFAULT,
		};
		ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
		if (ret == ESP_OK)
			calibrated = true;
	}
#endif

#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
	if (!calibrated)
	{
		ESP_LOGI(TAG, "AtoD Calibrate - Calibration scheme version is %s", "Line Fitting");
		adc_cali_line_fitting_config_t cali_config = {
			.unit_id = unit,
			.atten = atten,
			.bitwidth = ADC_BITWIDTH_DEFAULT,
		};
		ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
		if (ret == ESP_OK)
			calibrated = true;
	}
#endif

	*out_handle = handle;
	if (ret == ESP_OK)
		ESP_LOGI(TAG, "AtoD Calibrate - Calibration Success");
	else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated)
		ESP_LOGW(TAG, "AtoD Calibrate - eFuse not burnt, skip software calibration");
	else
		ESP_LOGE(TAG, "AtoD Calibrate - Invalid arg or no memory");

	return calibrated;
}


//*******************************************************
//*******************************************************
//********** A TO D CALIBRATION  DE-INITIALISE **********
//*******************************************************
//*******************************************************
/*
static void AtoDCalibrationDeInitialise(adc_cali_handle_t handle)
{
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
	ESP_LOGI(TAG, "deregister %s calibration scheme", "Curve Fitting");
	adc_cali_delete_scheme_curve_fitting(handle);

#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
	ESP_LOGI(TAG, "deregister %s calibration scheme", "Line Fitting");
	adc_cali_delete_scheme_line_fitting(handle);
#endif
}
*/

Example function that uses as simple averaging filter

int AtoD1msTimer = 0;

//----- ADD THIS TO YOUR 1MS HEARTBEAT -----
	if (AtoD1msTimer > 0)
		AtoD1msTimer--;


//************************************
//************************************
//********** PROCESS A TO D **********
//************************************
//************************************
void ProcessAtoD (void)
{
	static int NextAtoDChannel = 0;		//<<<Set first channel number
	static int AveragingFilterCount = 0;
	static uint64_t AdcRawValueBufferChannel_0 = 0;
	static uint64_t AdcRawValueBufferChannel_3 = 0;
	int AdcRawValue;
	


	if (AtoD1msTimer > 0)
		return;

	AtoD1msTimer = 10;		//<<<Read next AtoD every #mS



	//We read one inut each call
	//(You could do all, just seems sensible to split them out seeing as we are time based average filtering)
	switch (NextAtoDChannel)
	{
	case 0:
		//------------------------------
		//----- READ ADC_CHANNEL_0 -----
		//------------------------------
		adc_oneshot_read(Adc1Handle, ADC_CHANNEL_0, &AdcRawValue);		//Takes approx 130uS on ESP32S3
		if (AdcRawValue < 0)
			AdcRawValue = 0;
		AdcRawValueBufferChannel_0 += AdcRawValue;

		NextAtoDChannel = 3;		//<<<Set next channel number
		break;


	case 3:
		//------------------------------
		//----- READ ADC_CHANNEL_3 -----
		//------------------------------
		adc_oneshot_read(Adc1Handle, ADC_CHANNEL_3, &AdcRawValue);
		if (AdcRawValue < 0)
			AdcRawValue = 0;
		AdcRawValueBufferChannel_3 += AdcRawValue;

		//NextAtoDChannel = ;
		//break;			//<<<Last channel falls into switch() default state
		// \/
	default:
		NextAtoDChannel = 0;		//<<<Set first channel number

		AveragingFilterCount++;			//Do after a read of all the AtoD inputs

		if (AveragingFilterCount >= 16)		//<<<Set number of readings to average (also adjust the >>= below to match).
		{
			//------------------------------------
			//------------------------------------
			//----- DONE NEW SET OF READINGS -----
			//------------------------------------
			//------------------------------------
			
			//DO ADC_CHANNEL_0
			AdcRawValue = (int)(AdcRawValueBufferChannel_0 >> 4);			//16 samples needs >> 4 (each bitshift is /2)
			//ESP_LOGI(TAG, "ADC%d Channel %d - Raw Data: %d", (ADC_UNIT_1 + 1), ADC_CHANNEL_0, AdcRawValue);
			if (Adc1DoCalibration)
			{
				adc_cali_raw_to_voltage(Adc1CalibrationHandle, AdcRawValue, &AdcVoltageChannel_0);		//<<Takes approx 30uS on ESP32S3
				//ESP_LOGI(TAG, "ADC%d Channel %d - Calibrated Voltage: %d mV", (ADC_UNIT_1 + 1), ADC_CHANNEL_0, AdcVoltageChannel_0);
			}

			//DO ADC_CHANNEL_3
			AdcRawValue = (int)(AdcRawValueBufferChannel_3 >> 4);			//16 samples needs >> 4 (each bitshift is /2)
			//ESP_LOGI(TAG, "ADC%d Channel %d - Raw Data: %d", (ADC_UNIT_1 + 1), ADC_CHANNEL_3, AdcRawValue);
			if (Adc1DoCalibration)
			{
				adc_cali_raw_to_voltage(Adc1CalibrationHandle, AdcRawValue, &AdcVoltageChannel_3);		//<<Takes approx 30uS on ESP32S3
				//ESP_LOGI(TAG, "ADC%d Channel %d - Calibrated Voltage: %d mV", (ADC_UNIT_1 + 1), ADC_CHANNEL_3, AdcVoltageChannel_3);
			}


			//RESET FOR NEW SAMPLE
			AveragingFilterCount = 0;
			AdcRawValueBufferChannel_0 = 0;
			AdcRawValueBufferChannel_3 = 0;
		}

		break;
	} //switch (NextAtoDChannel)

}

Disable AtoD

    //----- DISABLE AtoD -----
    adc_oneshot_del_unit(Adc1Handle);
    if (Adc1DoCalibration)
	{
        AtoDCalibrationDeInitialise(Adc1CalibrationHandle);
    }
USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.
Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.

Comments

Your email address will not be published. Required fields are marked *