模数转换器 (ADC) 单次转换模式驱动

[English]

简介

本文档介绍了 ESP32-S2 上的 ADC 单次转换模式驱动。

单次转换模式允许在选定的模拟输入通道上执行按需单次 ADC 转换。该模式适用于需要低频采样或触发采样的应用场景,而非持续的数据采集。

如需执行连续数据采集,ESP32-S2 提供了 ADC 连续转换模式驱动

功能概述

下文将分节概述安装和运行 ADC 的基本步骤:

  • 资源分配 - 介绍获取 ADC 句柄所需设置的参数,以及如何在 ADC 完成工作后回收资源。

  • 配置 ADC 单元实例 - 介绍配置 ADC 单元所需设置的参数,用于获取 ADC 转换的原始结果。

  • 读取转换结果 - 介绍如何获取 ADC 转换的原始结果。

  • 硬件限制 - 介绍与 ADC 相关的硬件限制。

  • 电源管理 - 介绍电源管理的相关内容。

  • IRAM 安全 - 介绍在禁用 cache 时,如何读取 ADC 转换的原始结果。

  • 线程安全 - 介绍由驱动程序认证为线程安全的 API。

  • Kconfig 选项 - 介绍支持的 Kconfig 选项,不同选项对驱动程序的操作会产生不同影响。

资源分配

ADC 单次转换模式驱动基于 ESP32-S2 SAR ADC 模块实现,不同的 ESP 芯片可能拥有不同数量的独立 ADC。对于单次转换模式驱动而言,ADC 实例以 adc_oneshot_unit_handle_t 表示。

请设置所需的初始配置结构体 adc_oneshot_unit_init_cfg_t 安装 ADC 实例,具体如下:

完成 ADC 初始配置后,使用已设置的初始配置结构体 adc_oneshot_unit_init_cfg_t 调用 adc_oneshot_new_unit()。如果分配成功,该函数将返回 ADC 单元实例句柄。

该函数可能因参数无效、内存不足等原因返回错误代码。比如,当要分配的 ADC 实例已经注册时,该函数会返回 ESP_ERR_NOT_FOUND 错误。可用 ADC 数量可通过 SOC_ADC_PERIPH_NUM 查看。

如果不再需要先前创建的 ADC 单元实例,请调用 adc_oneshot_del_unit() 回收该实例,相关的硬件和软件资源也会回收。

在普通单次转换模式下创建 ADC 单元实例句柄

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));

回收 ADC 单元实例

ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));

配置 ADC 单元实例

创建 ADC 单元实例后,请设置 adc_oneshot_chan_cfg_t 配置 ADC IO 以测量模拟信号,具体如下:

备注

ADC IO 及其对应的 ADC 通道编号,请参阅 技术规格书

此外,可以使用 adc_continuous_io_to_channel()adc_continuous_channel_to_io() 了解 ADC 通道和 ADC IO。

为使以上设置生效,请使用上述配置结构体调用 adc_oneshot_config_channel(),并指定要配置的 ADC 通道。函数 adc_oneshot_config_channel() 支持多次调用,以配置不同的 ADC 通道。驱动程序将在内部保存每个通道的配置。

配置两个 ADC 通道

adc_oneshot_chan_cfg_t config = {
    .bitwidth = ADC_BITWIDTH_DEFAULT,
    .atten = ADC_ATTEN_DB_12,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN0, &config));
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN1, &config));

读取转换结果

完成上述配置后,ADC 即可测量来自配置好的 ADC 通道的模拟信号。调用 adc_oneshot_read() 可以获取 ADC 通道的原始转换结果。

  • adc_oneshot_read() 可安全使用。ADC 由其他驱动程序/外设共享,请参阅 硬件限制。函数 adc_oneshot_read() 使用互斥锁,避免与其他函数同时使用硬件,因此该函数不应在 ISR 上下文中使用。当 ADC 由其他驱动程序/外设占用时,该函数可能出错,并返回 ESP_ERR_TIMEOUT 错误。此时,ADC 原始结果无效。

该函数可能因参数无效而调用失败。

通过该函数获取的 ADC 转换结果为原始数据。可以使用以下公式,根据 ADC 原始结果计算电压:

Vout = Dout * Vmax / Dmax       (1)

其中:

Vout

数字输出结果,代表电压。

Dout

ADC 原始数字读取结果。

Vmax

可测量的最大模拟输入电压,与 ADC 衰减相关,请参考 技术参考手册 > 片上传感器与模拟信号处理

Dmax

输出 ADC 原始数字读取结果的最大值,即 2^位宽,位宽即之前配置的 adc_oneshot_chan_cfg_t::bitwidth

若需进一步校准,将 ADC 原始结果转换为以 mV 为单位的电压数据,请参考校准文档 模数转换器 (ADC) 校准驱动程序

读取原始结果

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]);

硬件限制

  • 随机数生成器 (RNG) 以 ADC 为输入源。使用 ADC 单次转换模式驱动从 RNG 生成随机数时,随机性会减弱。

  • 一个 ADC 单元每次只能在一种操作模式下运行,可以是连续模式或单次模式。adc_oneshot_start() 提供了保护措施。

  • Wi-Fi 也使用 ADC2,adc_oneshot_read() 提供了 Wi-Fi 驱动与 ADC 单次转换模式驱动间的保护。

电源管理

启用电源管理,即启用 CONFIG_PM_ENABLE 时,系统在空闲状态下可能会调整系统时钟频率。然而,ADC 单次转换模式驱动以轮询例程运行,adc_oneshot_read() 会不断检查 CPU 是否完成读取,直到函数返回。在此期间,ADC 单次转换模式驱动程序所在的任务不会受阻塞。因此,在读取时时钟频率保持稳定。

IRAM 安全

flash 写入/擦除、OTA 等原因都可能导致 cache 禁用,此时,默认不应运行任何 ADC 单次转换模式驱动 API。如果在禁用 cache 时执行了 ADC 单次转换模式驱动 API,可能会出现类似 Illegal InstructionLoad/Store Prohibited 的错误。

线程安全

上述函数均为线程安全,使用时,可以直接从不同的 RTOS 任务中调用以上函数,无需额外锁保护。

Kconfig 选项

应用示例

  • peripherals/adc/oneshot_read 演示了如何使用 ADC 单次模式驱动程序从 GPIO 管脚获取单次 ADC 数值,并展示了如何使用 ADC 校准功能在 ESP32-S2 上获得校准后的结果,单位为毫伏。

API 参考

Header File

  • components/esp_adc/include/esp_adc/adc_oneshot.h

  • This header file can be included with:

    #include "esp_adc/adc_oneshot.h"
    
  • This header file is a part of the API provided by the esp_adc component. To declare that your component depends on esp_adc, add the following to your CMakeLists.txt:

    REQUIRES esp_adc
    

    or

    PRIV_REQUIRES esp_adc
    

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_FAIL: Clock source isn't initialised correctly

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 *const unit_id, adc_channel_t *const 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 *const 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

esp_err_t adc_oneshot_get_calibrated_result(adc_oneshot_unit_handle_t handle, adc_cali_handle_t cali_handle, adc_channel_t chan, int *cali_result)

Convenience function to get ADC calibrated result.

This is an all-in-one function which does:

  • oneshot read ADC raw result

  • calibrate the raw result and convert it into calibrated result (in mV)

参数:
  • handle -- [in] ADC oneshot handle, you should call adc_oneshot_new_unit() to get this handle

  • cali_handle -- [in] ADC calibration handle, you should call adc_cali_create_scheme_x() in adc_cali_scheme.h to create a handle

  • chan -- [in] ADC channel

  • cali_result -- [out] Calibrated ADC result (in mV)

返回:

  • ESP_OK Other return errors from adc_oneshot_read() and adc_cali_raw_to_voltage()

Structures

struct adc_oneshot_unit_init_cfg_t

ADC oneshot driver initial configurations.

Public Members

adc_unit_t unit_id

ADC unit.

adc_oneshot_clk_src_t clk_src

Clock source.

adc_ulp_mode_t ulp_mode

ADC controlled by ULP, see adc_ulp_mode_t

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.

Type Definitions

typedef struct adc_oneshot_unit_ctx_t *adc_oneshot_unit_handle_t

Type of ADC unit handle for oneshot mode.


此文档对您有帮助吗?