警告
This document is not updated for ESP32P4 yet, so some of the content may not be correct.
This warning was automatically inserted due to the source file being in the add_warnings_pages list.
模数转换器 (ADC) 连续转换模式驱动
简介
ESP32-P4 芯片集成了模数转换器 (ADC),支持测量特定模拟 IO 管脚的模拟信号。此外,ADC 还支持直接内存访问 (DMA) 功能,高效获取 ADC 转换结果。
ESP32-P4 具有 两 个 ADC 单元,可应用于以下场景:
生成单次 ADC 转换结果
生成连续 ADC 转换结果
本指南介绍了 ADC 连续转换模式。
ADC 连续转换模式驱动概念
ADC 连续转换模式驱动由多个转换帧组成。
转换帧:一个转换帧包含多个转换结果。转换帧大小以字节为单位,在
adc_continuous_new_handle()
中配置。转换结果:一个转换结果包含多个字节,即
SOC_ADC_DIGI_RESULT_BYTES
。转换结果的数据结构由adc_digi_output_data_t
定义,包括 ADC 单元、ADC 通道以及原始数据。
功能概述
下文将分节概述安装 ADC 连续转换模式驱动、并从一组 ADC 通道连续读取 ADC 转换结果的基本步骤:
资源分配:介绍初始化 ADC 连续转换模式驱动所需设置的参数,以及如何将驱动去初始化。
配置 ADC:介绍如何将 ADC 配置为在连续转换模式下工作。
ADC 控制:介绍 ADC 控制函数。
注册事件回调:介绍如何将特定用户代码链接到 ADC 连续转换模式事件回调函数。
读取转换结果:介绍如何获取 ADC 转换结果。
硬件限制:介绍与 ADC 相关的硬件限制。
电源管理:介绍电源管理的相关内容。
IRAM 安全:介绍与 IRAM 安全相关的函数。
线程安全:介绍由驱动程序认证为线程安全的 API。
资源分配
ADC 连续转换模式驱动基于 ESP32-P4 SAR ADC 模块实现,不同的 ESP 目标芯片可能拥有不同数量的独立 ADC。
请按照以下步骤设置配置结构体 adc_continuous_handle_cfg_t
,创建 ADC 连续转换模式驱动的句柄:
adc_continuous_handle_cfg_t::max_store_buf_size
:以字节为单位设置最大缓冲池的大小,驱动程序将 ADC 转换结果保存到该缓冲池中。缓冲池已满时,新的转换将丢失。adc_continuous_handle_cfg_t::conv_frame_size
:以字节为单位设置 ADC 转换帧大小。adc_continuous_handle_cfg_t::flags
:设置可以改变驱动程序行为的标志。flush_pool
:缓冲池满时自动清空缓冲池。
完成以上 ADC 配置后,使用已设置的配置结构体 adc_continuous_handle_cfg_t
调用 adc_continuous_new_handle()
。该函数可能将在特定情况下返回错误值,如无效参数、内存不足等。
函数返回 ESP_ERR_NOT_FOUND
时,表明 GDMA 空闲通道不足。
如果不再使用 ADC 连续转换模式驱动,请调用 adc_continuous_deinit()
将驱动去初始化。
初始化 ADC 连续转换模式驱动
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));
回收 ADC 单元
ESP_ERROR_CHECK(adc_continuous_deinit());
配置 ADC
初始化 ADC 连续转换模式驱动后,设置 adc_continuous_config_t
配置 ADC IO,测量模拟信号:
adc_continuous_config_t::pattern_num
:要使用的 ADC 通道数量。adc_continuous_config_t::adc_pattern
:每个要使用的 ADC 通道的配置列表,请参阅下文描述。adc_continuous_config_t::sample_freq_hz
:期望的 ADC 采样频率,单位为 Hz。adc_continuous_config_t::format
:转换模式结果的输出格式。
按照以下步骤设置 adc_digi_pattern_config_t
:
adc_digi_pattern_config_t::atten
:ADC 衰减。请参阅 技术参考手册 中的片上传感器与模拟信号处理章节。adc_digi_pattern_config_t::channel
:IO 对应的 ADC 通道号,请参阅下文注意事项。adc_digi_pattern_config_t::unit
:IO 所属的 ADC 单元。adc_digi_pattern_config_t::bit_width
:原始转换结果的位宽。
备注
对于 IO 对应的 ADC 通道号,请参阅 技术参考手册 获取 ADC IO 管脚的详细信息。另外,可以使用 adc_continuous_io_to_channel()
和 adc_continuous_channel_to_io()
获取 ADC 通道和 ADC IO 的对应关系。
为使这些设置生效,请使用上述配置结构体,调用 adc_continuous_config()
。此 API 可能由于 ESP_ERR_INVALID_ARG
等原因返回错误。当它返回 ESP_ERR_INVALID_STATE
时,意味着 ADC 连续转换模式驱动已经启动,此时不应调用此 API。
请参考 ADC 连续转换模式示例 peripherals/adc/continuous_read,查看相应配置代码。
ADC 控制
启动和停止
调用 adc_continuous_start()
,将使 ADC 开始从配置好的 ADC 通道测量模拟信号,并生成转换结果。
相反,调用 adc_continuous_stop()
则会停止 ADC 转换。
ESP_ERROR_CHECK(adc_continuous_stop());
注册事件回调
调用 adc_continuous_register_event_callbacks()
,可以将自己的函数链接到驱动程序的 ISR 中。通过 adc_continuous_evt_cbs_t
可查看所有支持的事件回调。
adc_continuous_evt_cbs_t::on_conv_done
:当一个转换帧完成时,触发此事件。adc_continuous_evt_cbs_t::on_pool_ovf
:当内部缓冲池已满时,触发此事件,新的转换结果将丢失。
由于上述回调函数在 ISR 中调用,请确保回调函数适合在 ISR 上下文中运行,且这些回调不应涉及阻塞逻辑。回调函数的原型在 adc_continuous_callback_t
中声明。
在调用 adc_continuous_register_event_callbacks()
时,还可以通过参数 user_data
注册自己的上下文,该用户数据将直接传递给回调函数。
此回调函数可能由于 ESP_ERR_INVALID_ARG
等原因返回错误。启用 CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE 时,如果回调函数失败并报错,可能是因为回调函数不在内部 RAM 中,请查看错误日志了解详情。此外,如果回调函数出现 ESP_ERR_INVALID_STATE
错误,表明 ADC 连续转换模式驱动已经启动,此时不应添加回调。
转换完成事件
当驱动程序完成一次转换后,会触发 adc_continuous_evt_cbs_t::on_conv_done
事件,并填充事件数据。事件数据包含一个指向转换帧缓冲区的指针,以及转换帧缓冲区大小。要了解事件数据结构,请参阅 adc_continuous_evt_data_t
。
备注
注意,数据缓冲区 adc_continuous_evt_data_t::conv_frame_buffer
由驱动程序本身维护,请勿释放此内存。
备注
启用 Kconfig 选项 CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE 时,注册的回调函数以及回调函数中调用的函数应放置在 IRAM 中,涉及的变量也应放置在内部 RAM 中。
缓冲池溢出事件
ADC 连续转换模式驱动使用内部缓冲池保存转换结果,缓冲池满时将发生缓冲池溢出事件。此时,驱动程序不会继续填充事件数据。缓冲池溢出通常是因为调用 adc_continuous_read()
从池中读取数据的速度远低于 ADC 转换的速度。
读取转换结果
调用 adc_continuous_start()
启动 ADC 连续转换,调用 adc_continuous_read()
可以获取 ADC 通道的转换结果。注意提供缓冲区,获取原始结果。
函数 adc_continuous_read()
每次都会尝试以期望长度读取转换结果。
调用
adc_continuous_read()
可以请求读取指定长度的转换结果。但有时实际可用的转换结果可能少于请求长度,此时,函数仍会将数据从内部池移动到你提供的缓冲区中。因此,请查看out_length
的值,了解实际移动到缓冲区中的转换结果数量。如果内部池中没有生成转换结果,函数将会阻塞一段时间,即
timeout_ms
,直到转换结果生成。如果始终没有转换结果生成,函数将返回ESP_ERR_TIMEOUT
。如果 ADC 连续转换生成的结果填满了内部池,新产生的结果将丢失。下次调用
adc_continuous_read()
时,将返回ESP_ERR_INVALID_STATE
,提示此情况发生。
此 API 提供了一个读取所有 ADC 连续转换结果的机会。
从上述函数读取的 ADC 转换结果为原始数据。要根据 ADC 原始结果计算电压,可以使用以下公式:
Vout = Dout * Vmax / Dmax (1)
其中:
Vout |
数据输出结果,代表电压。 |
---|---|
Dout |
ADC 原始数据读取结果。 |
Vmax |
可测量的最大模拟输入电压,与 ADC 衰减相关,请参考 技术参考手册 中的片上传感器与模拟信号处理章节。 |
Dmax |
输出 ADC 原始数据读取结果的最大值,即 2^位宽,位宽即之前配置的 |
若需进一步校准,将 ADC 原始结果转换为以 mV 为单位的电压数据,请参考 模数转换器 (ADC) 校准驱动程序。
硬件限制
一个 ADC 单元一次只能运行一种操作模式,即连续模式或单次模式。
adc_continuous_start()
提供了保护措施。随机数生成器 (RNG) 以 ADC 为输入源。使用 ADC 连续转换模式驱动从 RNG 生成随机数时,随机性会减弱。
电源管理
启用电源管理,即启用 CONFIG_PM_ENABLE 时,系统在空闲状态下,可能会调整 APB 时钟频率,这可能会改变 ADC 连续转换的行为。
然而,通过获取类型为 ESP_PM_APB_FREQ_MAX
的电源管理锁,ADC 连续转换模式驱动可以阻止这种改变。调用 adc_continuous_start()
启动连续转换后即可获取该锁。同样,调用 adc_continuous_stop()
停止转换后将释放该锁。因此,必须确保 adc_continuous_start()
和 adc_continuous_stop()
成对出现,否则电源管理将失效。
IRAM 安全
ADC 连续转换模式驱动的所有 API 均非 IRAM 安全。禁用 cache 时,不应运行这类 API。启用 Kconfig 选项 CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE 可确保驱动的内部 ISR 处理程序为 IRAM 安全,此时即使禁用 cache,驱动仍然会将转换结果保存到其内部缓冲池中。
线程安全
ADC 连续转换模式驱动的 API 不一定线程安全,但驱动程序提供了共享硬件互斥,详情请参阅 硬件限制。
应用示例
ADC 连续转换模式示例:peripherals/adc/continuous_read。
API 参考
Header File
This header file can be included with:
#include "esp_adc/adc_continuous.h"
This header file is a part of the API provided by the
esp_adc
component. To declare that your component depends onesp_adc
, add the following to your CMakeLists.txt:REQUIRES esp_adc
or
PRIV_REQUIRES esp_adc
Functions
-
esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_config, adc_continuous_handle_t *ret_handle)
Initialize ADC continuous driver and get a handle to it.
- 参数
hdl_config -- [in] Pointer to ADC initialization config. Refer to
adc_continuous_handle_cfg_t
.ret_handle -- [out] ADC continuous mode driver handle
- 返回
ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
ESP_ERR_NO_MEM If out of memory
ESP_OK On success
-
esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_continuous_config_t *config)
Set ADC continuous mode required configurations.
- 参数
handle -- [in] ADC continuous mode driver handle
config -- [in] Refer to
adc_digi_config_t
.
- 返回
ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
ESP_ERR_INVALID_ARG: If the combination of arguments is invalid.
ESP_OK: On success
-
esp_err_t adc_continuous_register_event_callbacks(adc_continuous_handle_t handle, const adc_continuous_evt_cbs_t *cbs, void *user_data)
Register callbacks.
备注
User can deregister a previously registered callback by calling this function and setting the to-be-deregistered callback member in the
cbs
structure to NULL.备注
When CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. Involved variables (including
user_data
) should be in internal RAM as well.备注
You should only call this API when the ADC continuous mode driver isn't started. Check return value to know this.
- 参数
handle -- [in] ADC continuous mode driver handle
cbs -- [in] Group of callback functions
user_data -- [in] User data, which will be delivered to the callback functions directly
- 返回
ESP_OK: On success
ESP_ERR_INVALID_ARG: Invalid arguments
ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
-
esp_err_t adc_continuous_start(adc_continuous_handle_t handle)
Start the ADC under continuous mode. After this, the hardware starts working.
- 参数
handle -- [in] ADC continuous mode driver handle
- 返回
ESP_ERR_INVALID_STATE Driver state is invalid.
ESP_OK On success
-
esp_err_t adc_continuous_read(adc_continuous_handle_t handle, uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms)
Read bytes from ADC under continuous mode.
- 参数
handle -- [in] ADC continuous mode driver handle
buf -- [out] Conversion result buffer to read from ADC. Suggest convert to
adc_digi_output_data_t
forADC Conversion Results
. See the subsectionDriver Backgrounds
in this header file to learn about this concept.length_max -- [in] Expected length of the Conversion Results read from the ADC, in bytes.
out_length -- [out] Real length of the Conversion Results read from the ADC via this API, in bytes.
timeout_ms -- [in] Time to wait for data via this API, in millisecond.
- 返回
ESP_ERR_INVALID_STATE Driver state is invalid. Usually it means the ADC sampling rate is faster than the task processing rate.
ESP_ERR_TIMEOUT Operation timed out
ESP_OK On success
-
esp_err_t adc_continuous_stop(adc_continuous_handle_t handle)
Stop the ADC. After this, the hardware stops working.
- 参数
handle -- [in] ADC continuous mode driver handle
- 返回
ESP_ERR_INVALID_STATE Driver state is invalid.
ESP_OK On success
-
esp_err_t adc_continuous_deinit(adc_continuous_handle_t handle)
Deinitialize the ADC continuous driver.
- 参数
handle -- [in] ADC continuous mode driver handle
- 返回
ESP_ERR_INVALID_STATE Driver state is invalid.
ESP_OK On success
-
esp_err_t adc_continuous_flush_pool(adc_continuous_handle_t handle)
Flush the driver internal pool.
备注
This API is not supposed to be called in an ISR context
- 参数
handle -- [in] ADC continuous mode driver handle
- 返回
ESP_ERR_INVALID_STATE Driver state is invalid, you should call this API when it's in init state
ESP_ERR_INVALID_ARG: Invalid arguments
ESP_OK On success
-
esp_err_t adc_continuous_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_continuous_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
Structures
-
struct adc_continuous_handle_cfg_t
ADC continuous mode driver initial configurations.
Public Members
-
uint32_t max_store_buf_size
Max length of the conversion results that driver can store, in bytes.
-
uint32_t conv_frame_size
Conversion frame size, in bytes. This should be in multiples of
SOC_ADC_DIGI_DATA_BYTES_PER_CONV
.
-
uint32_t flush_pool
Flush the internal pool when the pool is full.
-
struct adc_continuous_handle_cfg_t::[anonymous] flags
Driver flags.
-
uint32_t max_store_buf_size
-
struct adc_continuous_config_t
ADC continuous mode driver configurations.
Public Members
-
uint32_t pattern_num
Number of ADC channels that will be used.
-
adc_digi_pattern_config_t *adc_pattern
List of configs for each ADC channel that will be used.
-
uint32_t sample_freq_hz
The expected ADC sampling frequency in Hz. Please refer to
soc/soc_caps.h
to know available sampling frequency range
-
adc_digi_convert_mode_t conv_mode
ADC DMA conversion mode, see
adc_digi_convert_mode_t
.
-
adc_digi_output_format_t format
ADC DMA conversion output format, see
adc_digi_output_format_t
.
-
uint32_t pattern_num
-
struct adc_continuous_evt_data_t
Event data structure.
备注
The
conv_frame_buffer
is maintained by the driver itself, so never free this piece of memory.
-
struct adc_continuous_evt_cbs_t
Group of ADC continuous mode callbacks.
备注
These callbacks are all running in an ISR environment.
备注
When CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. Involved variables should be in internal RAM as well.
Public Members
-
adc_continuous_callback_t on_conv_done
Event callback, invoked when one conversion frame is done. See the subsection
Driver Backgrounds
in this header file to learn about theconversion frame
concept.
-
adc_continuous_callback_t on_pool_ovf
Event callback, invoked when the internal pool is full.
-
adc_continuous_callback_t on_conv_done
Macros
-
ADC_MAX_DELAY
ADC read max timeout value, it may make the
adc_continuous_read
block forever if the OS supports.
Type Definitions
-
typedef struct adc_continuous_ctx_t *adc_continuous_handle_t
Type of adc continuous mode driver handle.
-
typedef bool (*adc_continuous_callback_t)(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
Prototype of ADC continuous mode event callback.
- Param handle
[in] ADC continuous mode driver handle
- Param edata
[in] Pointer to ADC continuous mode event data
- Param user_data
[in] User registered context, registered when in
adc_continuous_register_event_callbacks()
- Return
Whether a high priority task is woken up by this function