mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-05 12:25:03 +02:00
esp_adc: new esp_adc component and adc drivers
This commit is contained in:
@@ -1,463 +0,0 @@
|
||||
Analog to Digital Converter (ADC)
|
||||
=================================
|
||||
|
||||
{IDF_TARGET_ADC1_CH0: default="GPIO 0", esp32="GPIO 36"}
|
||||
{IDF_TARGET_ADC2_CH7: default="GPIO 0", esp32="GPIO 27"}
|
||||
|
||||
|
||||
ADC Channels
|
||||
------------
|
||||
|
||||
{IDF_TARGET_ADC_TOTAL_CHAN:default="20", esp32="18", esp32s2="20", esp32c3="6"}
|
||||
{IDF_TARGET_ADC_UNIT_NUM:default="2"}
|
||||
|
||||
The {IDF_TARGET_NAME} integrates {IDF_TARGET_ADC_UNIT_NUM} SAR (`Successive Approximation Register <https://en.wikipedia.org/wiki/Successive_approximation_ADC>`_) ADCs, supporting a total of {IDF_TARGET_ADC_TOTAL_CHAN} measurement channels (analog enabled pins).
|
||||
|
||||
These channels are supported:
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
ADC1:
|
||||
- 8 channels: GPIO32 - GPIO39
|
||||
ADC2:
|
||||
- 10 channels: GPIO0, GPIO2, GPIO4, GPIO12 - GPIO15, GOIO25 - GPIO27
|
||||
|
||||
.. only:: esp32s2 or esp32s3
|
||||
|
||||
ADC1:
|
||||
- 10 channels: GPIO1 - GPIO10
|
||||
ADC2:
|
||||
- 10 channels: GPIO11 - GPIO20
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
ADC1:
|
||||
- 5 channels: GPIO0 - GPIO4
|
||||
ADC2:
|
||||
- 1 channels: GPIO5
|
||||
|
||||
|
||||
.. _adc_attenuation:
|
||||
|
||||
ADC Attenuation
|
||||
---------------
|
||||
{IDF_TARGET_ADC_V_MIN_ATTEN0:default="0", esp32="100"}
|
||||
{IDF_TARGET_ADC_V_MAX_ATTEN0:default="950", esp32s2="750", esp32c3="750", esp32s3="950"}
|
||||
|
||||
{IDF_TARGET_ADC_V_MIN_ATTEN1:default="0", esp32="100"}
|
||||
{IDF_TARGET_ADC_V_MAX_ATTEN1:default="1250", esp32s2="1050", esp32c3="1050", esp32s3="1250"}
|
||||
|
||||
{IDF_TARGET_ADC_V_MIN_ATTEN2:default="0", esp32="150"}
|
||||
{IDF_TARGET_ADC_V_MAX_ATTEN2:default="1750", esp32s2="1300", esp32c3="1300", esp32s3="1750"}
|
||||
|
||||
{IDF_TARGET_ADC_V_MIN_ATTEN3:default="0", esp32="150"}
|
||||
{IDF_TARGET_ADC_V_MAX_ATTEN3:default="2450", esp32s2="2500", esp32c3="2500", esp32s3="3100"}
|
||||
|
||||
|
||||
Vref is the reference voltage used internally by {IDF_TARGET_NAME} ADCs for measuring the input voltage. The {IDF_TARGET_NAME} ADCs can measure analog voltages from 0 V to Vref. Among different chips, the Vref varies, the median is 1.1 V. In order to convert voltages larger than Vref, input voltages can be attenuated before being input to the ADCs. There are 4 available attenuation options, the higher the attenuation is, the higher the measurable input voltage could be.
|
||||
|
||||
===================== =========================================================================================================
|
||||
Attenuation Measurable input voltage range
|
||||
===================== =========================================================================================================
|
||||
``ADC_ATTEN_DB_0`` {IDF_TARGET_ADC_V_MIN_ATTEN0} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN0} mV
|
||||
``ADC_ATTEN_DB_2_5`` {IDF_TARGET_ADC_V_MIN_ATTEN1} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN1} mV
|
||||
``ADC_ATTEN_DB_6`` {IDF_TARGET_ADC_V_MIN_ATTEN2} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN2} mV
|
||||
``ADC_ATTEN_DB_11`` {IDF_TARGET_ADC_V_MIN_ATTEN3} mV ~ {IDF_TARGET_ADC_V_MAX_ATTEN3} mV
|
||||
===================== =========================================================================================================
|
||||
|
||||
|
||||
.. _adc_conversion:
|
||||
|
||||
ADC Conversion
|
||||
--------------
|
||||
|
||||
{IDF_TARGET_ADC_SINGLE_MAX_WIDTH:default="12", esp32s2="13}
|
||||
{IDF_TARGET_ADC_SINGLE_RAW_MAX:default="4095", esp32s2="8191"}
|
||||
{IDF_TARGET_ADC_CONTINUOUS_MAX_WIDTH:default="12", esp32s3="13}
|
||||
{IDF_TARGET_ADC_CONTINUOUS_RAW_MAX:default="4095", esp32s3="8191"}
|
||||
|
||||
|
||||
An ADC conversion is to convert the input analog voltage to a digital value. The ADC conversion results provided by the ADC driver APIs are raw data. Resolution of {IDF_TARGET_NAME} ADC raw results under Single Read mode is {IDF_TARGET_ADC_SINGLE_MAX_WIDTH}-bit.
|
||||
|
||||
- :cpp:func:`adc1_get_raw`
|
||||
- :cpp:func:`adc2_get_raw`
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
- :cpp:func:`adc_digi_read_bytes`
|
||||
|
||||
To calculate the voltage based on the ADC raw results, this formula can be used:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
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, see :ref:`adc_attenuation`.
|
||||
Dmax Maximum of the output ADC raw digital reading result, which is {IDF_TARGET_ADC_SINGLE_RAW_MAX} under Single Read mode, {IDF_TARGET_ADC_CONTINUOUS_RAW_MAX} under Continuous Read mode.
|
||||
====== =============================================================
|
||||
|
||||
For boards with eFuse ADC calibration bits, :cpp:func:`esp_adc_cal_raw_to_voltage` can be used to get the calibrated conversion results. These results stand for the actual voltage (in mV). No need to transform these data via the formula (1).
|
||||
If ADC calibration APIs are used on boards without eFuse ADC calibration bits, warnings will be generated. See :ref:`adc_calibration`.
|
||||
|
||||
|
||||
.. _adc_limitations:
|
||||
|
||||
ADC Limitations
|
||||
---------------
|
||||
|
||||
.. note::
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
- Some of the ADC2 pins are used as strapping pins (GPIO 0, 2, 15) thus cannot be used freely. Such is the case in the following official Development Kits:
|
||||
- ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits.
|
||||
- ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes.
|
||||
- Since the ADC2 module is also used by the Wi-Fi, only one of them could get the preemption when using together, which means the :cpp:func:`adc2_get_raw` may get blocked until Wi-Fi stops, and vice versa.
|
||||
|
||||
.. only:: not esp32
|
||||
|
||||
- Since the ADC2 module is also used by the Wi-Fi, reading operation of :cpp:func:`adc2_get_raw` may fail between :cpp:func:`esp_wifi_start()` and :cpp:func:`esp_wifi_stop()`. Use the return code to see whether the reading is successful.
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
- A specific ADC module can only work under one operating mode at any one time, either Continuous Read Mode or Single Read Mode.
|
||||
- ADC1 and ADC2 can not work under Singel Read Mode simultaneously. One of them will get blocked until another one finishes.
|
||||
- For continuous (DMA) read mode, the ADC sampling frequency (the ``sample_freq_hz`` member of :cpp:type:`adc_digi_config_t`) should be within ``SOC_ADC_SAMPLE_FREQ_THRES_LOW`` and ``SOC_ADC_SAMPLE_FREQ_THRES_HIGH``.
|
||||
|
||||
Driver Usage
|
||||
------------
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
Each ADC unit supports two work modes, ADC single read mode and ADC continuous (DMA) mode. ADC single read mode is suitable for low-frequency sampling operations. ADC continuous (DMA) read mode is suitable for high-frequency continuous sampling actions.
|
||||
|
||||
.. only:: not esp32c3
|
||||
|
||||
Both of the ADC units support single read mode, which is suitable for low-frequency sampling operations.
|
||||
|
||||
.. note::
|
||||
|
||||
ADC readings from a pin not connected to any signal are random.
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
ADC Continuous (DMA) Read mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To use the ADC continuous read mode driver, execute the following steps:
|
||||
|
||||
1. Initialize the ADC driver by calling the function :cpp:func:`adc_digi_initialize`.
|
||||
2. Initialize the ADC controller by calling the function :cpp:func:`adc_digi_controller_config`.
|
||||
3. Start the ADC continuous reading by calling the function :cpp:func:`adc_digi_start`.
|
||||
4. After starting the ADC, you can get the ADC reading result by calling the function :cpp:func:`adc_digi_read_bytes`. Before stopping the ADC (by calling :cpp:func:`adc_digi_stop`), the driver will keep converting the analog data to digital data.
|
||||
5. Stop the ADC reading by calling the function :cpp:func:`adc_digi_stop`.
|
||||
6. Deinitialize the ADC driver by calling the function :cpp:func:`adc_digi_deinitialize`.
|
||||
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
The code example for using ADC continuous (DMA) read mode can be found in the :example:`peripherals/adc/dma_read` directory of ESP-IDF examples.
|
||||
|
||||
.. note:: See :ref:`adc_limitations` for the limitation of using ADC continuous (DMA) read mode.
|
||||
|
||||
ADC Single Read mode
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ADC should be configured before reading is taken.
|
||||
|
||||
- For ADC1, configure desired precision and attenuation by calling functions :cpp:func:`adc1_config_width` and :cpp:func:`adc1_config_channel_atten`.
|
||||
- For ADC2, configure the attenuation by :cpp:func:`adc2_config_channel_atten`. The reading width of ADC2 is configured every time you take the reading.
|
||||
|
||||
Attenuation configuration is done per channel, see :cpp:type:`adc1_channel_t` and :cpp:type:`adc2_channel_t`, set as a parameter of above functions.
|
||||
|
||||
Then it is possible to read ADC conversion result with :cpp:func:`adc1_get_raw` and :cpp:func:`adc2_get_raw`. Reading width of ADC2 should be set as a parameter of :cpp:func:`adc2_get_raw` instead of in the configuration functions.
|
||||
|
||||
Single Read mode ADC example can be found in :example:`peripherals/adc/single_read` directory of ESP-IDF examples.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
It is also possible to read the internal hall effect sensor via ADC1 by calling dedicated function :cpp:func:`hall_sensor_read`. Note that even the hall sensor is internal to ESP32, reading from it uses channels 0 and 3 of ADC1 (GPIO 36 and 39). Do not connect anything else to these pins and do not change their configuration. Otherwise it may affect the measurement of low value signal from the sensor.
|
||||
|
||||
.. only:: SOC_ULP_SUPPORTED
|
||||
|
||||
This API provides convenient way to configure ADC1 for reading from :doc:`ULP <../../api-reference/system/ulp>`. To do so, call function :cpp:func:`adc1_ulp_enable` and then set precision and attenuation as discussed above.
|
||||
|
||||
.. only:: esp32 or esp32s2
|
||||
|
||||
There is another specific function :cpp:func:`adc_vref_to_gpio` used to route internal reference voltage to a GPIO pin. It comes handy to calibrate ADC reading and this is discussed in section :ref:`adc_calibration`.
|
||||
|
||||
|
||||
.. note:: See :ref:`adc_limitations` for the limitation of using ADC single read mode.
|
||||
|
||||
|
||||
Minimizing Noise
|
||||
----------------
|
||||
|
||||
The {IDF_TARGET_NAME} ADC can be sensitive to noise leading to large discrepancies in ADC readings. Depending on the usage scenario, users may connect a bypass capacitor (e.g. a 100 nF ceramic capacitor) to the ADC input pad in use, to minimize noise. Besides, multisampling may also be used to further mitigate the effects of noise.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-noise-graph.jpg
|
||||
:align: center
|
||||
:alt: ADC noise mitigation
|
||||
|
||||
Graph illustrating noise mitigation using capacitor and multisampling of 64 samples.
|
||||
|
||||
|
||||
.. _adc_calibration:
|
||||
|
||||
ADC Calibration
|
||||
---------------
|
||||
|
||||
.. only:: esp32 or esp32s2
|
||||
|
||||
The :component_file:`esp_adc_cal/include/esp_adc_cal.h` API provides functions to correct for differences in measured voltages caused by variation of ADC reference voltages (Vref) between chips. Per design the ADC reference voltage is 1100 mV, however the true reference voltage can range from 1000 mV to 1200 mV amongst different {IDF_TARGET_NAME}s.
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-vref-graph.jpg
|
||||
:align: center
|
||||
:alt: ADC reference voltage comparison
|
||||
|
||||
Graph illustrating effect of differing reference voltages on the ADC voltage curve.
|
||||
|
||||
Correcting ADC readings using this API involves characterizing one of the ADCs at a given attenuation to obtain a characteristics curve (ADC-Voltage curve) that takes into account the difference in ADC reference voltage. The characteristics curve is in the form of ``y = coeff_a * x + coeff_b`` and is used to convert ADC readings to voltages in mV. Calculation of the characteristics curve is based on calibration values which can be stored in eFuse or provided by the user.
|
||||
|
||||
Calibration Values
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
{IDF_TARGET_ADC_CALI_SOURCE: default="3", esp32="3", esp32s2="1"}
|
||||
|
||||
Calibration values are used to generate characteristic curves that account for the variation of ADC reference voltage of a particular {IDF_TARGET_NAME} chip. There are currently {IDF_TARGET_ADC_CALI_SOURCE} source(s) of calibration values on {IDF_TARGET_NAME}. The availability of these calibration values will depend on the type and production date of the {IDF_TARGET_NAME} chip/module.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
* **Two Point** values represent each of the ADCs’ readings at 150 mV and 850 mV. To obtain more accurate calibration results these values should be measured by user and burned into eFuse ``BLOCK3``.
|
||||
|
||||
* **eFuse Vref** represents the true ADC reference voltage. This value is measured and burned into eFuse ``BLOCK0`` during factory calibration.
|
||||
|
||||
* **Default Vref** is an estimate of the ADC reference voltage provided by the user as a parameter during characterization. If Two Point or eFuse Vref values are unavailable, **Default Vref** will be used.
|
||||
|
||||
Individual measurement and burning of the **eFuse Vref** has been applied to ESP32-D0WD and ESP32-D0WDQ6 chips produced on/after the 1st week of 2018. Such chips may be recognized by date codes on/later than 012018 (see Line 4 on figure below).
|
||||
|
||||
.. figure:: ../../../_static/chip_surface_marking.png
|
||||
:align: center
|
||||
:alt: ESP32 Chip Surface Marking
|
||||
|
||||
ESP32 Chip Surface Marking
|
||||
|
||||
If you would like to purchase chips or modules with calibration, double check with distributor or Espressif (sales@espressif.com) directly.
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
If you are unable to check the date code (i.e. the chip may be enclosed inside a canned module, etc.), you can still verify if **eFuse Vref** is present by running the `espefuse.py <https://docs.espressif.com/projects/esptool/en/latest/{IDF_TARGET_PATH_NAME}/espefuse/index.html>`_ tool with ``adc_info`` parameter ::
|
||||
|
||||
$IDF_PATH/components/esptool_py/esptool/espefuse.py --port /dev/ttyUSB0 adc_info
|
||||
|
||||
Replace ``/dev/ttyUSB0`` with {IDF_TARGET_NAME} board's port name.
|
||||
|
||||
A chip that has specific **eFuse Vref** value programmed (in this case 1093 mV) will be reported as follows::
|
||||
|
||||
ADC VRef calibration: 1093 mV
|
||||
|
||||
In another example below the **eFuse Vref** is not programmed::
|
||||
|
||||
ADC VRef calibration: None (1100 mV nominal)
|
||||
|
||||
For a chip with two point calibration the message will look similar to::
|
||||
|
||||
ADC VRef calibration: 1149 mV
|
||||
ADC readings stored in efuse BLK3:
|
||||
ADC1 Low reading (150 mV): 306
|
||||
ADC1 High reading (850 mV): 3153
|
||||
ADC2 Low reading (150 mV): 389
|
||||
ADC2 High reading (850 mV): 3206
|
||||
|
||||
.. only:: esp32s2
|
||||
|
||||
* **eFuse Two Point** values calibrates the ADC output at two different voltages. This value is measured and burned into eFuse ``BLOCK0`` during factory calibration on newly manufactured ESP32-S2 chips and modules. If you would like to purchase chips or modules with calibration, double check with distributor or Espressif (sales@espressif.com) directly.
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
You can verify if **eFuse Two Point** is present by running the `espefuse.py <https://docs.espressif.com/projects/esptool/en/latest/{IDF_TARGET_PATH_NAME}/espefuse/index.html>`_ tool with ``adc_info`` parameter ::
|
||||
|
||||
$IDF_PATH/components/esptool_py/esptool/espefuse.py --port /dev/ttyUSB0 adc_info
|
||||
|
||||
Replace ``/dev/ttyUSB0`` with {IDF_TARGET_NAME} board's port name.
|
||||
|
||||
|
||||
|
||||
.. only:: esp32c3 or esp32s3
|
||||
|
||||
{IDF_TARGET_NAME} ADC Calibration contains 2 steps: Hardware Calibration and Software Calibration.
|
||||
|
||||
|
||||
Hardware Calibration
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Based on series of comparisons with the reference voltage, {IDF_TARGET_NAME} ADC determines each bit of the output digital result. Per design the {IDF_TARGET_NAME} ADC reference voltage is 1100 mV, however the true reference voltage can range from 1000 mV to 1200 mV among different chips. To minimize this difference, hardware calibration is introduced.
|
||||
|
||||
Hardware calibration contains 2 steps:
|
||||
|
||||
1. Set an auto-calibration parameter of bandgap voltage reference. In this way, the difference mentioned above can be minimized.
|
||||
2. Correct the offset of the ADC Vin-Dout characteristics. ADC characteristics is generally a function: f(x) = A * x + B, where B is the offset.
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
An uncalibrated ADC characteristics is as follows:
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-uncali-raw-c3.png
|
||||
:align: center
|
||||
:alt: ADC uncalibrated conversion result
|
||||
|
||||
.. only:: esp32s3
|
||||
|
||||
An uncalibrated ADC characteristics is as follows:
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-uncali-raw-s3.png
|
||||
:align: center
|
||||
:alt: ADC uncalibrated conversion result
|
||||
|
||||
|
||||
The offset in the uncalibrated characteristics is significant. Step 2 is to correct the offset to 0.
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
After hardware calibration, the ADC characteristics would be like:
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-hw-cali-c3.png
|
||||
:align: center
|
||||
:alt: ADC conversion results after hardware calibration
|
||||
|
||||
.. only:: esp32s3
|
||||
|
||||
After hardware calibration, the ADC characteristics would be like:
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-hw-cali-s3.png
|
||||
:align: center
|
||||
:alt: ADC conversion results after hardware calibration
|
||||
|
||||
Hardware calibration is done internally by the ADC driver. The consequent results are raw data. A transformation is needed to get the final result, see :ref:`adc_conversion`.
|
||||
|
||||
|
||||
Software Calibration
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To convert ADC raw data to calibrated digital data, following steps should be followed:
|
||||
|
||||
1. Check the eFuse to know if the software calibration is supported via :cpp:func:`esp_adc_cal_check_efuse`.
|
||||
2. Calculate the ADC calibration characteristics via :cpp:func:`esp_adc_cal_characterize`. The ADC software calibration characteristics are per ADC module and per attenuation. For example, characteristics of ADC1 channel 0 under 11 dB attenuation are the same as characteristics of ADC1 channel 2 under 11 dB attenuation. But characteristics of ADC1 channel 0 under 11 dB attenuation are different with characteristics of ADC2 channel 0 under 11 dB attenuation. Also characteristics of ADC1 channel 0 under 11 dB attenuation are different with characteristics of ADC1 channel 0 under 6 dB attenuation.
|
||||
3. Get the actual voltage value via :cpp:func:`esp_adc_cal_raw_to_voltage`.
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
After software calibration, the ADC characteristics would be like:
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-all-cali-c3.png
|
||||
:align: center
|
||||
:alt: ADC conversion results after hardware calibration
|
||||
|
||||
.. only:: esp32s3
|
||||
|
||||
After software calibration, the ADC characteristics would be like:
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-all-cali-s3.png
|
||||
:align: center
|
||||
:alt: ADC conversion results after hardware calibration
|
||||
|
||||
|
||||
The results provided by the ADC calibration APIs indicate the actual voltage values. ADC software calibration example can be found in :example:`peripherals/adc/single_read` directory of ESP-IDF examples.
|
||||
|
||||
|
||||
.. only:: esp32 or esp32s2
|
||||
|
||||
Application Extensions
|
||||
----------------------
|
||||
|
||||
For a full example see esp-idf: :example:`peripherals/adc/single_read`
|
||||
|
||||
Characterizing an ADC at a particular attenuation::
|
||||
|
||||
#include "driver/adc.h"
|
||||
#include "esp_adc_cal.h"
|
||||
|
||||
...
|
||||
|
||||
//Characterize ADC at particular atten
|
||||
esp_adc_cal_characteristics_t *adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
|
||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
|
||||
//Check type of calibration value used to characterize ADC
|
||||
if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||
printf("eFuse Vref");
|
||||
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
printf("Two Point");
|
||||
} else {
|
||||
printf("Default");
|
||||
}
|
||||
|
||||
Reading an ADC then converting the reading to a voltage::
|
||||
|
||||
#include "driver/adc.h"
|
||||
#include "esp_adc_cal.h"
|
||||
|
||||
...
|
||||
uint32_t reading = adc1_get_raw(ADC1_CHANNEL_5);
|
||||
uint32_t voltage = esp_adc_cal_raw_to_voltage(reading, adc_chars);
|
||||
|
||||
Routing ADC reference voltage to GPIO, so it can be manually measured (for **Default Vref**)::
|
||||
|
||||
#include "driver/adc.h"
|
||||
|
||||
...
|
||||
|
||||
esp_err_t status = adc_vref_to_gpio(ADC_UNIT_1, GPIO_NUM_25);
|
||||
if (status == ESP_OK) {
|
||||
printf("v_ref routed to GPIO\n");
|
||||
} else {
|
||||
printf("failed to route v_ref\n");
|
||||
}
|
||||
|
||||
GPIO Lookup Macros
|
||||
------------------
|
||||
|
||||
There are macros available to specify the GPIO number of a ADC channel, or vice versa.
|
||||
e.g.
|
||||
|
||||
1. ``ADC1_CHANNEL_0_GPIO_NUM`` is the GPIO number of ADC1 channel 0.
|
||||
2. ``ADC1_GPIOn_CHANNEL`` is the ADC1 channel number of GPIO n.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
This reference covers three components:
|
||||
|
||||
* :ref:`adc-api-reference-adc-driver`
|
||||
* :ref:`adc-api-reference-adc-calibration`
|
||||
* :ref:`adc-api-reference-gpio-lookup-macros`
|
||||
|
||||
|
||||
.. _adc-api-reference-adc-driver:
|
||||
|
||||
ADC driver
|
||||
^^^^^^^^^^
|
||||
|
||||
.. include-build-file:: inc/adc.inc
|
||||
|
||||
.. include-build-file:: inc/adc_types.inc
|
||||
|
||||
.. _adc-api-reference-adc-calibration:
|
||||
|
||||
ADC Calibration
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
.. include-build-file:: inc/esp_adc_cal.inc
|
||||
|
||||
.. _adc-api-reference-gpio-lookup-macros:
|
||||
|
||||
GPIO Lookup Macros
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. include-build-file:: inc/adc_channel.inc
|
||||
@@ -0,0 +1,184 @@
|
||||
Analog to Digital Converter (ADC) Calibration Driver
|
||||
====================================================
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Based on series of comparisons with the reference voltage, {IDF_TARGET_NAME} ADC determines each bit of the output digital result. Per design the {IDF_TARGET_NAME} ADC reference voltage is 1100 mV, however the true reference voltage can range from 1000 mV to 1200 mV among different chips. This guide will introduce an ADC calibration driver to minimize this difference.
|
||||
|
||||
|
||||
Functional Overview
|
||||
-------------------
|
||||
|
||||
The following sections of this document cover the typical steps to install and use the ADC calibration driver:
|
||||
|
||||
- `Calibration Scheme Creation <#calibration-scheme-creation>`__ - covers how to create a calibration scheme handle and delete the calibration scheme handle.
|
||||
- `Calibration Configuration <#calibration-configuration>`__ - covers how to configure the calibration driver to calculate necessary characteristics used for calibration.
|
||||
- `Result Conversion <#result-conversion>`__ - convers how to convert ADC raw result to calibrated result.
|
||||
- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver.
|
||||
- `Minimize Noise <#minimize-noise>`__ - describes a general way to minimize the noise.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
- `Kconfig Options <#kconfig-options>`__ - lists the supported Kconfig options that can be used to make a different effect on driver behavior.
|
||||
|
||||
|
||||
Calibration Scheme Creation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ADC calibration driver provides ADC calibration scheme(s). From calibration driver's point of view, an ADC calibration scheme is created to an ADC calibration handle :cpp:type:`adc_cali_handle_t`.
|
||||
|
||||
:cpp:func:`adc_cali_check_scheme` can be used to know which calibration scheme is supported on the chip. For those users who are already aware of the supported scheme, this step can be skipped. Just call the corresponding function to create the scheme handle.
|
||||
|
||||
For those users who use their custom ADC calibration schemes, you could either modify this function :cpp:func:`adc_cali_check_scheme`, or just skip this step and call your custom creation function.
|
||||
|
||||
.. only:: esp32 or esp32s2
|
||||
|
||||
ADC Calibration Line Fitting Scheme
|
||||
```````````````````````````````````
|
||||
|
||||
{IDF_TARGET_NAME} supports :c:macro:`ADC_CALI_SCHEME_VER_LINE_FITTING` scheme. To create this scheme, set up :cpp:type:`adc_cali_line_fitting_config_t` first.
|
||||
|
||||
- :cpp:member:`adc_cali_line_fitting_config_t::unit_id`, the ADC that your ADC raw results are from.
|
||||
- :cpp:member:`adc_cali_line_fitting_config_t::atten`, ADC attenuation that your ADC raw results use.
|
||||
- :cpp:member:`adc_cali_line_fitting_config_t::bitwidth`, the ADC raw result bitwidth.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
There is also a configuration :cpp:member:`adc_cali_line_fitting_config_t::default_vref`. Normally this can be simply set to 0. Line Fitting scheme doesn't rely on this value. However, if the Line Fitting scheme required eFuse bits are not burnt on your board, driver will rely on this value to do the calibration.
|
||||
|
||||
You can use :cpp:func:`adc_cali_scheme_line_fitting_check_efuse` to check the eFuse bits. Normally the Line Fitting scheme eFuse value will be :c:macro:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP` or :c:macro:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF`. This means Line Fitting scheme will use calibration parameters burnt in the eFuse to do the calibration.
|
||||
|
||||
When the Line Fitting scheme eFuse value is :c:macro:`ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF`, you need to set the :cpp:member:`esp_adc_cali_line_fitting_init::default_vref`. Default vref is an estimate of the ADC reference voltage provided by the users as a parameter during calibration.
|
||||
|
||||
After setting up the configuration structure, call :cpp:func:`adc_cali_create_scheme_line_fitting` to create a Line Fitting calibration scheme handle.
|
||||
|
||||
.. only:: esp32s2
|
||||
|
||||
This function may fail due to reasons such as :c:macro:`ESP_ERR_INVALID_ARG` or :c:macro:`ESP_ERR_NO_MEM`. Especially, when the function return :c:macro:`ESP_ERR_NOT_SUPPORTED`, this means the calibration scheme required eFuse bits are not burnt on your board.
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting");
|
||||
adc_cali_line_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(&cali_config, &handle));
|
||||
|
||||
|
||||
When the ADC calibration is no longer used, please delete the calibration scheme handle by calling :cpp:func:`adc_cali_delete_scheme_line_fitting`.
|
||||
|
||||
|
||||
Delete Line Fitting Scheme
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_LOGI(TAG, "delete %s calibration scheme", "Line Fitting");
|
||||
ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle));
|
||||
|
||||
|
||||
.. only:: esp32c3 or esp32s3
|
||||
|
||||
ADC Calibration Curve Fitting Scheme
|
||||
````````````````````````````````````
|
||||
|
||||
{IDF_TARGET_NAME} supports :c:macro:`ADC_CALI_SCHEME_VER_CURVE_FITTING` scheme. To create this scheme, set up :cpp:type:`adc_cali_curve_fitting_config_t` first.
|
||||
|
||||
- :cpp:member:`adc_cali_curve_fitting_config_t::unit_id`, the ADC that your ADC raw results are from.
|
||||
- :cpp:member:`adc_cali_curve_fitting_config_t::atten`, ADC attenuation that your ADC raw results use.
|
||||
- :cpp:member:`adc_cali_curve_fitting_config_t::bitwidth`, the ADC raw result bitwidth.
|
||||
|
||||
After setting up the configuration structure, call :cpp:func:`adc_cali_create_scheme_curve_fitting` to create a Curve Fitting calibration scheme handle. This function may fail due to reasons such as :c:macro:`ESP_ERR_INVALID_ARG` or :c:macro:`ESP_ERR_NO_MEM`. Especially, when the function return :c:macro:`ESP_ERR_NOT_SUPPORTED`, this means the calibration scheme required eFuse bits are not burnt on your board.
|
||||
|
||||
Create Curve Fitting Scheme
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = unit,
|
||||
.atten = atten,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &handle));
|
||||
|
||||
|
||||
When the ADC calibration is no longer used, please delete the calibration scheme driver from the calibration handle by calling :cpp:func:`adc_cali_delete_scheme_curve_fitting`.
|
||||
|
||||
|
||||
Delete Curve Fitting Scheme
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_LOGI(TAG, "delete %s calibration scheme", "Curve Fitting");
|
||||
ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle));
|
||||
|
||||
|
||||
.. only:: esp32c2 or esp32h2
|
||||
|
||||
There is no supported calibration scheme yet.
|
||||
|
||||
.. note::
|
||||
|
||||
For users who want to use their custom calibration schemes, you could provide a creation function to create your calibration scheme handle. Check the function table `adc_cali_scheme_t` in `components/esp_adc/interface/adc_cali_interface.h` to know the ESP ADC calibration interface.
|
||||
|
||||
|
||||
Result Conversion
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
After setting up the calibration characteristics, you can call :cpp:func:`adc_cali_raw_to_voltage` to convert the ADC raw result into calibrated result. The calibrated result is in the unit of mV. This function may fail due to invalid argument. Especailly, if this function returns :c:macro:`ESP_ERR_INVALID_STATE`, this means the calibration scheme isn't created. You need to create a calibration scheme handle, use :cpp:func:`adc_cali_check_scheme` to know the supported calibration scheme. On the other hand, you could also provide a custom calibration scheme and create the handle.
|
||||
|
||||
|
||||
Get Voltage
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle, adc_raw[0][0], &voltage[0][0]));
|
||||
ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, voltage[0][0]);
|
||||
|
||||
|
||||
Thread Safety
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The factory function :cpp:func:`esp_adc_cali_new_scheme` is guaranteed to be thread safe by the driver. Therefore, you can call them from different RTOS tasks without protection by extra locks.
|
||||
|
||||
Other functions that take the :cpp:type:`adc_cali_handle_t` as the first positional parameter are not thread safe, you should avoid calling them from multiple tasks.
|
||||
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
Kconfig Options
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
- :ref:`CONFIG_ADC_CAL_EFUSE_TP_ENABLE`, disable this to decrease the code size, if you are aware of the calibration eFuse value :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP` isn't this one.
|
||||
- :ref:`CONFIG_ADC_CAL_EFUSE_VREF_ENABLE`, disable this to decrease the code size, if you are aware of the calibration eFuse value :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF` isn't this one.
|
||||
- :ref:`CONFIG_ADC_CAL_LUT_ENABLE`, disable this to decrease the code size, if you don't calibrate the ADC raw results under :c:macro:`ADC_ATTEN_DB_11`.
|
||||
|
||||
|
||||
Minimize Noise
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The {IDF_TARGET_NAME} ADC can be sensitive to noise leading to large discrepancies in ADC readings. Depending on the usage scenario, you may need to connect a bypass capacitor (e.g. a 100 nF ceramic capacitor) to the ADC input pad in use, to minimize noise. Besides, multisampling may also be used to further mitigate the effects of noise.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
.. figure:: ../../../_static/diagrams/adc/adc-noise-graph.jpg
|
||||
:align: center
|
||||
:alt: ADC noise mitigation
|
||||
|
||||
Graph illustrating noise mitigation using capacitor and multisampling of 64 samples.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
|
||||
.. include-build-file:: inc/adc_cali.inc
|
||||
.. include-build-file:: inc/adc_cali_scheme.inc
|
||||
@@ -0,0 +1,256 @@
|
||||
Analog to Digital Converter (ADC) Continuous Mode Driver
|
||||
========================================================
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The Analog to Digital Converter is an on-chip sensor which is able to measure analog signals from specific analog IO pads.
|
||||
|
||||
The ADC on {IDF_TARGET_NAME} can be used in scenario(s) like:
|
||||
|
||||
- Generate one-shot ADC conversion result
|
||||
- Generate continuous ADC conversion results
|
||||
|
||||
This guide will introduce ADC continuous mode conversion.
|
||||
|
||||
Driver Concepts
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
ADC continuous mode conversion is made up with multiple Conversion Frames.
|
||||
- Conversion Frame: One Conversion Frame contains multiple Conversion Results. Conversion Frame size is configured in :cpp:func:`adc_continuous_new_handle`, in bytes.
|
||||
- Conversion Result: One Conversion Result contains multiple bytes (see :c:macro:`SOC_ADC_DIGI_RESULT_BYTES`). Its structure is :cpp:type:`adc_digi_output_data_t`, including ADC unit, ADC channel and raw data.
|
||||
|
||||
.. image:: /../_static/diagrams/adc/adc_conversion_frame.png
|
||||
:scale: 100 %
|
||||
:align: center
|
||||
|
||||
Functional Overview
|
||||
-------------------
|
||||
|
||||
The following sections of this document cover the typical steps to install the ADC continuous mode driver, and read ADC conversion results from group of ADC channels continuously:
|
||||
|
||||
- `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to initialize the ADC continuous mode driver and how to deinitialize it.
|
||||
- `ADC Configurations <#adc-configurations>`__ - describes how to configure the ADC(s) to make it work under continuous mode.
|
||||
- `ADC Control <#adc-control>`__ - describes ADC control functions.
|
||||
- `Register Event Callbacks <#register-event-callbacks>`__ - describes how to hook user specific code to an ADC continuous mode event callback function.
|
||||
- `Read Conversion Result <#read-conversion-result>`__ - covers how to get ADC conversion result.
|
||||
- `Hardware Limitations <#hardware-limitations>`__ - describes the ADC related hardware limitations.
|
||||
- `Power Management <#power-management>`__ - covers power management related.
|
||||
- `IRAM Safe <#iram-safe>`__ - covers the IRAM safe functions.
|
||||
- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver.
|
||||
|
||||
|
||||
Resource Allocation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ADC continuous mode driver is implemented based on {IDF_TARGET_NAME} SAR ADC module. Different ESP targets might have different number of independent ADCs.
|
||||
|
||||
To create an ADC continuous mode driver handle, set up the required configuration structure :cpp:type:`adc_continuous_handle_cfg_t`:
|
||||
|
||||
- :cpp:member:`adc_continuous_handle_cfg_t::max_store_buf_size` set the maximum size (in bytes) of the pool that the driver saves ADC conversion result into. If this pool is full, new conversion results will be lost.
|
||||
- :cpp:member:`adc_continuous_handle_cfg_t::conv_frame_size` set the size of the ADC conversion frame, in bytes.
|
||||
|
||||
|
||||
After setting up above configurations for the ADC, call :cpp:func:`adc_continuous_new_handle` with the prepared :cpp:type:`adc_continuous_handle_cfg_t`. This function may fail due to various errors such as invalid argumemts, insufficient memory, etc.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the I2S0 peripheral is in use. See `Hardware Limitations <#hardware-limitations>`__ for more information.
|
||||
|
||||
.. only:: esp32s2
|
||||
|
||||
Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means the SPI3 peripheral is in use. See `Hardware Limitations <#hardware-limitations>`__ for more information.
|
||||
|
||||
.. only:: SOC_GDMA_SUPPORTED
|
||||
|
||||
Especially, when this function returns :c:macro:`ESP_ERR_NOT_FOUND`, this means there is no free GDMA channel.
|
||||
|
||||
If the ADC continuous mode driver is no longer used, you should deinitialize the driver by calling :cpp:func:`adc_continuous_deinit`.
|
||||
|
||||
|
||||
Initialize the ADC Continuous Mode Driver
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
adc_continuous_handle_cfg_t adc_config = {
|
||||
.max_store_buf_size = 1024,
|
||||
.conv_frame_size = 100,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config));
|
||||
|
||||
|
||||
Recycle the ADC Unit
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(adc_continuous_deinit());
|
||||
|
||||
|
||||
ADC Configurations
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
After the ADC continuous mode driver is initialized, set up the :cpp:type:`adc_continuous_config_t` to configure ADC IOs to measure analog signal:
|
||||
|
||||
- :cpp:member:`adc_continuous_config_t::pattern_num`, number of ADC channels that will be used.
|
||||
- :cpp:member:`adc_continuous_config_t::adc_pattern`, list of configs for each ADC channel that will be used, see below description.
|
||||
- :cpp:member:`adc_continuous_config_t::sample_freq_hz`, expected ADC sampling frequency in Hz.
|
||||
- :cpp:member:`adc_continuous_config_t::conv_mode`, continuous conversion mode.
|
||||
- :cpp:member:`adc_continuous_config_t::format`, conversion output format.
|
||||
|
||||
For :cpp:type:`adc_digi_pattern_config_t`:
|
||||
|
||||
- :cpp:member:`adc_digi_pattern_config_t::atten`, ADC attenuation. Refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__.
|
||||
- :cpp:member:`adc_digi_pattern_config_t::channel`, the IO corresponding ADC channel number. See below note.
|
||||
- :cpp:member:`adc_digi_pattern_config_t::unit`, the ADC that the IO is subordinate to.
|
||||
- :cpp:member:`adc_digi_pattern_config_t::bit_width`, the bitwidth of the raw conversion result.
|
||||
|
||||
.. note::
|
||||
|
||||
For the IO corresponding ADC channel number. Check `datasheet <{IDF_TARGET_TRM_EN_URL}>`__ to acquire the ADC IOs.
|
||||
On the other hand, :cpp:func:`adc_continuous_io_to_channel` and :cpp:func:`adc_continuous_channel_to_io` can be used to acquire the ADC channels and ADC IOs.
|
||||
|
||||
To make these settings take effect, call :cpp:func:`adc_continuous_config` with the configuration structure above.
|
||||
This API may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. When it returns :c:macro:`ESP_ERR_INVALID_STATE`, this means the ADC continuous mode driver is started, you shouldn't call this API at this moment.
|
||||
|
||||
See ADC continuous mode example :example:`peripherals/adc/continuous_read` to see configuration codes.
|
||||
|
||||
|
||||
ADC Control
|
||||
^^^^^^^^^^^
|
||||
|
||||
Start and Stop
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Calling :cpp:func:`adc_continuous_start` will make the ADC start to measure analog signals from the configured ADC channels, and generate the conversion results.
|
||||
On the contrary, calling :cpp:func:`adc_continuous_stop` will stop the ADC conversion.
|
||||
|
||||
.. code::c
|
||||
|
||||
ESP_ERROR_CHECK(adc_continuous_start());
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(adc_continuous_stop());
|
||||
|
||||
|
||||
Register Event Callbacks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
By calling :cpp:func:`adc_continuous_register_event_callbacks`, you can hook your own function to the driver ISR. Supported event callbacks are listed in :cpp:type:`adc_continuous_evt_cbs_t`
|
||||
- :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done`, this is invoked when one conversion frame finishes.
|
||||
- :cpp:member:`adc_continuous_evt_cbs_t::on_pool_ovf`, this is invoked when internal pool is full. Newer conversion results will be discarded.
|
||||
|
||||
As above callbacks are called in an ISR context, you should always ensure the callback function is suitable for an ISR context. Blocking logics should not appear in these callbacks. Callback function prototype is declared in :cpp:type:`adc_continuous_callback_t`.
|
||||
|
||||
You can also register your own context when calling :cpp:func:`adc_continuous_register_event_callbacks`, by the parameter ``user_data``. This user data will be passed to the callback functions directly.
|
||||
|
||||
This function may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`. Specially, when :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` is enabled, this error may indicate that the callback functions aren't in internal RAM. Check error log to know this. Besides, when it fails due to :c:macro:`ESP_ERR_INVALID_STATE`, this means the ADC continuous mode driver is started, you shouldn't add callback at this moment.
|
||||
|
||||
|
||||
Conversion Done Event
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The driver will fill in the event data of a :cpp:member:`adc_continuous_evt_cbs_t::on_conv_done` event. Event data contains a buffer pointer to a conversion frame buffer, together with the size. Refer to :cpp:type:`adc_continuous_evt_data_t` to know the event data structure.
|
||||
|
||||
.. note::
|
||||
|
||||
It is worth noting that, the data buffer :cpp:member:`adc_continuous_evt_data_t::conv_frame_buffer` is maintained by the driver itself. Therefore, never free this piece of memory.
|
||||
|
||||
.. note::
|
||||
|
||||
When the Kconfig option :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE` is enabled, the registered callbacks and the functions called by the callbacks should be placed in IRAM. The involved variables should be placed in internal RAM as well.
|
||||
|
||||
Pool Overflow Event
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ADC continuous mode driver has an internal pool to save the conversion results. When the pool is full, a pool overflow event will emerge. Under this condition, the driver won't fill in the event data. This usually happens the speed to read data from the pool (by calling :cpp:func:`adc_continuous_read`) is much slower than the ADC conversion speed.
|
||||
|
||||
|
||||
Read Conversion Result
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
After calling :cpp:func:`adc_continuous_start`, the ADC continuous conversion starts. Call :cpp:func:`adc_continuous_read` to get the conversion results of the ADC channels. You need to provide a buffer to get the raw results.
|
||||
|
||||
This function will try to read the expected length of conversion results each time.
|
||||
|
||||
- If the requested length isn't reached, the function will still move the data from the internal pool to the buffer you prepared. Therefore, check the `out_length` to know the actual size of conversion results.
|
||||
- If there is no conversion result generated in the internal pool, the function will block for `timeout_ms` until the conversion results are generated. If there is still no generated results, the function will return :c:macro:`ESP_ERR_TIMEOUT`.
|
||||
- If the generated results fill up the internal pool, new generated results will be lost. Next time when the :cpp:func:`adc_continuous_read` is called, this function will return :c:macro:`ESP_ERR_INVALID_STATE` indicating this situation.
|
||||
|
||||
This API aims to give you a chance to read all the ADC continuous conversion results.
|
||||
|
||||
The ADC conversion results read from above function are raw data. To calculate the voltage based on the ADC raw results, this formula can be used:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
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 <{IDF_TARGET_TRM_EN_URL}>`__.
|
||||
Dmax Maximum of the output ADC raw digital reading result, which is 2^bitwidth, where bitwidth is the :cpp:member::`adc_digi_pattern_config_t:bit_width` configured before.
|
||||
====== =============================================================
|
||||
|
||||
To do further calbration to convert the ADC raw result to voltage in mV, please refer to calibration doc :doc:`adc_calibration`.
|
||||
|
||||
|
||||
Hardware Limitations
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- A specific ADC unit can only work under one operating mode at any one time, either Continuous Mode or Oneshot Mode. :cpp:func:`adc_continuous_start` has provided the protection.
|
||||
|
||||
- Random Number Generator uses ADC as an input source. When ADC continuous mode driver works, the random number generated from RNG will be less random.
|
||||
|
||||
.. only:: esp32s2 or esp32c3 or esp32s3
|
||||
|
||||
- ADC2 is also used by the Wi-Fi. :cpp:func:`adc_continuous_start` has provided the protection between Wi-Fi driver and ADC continuous mode driver.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
- ADC continuous mode driver uses I2S0 peripheral as hardware DMA fifo. Therefore, if I2S0 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`.
|
||||
|
||||
- ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits.
|
||||
|
||||
- ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes.
|
||||
|
||||
.. only:: esp32s2
|
||||
|
||||
- ADC continuous mode driver uses SPI3 peripheral as hardware DMA fifo. Therefore, if SPI3 is in use already, the :cpp:func:`adc_continuous_new_handle` will return :c:macro:`ESP_ERR_NOT_FOUND`.
|
||||
|
||||
|
||||
Power Management
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
When power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the APB clock frequency may be adjusted when the system is in an idle state, thus potentially changing the behavior of ADC continuous conversion.
|
||||
|
||||
However, the continuous mode driver can prevent this change by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. The lock is acquired after the continuous conversion is started by :cpp:func:`adc_continuous_start`. Similarly, the lock will be released after :cpp:func:`adc_continuous_stop`. Therefore, :cpp:func:`adc_continuous_start` and :cpp:func:`adc_continuous_stop` should appear in pairs, otherwise the power management will be out of action.
|
||||
|
||||
|
||||
IRAM Safe
|
||||
^^^^^^^^^
|
||||
|
||||
All the ADC continuous mode driver APIs are not IRAM-safe. They are not supposed to be run when the Cache is disabled. By enabling the Kconfig option :ref:`CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE`, driver internal ISR handler is IRAM-safe, which means even when the Cache is disabled, the driver will still save the conversion results into its internal pool.
|
||||
|
||||
|
||||
Thread Safety
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
ADC continuous mode driver APIs are not guaranteed to be thread safe. However, the share hardware mutual exclusion is provided by the driver. See `Hardware Limitations <#hardware-limitations>`__ for more details.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
* ADC continuous mode example: :example:`peripherals/adc/continuous_read`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/adc_continuous.inc
|
||||
@@ -0,0 +1,210 @@
|
||||
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 {IDF_TARGET_NAME} can be used in scenario(s) like:
|
||||
|
||||
- Generate one-shot ADC conversion result
|
||||
|
||||
.. only:: SOC_ADC_DMA_SUPPORTED
|
||||
|
||||
- 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 <#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 <#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 <#read-conversion-result>`__ - covers how to get ADC conversion raw result.
|
||||
- `Hardware Limitations <#hardware-limitations>`__ - describes the ADC related hardware limitations.
|
||||
- `Power Management <#power-management>`__ - covers power management related.
|
||||
- `IRAM Safe <#iram-safe>`__ - describes tips on how to read ADC conversion raw result when cache is disabled.
|
||||
- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver.
|
||||
- `Kconfig Options <#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 {IDF_TARGET_NAME} 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 :cpp:type:`adc_oneshot_unit_handle_t`.
|
||||
|
||||
To install an ADC instance, set up the required initial configuration structure :cpp:type:`adc_oneshot_unit_init_cfg_t`:
|
||||
|
||||
- :cpp:member:`adc_oneshot_unit_init_cfg_t::unit_id` selects the ADC. Please refer to the `datasheet <{IDF_TARGET_TRM_EN_URL}>`__ to know dedicated analog IOs for this ADC.
|
||||
- :cpp:member:`adc_oneshot_unit_init_cfg_t::ulp_mode` sets if the ADC will be working under super low power mode.
|
||||
|
||||
.. todo::
|
||||
|
||||
Add ULP ADC related docs here.
|
||||
|
||||
After setting up the initial configurations for the ADC, call :cpp:func:`adc_oneshot_new_unit` with the prepared :cpp:type:`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 :c:macro:`ESP_ERR_NOT_FOUND` error. Number of available ADC(s) is recorded by :c:macro:`SOC_ADC_PERIPH_NUM`.
|
||||
|
||||
If a previously created ADC instance is no loger required, you should recycle the ADC instance by calling :cpp:func:`adc_oneshot_del_unit`, related hardware and software resources will be recycled as well.
|
||||
|
||||
|
||||
Create an ADC Unit Handle under Normal Oneshot Mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
adc_oneshot_unit_handle_t adc1_handle;
|
||||
adc_oneshot_unit_init_cfg_t init_config1 = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.ulp_mode = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
|
||||
|
||||
|
||||
Recycle the ADC Unit
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));
|
||||
|
||||
|
||||
Unit Configuration
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
After an ADC instance is created, set up the :cpp:type:`adc_oneshot_chan_cfg_t` to configure ADC IO to measure analog signal:
|
||||
|
||||
- :cpp:member:`adc_oneshot_chan_cfg_t::atten`, ADC attenuation. Refer to the On-Chip Sensor chapter in `TRM <{IDF_TARGET_TRM_EN_URL}>`__.
|
||||
- :cpp:member:`adc_oneshot_chan_cfg_t::channel`, the IO corresponding ADC channel number. See below note.
|
||||
- :cpp:member:`adc_oneshot_chan_cfg_t::bitwidth`, the bitwidth of the raw conversion result.
|
||||
|
||||
.. note::
|
||||
|
||||
For the IO corresponding ADC channel number. Check `datasheet <{IDF_TARGET_TRM_EN_URL}>`__ to know the ADC IOs.
|
||||
On the other hand, :cpp:func:`adc_continuous_io_to_channel` and :cpp:func:`adc_continuous_channel_to_io` can be used to know the ADC channels and ADC IOs.
|
||||
|
||||
To make these settings take effect, call :cpp:func:`adc_oneshot_config_channel` with above configuration structure. Especially, this :cpp:func:`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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
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 :cpp:func:`adc_oneshot_read` to get the conversion raw result of an ADC channel.
|
||||
|
||||
- :cpp:func:`adc_oneshot_read` is safer. ADC(s) are shared by some other drivers / peripherals, see `Hardware Limitations <#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 :c:macro:`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:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
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 <{IDF_TARGET_TRM_EN_URL}>`__.
|
||||
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 :doc:`adc_calibration`.
|
||||
|
||||
|
||||
Read Raw Result
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
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 :cpp:func:`adc_oneshot_read` works, the random number generated from RNG will be less random.
|
||||
|
||||
.. only:: SOC_ADC_DMA_SUPPORTED
|
||||
|
||||
- A specific ADC unit can only work under one operating mode at any one time, either Continuous Mode or Oneshot Mode. :cpp:func:`adc_oneshot_read` has provided the protection.
|
||||
|
||||
.. only:: esp32s2 or esp32c3 or esp32s3
|
||||
|
||||
- ADC2 is also used by the Wi-Fi. :cpp:func:`adc_oneshot_read` has provided the protection between Wi-Fi driver and ADC continuous mode driver.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
- ESP32 DevKitC: GPIO 0 cannot be used due to external auto program circuits.
|
||||
|
||||
- ESP-WROVER-KIT: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes.
|
||||
|
||||
|
||||
Power Management
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
When power management is enabled (i.e. :ref:`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 :cpp:func:`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
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
- :cpp:func:`adc_oneshot_new_unit`
|
||||
- :cpp:func:`adc_oneshot_config_channel`
|
||||
- :cpp:func:`adc_oneshot_read`
|
||||
|
||||
Above functions are guaranteed to be thread safe. Therefore, you can call them from different RTOS tasks without protection by extra locks.
|
||||
|
||||
- :cpp:func:`adc_oneshot_del_unit` is not thread safe. Besides, concurrently calling this function may result in thread-safe APIs fail.
|
||||
|
||||
|
||||
Kconfig Options
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
- :ref:`CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM` controls where to place the ADC fast read function (IRAM or Flash), see `IRAM Safe <#iram-safe>`__ for more details.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
* ADC oneshot mode example: :example:`peripherals/adc/oneshot_read`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/adc_types.inc
|
||||
.. include-build-file:: inc/adc_oneshot.inc
|
||||
@@ -6,7 +6,9 @@ Peripherals API
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
adc
|
||||
adc_oneshot
|
||||
:SOC_ADC_DMA_SUPPORTED: adc_continuous
|
||||
adc_calibration
|
||||
clk_tree
|
||||
:SOC_DAC_SUPPORTED: dac
|
||||
gpio
|
||||
@@ -38,4 +40,4 @@ Peripherals API
|
||||
:SOC_USB_OTG_SUPPORTED: usb_device
|
||||
:SOC_USB_OTG_SUPPORTED: usb_host
|
||||
|
||||
Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples.
|
||||
Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples.
|
||||
|
||||
Reference in New Issue
Block a user