此篇博客用来解读 ESP32 ADC 相关参数用法以及常见问题整理。
1 概述
通过查阅《ESP32 Datasheet》 与 ADC 编程指南 可了解到 ESP32 集成了 2 个 12-bit SAR ADC,共支持 18 个模拟通道输入。接下来将会一一解读 ADC 各项参数。
注:2 个模数转换器指的是 ADC1 和 ADC2,12 bit 即为 ADC 的最高精度 2^12 = 4096。精度可配置 12 位、11 位、10 位、9 位多种分辨率,参见 《ESP32 技术参考手册》 的第 583 页。
2 ADC 各项参数解读
2.1 ADC 精度
ESP32 ADC 的最高精度为 12 bit,即为 2^12 = 4096。对应程序如下:
adc_bits_width_t width = ADC_WIDTH_BIT_12;
typedef enum {
ADC_WIDTH_BIT_9 = 0, /*!< ADC capture width is 9Bit. Only ESP32 is supported. */
ADC_WIDTH_BIT_10 = 1, /*!< ADC capture width is 10Bit. Only ESP32 is supported. */
ADC_WIDTH_BIT_11 = 2, /*!< ADC capture width is 11Bit. Only ESP32 is supported. */
ADC_WIDTH_BIT_12 = 3, /*!< ADC capture width is 12Bit. Only ESP32 is supported. */
#if !CONFIG_IDF_TARGET_ESP32
ADC_WIDTH_BIT_13 = 4, /*!< ADC capture width is 13Bit. Only ESP32-S2 is supported. */
#endif
ADC_WIDTH_MAX,
} adc_bits_width_t;
注:精度可配置 12 位、11 位、10 位、9 位多种分辨率,参见 《ESP32 技术参考手册》 的第 583 页。
2.2 ADC 通道
ESP32 一共有 18 个通道,可测量来自 18 个管脚的模拟信号。分别为:
- ADC1:8 个通道,GPIO32~GPIO39
- ADC2:10 个通道,GPIO0、GPIO2、GPIO4、GPIO12-GPIO15、GPIO25-GPIO27
在使用过程中有以下三点需要注意:
- ADC1 的电源打开时,GPIO36 和 GPIO39 的数字输入会被拉低约 80 ns。使用 ADC1 的 Channel 0(GPIO36)和 Channel 3(GPIO39)时,不要将任何其他的东西接在这两个管脚上也不要改变他们的配置,否则可能会影响低频信号的测量值
- 由于 GPIO0、GPIO2、GPIO15 为 Strapping 管脚,因此不能自由使用
- Wi-Fi 驱动程序使用 ADC2。因此,只能在未启动 Wi-Fi 驱动程序时使用 ADC2。但 ADC2 可与 蓝牙同时使用
2.3 ADC 特性
通过查询 《ESP32 技术参考手册》,可以发现下图:
同时可以总结出以下特性:
- 采用 2 个 SAR ADC,可支持同时采样与转换
- 采用 5 个专用 ADC 控制器:RTC ADC1 CTRL、RTC ADC2 CTRL、DIG ADC1 CTRL、DIG ADC2 CTRL,及 PWDET CTRL。可支持不同应用场景(比如,高性能、低功耗,或功率检测和峰值检测)
- 支持 18 个模拟输入管脚
- 1 个内部电压 vdd33 通道、2 个 pa_pkdet 通道(ADC2 控制器支持)
- 可配置 12 位、11 位、10 位、9 位多种分辨率
- 支持 DMA(ADC1 控制器支持)
- 支持多通道扫描模式(2 个控制器支持)
- 支持 Deep-sleep 模式运行(2 个控制器支持)
- 支持 ULP 协处理器控制(2 个控制器支持)
5 个专用 ADC 控制器的具体使用范围如下:
同时 DNL 和 INL 也是较为关心的 ADC 特性,如下:
2.4 ADC 工作模式
ESP32 的 ADC 模式目前有以下两种:
- ADC 单次读取模式:适用于低频采样,采样频率要求 1 kHz
- ADC 连续(DMA)模式:适用于高频连续采样,以 mKz 为单位的频率,可参考 I2S_ADC_DAC 例程
2.5 ADC 衰减配置
通过配置 ADC 的衰减可以确定 ADC 的读数范围,同时 ADC 的衰减配置是按通道进行的,具体需要配置参数 adc_atten_t
,此衰减配置参数有 4 个等级,如下:
- ADC_ATTEN_DB_0 = 0:满量程电压 1100 mV
- ADC_ATTEN_DB_2_5 = 1:满量程电压 1500 mV
- ADC_ATTEN_DB_6 = 2:满量程电压 2200 mV
- ADC_ATTEN_DB_11 = 3:满量程电压 3900 mV
满量程电压也可以参考 ESP-IDF 里的这段注释,不同衰减等级的 ADC 推荐量程可以参考下图:
为了获得最大的测量精度,请使用这些推荐范围内的 ADC 测量电压。默认 ADC 满量程电压为 1100 mv,要读取更高的电压(最高为引脚的最大电压,通常为 3.3 V),则要求将该通道的 ADC 衰减参数设为 > 0dB 。在使用 11 dB 衰减参数时,最大测量电压受 VDD_A(模拟电源 2.3 V ∼ 3.6 V,由于 ESP32 供电一般是 3.3V ,即 VDD_A 最高也是 3.3V)的限制,而不是满量程电压。
注 :ADC 未连接任何信号的引脚的读数是随机的。
2.5 ADC 校准方式
ESP32 有以下三种校准方式:
-
两点校准:两点校准的 ADC 读数分别为 150 mv 和 850 mv ,这些值应由用户测量并刻录到 eFuse 的 BLOCK3 中
-
eFuse Vref 校准:代表真实的 ADC 参考电压,在工厂校准期间会测量此值并将其刻录到 eFuse BLOCK0 中,是默认使用的 ADC 校准方式
-
Default Vref 校准:在表征过程中提供的 ADC 参考电压。如果 “两点校准” 或 "eFuse Vref " 值不可用,将使用 Default Vref。对应的参数定义为
#define DEFAULT_VREF 1100
上述三种方式对应的结构体如下:
typedef enum {
ESP_ADC_CAL_VAL_EFUSE_VREF = 0, /**< Characterization based on reference voltage stored in eFuse*/
ESP_ADC_CAL_VAL_EFUSE_TP = 1, /**< Characterization based on Two Point values stored in eFuse*/
ESP_ADC_CAL_VAL_DEFAULT_VREF = 2, /**< Characterization based on default reference voltage*/
ESP_ADC_CAL_VAL_MAX
} esp_adc_cal_value_t;
3 ADC 常见问题整理
Q1. 使用 adc 例程,采集电压值发现采集低电压的时候误差会稍微偏大
[Ans] 默认的 ADC 电压是 0 db 衰减,为了获得最大的精度,请使用 ADC 校准 API 并测量这些建议范围内的电压(默认为 100 mV ~950 mV )。如下图,对于大电压的测量修改 ADC 的衰减配置参数,超过 3.3 V 的测量电压建议进行分压测量。请参考 ADC 的衰减配置参数 。
Q2. ADC1 的单通道采样频率是多大?
[Ans] ADC1 单通道的采样频率要求是 1KHz ,可参见 adc_digi_config_t 说明。
Q3. 如何擦除(修改)出厂刻录的 eFuse Vref 参考电压,而写入自定义的 “两点校准” 的参考电压?
[Ans] 芯片默认出厂烧录的 ADC eFuse_vref 无法擦除,但可以不使用,可在 menuconfig -> Component config -> ADC Calibration
配置选项中进行关闭,如下:
注:eFuse Vref ADC 参考电压和 “两点校准”的 ADC 参考电压可共存,若在 menuconfig 中将两种校准方式都开启,且 eFuse 中都写入了 eFuse Vref 和 “两点校准” 的 ADC 参考电压,以 “两点校准”的参考电压为准。
Q4. 如何写 “两点校准”值到 Efuse Block3 中?
[Ans] 可参考以下三篇文档:
来进行操作,举例:需要将 ADC 校准值写成二进制文件,然后烧录到 eFuse BLK3 的第 12 bytes,在终端输入以下指令即可:
espefuse.py -p /dev/ttyUSB0 burn_block_data --offset 12 BLK3 ADC_new2.bin
espefuse.py -p /dev/ttyUSB0 burn_efuse BLK3_PART_RESERVE 1
Q5. 修改 esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_12Bit, DEFAULT_VREF, adc_chars)
的参数 DEFAULT_VREF
发现 ADC 测量精度效果改善并不明显?
[Ans] DEFAULT_VREF
为表征过程中提供的 ADC 参考电压,默认是 1100 mV,不允许自定义修改。如果两点校准或 eFuse Vref 值不可用,将使用 Default Vref。ESP32 的出厂默认参考电压为 eFuse Vref ,存储在 eFuse 中,为 1100 mv
注:仅在 ESP32 中,如果无法使用 eFuse Vref 和 “两点校准”的值,则设置该参数作为参考电压有效。如果 eFuse 中没有刻录 eFuse_vref 或 在 menuconfig 中关闭了默认的 ADC 校准方式的情况下,可使用 Default Vref 。当 eFuse 中已经刻录 eFuse_vref 值时, 软件方式修改此参数并不能改变默认 ADC 参考电压值 。可参考 ADC 文档。
Q6. 是否可以修改 eFuse Vref 值来提升精度?或者有什么其他的方案可以提高 ADC 采集电压的精度吗?
[Ans] ADC 默认的最高采样精度为 12 bit , 即 2^12 =4096 ,无法做到更高的采样精度。可以尝试减小 ADC 采样误差来 “提升精度”,方法如下:
- 通过修改 esp_adc_cal_value_t 校准值的类型来修改 ADC 的参考电压
- 通过在 efuse 中刻录 ADC 的 Vref 为两点校准值来提高测量精度。可参见 Calibration Values
Q7. 当没有给 ADC 采集引脚电压的时候,默认会采集 284mV 的电压,实际检测输入端口只有几十 mv , 这个是否有解决方法呢?
[Ans] 当采集引脚没有给电压(或悬空)的时候,ADC 采集的值并不准确(会在 0 到 3.3 V 随机)。如果想避免这种随机值,可以进行上下拉。
Q8. 使用 0-1 V 的 ADC 输入电压时为什么在 0~200 mV 之间的 ADC 采集值都是 284 mV?
[Ans] ADC 默认使用的衰减参数是 0 dbm,建议的 ADC 测量电压范围是 100 mv~950 mV;在实际使用中,建议最低测量电压不低于 300 mV 。
Q9. ADC 的测量误差有多大?有效测量范围是?
[Ans] 默认情况下,芯片 ADC 之间的测量差异会有 ±6%。ESP-IDF 提供了对 ADC1 的多种 校准方法。使用 (默认的)eFuse Vref 参考值校准后的结果如下图所示。用户如需要更高的精度可选用其他方法自行校准。
Q10. 如何验证是否刻录 eFuse Vref 参考电压?
[Ans] 可通过 esptool 工具,使用如下命令进行查询:
espefuse.py --port /dev/ttyUSB0 adc_info
此时如果有 eFuse Vref ,则返回的结果如下:
ADC VRef calibration: 1093 mV
如果没有 eFuse Vref ,则返回的结果如下:
ADC VRef calibration: None (1100 mV nominal)
如果刻录的是两点校准参数,则返回的结果类似于:
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
在 ADC 单次读取的应用程序模式下,会先检查 eFuse 是否已经刻录 ADC 参考电压值。
Q11. ESP32 的 ADC DMA 模式的最高采样率是多大?
[Ans] ESP32 的 ADC DMA 模式只支持 Dig ADC (ADC 数字信号控制器),故 ADC DMA 只支持模拟信号转数字信号的应用。以 I2S_ADC_DAC 例程为例,所以 ADC DMA 模式的最高采样率取决于 I2S 的采样率 。