EspAdc provides ESP32 ADC (Analog-to-Digital Converter) functionality with comprehensive support
for all ESP32 variants using ESP-IDF v5.5+.
It implements the BaseAdc interface with hardware-specific optimizations for one-shot and
continuous sampling modes, calibration, filtering, and threshold monitoring.
Features
Multi-Variant Support - ESP32-C6, ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C2, ESP32-H2
Dual Operation Modes - One-shot and continuous (DMA) sampling
Hardware Calibration - Automatic calibration using eFuse data
Digital Filtering - Up to 2 IIR filters for noise reduction
Threshold Monitoring - Up to 2 monitors with ISR callbacks
Multi-Channel Support - Configurable channels with individual settings
Thread Safety - Mutex-protected operations for multi-threaded access
Comprehensive Diagnostics - Statistics tracking and error reporting
classEspAdc:publicBaseAdc{public:// Constructor with configuration structureexplicitEspAdc(consthf_adc_unit_config_t&config)noexcept;// Destructor with proper cleanup~EspAdc()noexceptoverride;// Copy and move operations disabled for resource safetyEspAdc(constEspAdc&)=delete;EspAdc&operator=(constEspAdc&)=delete;EspAdc(EspAdc&&)=delete;EspAdc&operator=(EspAdc&&)=delete;// BaseAdc interface implementationboolInitialize()noexceptoverride;boolDeinitialize()noexceptoverride;hf_u8_tGetMaxChannels()constnoexceptoverride;boolIsChannelAvailable(hf_channel_id_tchannel_id)constnoexceptoverride;// Reading operationshf_adc_err_tReadChannelV(hf_channel_id_tchannel_id,float&channel_reading_v,hf_u8_tnumOfSamplesToAvg=1,hf_time_ttimeBetweenSamples=0)noexceptoverride;hf_adc_err_tReadChannelCount(hf_channel_id_tchannel_id,hf_u32_t&channel_reading_count,hf_u8_tnumOfSamplesToAvg=1,hf_time_ttimeBetweenSamples=0)noexceptoverride;hf_adc_err_tReadChannel(hf_channel_id_tchannel_id,hf_u32_t&channel_reading_count,float&channel_reading_v,hf_u8_tnumOfSamplesToAvg=1,hf_time_ttimeBetweenSamples=0)noexceptoverride;// Advanced operationshf_adc_err_tSetMode(hf_adc_mode_tmode)noexcept;hf_adc_err_tConfigureChannel(hf_channel_id_tchannel_id,hf_adc_atten_tattenuation,hf_adc_bitwidth_tbitwidth=hf_adc_bitwidth_t::WIDTH_DEFAULT)noexcept;hf_adc_err_tEnableChannel(hf_channel_id_tchannel_id)noexcept;hf_adc_err_tDisableChannel(hf_channel_id_tchannel_id)noexcept;// Continuous mode operationshf_adc_err_tConfigureContinuous(consthf_adc_continuous_config_t&config)noexcept;hf_adc_err_tSetContinuousCallback(hf_adc_continuous_callback_tcallback,void*user_data=nullptr)noexcept;hf_adc_err_tStartContinuous()noexcept;hf_adc_err_tStopContinuous()noexcept;hf_adc_err_tReadContinuousData(hf_u8_t*buffer,hf_u32_tbuffer_size,hf_u32_t&bytes_read,hf_time_ttimeout_ms)noexcept;// Calibration operationshf_adc_err_tInitializeCalibration(hf_adc_atten_tattenuation,hf_adc_bitwidth_tbitwidth=hf_adc_bitwidth_t::WIDTH_DEFAULT)noexcept;boolIsCalibrationAvailable(hf_adc_atten_tattenuation)constnoexcept;hf_adc_err_tRawToVoltage(hf_u32_traw_count,hf_adc_atten_tattenuation,hf_u32_t&voltage_mv)noexcept;// Filter operationshf_adc_err_tConfigureFilter(consthf_adc_filter_config_t&filter_config)noexcept;hf_adc_err_tSetFilterEnabled(hf_u8_tfilter_id,boolenabled)noexcept;// Monitor operationshf_adc_err_tConfigureMonitor(consthf_adc_monitor_config_t&monitor_config)noexcept;hf_adc_err_tSetMonitorCallback(hf_u8_tmonitor_id,hf_adc_monitor_callback_tcallback,void*user_data=nullptr)noexcept;hf_adc_err_tSetMonitorEnabled(hf_u8_tmonitor_id,boolenabled)noexcept;// Diagnosticshf_adc_err_tGetStatistics(hf_adc_statistics_t&statistics)noexceptoverride;hf_adc_err_tGetDiagnostics(hf_adc_diagnostics_t&diagnostics)noexceptoverride;hf_adc_err_tResetStatistics()noexceptoverride;};
Configuration Structures
ADC Unit Configuration
1
2
3
4
5
6
7
8
structhf_adc_unit_config_t{uint8_tunit_id;// ADC unit ID (0 for ADC1, 1 for ADC2)hf_adc_mode_tmode;// Operating mode (ONESHOT/CONTINUOUS)hf_adc_bitwidth_tbit_width;// ADC resolutionhf_adc_channel_config_tchannel_configs[7];// Channel configurationshf_adc_continuous_config_tcontinuous_config;// Continuous mode settingshf_adc_calibration_config_tcalibration_config;// Calibration settings};
Channel Configuration
1
2
3
4
5
6
structhf_adc_channel_config_t{hf_channel_id_tchannel_id;// Channel ID (0-6 for ESP32-C6)hf_adc_atten_tattenuation;// Input attenuation levelhf_adc_bitwidth_tbitwidth;// Resolution for this channelboolenabled;// Channel enable flag};
Continuous Mode Configuration
1
2
3
4
5
6
structhf_adc_continuous_config_t{uint32_tsample_freq_hz;// Sampling frequency (10Hz - 100kHz)uint32_tsamples_per_frame;// Samples per frame per channel (64-1024)uint32_tmax_store_frames;// Maximum frames to store (1-8)boolflush_pool;// Flush pool flag};
// Global variables for continuous modestaticQueueHandle_tadc_queue;staticvolatilebooldata_ready=false;// ISR-safe callback functionbooladc_continuous_callback(consthf_adc_continuous_data_t*data,void*user_data){// Signal that new data is availabledata_ready=true;// Send notification to processing taskBaseType_thigher_priority_task_woken=pdFALSE;xQueueSendFromISR(adc_queue,&data->conversion_count,&higher_priority_task_woken);returnhigher_priority_task_woken==pdTRUE;}// Configure continuous modehf_adc_unit_config_tconfig={};config.unit_id=0;config.mode=hf_adc_mode_t::CONTINUOUS;config.continuous_config.sample_freq_hz=1000;// 1kHz samplingconfig.continuous_config.samples_per_frame=64;// 64 samples per frameconfig.continuous_config.max_store_frames=4;// 4 frame buffer// Enable channels for continuous samplingconfig.channel_configs[0].enabled=true;config.channel_configs[1].enabled=true;EspAdcadc(config);adc.EnsureInitialized();// Configure continuous mode and set callbackadc.ConfigureContinuous(config.continuous_config);adc.SetContinuousCallback(adc_continuous_callback,nullptr);// Start continuous samplingadc.StartContinuous();// Process data in main loop (have enough buffer size)uint8_tbuffer[256];uint32_tbytes_read;while(true){if(data_ready){data_ready=false;// Read latest data with zero timeout (non-blocking)hf_adc_err_tresult=adc.ReadContinuousData(buffer,sizeof(buffer),bytes_read,0);if(result==hf_adc_err_t::ADC_SUCCESS){// Process the data bufferprocess_adc_data(buffer,bytes_read);}}vTaskDelay(pdMS_TO_TICKS(10));}// Stop continuous modeadc.StopContinuous();
// Initialize calibration for specific attenuationhf_adc_err_tresult=adc.InitializeCalibration(hf_adc_atten_t::ATTEN_DB_12);if(result==hf_adc_err_t::ADC_SUCCESS){printf("Calibration initialized successfully\n");}else{printf("Calibration not available, using linear conversion\n");}// Check calibration availabilityif(adc.IsCalibrationAvailable(hf_adc_atten_t::ATTEN_DB_12)){// Read raw value and convert using calibrationuint32_traw_value;adc.ReadSingleRaw(0,raw_value);uint32_tcalibrated_voltage_mv;result=adc.RawToVoltage(raw_value,hf_adc_atten_t::ATTEN_DB_12,calibrated_voltage_mv);if(result==hf_adc_err_t::ADC_SUCCESS){printf("Calibrated voltage: %u mV\n",calibrated_voltage_mv);}}
ESP32 Variant Specifications
ESP32-C6
ADC Units: 1 (ADC1)
Channels: 7 (0-6)
Resolution: 12-bit (4096 levels)
Sampling Rate: 10 Hz - 100 kHz
Input Range: 0-3.3V (with 12dB attenuation)
Filters: 2 IIR filters
Monitors: 2 threshold monitors
ESP32 Classic
ADC Units: 2 (ADC1, ADC2)
Channels: 8 per unit (0-7)
Resolution: 12-bit (4096 levels)
Sampling Rate: 10 Hz - 200 kHz
Input Range: 0-3.3V (with 12dB attenuation)
Filters: 2 IIR filters
Monitors: 2 threshold monitors
Attenuation Levels
Attenuation
Input Range
Use Case
|โโโโ-|โโโโ-|โโโ-|
0dB
0-0.95V
Low voltage sensors
2.5dB
0-1.32V
1.2V logic levels
6dB
0-1.98V
1.8V logic levels
12dB
0-3.3V
Full voltage range
Error Handling
The EspAdc class provides comprehensive error reporting through the hf_adc_err_t enumeration:
ADC_SUCCESS - Operation completed successfully
ADC_ERR_NOT_INITIALIZED - ADC not initialized
ADC_ERR_INVALID_CHANNEL - Invalid channel ID
ADC_ERR_CHANNEL_NOT_ENABLED - Channel not enabled
ADC_ERR_CALIBRATION - Calibration error
ADC_ERR_TIMEOUT - Operation timeout
ADC_ERR_BUSY - Resource busy
ADC_ERR_HARDWARE_FAILURE - Hardware failure
Performance Considerations
One-Shot Mode: ~50ยตs per conversion (including calibration)
Continuous Mode: Sustained sampling up to maximum frequency
Calibration: Improves accuracy by ยฑ10mV typically
Filtering: Reduces noise at the cost of response time
Multi-Channel: Round-robin sampling in continuous mode
Thread Safety
The EspAdc class uses mutex protection for thread-safe operation.
Multiple threads can safely call ADC methods simultaneously.