Analog to Digital Converter (ADC) Oneshot Mode Driver
Introduction
The Analog to Digital Converter is an on-chip sensor which is able to measure analog signals from dedicated analog IO pads.
The ADC on ESP32-C3 can be used in scenario(s) like:
- Generate one-shot ADC conversion result 
- Generate continuous ADC conversion results 
This guide will introduce ADC oneshot mode conversion.
Functional Overview
The following sections of this document cover the typical steps to install and operate an ADC:
- Resource Allocation - covers which parameters should be set up to get an ADC handle and how to recycle the resources when ADC finishes working. 
- Unit Configuration - covers the parameters that should be set up to configure the ADC unit, so as to get ADC conversion raw result. 
- Read Conversion Result - covers how to get ADC conversion raw result. 
- Hardware Limitations - describes the ADC related hardware limitations. 
- Power Management - covers power management related. 
- IRAM Safe - describes tips on how to read ADC conversion raw result when cache is disabled. 
- Thread Safety - lists which APIs are guaranteed to be thread safe by the driver. 
- Kconfig Options - lists the supported Kconfig options that can be used to make a different effect on driver behavior. 
Resource Allocation
The ADC oneshot mode driver is implemented based on ESP32-C3 SAR ADC module. Different ESP chips might have different number of independent ADCs. From oneshot mode driver’s point of view, an ADC instance is represented by adc_oneshot_unit_handle_t.
To install an ADC instance, set up the required initial configuration structure adc_oneshot_unit_init_cfg_t:
- adc_oneshot_unit_init_cfg_t::unit_idselects the ADC. Please refer to the datasheet to know dedicated analog IOs for this ADC.
- adc_oneshot_unit_init_cfg_t::ulp_modesets if the ADC will be working under super low power mode.
After setting up the initial configurations for the ADC, call adc_oneshot_new_unit() with the prepared adc_oneshot_unit_init_cfg_t. This function will return an ADC unit handle, if the allocation is successful.
This function may fail due to various errors such as invalid argumemts, insufficient memory, etc. Specifically, when the to-be-allocated ADC instance is registered already, this function will return ESP_ERR_NOT_FOUND error. Number of available ADC(s) is recorded by SOC_ADC_PERIPH_NUM.
If a previously created ADC instance is no loger required, you should recycle the ADC instance by calling adc_oneshot_del_unit(), related hardware and software resources will be recycled as well.
Create an ADC Unit Handle under Normal Oneshot Mode
adc_oneshot_unit_handle_t adc1_handle;
adc_oneshot_unit_init_cfg_t init_config1 = {
    .unit_id = ADC_UNIT_1,
    .ulp_mode = ADC_ULP_MODE_DISABLE,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
Recycle the ADC Unit
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));
Unit Configuration
After an ADC instance is created, set up the adc_oneshot_chan_cfg_t to configure ADC IO to measure analog signal:
- adc_oneshot_chan_cfg_t::atten, ADC attenuation. Refer to the On-Chip Sensor chapter in TRM.
- adc_oneshot_chan_cfg_t::channel, the IO corresponding ADC channel number. See below note.
- adc_oneshot_chan_cfg_t::bitwidth, the bitwidth of the raw conversion result.
备注
For the IO corresponding ADC channel number. Check datasheet to know the ADC IOs.
On the other hand, adc_continuous_io_to_channel() and adc_continuous_channel_to_io() can be used to know the ADC channels and ADC IOs.
To make these settings take effect, call adc_oneshot_config_channel() with above configuration structure. Especially, this adc_oneshot_config_channel() can be called multiple times to configure different ADC channels. Drvier will save these per channel configurations internally.
Configure Two ADC Channels
adc_oneshot_chan_cfg_t config = {
    .channel = EXAMPLE_ADC1_CHAN0,
    .bitwidth = ADC_BITWIDTH_DEFAULT,
    .atten = ADC_ATTEN_DB_11,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, &config));
config.channel = EXAMPLE_ADC1_CHAN1;
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, &config));
Read Conversion Result
After above configurations, the ADC is ready to measure the analog siganl(s) from the configured ADC channel(s). Call adc_oneshot_read() to get the conversion raw result of an ADC channel.
- adc_oneshot_read()is safer. ADC(s) are shared by some other drivers / peripherals, see Hardware Limitations. This function takes some mutexes, to avoid concurrent hardware usage. Therefore, this function should not be used in an ISR context. This function may fail when the ADC is in use by other drivers / peripherals, and return- ESP_ERR_TIMEOUT. Under this condition, the ADC raw result is invalid.
These two functions will both fail due to invalid arguments.
The ADC conversion results read from these two functions are raw data. To calculate the voltage based on the ADC raw results, this formula can be used:
Vout = Dout * Vmax / Dmax       (1)
where:
| Vout | Digital output result, standing for the voltage. | 
| Dout | ADC raw digital reading result. | 
| Vmax | Maximum measurable input analog voltage, this is related to the ADC attenuation, please refer to the On-Chip Sensor chapter in TRM. | 
| Dmax | Maximum of the output ADC raw digital reading result, which is 2^bitwidth, where bitwidth is the :cpp:member::adc_oneshot_chan_cfg_t:bitwidth configured before. | 
To do further calbration to convert the ADC raw result to voltage in mV, please refer to calibration doc Analog to Digital Converter (ADC) Calibration Driver.
Read Raw Result
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0][0]));
ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, adc_raw[0][0]);
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN1, &adc_raw[0][1]));
ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN1, adc_raw[0][1]);
Hardware Limitations
- Random Number Generator uses ADC as a input source. When ADC - adc_oneshot_read()works, the random number generated from RNG will be less random.
- A specific ADC unit can only work under one operating mode at any one time, either Continuous Mode or Oneshot Mode. - adc_oneshot_read()has provided the protection.
- ADC2 oneshot mode is no longer supported, due to hardware limitation. The results are not stable. This issue can be found in ESP32C3 Errata <https://www.espressif.com/sites/default/files/documentation/esp32-c3_errata_en.pdf>. For compatibility, you can enable CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 to force use ADC2. 
Power Management
When power management is enabled (i.e. CONFIG_PM_ENABLE is on), the system clock frequency may be adjusted when the system is in an idle state. However, the ADC oneshot mode driver works in a polling routine, the adc_oneshot_read() will poll the CPU until the function returns. During this period of time, the task in which ADC oneshot mode driver resides won’t be blocked. Therefore the clock frequency is stable when reading.
IRAM Safe
By default, all the ADC oneshot mode driver APIs are not supposed to be run when the Cache is disabled (Cache may be disabled due to many reasons, such as Flash writing/erasing, OTA, etc.). If these APIs executes when the Cache is disabled, you will probably see errors like Illegal Instruction or Load/Store Prohibited.
Thread Safety
Above functions are guaranteed to be thread safe. Therefore, you can call them from different RTOS tasks without protection by extra locks.
- adc_oneshot_del_unit()is not thread safe. Besides, concurrently calling this function may result in thread-safe APIs fail.
Kconfig Options
- CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM controls where to place the ADC fast read function (IRAM or Flash), see IRAM Safe for more details. 
Application Examples
- ADC oneshot mode example: peripherals/adc/oneshot_read. 
API Reference
Header File
Structures
- 
struct adc_digi_pattern_config_t
- ADC digital controller pattern configuration. 
- 
struct adc_digi_output_data_t
- ADC digital controller (DMA mode) output data format. Used to analyze the acquired ADC (DMA) data. - Public Members - 
uint32_t data
- ADC real output data info. Resolution: 12 bit. 
 - 
uint32_t reserved12
- Reserved12. 
 - 
uint32_t channel
- ADC channel index info. If (channel < ADC_CHANNEL_MAX), The data is valid. If (channel > ADC_CHANNEL_MAX), The data is invalid. 
 - 
uint32_t unit
- ADC unit index info. 0: ADC1; 1: ADC2. 
 - 
uint32_t reserved17_31
- Reserved17. 
 - 
struct adc_digi_output_data_t::[anonymous]::[anonymous] type2
- When the configured output format is 12bit. 
 - 
uint32_t val
- Raw data value 
 
- 
uint32_t data
Enumerations
- 
enum adc_unit_t
- ADC unit. - Values: - 
enumerator ADC_UNIT_1
- SAR ADC 1. 
 - 
enumerator ADC_UNIT_2
- SAR ADC 2. 
 
- 
enumerator ADC_UNIT_1
- 
enum adc_channel_t
- ADC channels. - Values: - 
enumerator ADC_CHANNEL_0
- ADC channel. 
 - 
enumerator ADC_CHANNEL_1
- ADC channel. 
 - 
enumerator ADC_CHANNEL_2
- ADC channel. 
 - 
enumerator ADC_CHANNEL_3
- ADC channel. 
 - 
enumerator ADC_CHANNEL_4
- ADC channel. 
 - 
enumerator ADC_CHANNEL_5
- ADC channel. 
 - 
enumerator ADC_CHANNEL_6
- ADC channel. 
 - 
enumerator ADC_CHANNEL_7
- ADC channel. 
 - 
enumerator ADC_CHANNEL_8
- ADC channel. 
 - 
enumerator ADC_CHANNEL_9
- ADC channel. 
 
- 
enumerator ADC_CHANNEL_0
- 
enum adc_atten_t
- ADC attenuation parameter. Different parameters determine the range of the ADC. - Values: - 
enumerator ADC_ATTEN_DB_0
- No input attenuation, ADC can measure up to approx. 
 - 
enumerator ADC_ATTEN_DB_2_5
- The input voltage of ADC will be attenuated extending the range of measurement by about 2.5 dB (1.33 x) 
 - 
enumerator ADC_ATTEN_DB_6
- The input voltage of ADC will be attenuated extending the range of measurement by about 6 dB (2 x) 
 - 
enumerator ADC_ATTEN_DB_11
- The input voltage of ADC will be attenuated extending the range of measurement by about 11 dB (3.55 x) 
 
- 
enumerator ADC_ATTEN_DB_0
- 
enum adc_bitwidth_t
- Values: - 
enumerator ADC_BITWIDTH_DEFAULT
- Default ADC output bits, max supported width will be selected. 
 - 
enumerator ADC_BITWIDTH_9
- ADC output width is 9Bit. 
 - 
enumerator ADC_BITWIDTH_10
- ADC output width is 10Bit. 
 - 
enumerator ADC_BITWIDTH_11
- ADC output width is 11Bit. 
 - 
enumerator ADC_BITWIDTH_12
- ADC output width is 12Bit. 
 - 
enumerator ADC_BITWIDTH_13
- ADC output width is 13Bit. 
 
- 
enumerator ADC_BITWIDTH_DEFAULT
- 
enum adc_ulp_mode_t
- Values: - 
enumerator ADC_ULP_MODE_DISABLE
- ADC ULP mode is disabled. 
 - 
enumerator ADC_ULP_MODE_FSM
- ADC is controlled by ULP FSM. 
 - 
enumerator ADC_ULP_MODE_RISCV
- ADC is controlled by ULP RISCV. 
 
- 
enumerator ADC_ULP_MODE_DISABLE
- 
enum adc_digi_convert_mode_t
- ADC digital controller (DMA mode) work mode. - Values: - 
enumerator ADC_CONV_SINGLE_UNIT_1
- Only use ADC1 for conversion. 
 - 
enumerator ADC_CONV_SINGLE_UNIT_2
- Only use ADC2 for conversion. 
 - 
enumerator ADC_CONV_BOTH_UNIT
- Use Both ADC1 and ADC2 for conversion simultaneously. 
 - 
enumerator ADC_CONV_ALTER_UNIT
- Use both ADC1 and ADC2 for conversion by turn. e.g. ADC1 -> ADC2 -> ADC1 -> ADC2 ….. 
 
- 
enumerator ADC_CONV_SINGLE_UNIT_1
Header File
Functions
- 
esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, adc_oneshot_unit_handle_t *ret_unit)
- Create a handle to a specific ADC unit. - 备注 - This API is thread-safe. For more details, see ADC programming guide - 参数
- init_config – [in] Driver initial configurations 
- ret_unit – [out] ADC unit handle 
 
- 返回
- ESP_OK: On success 
- ESP_ERR_INVALID_ARG: Invalid arguments 
- ESP_ERR_NO_MEM: No memory 
- ESP_ERR_NOT_FOUND: The ADC peripheral to be claimed is already in use 
 
 
- 
esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_channel_t channel, const adc_oneshot_chan_cfg_t *config)
- Set ADC oneshot mode required configurations. - 备注 - This API is thread-safe. For more details, see ADC programming guide - 参数
- handle – [in] ADC handle 
- channel – [in] ADC channel to be configured 
- config – [in] ADC configurations 
 
- 返回
- ESP_OK: On success 
- ESP_ERR_INVALID_ARG: Invalid arguments 
 
 
- 
esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw)
- Get one ADC conversion raw result. - 备注 - This API is thread-safe. For more details, see ADC programming guide - 备注 - This API should NOT be called in an ISR context - 参数
- handle – [in] ADC handle 
- chan – [in] ADC channel 
- out_raw – [out] ADC conversion raw result 
 
- 返回
- ESP_OK: On success 
- ESP_ERR_INVALID_ARG: Invalid arguments 
- ESP_ERR_TIMEOUT: Timeout, the ADC result is invalid 
 
 
- 
esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle)
- Delete the ADC unit handle. - 备注 - This API is thread-safe. For more details, see ADC programming guide - 参数
- handle – [in] ADC handle 
- 返回
- ESP_OK: On success 
- ESP_ERR_INVALID_ARG: Invalid arguments 
- ESP_ERR_NOT_FOUND: The ADC peripheral to be disclaimed isn’t in use 
 
 
- 
esp_err_t adc_oneshot_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *channel)
- Get ADC channel from the given GPIO number. - 参数
- io_num – [in] GPIO number 
- unit_id – [out] ADC unit 
- channel – [out] ADC channel 
 
- 返回
- ESP_OK: On success 
- ESP_ERR_INVALID_ARG: Invalid argument 
- ESP_ERR_NOT_FOUND: The IO is not a valid ADC pad 
 
 
- 
esp_err_t adc_oneshot_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num)
- Get GPIO number from the given ADC channel. - 参数
- unit_id – [in] ADC unit 
- channel – [in] ADC channel 
- io_num – [out] GPIO number 
- - – ESP_OK: On success - ESP_ERR_INVALID_ARG: Invalid argument 
 
 
 
Structures
- 
struct adc_oneshot_unit_init_cfg_t
- ADC oneshot driver initial configurations. - Public Members - 
adc_unit_t unit_id
- ADC unit. 
 - 
adc_ulp_mode_t ulp_mode
- ADC controlled by ULP, see - adc_ulp_mode_t
 
- 
adc_unit_t unit_id
- 
struct adc_oneshot_chan_cfg_t
- ADC channel configurations. - Public Members - 
adc_atten_t atten
- ADC attenuation. 
 - 
adc_bitwidth_t bitwidth
- ADC conversion result bits. 
 
- 
adc_atten_t atten
Type Definitions
- 
typedef struct adc_oneshot_unit_ctx_t *adc_oneshot_unit_handle_t
- Type of ADC unit handle for oneshot mode.